Skip to content

support more information for CAN bus #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
[package]
name = "can-viewer"
version = "0.2.0"
version = "0.2.1"
edition = "2021"
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"] }
Expand All @@ -15,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]
Expand All @@ -24,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"
Expand All @@ -34,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"
144 changes: 115 additions & 29 deletions src/event_handler/can_handler.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
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};
#[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;
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;
Expand All @@ -23,6 +25,7 @@ pub struct CanHandler<'a> {
pub iface: UsbCanSocket,
pub ui_handle: &'a Weak<AppWindow>,
pub mspc_rx: &'a Arc<Mutex<Receiver<DBC>>>,
pub bitrate: String,
}

static mut NEW_DBC_CHECK: bool = false;
Expand All @@ -33,8 +36,12 @@ impl<'a> CanHandler<'a> {
if let Ok(dbc) = self.mspc_rx.lock().unwrap().try_recv() {
#[cfg(target_os = "linux")]
{
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);
self.process_ui_events(dbc, can_socket, can_if);
}
#[cfg(target_os = "windows")]
self.process_ui_events(dbc);
Expand All @@ -60,8 +67,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() {
Expand All @@ -71,6 +97,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 {
Expand All @@ -79,6 +110,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) {
Expand Down Expand Up @@ -106,9 +138,19 @@ 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 / 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() {
Expand All @@ -118,39 +160,54 @@ 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);
}
});
unsafe {
if NEW_DBC_CHECK {
NEW_DBC_CHECK = false;
break;
}
}
if let Ok(frame) = self.iface.recv_frame() {
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<CanData> = 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<CanData> = if !is_filter {
ui.get_messages()
} else {
ui.get_filter_messages()
};
Self::update_ui_with_signals(
&messages,
frame_id,
signal_data,
hex_string,
);
});
}
}
}
} else {
sleep(Duration::from_millis(50));
Err(e) => {
let _ = self.ui_handle.upgrade_in_event_loop(move |ui| {
if e != PcanError::QrcvEmpty {
ui.set_state(format!("{:?}", e).into());
}
});
}
}
}
}
Expand All @@ -163,7 +220,10 @@ 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_signals = Self::create_can_signals(&message, &signal_data);
let circle_time =
(now - (message.time_stamp).parse::<i64>().unwrap()) as f32 / 1000.0;
messages.set_row_data(
message_count,
CanData {
Expand All @@ -177,6 +237,8 @@ impl<'a> CanHandler<'a> {
} else {
ODD_COLOR
},
circle_time: format!("{:.02} ms", circle_time).into(),
time_stamp: now.to_string().into(),
},
);
break;
Expand Down Expand Up @@ -240,4 +302,28 @@ impl<'a> CanHandler<'a> {
hex_string.pop(); // Remove the trailing space
hex_string
}

fn bitrate(&self) -> Option<u32> {
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),
("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),
("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()
}
}
4 changes: 4 additions & 0 deletions src/event_handler/dbc_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
));
Expand Down Expand Up @@ -83,6 +85,8 @@ impl<'a> DBCFile<'a> {
} else {
ODD_COLOR
},
circle_time: "0.0".into(),
time_stamp: "0".into(),
};

if message_count == 0 {
Expand Down
23 changes: 23 additions & 0 deletions src/event_handler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Baudrate> {
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,
}
}
2 changes: 2 additions & 0 deletions src/event_handler/packet_filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading