Skip to content

Commit fc7be68

Browse files
authored
support more information for CAN bus (#6)
* busload, bus state, circle time, bitrate support * remove setting bitrate - because of PRIVILEGE * also add bus load and circle time for windows * support CAN bus bitrate configuration * also support bitrate configuration for Windows
1 parent 32fd4ae commit fc7be68

10 files changed

+231
-55
lines changed

Cargo.toml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
[package]
22
name = "can-viewer"
3-
version = "0.2.0"
3+
version = "0.2.1"
44
edition = "2021"
55
description = "view real-time CAN packages"
66

77
[dependencies]
8+
chrono = "0.4.38"
9+
sudo = "0.6"
810
can-dbc = { git="https://github.com/TuEmb/can-dbc.git", branch="dev" }
911
rfd = "0.14.1"
1012
slint = { version = "1.7.1", default-features = false, features = ["backend-winit", "compat-1-2", "renderer-winit-femtovg"] }
@@ -15,6 +17,7 @@ winapi = { version = "0.3.9", features = ["winuser"] }
1517
pcan-basic = { git = "https://github.com/TuEmb/pcan-basic.git", branch="main"}
1618

1719
[target.'cfg(unix)'.dependencies]
20+
privilege-rs = "0.1.0"
1821
socketcan = { git = "https://github.com/socketcan-rs/socketcan-rs.git", rev="e0d7760eca8085b247f37ea22f0aa41e00fa25fa", features = ["enumerate"] }
1922

2023
[build-dependencies]
@@ -24,7 +27,7 @@ winresource = "0.1.17"
2427
[package.metadata.bundle]
2528
name = "can-viewer"
2629
icon = ["ui/images/can_viewer_32px.png", "ui/images/can_viewer_128px.png", "ui/images/can_viewer_256px.png"]
27-
version = "1.0.0"
30+
version = "0.2.1"
2831
copyright = "Copyright (c) Tu Nguyen 2024. All rights reserved."
2932
category = "Developer Tool"
3033
short_description = "view real-time CAN packages"
@@ -34,5 +37,5 @@ can-view can records real-time can packages and parse data with DBC input.
3437
"""
3538

3639
[package.metadata.winresource]
37-
OriginalFilename = "can-viewer.exe"
40+
OriginalFilename = "can-viewer_0.2.1.exe"
3841
LegalCopyright = "Copyright © 2024"

src/event_handler/can_handler.rs

Lines changed: 115 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
use can_dbc::DBC;
2+
use chrono::Utc;
23
#[cfg(target_os = "windows")]
34
use pcan_basic::socket::usb::UsbCanSocket;
45
use slint::{Model, VecModel, Weak};
56
use slint::{ModelRc, SharedString};
67
#[cfg(target_os = "linux")]
7-
use socketcan::{CanSocket, EmbeddedFrame, Frame, Socket};
8+
use socketcan::{CanInterface, CanSocket, EmbeddedFrame, Frame, Socket};
89
use std::collections::HashMap;
910
use std::fmt::Write;
1011
use std::rc::Rc;
1112
use std::sync::mpsc::Receiver;
1213
use std::sync::{Arc, Mutex};
1314
use std::thread::sleep;
1415
use std::time::Duration;
16+
use std::time::Instant;
1517

1618
use crate::slint_generatedAppWindow::AppWindow;
1719
use crate::slint_generatedAppWindow::CanData;
@@ -23,6 +25,7 @@ pub struct CanHandler<'a> {
2325
pub iface: UsbCanSocket,
2426
pub ui_handle: &'a Weak<AppWindow>,
2527
pub mspc_rx: &'a Arc<Mutex<Receiver<DBC>>>,
28+
pub bitrate: String,
2629
}
2730

2831
static mut NEW_DBC_CHECK: bool = false;
@@ -33,8 +36,12 @@ impl<'a> CanHandler<'a> {
3336
if let Ok(dbc) = self.mspc_rx.lock().unwrap().try_recv() {
3437
#[cfg(target_os = "linux")]
3538
{
39+
let can_if = CanInterface::open(self.iface).unwrap();
40+
let _ = can_if.bring_down();
41+
let _ = can_if.set_bitrate(self.bitrate().unwrap(), None);
42+
let _ = can_if.bring_up();
3643
let can_socket = self.open_can_socket();
37-
self.process_ui_events(dbc, can_socket);
44+
self.process_ui_events(dbc, can_socket, can_if);
3845
}
3946
#[cfg(target_os = "windows")]
4047
self.process_ui_events(dbc);
@@ -60,8 +67,27 @@ impl<'a> CanHandler<'a> {
6067
}
6168
}
6269
#[cfg(target_os = "linux")]
63-
fn process_ui_events(&self, dbc: DBC, can_socket: CanSocket) {
70+
fn process_ui_events(&self, dbc: DBC, can_socket: CanSocket, can_if: CanInterface) {
71+
let mut start_bus_load = Instant::now();
72+
let mut total_bits = 0;
6473
loop {
74+
let bus_state = match can_if.state().unwrap().unwrap() {
75+
socketcan::nl::CanState::ErrorActive => "ERR_ACTIVE",
76+
socketcan::nl::CanState::ErrorWarning => "ERR_WARNING",
77+
socketcan::nl::CanState::ErrorPassive => "ERR_PASSIVE",
78+
socketcan::nl::CanState::BusOff => "BUSOFF",
79+
socketcan::nl::CanState::Stopped => "STOPPED",
80+
socketcan::nl::CanState::Sleeping => "SLEEPING",
81+
};
82+
let bitrate = can_if.bit_rate().unwrap().unwrap();
83+
let busload = if start_bus_load.elapsed() >= Duration::from_millis(1000) {
84+
start_bus_load = Instant::now();
85+
let bus_load = (total_bits as f64 / bitrate as f64) * 100.0;
86+
total_bits = 0;
87+
bus_load
88+
} else {
89+
0.0
90+
};
6591
let _ = self.ui_handle.upgrade_in_event_loop(move |ui| unsafe {
6692
if ui.get_is_new_dbc() {
6793
if ui.get_is_first_open() {
@@ -71,6 +97,11 @@ impl<'a> CanHandler<'a> {
7197
}
7298
ui.set_is_new_dbc(false);
7399
}
100+
ui.set_state(bus_state.into());
101+
ui.set_bitrate(bitrate as i32);
102+
if busload > 0.0 {
103+
ui.set_bus_load(busload as i32);
104+
}
74105
});
75106
unsafe {
76107
if NEW_DBC_CHECK {
@@ -79,6 +110,7 @@ impl<'a> CanHandler<'a> {
79110
}
80111
}
81112
if let Ok(frame) = can_socket.read_frame() {
113+
total_bits += (frame.len() + 6) * 8; // Data length + overhead (approximation)
82114
let frame_id = frame.raw_id() & !0x80000000;
83115
for message in dbc.messages() {
84116
if frame_id == (message.message_id().raw() & !0x80000000) {
@@ -106,9 +138,19 @@ impl<'a> CanHandler<'a> {
106138
}
107139
#[cfg(target_os = "windows")]
108140
fn process_ui_events(&mut self, dbc: DBC) {
109-
use pcan_basic::socket::RecvCan;
110-
141+
use pcan_basic::{error::PcanError, socket::RecvCan};
142+
let mut start_bus_load = Instant::now();
143+
let mut total_bits = 0;
111144
loop {
145+
let bitrate = self.bitrate().unwrap();
146+
let busload = if start_bus_load.elapsed() >= Duration::from_millis(1000) {
147+
start_bus_load = Instant::now();
148+
let bus_load = (total_bits as f64 / bitrate as f64) * 100.0;
149+
total_bits = 0;
150+
bus_load
151+
} else {
152+
0.0
153+
};
112154
let _ = self.ui_handle.upgrade_in_event_loop(move |ui| unsafe {
113155
if ui.get_is_new_dbc() {
114156
if ui.get_is_first_open() {
@@ -118,39 +160,54 @@ impl<'a> CanHandler<'a> {
118160
}
119161
ui.set_is_new_dbc(false);
120162
}
163+
ui.set_bitrate(bitrate as i32);
164+
if busload > 0.0 {
165+
ui.set_bus_load(busload as i32);
166+
}
121167
});
122168
unsafe {
123169
if NEW_DBC_CHECK {
124170
NEW_DBC_CHECK = false;
125171
break;
126172
}
127173
}
128-
if let Ok(frame) = self.iface.recv_frame() {
129-
let id = frame.can_id();
130-
let frame_id = id & !0x80000000;
131-
for message in dbc.messages() {
132-
if frame_id == (message.message_id().raw() & !0x80000000) {
133-
let padding_data = Self::pad_to_8_bytes(frame.data());
134-
let hex_string = Self::array_to_hex_string(frame.data());
135-
let signal_data = message.parse_from_can(&padding_data);
136-
let _ = self.ui_handle.upgrade_in_event_loop(move |ui| {
137-
let is_filter = ui.get_is_filter();
138-
let messages: ModelRc<CanData> = if !is_filter {
139-
ui.get_messages()
140-
} else {
141-
ui.get_filter_messages()
142-
};
143-
Self::update_ui_with_signals(
144-
&messages,
145-
frame_id,
146-
signal_data,
147-
hex_string,
148-
);
149-
});
174+
match self.iface.recv_frame() {
175+
Ok(frame) => {
176+
let _ = self.ui_handle.upgrade_in_event_loop(move |ui| {
177+
ui.set_state("OK".into());
178+
});
179+
total_bits += (frame.dlc() as u32 + 6) * 8; // Data length + overhead (approximation)
180+
let id = frame.can_id();
181+
let frame_id = id & !0x80000000;
182+
for message in dbc.messages() {
183+
if frame_id == (message.message_id().raw() & !0x80000000) {
184+
let padding_data = Self::pad_to_8_bytes(frame.data());
185+
let hex_string = Self::array_to_hex_string(frame.data());
186+
let signal_data = message.parse_from_can(&padding_data);
187+
let _ = self.ui_handle.upgrade_in_event_loop(move |ui| {
188+
let is_filter = ui.get_is_filter();
189+
let messages: ModelRc<CanData> = if !is_filter {
190+
ui.get_messages()
191+
} else {
192+
ui.get_filter_messages()
193+
};
194+
Self::update_ui_with_signals(
195+
&messages,
196+
frame_id,
197+
signal_data,
198+
hex_string,
199+
);
200+
});
201+
}
150202
}
151203
}
152-
} else {
153-
sleep(Duration::from_millis(50));
204+
Err(e) => {
205+
let _ = self.ui_handle.upgrade_in_event_loop(move |ui| {
206+
if e != PcanError::QrcvEmpty {
207+
ui.set_state(format!("{:?}", e).into());
208+
}
209+
});
210+
}
154211
}
155212
}
156213
}
@@ -163,7 +220,10 @@ impl<'a> CanHandler<'a> {
163220
) {
164221
for (message_count, message) in messages.iter().enumerate() {
165222
if message.can_id == format!("{:08X}", frame_id) {
223+
let now = Utc::now().timestamp_micros();
166224
let can_signals = Self::create_can_signals(&message, &signal_data);
225+
let circle_time =
226+
(now - (message.time_stamp).parse::<i64>().unwrap()) as f32 / 1000.0;
167227
messages.set_row_data(
168228
message_count,
169229
CanData {
@@ -177,6 +237,8 @@ impl<'a> CanHandler<'a> {
177237
} else {
178238
ODD_COLOR
179239
},
240+
circle_time: format!("{:.02} ms", circle_time).into(),
241+
time_stamp: now.to_string().into(),
180242
},
181243
);
182244
break;
@@ -240,4 +302,28 @@ impl<'a> CanHandler<'a> {
240302
hex_string.pop(); // Remove the trailing space
241303
hex_string
242304
}
305+
306+
fn bitrate(&self) -> Option<u32> {
307+
let bitrate_map: HashMap<&str, u32> = [
308+
("1 Mbit/s", 1_000_000),
309+
("800 kbit/s", 800_000),
310+
("500 kbit/s", 500_000),
311+
("250 kbit/s", 250_000),
312+
("125 kbit/s", 125_000),
313+
("100 kbit/s", 100_000),
314+
("95.238 kbit/s", 95_238),
315+
("83.333 kbit/s", 83_333),
316+
("50 kbit/s", 50_000),
317+
("47.619 kbit/s", 47_619),
318+
("33.333 kbit/s", 33_333),
319+
("20 kbit/s", 20_000),
320+
("10 kbit/s", 10_000),
321+
("5 kbit/s", 5_000),
322+
]
323+
.iter()
324+
.cloned()
325+
.collect();
326+
327+
bitrate_map.get(self.bitrate.as_str()).copied()
328+
}
243329
}

src/event_handler/dbc_file.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ impl<'a> DBCFile<'a> {
3939
counter: 0,
4040
raw_can: SharedString::from("default"),
4141
color: ODD_COLOR,
42+
circle_time: "0.0".into(),
43+
time_stamp: "0".into(),
4244
}]
4345
.to_vec(),
4446
));
@@ -83,6 +85,8 @@ impl<'a> DBCFile<'a> {
8385
} else {
8486
ODD_COLOR
8587
},
88+
circle_time: "0.0".into(),
89+
time_stamp: "0".into(),
8690
};
8791

8892
if message_count == 0 {

src/event_handler/mod.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,30 @@ pub(crate) mod packet_filter;
55
pub use can_handler::CanHandler;
66
pub use dbc_file::DBCFile;
77
pub use packet_filter::PacketFilter;
8+
#[cfg(target_os = "windows")]
9+
use pcan_basic::socket::Baudrate;
810
use slint::Color;
911

1012
const ODD_COLOR: Color = Color::from_rgb_u8(0x18, 0x1c, 0x27);
1113
const EVEN_COLOR: Color = Color::from_rgb_u8(0x13, 0x16, 0x1f);
14+
15+
#[cfg(target_os = "windows")]
16+
pub fn p_can_bitrate(bitrate: &str) -> Option<Baudrate> {
17+
match bitrate {
18+
"1 Mbit/s" => Some(Baudrate::Baud1M),
19+
"800 kbit/s" => Some(Baudrate::Baud800K),
20+
"500 kbit/s" => Some(Baudrate::Baud500K),
21+
"250 kbit/s" => Some(Baudrate::Baud250K),
22+
"125 kbit/s" => Some(Baudrate::Baud125K),
23+
"100 kbit/s" => Some(Baudrate::Baud100K),
24+
"95.238 kbit/s" => Some(Baudrate::Baud95K),
25+
"83.333 kbit/s" => Some(Baudrate::Baud83),
26+
"50 kbit/s" => Some(Baudrate::Baud50K),
27+
"47.619 kbit/s" => Some(Baudrate::Baud47K),
28+
"33.333 kbit/s" => Some(Baudrate::Baud33K),
29+
"20 kbit/s" => Some(Baudrate::Baud20K),
30+
"10 kbit/s" => Some(Baudrate::Baud10K),
31+
"5 kbit/s" => Some(Baudrate::Baud5K),
32+
_ => None,
33+
}
34+
}

src/event_handler/packet_filter.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ impl<'a> PacketFilter<'a> {
2929
packet_name: self.filter.packet_name,
3030
raw_can: self.filter.raw_can,
3131
signal_value: self.filter.signal_value,
32+
circle_time: "0.0".into(),
33+
time_stamp: "0".into(),
3234
});
3335
} else {
3436
// Remove filter ID

0 commit comments

Comments
 (0)