1use crate::decode::{DecodeResult, decode_frame};
4use crate::dto::{CanFrameDto, DecodeResponse};
5use crate::state::AppState;
6use dbc_rs::Dbc;
7use serde::Serialize;
8use std::sync::Arc;
9use tauri::State;
10
11#[derive(Debug, Clone, Serialize)]
13pub struct SignalInfo {
14 pub name: String,
15 pub start_bit: u32,
16 pub length: u32,
17 pub byte_order: String,
18 pub is_signed: bool,
19 pub factor: f64,
20 pub offset: f64,
21 pub min: f64,
22 pub max: f64,
23 pub unit: String,
24 pub comment: Option<String>,
26}
27
28#[derive(Debug, Clone, Serialize)]
30pub struct MessageInfo {
31 pub id: u32,
32 pub name: String,
33 pub dlc: u8,
34 pub sender: String,
35 pub signals: Vec<SignalInfo>,
36 pub comment: Option<String>,
38}
39
40#[derive(Debug, Clone, Serialize)]
42pub struct DbcInfo {
43 pub messages: Vec<MessageInfo>,
44}
45
46#[tauri::command]
49pub async fn load_dbc(path: String, state: State<'_, Arc<AppState>>) -> Result<String, String> {
50 let content =
51 std::fs::read_to_string(&path).map_err(|e| format!("Failed to read DBC: {}", e))?;
52
53 let dbc = Dbc::parse(&content).map_err(|e| format!("Failed to parse DBC: {:?}", e))?;
54 let msg_count = dbc.messages().len();
55
56 state.set_dbc(dbc);
57 *state.dbc_path.lock() = Some(path.clone());
58
59 if let Err(e) = state.session.lock().set_dbc_path(Some(path.clone())) {
61 log::warn!("Failed to save session: {}", e);
62 }
63
64 Ok(format!("Loaded {} messages", msg_count))
65}
66
67#[tauri::command]
70pub async fn clear_dbc(state: State<'_, Arc<AppState>>) -> Result<(), String> {
71 state.clear_dbc();
72 *state.dbc_path.lock() = None;
73
74 if let Err(e) = state.session.lock().set_dbc_path(None) {
76 log::warn!("Failed to save session: {}", e);
77 }
78
79 Ok(())
80}
81
82#[tauri::command]
84pub async fn get_dbc_path(state: State<'_, Arc<AppState>>) -> Result<Option<String>, String> {
85 Ok(state.dbc_path.lock().clone())
86}
87
88#[tauri::command]
90pub async fn decode_single_frame(
91 frame: CanFrameDto,
92 state: State<'_, Arc<AppState>>,
93) -> Result<DecodeResponse, String> {
94 let dbc_guard = state.dbc.lock();
95 let Some(ref dbc) = *dbc_guard else {
96 return Ok(DecodeResponse {
97 signals: Vec::new(),
98 errors: Vec::new(),
99 });
100 };
101
102 match decode_frame(&frame, dbc) {
103 DecodeResult::Signals(signals) => Ok(DecodeResponse {
104 signals,
105 errors: Vec::new(),
106 }),
107 DecodeResult::Error(err) => Ok(DecodeResponse {
108 signals: Vec::new(),
109 errors: vec![err],
110 }),
111 }
112}
113
114#[tauri::command]
116pub async fn decode_frames(
117 frames: Vec<CanFrameDto>,
118 state: State<'_, Arc<AppState>>,
119) -> Result<DecodeResponse, String> {
120 let dbc_guard = state.dbc.lock();
121 let Some(ref dbc) = *dbc_guard else {
122 return Ok(DecodeResponse {
123 signals: Vec::new(),
124 errors: Vec::new(),
125 });
126 };
127
128 let mut signals = Vec::new();
129 let mut errors = Vec::new();
130
131 for frame in &frames {
132 match decode_frame(frame, dbc) {
133 DecodeResult::Signals(sigs) => signals.extend(sigs),
134 DecodeResult::Error(err) => errors.push(err),
135 }
136 }
137
138 Ok(DecodeResponse { signals, errors })
139}
140
141#[tauri::command]
144pub async fn save_dbc_content(
145 path: String,
146 content: String,
147 state: State<'_, Arc<AppState>>,
148) -> Result<(), String> {
149 let dbc = Dbc::parse(&content).map_err(|e| format!("Invalid DBC content: {:?}", e))?;
151
152 std::fs::write(&path, &content).map_err(|e| format!("Failed to write DBC: {}", e))?;
154
155 state.set_dbc(dbc);
157 *state.dbc_path.lock() = Some(path.clone());
158
159 if let Err(e) = state.session.lock().set_dbc_path(Some(path.clone())) {
161 log::warn!("Failed to save session: {}", e);
162 }
163
164 Ok(())
165}
166
167#[tauri::command]
170pub async fn update_dbc_content(
171 content: String,
172 state: State<'_, Arc<AppState>>,
173) -> Result<String, String> {
174 let dbc = Dbc::parse(&content).map_err(|e| format!("Failed to parse DBC: {:?}", e))?;
175 let msg_count = dbc.messages().len();
176
177 state.set_dbc(dbc);
178 Ok(format!("Updated DBC with {} messages", msg_count))
179}
180
181#[tauri::command]
183pub async fn get_dbc_info(state: State<'_, Arc<AppState>>) -> Result<Option<DbcInfo>, String> {
184 let dbc_guard = state.dbc.lock();
185 let Some(ref dbc) = *dbc_guard else {
186 return Ok(None);
187 };
188
189 let messages: Vec<MessageInfo> = dbc
190 .messages()
191 .iter()
192 .map(|msg| {
193 let signals: Vec<SignalInfo> = msg
194 .signals()
195 .iter()
196 .map(|sig| {
197 let byte_order = match sig.byte_order() {
198 dbc_rs::ByteOrder::BigEndian => "big_endian",
199 dbc_rs::ByteOrder::LittleEndian => "little_endian",
200 };
201 SignalInfo {
202 name: sig.name().to_string(),
203 start_bit: sig.start_bit() as u32,
204 length: sig.length() as u32,
205 byte_order: byte_order.to_string(),
206 is_signed: !sig.is_unsigned(),
207 factor: sig.factor(),
208 offset: sig.offset(),
209 min: sig.min(),
210 max: sig.max(),
211 unit: sig.unit().unwrap_or("").to_string(),
212 comment: sig.comment().map(|s| s.to_string()),
213 }
214 })
215 .collect();
216
217 MessageInfo {
218 id: msg.id(),
219 name: msg.name().to_string(),
220 dlc: msg.dlc(),
221 sender: msg.sender().to_string(),
222 signals,
223 comment: msg.comment().map(|s| s.to_string()),
224 }
225 })
226 .collect();
227
228 Ok(Some(DbcInfo { messages }))
229}