From 19340e100926fb8671ca914052a0aa8368298ebf Mon Sep 17 00:00:00 2001 From: Tu Nguyen Date: Thu, 12 Sep 2024 11:00:59 +0700 Subject: [PATCH 1/5] busload, bus state, circle time, bitrate support --- Cargo.toml | 1 + src/event_handler/can_handler.rs | 41 ++++++++++++++++++++++++++++-- src/event_handler/dbc_file.rs | 4 +++ src/event_handler/packet_filter.rs | 2 ++ src/main.rs | 1 + ui/app.slint | 6 +++++ ui/messages.slint | 30 ++++++++++++++++------ ui/view_page.slint | 28 ++++++++++++++++++++ 8 files changed, 103 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2f96c2e..4b3a145 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" description = "view real-time CAN packages" [dependencies] +chrono = "0.4.38" can-dbc = { git="https://github.com/TuEmb/can-dbc.git", branch="dev" } rfd = "0.14.1" slint = { version = "1.7.1", default-features = false, features = ["backend-winit", "compat-1-2", "renderer-winit-femtovg"] } diff --git a/src/event_handler/can_handler.rs b/src/event_handler/can_handler.rs index 6f60e6b..8c899bd 100644 --- a/src/event_handler/can_handler.rs +++ b/src/event_handler/can_handler.rs @@ -1,8 +1,10 @@ use can_dbc::DBC; +use chrono::Utc; #[cfg(target_os = "windows")] use pcan_basic::socket::usb::UsbCanSocket; use slint::{Model, VecModel, Weak}; use slint::{ModelRc, SharedString}; +use socketcan::CanInterface; #[cfg(target_os = "linux")] use socketcan::{CanSocket, EmbeddedFrame, Frame, Socket}; use std::collections::HashMap; @@ -12,6 +14,7 @@ use std::sync::mpsc::Receiver; use std::sync::{Arc, Mutex}; use std::thread::sleep; use std::time::Duration; +use std::time::Instant; use crate::slint_generatedAppWindow::AppWindow; use crate::slint_generatedAppWindow::CanData; @@ -23,6 +26,7 @@ pub struct CanHandler<'a> { pub iface: UsbCanSocket, pub ui_handle: &'a Weak, pub mspc_rx: &'a Arc>>, + pub bitrate: u32, } static mut NEW_DBC_CHECK: bool = false; @@ -34,7 +38,9 @@ impl<'a> CanHandler<'a> { #[cfg(target_os = "linux")] { let can_socket = self.open_can_socket(); - self.process_ui_events(dbc, can_socket); + let can_if = CanInterface::open(self.iface).unwrap(); + let _ = can_if.set_bitrate(self.bitrate, 700); + self.process_ui_events(dbc, can_socket, can_if); } #[cfg(target_os = "windows")] self.process_ui_events(dbc); @@ -60,8 +66,27 @@ impl<'a> CanHandler<'a> { } } #[cfg(target_os = "linux")] - fn process_ui_events(&self, dbc: DBC, can_socket: CanSocket) { + fn process_ui_events(&self, dbc: DBC, can_socket: CanSocket, can_if: CanInterface) { + let mut start_bus_load = Instant::now(); + let mut total_bits = 0; loop { + let bus_state = match can_if.state().unwrap().unwrap() { + socketcan::nl::CanState::ErrorActive => "ERR_ACTIVE", + socketcan::nl::CanState::ErrorWarning => "ERR_WARNING", + socketcan::nl::CanState::ErrorPassive => "ERR_PASSIVE", + socketcan::nl::CanState::BusOff => "BUSOFF", + socketcan::nl::CanState::Stopped => "STOPPED", + socketcan::nl::CanState::Sleeping => "SLEEPING", + }; + let bitrate = can_if.bit_rate().unwrap().unwrap(); + let busload = if start_bus_load.elapsed() >= Duration::from_millis(1000) { + start_bus_load = Instant::now(); + let bus_load = (total_bits as f64 / bitrate as f64) * 100.0; + total_bits = 0; + bus_load + } else { + 0.0 + }; let _ = self.ui_handle.upgrade_in_event_loop(move |ui| unsafe { if ui.get_is_new_dbc() { if ui.get_is_first_open() { @@ -71,6 +96,11 @@ impl<'a> CanHandler<'a> { } ui.set_is_new_dbc(false); } + ui.set_state(bus_state.into()); + ui.set_bitrate(bitrate as i32); + if busload > 0.0 { + ui.set_bus_load(busload as i32); + } }); unsafe { if NEW_DBC_CHECK { @@ -79,6 +109,7 @@ impl<'a> CanHandler<'a> { } } if let Ok(frame) = can_socket.read_frame() { + total_bits += (frame.len() + 6) * 8; // Data length + overhead (approximation) let frame_id = frame.raw_id() & !0x80000000; for message in dbc.messages() { if frame_id == (message.message_id().raw() & !0x80000000) { @@ -163,7 +194,11 @@ impl<'a> CanHandler<'a> { ) { for (message_count, message) in messages.iter().enumerate() { if message.can_id == format!("{:08X}", frame_id) { + let now = Utc::now().timestamp_micros(); + let can_data = messages.row_data(message_count).unwrap(); let can_signals = Self::create_can_signals(&message, &signal_data); + let circle_time = + (now - (can_data.time_stamp).parse::().unwrap()) as f32 / 1000.0; messages.set_row_data( message_count, CanData { @@ -177,6 +212,8 @@ impl<'a> CanHandler<'a> { } else { ODD_COLOR }, + circle_time: format!("{:.02} ms", circle_time).into(), + time_stamp: now.to_string().into(), }, ); break; diff --git a/src/event_handler/dbc_file.rs b/src/event_handler/dbc_file.rs index 691fe3d..d68e025 100644 --- a/src/event_handler/dbc_file.rs +++ b/src/event_handler/dbc_file.rs @@ -39,6 +39,8 @@ impl<'a> DBCFile<'a> { counter: 0, raw_can: SharedString::from("default"), color: ODD_COLOR, + circle_time: "0.0".into(), + time_stamp: "0".into(), }] .to_vec(), )); @@ -83,6 +85,8 @@ impl<'a> DBCFile<'a> { } else { ODD_COLOR }, + circle_time: "0.0".into(), + time_stamp: "0".into(), }; if message_count == 0 { diff --git a/src/event_handler/packet_filter.rs b/src/event_handler/packet_filter.rs index 29d930b..3ce5842 100644 --- a/src/event_handler/packet_filter.rs +++ b/src/event_handler/packet_filter.rs @@ -29,6 +29,8 @@ impl<'a> PacketFilter<'a> { packet_name: self.filter.packet_name, raw_can: self.filter.raw_can, signal_value: self.filter.signal_value, + circle_time: "0.0".into(), + time_stamp: "0".into(), }); } else { // Remove filter ID diff --git a/src/main.rs b/src/main.rs index caf75cb..33e8b10 100644 --- a/src/main.rs +++ b/src/main.rs @@ -209,6 +209,7 @@ async fn main() -> io::Result<()> { iface: &can_if, ui_handle: &ui_handle, mspc_rx: &rx, + bitrate: 250000, }; loop { can_handler.process_can_messages(); diff --git a/ui/app.slint b/ui/app.slint index ebd77b7..d97a15f 100644 --- a/ui/app.slint +++ b/ui/app.slint @@ -17,6 +17,9 @@ export component AppWindow inherits Window { in property can_sockets; in property <[CanData]> messages; in property <[CanData]> filter_messages; + in-out property state; + in-out property bus_load; + in-out property bitrate; in-out property active-page: 0; @@ -96,6 +99,9 @@ export component AppWindow inherits Window { } if root.active-page == 0: viewPage { + state: state; + bitrate: bitrate; + bus_load: bus_load; page-num: 0; is_filter: root.is_filter; messages: root.messages; diff --git a/ui/messages.slint b/ui/messages.slint index 3060c21..61f3c4c 100644 --- a/ui/messages.slint +++ b/ui/messages.slint @@ -12,6 +12,8 @@ export struct CanData { packet_name: string, raw_can: string, counter: int, + time_stamp: string, + circle_time: string, signal_value: [CanSignal], color: color } @@ -21,15 +23,16 @@ export component CanMessage inherits VerticalLayout { in property raw_data: "0x01 0x02 0x03 0x04"; in property message_name: "packet_xxx"; in property counter: 0; + in property circle_time: 0; in property back_ground; in property <[CanSignal]> signals: [ - {signal_name: "signal_1", signal_value: "100", unit: "Hz", factor: "1.0"}, - {signal_name: "signal_2", signal_value: "999", unit: "Km", factor: "1.0"}, - {signal_name: "signal_3", signal_value: "203", unit: "second", factor: "1.0"}, - {signal_name: "signal_4", signal_value: "15.6", unit: "mWh", factor: "1.0"}, - {signal_name: "signal_5", signal_value: "20.9", unit: "A", factor: "1.0"}, - {signal_name: "signal_6", signal_value: "10", unit: "Volt", factor: "1.0"}, - {signal_name: "signal_7", signal_value: "1", unit: "mA", factor: "1.0"}]; + {signal_name: "signal_1", signal_value: "100", unit: "Hz", factor: "1.0", circle_time: "1 ms"}, + {signal_name: "signal_2", signal_value: "999", unit: "Km", factor: "1.0", circle_time: "1 ms"}, + {signal_name: "signal_3", signal_value: "203", unit: "second", factor: "1.0", circle_time: "1 ms"}, + {signal_name: "signal_4", signal_value: "15.6", unit: "mWh", factor: "1.0", circle_time: "1 ms"}, + {signal_name: "signal_5", signal_value: "20.9", unit: "A", factor: "1.0", circle_time: "1 ms"}, + {signal_name: "signal_6", signal_value: "10", unit: "Volt", factor: "1.0", circle_time: "1 ms"}, + {signal_name: "signal_7", signal_value: "1", unit: "mA", factor: "1.0", circle_time: "1 ms"}]; height: (signals.length < 3)? 75px: signals.length * 25px; Rectangle { background: back_ground; @@ -70,7 +73,7 @@ export component CanMessage inherits VerticalLayout { } Rectangle { - width: root.width * 40%; + width: root.width * 30%; border-color: white; border-width: 0.25px; Text { @@ -80,6 +83,17 @@ export component CanMessage inherits VerticalLayout { color: white; } } + Rectangle { + width: root.width * 10%; + border-color: white; + border-width: 0.25px; + Text { + text: root.circle_time; + horizontal-alignment: center; + vertical-alignment: center; + color: white; + } + } } } } diff --git a/ui/view_page.slint b/ui/view_page.slint index b2197d3..11f444c 100644 --- a/ui/view_page.slint +++ b/ui/view_page.slint @@ -7,6 +7,9 @@ export component viewPage inherits Rectangle { in-out property <[CanData]> messages; in-out property <[CanData]> filter_messages; in-out property page-num; + in-out property state; + in-out property bus_load: 0; + in-out property bitrate: 0; callback open_dbc_file(); VerticalLayout { HorizontalLayout { @@ -18,6 +21,29 @@ export component viewPage inherits Rectangle { } } Rectangle {} + Rectangle { + Text { + text: "State: " + state; + color: white; + } + } + Rectangle {} + Rectangle { + Text { + text: "Bitrate: " + bitrate; + color: white; + } + } + Rectangle {} + Rectangle { + Text { + text: "Bus Load: " + bus_load + "%"; + color: white; + } + } + Rectangle { + width: 50px; + } } Rectangle { height: 1px; @@ -27,6 +53,7 @@ export component viewPage inherits Rectangle { ListView { for message in messages: CanMessage { message_id: message.can-id; + circle_time: message.circle-time; message_name: message.packet-name; counter: message.counter; signals: message.signal-value; @@ -38,6 +65,7 @@ export component viewPage inherits Rectangle { ListView { for message in filter_messages: CanMessage { message_id: message.can-id; + circle_time: message.circle-time; message_name: message.packet-name; counter: message.counter; signals: message.signal-value; From c1731d45ad4a58e29c549fc20ef2b1b6febb2923 Mon Sep 17 00:00:00 2001 From: Tu Nguyen Date: Thu, 12 Sep 2024 11:43:00 +0700 Subject: [PATCH 2/5] remove setting bitrate - because of PRIVILEGE --- src/event_handler/can_handler.rs | 2 -- src/main.rs | 1 - ui/app.slint | 2 +- ui/init_page.slint | 8 +++++++- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/event_handler/can_handler.rs b/src/event_handler/can_handler.rs index 8c899bd..ec2f226 100644 --- a/src/event_handler/can_handler.rs +++ b/src/event_handler/can_handler.rs @@ -26,7 +26,6 @@ pub struct CanHandler<'a> { pub iface: UsbCanSocket, pub ui_handle: &'a Weak, pub mspc_rx: &'a Arc>>, - pub bitrate: u32, } static mut NEW_DBC_CHECK: bool = false; @@ -39,7 +38,6 @@ impl<'a> CanHandler<'a> { { let can_socket = self.open_can_socket(); let can_if = CanInterface::open(self.iface).unwrap(); - let _ = can_if.set_bitrate(self.bitrate, 700); self.process_ui_events(dbc, can_socket, can_if); } #[cfg(target_os = "windows")] diff --git a/src/main.rs b/src/main.rs index 33e8b10..caf75cb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -209,7 +209,6 @@ async fn main() -> io::Result<()> { iface: &can_if, ui_handle: &ui_handle, mspc_rx: &rx, - bitrate: 250000, }; loop { can_handler.process_can_messages(); diff --git a/ui/app.slint b/ui/app.slint index d97a15f..f908ca5 100644 --- a/ui/app.slint +++ b/ui/app.slint @@ -39,7 +39,7 @@ export component AppWindow inherits Window { out: init_string; can_sockets: can_sockets; start(name, index) => { - start(name, index) + start(name, index); } } diff --git a/ui/init_page.slint b/ui/init_page.slint index a01ced6..7a680f9 100644 --- a/ui/init_page.slint +++ b/ui/init_page.slint @@ -12,7 +12,7 @@ export component initPage inherits Rectangle { background: #1a1f2b; in property can_sockets; in property out: "Please select CAN device to start"; - callback start(string, int); + callback start(string /* name */, int /* index */); VerticalLayout { Rectangle {} Text { @@ -31,6 +31,12 @@ export component initPage inherits Rectangle { current-value: can_sockets.name[0]; } } + // bitrate_box := ComboBox { + // model: ["1 Mbit/s", "800 kbit/s", "500 kbit/s", "250 kbit/s", "200 kbit/s", "125 kbit/s", + // "100 kbit/s", "95.238 kbit/s", "83.333 kbit/s", "50 kbit/s", "47.619 kbit/s", + // "40 kbit/s", "33.333 kbit/s", "20 kbit/s", "10 kbit/s", "5 kbit/s"]; + // current-value: "250 kbit/s"; + // } Button { text: "start"; clicked => { From 0176621706fa7db6b93d2f47a6a2c320ce42c7f1 Mon Sep 17 00:00:00 2001 From: Tu Nguyen Date: Thu, 12 Sep 2024 15:02:53 +0700 Subject: [PATCH 3/5] also add bus load and circle time for windows --- src/event_handler/can_handler.rs | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/event_handler/can_handler.rs b/src/event_handler/can_handler.rs index ec2f226..699070e 100644 --- a/src/event_handler/can_handler.rs +++ b/src/event_handler/can_handler.rs @@ -4,9 +4,8 @@ use chrono::Utc; use pcan_basic::socket::usb::UsbCanSocket; use slint::{Model, VecModel, Weak}; use slint::{ModelRc, SharedString}; -use socketcan::CanInterface; #[cfg(target_os = "linux")] -use socketcan::{CanSocket, EmbeddedFrame, Frame, Socket}; +use socketcan::{CanInterface, CanSocket, EmbeddedFrame, Frame, Socket}; use std::collections::HashMap; use std::fmt::Write; use std::rc::Rc; @@ -136,8 +135,17 @@ impl<'a> CanHandler<'a> { #[cfg(target_os = "windows")] fn process_ui_events(&mut self, dbc: DBC) { use pcan_basic::socket::RecvCan; - + let mut start_bus_load = Instant::now(); + let mut total_bits = 0; loop { + let busload = if start_bus_load.elapsed() >= Duration::from_millis(1000) { + start_bus_load = Instant::now(); + let bus_load = (total_bits as f64 / 250000_f64) * 100.0; + total_bits = 0; + bus_load + } else { + 0.0 + }; let _ = self.ui_handle.upgrade_in_event_loop(move |ui| unsafe { if ui.get_is_new_dbc() { if ui.get_is_first_open() { @@ -147,6 +155,9 @@ impl<'a> CanHandler<'a> { } ui.set_is_new_dbc(false); } + if busload > 0.0 { + ui.set_bus_load(busload as i32); + } }); unsafe { if NEW_DBC_CHECK { @@ -155,6 +166,7 @@ impl<'a> CanHandler<'a> { } } if let Ok(frame) = self.iface.recv_frame() { + total_bits += (frame.dlc() as u32 + 6) * 8; // Data length + overhead (approximation) let id = frame.can_id(); let frame_id = id & !0x80000000; for message in dbc.messages() { @@ -178,8 +190,6 @@ impl<'a> CanHandler<'a> { }); } } - } else { - sleep(Duration::from_millis(50)); } } } @@ -193,10 +203,9 @@ impl<'a> CanHandler<'a> { for (message_count, message) in messages.iter().enumerate() { if message.can_id == format!("{:08X}", frame_id) { let now = Utc::now().timestamp_micros(); - let can_data = messages.row_data(message_count).unwrap(); let can_signals = Self::create_can_signals(&message, &signal_data); let circle_time = - (now - (can_data.time_stamp).parse::().unwrap()) as f32 / 1000.0; + (now - (message.time_stamp).parse::().unwrap()) as f32 / 1000.0; messages.set_row_data( message_count, CanData { From 0f5b37b7b2ef9b971eb56ce1cddf3ab2d1675ffe Mon Sep 17 00:00:00 2001 From: Tu Nguyen Date: Mon, 16 Sep 2024 11:58:35 +0700 Subject: [PATCH 4/5] support CAN bus bitrate configuration --- Cargo.toml | 2 ++ src/event_handler/can_handler.rs | 32 +++++++++++++++++++++++++++++++- src/main.rs | 10 +++++++--- ui/app.slint | 6 +++--- ui/init_page.slint | 16 ++++++++-------- 5 files changed, 51 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4b3a145..336fb30 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ description = "view real-time CAN packages" [dependencies] chrono = "0.4.38" +sudo = "0.6" can-dbc = { git="https://github.com/TuEmb/can-dbc.git", branch="dev" } rfd = "0.14.1" slint = { version = "1.7.1", default-features = false, features = ["backend-winit", "compat-1-2", "renderer-winit-femtovg"] } @@ -16,6 +17,7 @@ winapi = { version = "0.3.9", features = ["winuser"] } pcan-basic = { git = "https://github.com/TuEmb/pcan-basic.git", branch="main"} [target.'cfg(unix)'.dependencies] +privilege-rs = "0.1.0" socketcan = { git = "https://github.com/socketcan-rs/socketcan-rs.git", rev="e0d7760eca8085b247f37ea22f0aa41e00fa25fa", features = ["enumerate"] } [build-dependencies] diff --git a/src/event_handler/can_handler.rs b/src/event_handler/can_handler.rs index 699070e..416bfbf 100644 --- a/src/event_handler/can_handler.rs +++ b/src/event_handler/can_handler.rs @@ -25,6 +25,7 @@ pub struct CanHandler<'a> { pub iface: UsbCanSocket, pub ui_handle: &'a Weak, pub mspc_rx: &'a Arc>>, + pub bitrate: String, } static mut NEW_DBC_CHECK: bool = false; @@ -35,8 +36,11 @@ impl<'a> CanHandler<'a> { if let Ok(dbc) = self.mspc_rx.lock().unwrap().try_recv() { #[cfg(target_os = "linux")] { - let can_socket = self.open_can_socket(); let can_if = CanInterface::open(self.iface).unwrap(); + let _ = can_if.bring_down(); + let _ = can_if.set_bitrate(self.bitrate().unwrap(), None); + let _ = can_if.bring_up(); + let can_socket = self.open_can_socket(); self.process_ui_events(dbc, can_socket, can_if); } #[cfg(target_os = "windows")] @@ -284,4 +288,30 @@ impl<'a> CanHandler<'a> { hex_string.pop(); // Remove the trailing space hex_string } + + fn bitrate(&self) -> Option { + let bitrate_map: HashMap<&str, u32> = [ + ("1 Mbit/s", 1_000_000), + ("800 kbit/s", 800_000), + ("500 kbit/s", 500_000), + ("250 kbit/s", 250_000), + ("200 kbit/s", 200_000), + ("125 kbit/s", 125_000), + ("100 kbit/s", 100_000), + ("95.238 kbit/s", 95_238), + ("83.333 kbit/s", 83_333), + ("50 kbit/s", 50_000), + ("47.619 kbit/s", 47_619), + ("40 kbit/s", 40_000), + ("33.333 kbit/s", 33_333), + ("20 kbit/s", 20_000), + ("10 kbit/s", 10_000), + ("5 kbit/s", 5_000), + ] + .iter() + .cloned() + .collect(); + + bitrate_map.get(self.bitrate.as_str()).copied() + } } diff --git a/src/main.rs b/src/main.rs index caf75cb..51fe0fb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,8 @@ use pcan_basic::{ hw::attached_channels, socket::{usb::UsbCanSocket, Baudrate}, }; +#[cfg(target_os = "linux")] +use privilege_rs::privilege_request; #[cfg(target_os = "windows")] use slint::Model; use slint::{ModelRc, SharedString, VecModel}; @@ -25,6 +27,7 @@ slint::include_modules!(); #[tokio::main] async fn main() -> io::Result<()> { + privilege_request(); let ui = AppWindow::new().unwrap(); let (tx, rx) = mpsc::channel::(); @@ -161,7 +164,7 @@ async fn main() -> io::Result<()> { let (start_tx, start_rx) = mpsc::channel(); // Handle start event let ui_handle = ui.as_weak(); - ui.on_start(move |_name, _index| { + ui.on_start(move |_name, _index, bitrate| { // start_tx.send((_name, _index)); #[cfg(target_os = "linux")] { @@ -170,7 +173,7 @@ async fn main() -> io::Result<()> { ui.set_init_string(SharedString::from("No device found!!!")); } else { ui.set_is_init(true); - let _ = start_tx.send(_name); + let _ = start_tx.send((_name, bitrate)); } } #[cfg(target_os = "windows")] @@ -201,7 +204,7 @@ async fn main() -> io::Result<()> { let ui_handle = ui.as_weak(); tokio::spawn(async move { - if let Ok(can_if) = start_rx.recv() { + if let Ok((can_if, bitrate)) = start_rx.recv() { let mut can_handler = CanHandler { #[cfg(target_os = "windows")] iface: can_if, @@ -209,6 +212,7 @@ async fn main() -> io::Result<()> { iface: &can_if, ui_handle: &ui_handle, mspc_rx: &rx, + bitrate: bitrate.to_string(), }; loop { can_handler.process_can_messages(); diff --git a/ui/app.slint b/ui/app.slint index f908ca5..a48026b 100644 --- a/ui/app.slint +++ b/ui/app.slint @@ -25,7 +25,7 @@ export component AppWindow inherits Window { callback open_dbc_file(); callback filter_id(CanData, bool); - callback start(string, int); + callback start(string, int, string); title: @tr("CAN VIEWER (version 0.2.0)"); icon: @image-url("images/can_viewer_128px.png"); background: #1a1f2b; @@ -38,8 +38,8 @@ export component AppWindow inherits Window { initPage { out: init_string; can_sockets: can_sockets; - start(name, index) => { - start(name, index); + start(name, index, bitrate) => { + start(name, index, bitrate); } } diff --git a/ui/init_page.slint b/ui/init_page.slint index 7a680f9..cc95c96 100644 --- a/ui/init_page.slint +++ b/ui/init_page.slint @@ -12,7 +12,7 @@ export component initPage inherits Rectangle { background: #1a1f2b; in property can_sockets; in property out: "Please select CAN device to start"; - callback start(string /* name */, int /* index */); + callback start(string /* name */, int /* index */, string /* */); VerticalLayout { Rectangle {} Text { @@ -31,16 +31,16 @@ export component initPage inherits Rectangle { current-value: can_sockets.name[0]; } } - // bitrate_box := ComboBox { - // model: ["1 Mbit/s", "800 kbit/s", "500 kbit/s", "250 kbit/s", "200 kbit/s", "125 kbit/s", - // "100 kbit/s", "95.238 kbit/s", "83.333 kbit/s", "50 kbit/s", "47.619 kbit/s", - // "40 kbit/s", "33.333 kbit/s", "20 kbit/s", "10 kbit/s", "5 kbit/s"]; - // current-value: "250 kbit/s"; - // } + bitrate_box := ComboBox { + model: ["1 Mbit/s", "800 kbit/s", "500 kbit/s", "250 kbit/s", "200 kbit/s", "125 kbit/s", + "100 kbit/s", "95.238 kbit/s", "83.333 kbit/s", "50 kbit/s", "47.619 kbit/s", + "40 kbit/s", "33.333 kbit/s", "20 kbit/s", "10 kbit/s", "5 kbit/s"]; + current-value: "250 kbit/s"; + } Button { text: "start"; clicked => { - start(socket_can_box.current-value, socket_can_box.current-index); + start(socket_can_box.current-value, socket_can_box.current-index, bitrate_box.current-value); } } Rectangle {} From c690bb03910b8463249451985db5f3e1a0e0021c Mon Sep 17 00:00:00 2001 From: Tu Nguyen Date: Mon, 16 Sep 2024 13:00:05 +0700 Subject: [PATCH 5/5] also support bitrate configuration for Windows --- Cargo.toml | 6 +-- src/event_handler/can_handler.rs | 66 +++++++++++++++++++------------- src/event_handler/mod.rs | 23 +++++++++++ src/main.rs | 14 +++---- ui/init_page.slint | 4 +- 5 files changed, 74 insertions(+), 39 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 336fb30..4946882 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "can-viewer" -version = "0.2.0" +version = "0.2.1" edition = "2021" description = "view real-time CAN packages" @@ -27,7 +27,7 @@ winresource = "0.1.17" [package.metadata.bundle] name = "can-viewer" icon = ["ui/images/can_viewer_32px.png", "ui/images/can_viewer_128px.png", "ui/images/can_viewer_256px.png"] -version = "1.0.0" +version = "0.2.1" copyright = "Copyright (c) Tu Nguyen 2024. All rights reserved." category = "Developer Tool" short_description = "view real-time CAN packages" @@ -37,5 +37,5 @@ can-view can records real-time can packages and parse data with DBC input. """ [package.metadata.winresource] -OriginalFilename = "can-viewer.exe" +OriginalFilename = "can-viewer_0.2.1.exe" LegalCopyright = "Copyright © 2024" diff --git a/src/event_handler/can_handler.rs b/src/event_handler/can_handler.rs index 416bfbf..5ccd7ad 100644 --- a/src/event_handler/can_handler.rs +++ b/src/event_handler/can_handler.rs @@ -138,13 +138,14 @@ impl<'a> CanHandler<'a> { } #[cfg(target_os = "windows")] fn process_ui_events(&mut self, dbc: DBC) { - use pcan_basic::socket::RecvCan; + use pcan_basic::{error::PcanError, socket::RecvCan}; let mut start_bus_load = Instant::now(); let mut total_bits = 0; loop { + let bitrate = self.bitrate().unwrap(); let busload = if start_bus_load.elapsed() >= Duration::from_millis(1000) { start_bus_load = Instant::now(); - let bus_load = (total_bits as f64 / 250000_f64) * 100.0; + let bus_load = (total_bits as f64 / bitrate as f64) * 100.0; total_bits = 0; bus_load } else { @@ -159,6 +160,7 @@ impl<'a> CanHandler<'a> { } ui.set_is_new_dbc(false); } + ui.set_bitrate(bitrate as i32); if busload > 0.0 { ui.set_bus_load(busload as i32); } @@ -169,31 +171,43 @@ impl<'a> CanHandler<'a> { break; } } - if let Ok(frame) = self.iface.recv_frame() { - total_bits += (frame.dlc() as u32 + 6) * 8; // Data length + overhead (approximation) - let id = frame.can_id(); - let frame_id = id & !0x80000000; - for message in dbc.messages() { - if frame_id == (message.message_id().raw() & !0x80000000) { - let padding_data = Self::pad_to_8_bytes(frame.data()); - let hex_string = Self::array_to_hex_string(frame.data()); - let signal_data = message.parse_from_can(&padding_data); - let _ = self.ui_handle.upgrade_in_event_loop(move |ui| { - let is_filter = ui.get_is_filter(); - let messages: ModelRc = if !is_filter { - ui.get_messages() - } else { - ui.get_filter_messages() - }; - Self::update_ui_with_signals( - &messages, - frame_id, - signal_data, - hex_string, - ); - }); + match self.iface.recv_frame() { + Ok(frame) => { + let _ = self.ui_handle.upgrade_in_event_loop(move |ui| { + ui.set_state("OK".into()); + }); + total_bits += (frame.dlc() as u32 + 6) * 8; // Data length + overhead (approximation) + let id = frame.can_id(); + let frame_id = id & !0x80000000; + for message in dbc.messages() { + if frame_id == (message.message_id().raw() & !0x80000000) { + let padding_data = Self::pad_to_8_bytes(frame.data()); + let hex_string = Self::array_to_hex_string(frame.data()); + let signal_data = message.parse_from_can(&padding_data); + let _ = self.ui_handle.upgrade_in_event_loop(move |ui| { + let is_filter = ui.get_is_filter(); + let messages: ModelRc = if !is_filter { + ui.get_messages() + } else { + ui.get_filter_messages() + }; + Self::update_ui_with_signals( + &messages, + frame_id, + signal_data, + hex_string, + ); + }); + } } } + Err(e) => { + let _ = self.ui_handle.upgrade_in_event_loop(move |ui| { + if e != PcanError::QrcvEmpty { + ui.set_state(format!("{:?}", e).into()); + } + }); + } } } } @@ -295,14 +309,12 @@ impl<'a> CanHandler<'a> { ("800 kbit/s", 800_000), ("500 kbit/s", 500_000), ("250 kbit/s", 250_000), - ("200 kbit/s", 200_000), ("125 kbit/s", 125_000), ("100 kbit/s", 100_000), ("95.238 kbit/s", 95_238), ("83.333 kbit/s", 83_333), ("50 kbit/s", 50_000), ("47.619 kbit/s", 47_619), - ("40 kbit/s", 40_000), ("33.333 kbit/s", 33_333), ("20 kbit/s", 20_000), ("10 kbit/s", 10_000), diff --git a/src/event_handler/mod.rs b/src/event_handler/mod.rs index 965e5dd..a6fd7fd 100644 --- a/src/event_handler/mod.rs +++ b/src/event_handler/mod.rs @@ -5,7 +5,30 @@ pub(crate) mod packet_filter; pub use can_handler::CanHandler; pub use dbc_file::DBCFile; pub use packet_filter::PacketFilter; +#[cfg(target_os = "windows")] +use pcan_basic::socket::Baudrate; use slint::Color; const ODD_COLOR: Color = Color::from_rgb_u8(0x18, 0x1c, 0x27); const EVEN_COLOR: Color = Color::from_rgb_u8(0x13, 0x16, 0x1f); + +#[cfg(target_os = "windows")] +pub fn p_can_bitrate(bitrate: &str) -> Option { + match bitrate { + "1 Mbit/s" => Some(Baudrate::Baud1M), + "800 kbit/s" => Some(Baudrate::Baud800K), + "500 kbit/s" => Some(Baudrate::Baud500K), + "250 kbit/s" => Some(Baudrate::Baud250K), + "125 kbit/s" => Some(Baudrate::Baud125K), + "100 kbit/s" => Some(Baudrate::Baud100K), + "95.238 kbit/s" => Some(Baudrate::Baud95K), + "83.333 kbit/s" => Some(Baudrate::Baud83), + "50 kbit/s" => Some(Baudrate::Baud50K), + "47.619 kbit/s" => Some(Baudrate::Baud47K), + "33.333 kbit/s" => Some(Baudrate::Baud33K), + "20 kbit/s" => Some(Baudrate::Baud20K), + "10 kbit/s" => Some(Baudrate::Baud10K), + "5 kbit/s" => Some(Baudrate::Baud5K), + _ => None, + } +} diff --git a/src/main.rs b/src/main.rs index 51fe0fb..c6c220f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,13 +6,11 @@ use std::time::Duration; mod event_handler; use can_dbc::DBC; +#[cfg(target_os = "windows")] +use event_handler::p_can_bitrate; use event_handler::{CanHandler, DBCFile, PacketFilter}; #[cfg(target_os = "windows")] -use pcan_basic::{ - bus::UsbBus, - hw::attached_channels, - socket::{usb::UsbCanSocket, Baudrate}, -}; +use pcan_basic::{bus::UsbBus, hw::attached_channels, socket::usb::UsbCanSocket}; #[cfg(target_os = "linux")] use privilege_rs::privilege_request; #[cfg(target_os = "windows")] @@ -27,6 +25,7 @@ slint::include_modules!(); #[tokio::main] async fn main() -> io::Result<()> { + #[cfg(target_os = "linux")] privilege_request(); let ui = AppWindow::new().unwrap(); @@ -188,10 +187,11 @@ async fn main() -> io::Result<()> { }; let usb_can = UsbBus::try_from(get_device_handle as u16).unwrap(); let ui_handle = ui.as_weak(); - match UsbCanSocket::open(usb_can, Baudrate::Baud250K) { + let baudrate = p_can_bitrate(&bitrate).unwrap(); + match UsbCanSocket::open(usb_can, baudrate) { Ok(socket) => { ui_handle.unwrap().set_is_init(true); - let _ = start_tx.send(socket); + let _ = start_tx.send((socket, bitrate)); } Err(e) => { ui_handle diff --git a/ui/init_page.slint b/ui/init_page.slint index cc95c96..3ba2539 100644 --- a/ui/init_page.slint +++ b/ui/init_page.slint @@ -32,9 +32,9 @@ export component initPage inherits Rectangle { } } bitrate_box := ComboBox { - model: ["1 Mbit/s", "800 kbit/s", "500 kbit/s", "250 kbit/s", "200 kbit/s", "125 kbit/s", + model: ["1 Mbit/s", "800 kbit/s", "500 kbit/s", "250 kbit/s", "125 kbit/s", "100 kbit/s", "95.238 kbit/s", "83.333 kbit/s", "50 kbit/s", "47.619 kbit/s", - "40 kbit/s", "33.333 kbit/s", "20 kbit/s", "10 kbit/s", "5 kbit/s"]; + "33.333 kbit/s", "20 kbit/s", "10 kbit/s", "5 kbit/s"]; current-value: "250 kbit/s"; } Button {