Skip to content

Commit f32be2b

Browse files
committed
load file implemented in data_thread
1 parent d49a431 commit f32be2b

File tree

3 files changed

+141
-34
lines changed

3 files changed

+141
-34
lines changed

src/gui.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ pub struct MyApp {
127127
connected_lock: Arc<RwLock<bool>>,
128128
data_lock: Arc<RwLock<DataContainer>>,
129129
save_tx: Sender<FileOptions>,
130+
load_tx: Sender<PathBuf>,
130131
send_tx: Sender<String>,
131132
clear_tx: Sender<bool>,
132133
history: Vec<String>,
@@ -155,6 +156,7 @@ impl MyApp {
155156
connected_lock: Arc<RwLock<bool>>,
156157
gui_conf: GuiSettingsContainer,
157158
save_tx: Sender<FileOptions>,
159+
load_tx: Sender<PathBuf>,
158160
send_tx: Sender<String>,
159161
clear_tx: Sender<bool>,
160162
) -> Self {
@@ -214,6 +216,7 @@ impl MyApp {
214216
gui_conf,
215217
data_lock,
216218
save_tx,
219+
load_tx,
217220
send_tx,
218221
clear_tx,
219222
plotting_range: usize::MAX,
@@ -805,6 +808,8 @@ impl MyApp {
805808
.clicked()
806809
{
807810
self.file_opened = false;
811+
let _ = self.load_tx.send(PathBuf::new());
812+
self.file_dialog_state = FileDialogState::None;
808813
}
809814
});
810815
}
@@ -1157,9 +1162,9 @@ impl MyApp {
11571162
self.picked_path = path.to_path_buf();
11581163
self.file_opened = true;
11591164
self.file_dialog_state = FileDialogState::None;
1160-
// if let Err(e) = self.load_tx.send(self.picked_path.clone()) {
1161-
// log::error!("load_tx thread send failed: {:?}", e);
1162-
// }
1165+
if let Err(e) = self.load_tx.send(self.picked_path.clone()) {
1166+
log::error!("load_tx thread send failed: {:?}", e);
1167+
}
11631168
}
11641169
}
11651170
FileDialogState::SavePlot => {
@@ -1189,7 +1194,9 @@ impl MyApp {
11891194
}
11901195
}
11911196
}
1192-
FileDialogState::None => {}
1197+
FileDialogState::None => {
1198+
self.file_opened = false;
1199+
}
11931200
}
11941201
});
11951202
});

src/io.rs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::error::Error;
22
use std::path::PathBuf;
33

4-
use csv::WriterBuilder;
4+
use csv::{ReaderBuilder, WriterBuilder};
55

66
use crate::DataContainer;
77

@@ -14,6 +14,57 @@ pub struct FileOptions {
1414
pub names: Vec<String>,
1515
}
1616

17+
pub fn open_from_csv(
18+
data: &mut DataContainer,
19+
csv_options: &mut FileOptions,
20+
) -> Result<(), Box<dyn Error>> {
21+
let mut rdr = ReaderBuilder::new()
22+
.has_headers(true)
23+
.from_path(&csv_options.file_path)?;
24+
25+
csv_options.names = rdr
26+
.headers()
27+
.unwrap()
28+
.into_iter()
29+
.skip(1)
30+
.map(|s| s.to_string())
31+
.collect::<Vec<String>>();
32+
33+
// Clear any existing data in the DataContainer
34+
data.absolute_time.clear();
35+
data.time.clear();
36+
data.dataset = vec![vec![]; csv_options.names.len()];
37+
38+
// Read and parse each record in the CSV
39+
for result in rdr.records() {
40+
let record = result?;
41+
42+
// Ensure the record has the correct number of fields
43+
if record.len() != csv_options.names.len() + 1 {
44+
return Err("CSV record does not match the expected number of columns".into());
45+
}
46+
47+
// Parse the time field (first column)
48+
let time_value = record.get(0).unwrap();
49+
if csv_options.save_absolute_time {
50+
data.absolute_time.push(time_value.parse()?);
51+
} else {
52+
data.time.push(time_value.parse()?);
53+
}
54+
55+
// Parse the remaining columns and populate the dataset
56+
for (i, value) in record.iter().skip(1).enumerate() {
57+
if let Some(dataset_column) = data.dataset.get_mut(i) {
58+
dataset_column.push(value.parse()?);
59+
} else {
60+
return Err("Unexpected number of data columns in the CSV".into());
61+
}
62+
}
63+
}
64+
65+
Ok(())
66+
}
67+
1768
pub fn save_to_csv(data: &DataContainer, csv_options: &FileOptions) -> Result<(), Box<dyn Error>> {
1869
let mut wtr = WriterBuilder::new()
1970
.has_headers(false)

src/main.rs

Lines changed: 78 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@ extern crate preferences;
66
extern crate serde;
77

88
use std::cmp::max;
9+
use std::path::PathBuf;
910
use std::sync::mpsc::{Receiver, Sender};
1011
use std::sync::{mpsc, Arc, RwLock};
1112
use std::thread;
1213
use std::time::Duration;
1314

1415
use crate::data::{DataContainer, Packet};
1516
use crate::gui::{load_gui_settings, MyApp, RIGHT_PANEL_WIDTH};
16-
use crate::io::{save_to_csv, FileOptions};
17+
use crate::io::{open_from_csv, save_to_csv, FileOptions};
1718
use crate::serial::{load_serial_settings, serial_thread, Device};
1819
use eframe::egui::{vec2, ViewportBuilder, Visuals};
1920
use eframe::{egui, icon_data};
@@ -51,51 +52,90 @@ fn main_thread(
5152
data_lock: Arc<RwLock<DataContainer>>,
5253
raw_data_rx: Receiver<Packet>,
5354
save_rx: Receiver<FileOptions>,
55+
load_rx: Receiver<PathBuf>,
5456
clear_rx: Receiver<bool>,
5557
) {
5658
// reads data from mutex, samples and saves if needed
5759
let mut data = DataContainer::default();
5860
let mut failed_format_counter = 0;
61+
62+
let mut file_opened = false;
63+
5964
loop {
6065
if let Ok(cl) = clear_rx.recv_timeout(Duration::from_millis(1)) {
6166
if cl {
6267
data = DataContainer::default();
6368
failed_format_counter = 0;
6469
}
6570
}
66-
67-
if let Ok(packet) = raw_data_rx.recv_timeout(Duration::from_millis(1)) {
68-
if !packet.payload.is_empty() {
69-
sync_tx.send(true).expect("unable to send sync tx");
70-
data.raw_traffic.push(packet.clone());
71-
let split_data = split(&packet.payload);
72-
if data.dataset.is_empty() || failed_format_counter > 10 {
73-
// resetting dataset
74-
data.dataset = vec![vec![]; max(split_data.len(), 1)];
75-
failed_format_counter = 0;
76-
// println!("resetting dataset. split length = {}, length data.dataset = {}", split_data.len(), data.dataset.len());
77-
} else if split_data.len() == data.dataset.len() {
78-
// appending data
79-
for (i, set) in data.dataset.iter_mut().enumerate() {
80-
set.push(split_data[i]);
81-
failed_format_counter = 0;
82-
}
83-
data.time.push(packet.relative_time);
84-
data.absolute_time.push(packet.absolute_time);
85-
if data.time.len() != data.dataset[0].len() {
71+
if !file_opened {
72+
if let Ok(packet) = raw_data_rx.recv_timeout(Duration::from_millis(1)) {
73+
if !packet.payload.is_empty() {
74+
sync_tx.send(true).expect("unable to send sync tx");
75+
data.raw_traffic.push(packet.clone());
76+
let split_data = split(&packet.payload);
77+
if data.dataset.is_empty() || failed_format_counter > 10 {
8678
// resetting dataset
87-
data.time = vec![];
8879
data.dataset = vec![vec![]; max(split_data.len(), 1)];
80+
failed_format_counter = 0;
81+
// println!("resetting dataset. split length = {}, length data.dataset = {}", split_data.len(), data.dataset.len());
82+
} else if split_data.len() == data.dataset.len() {
83+
// appending data
84+
for (i, set) in data.dataset.iter_mut().enumerate() {
85+
set.push(split_data[i]);
86+
failed_format_counter = 0;
87+
}
88+
data.time.push(packet.relative_time);
89+
data.absolute_time.push(packet.absolute_time);
90+
if data.time.len() != data.dataset[0].len() {
91+
// resetting dataset
92+
data.time = vec![];
93+
data.dataset = vec![vec![]; max(split_data.len(), 1)];
94+
}
95+
} else {
96+
// not same length
97+
failed_format_counter += 1;
98+
// println!("not same length in main! length split_data = {}, length data.dataset = {}", split_data.len(), data.dataset.len())
8999
}
90-
} else {
91-
// not same length
92-
failed_format_counter += 1;
93-
// println!("not same length in main! length split_data = {}, length data.dataset = {}", split_data.len(), data.dataset.len())
94100
}
95-
if let Ok(mut write_guard) = data_lock.write() {
96-
*write_guard = data.clone();
101+
}
102+
}
103+
if let Ok(fp) = load_rx.recv_timeout(Duration::from_millis(10)) {
104+
if let Some(file_ending) = fp.extension() {
105+
match file_ending.to_str().unwrap() {
106+
"csv" => {
107+
file_opened = true;
108+
let mut file_options = FileOptions {
109+
file_path: fp.clone(),
110+
save_absolute_time: false,
111+
save_raw_traffic: false,
112+
names: vec![],
113+
};
114+
match open_from_csv(&mut data, &mut file_options) {
115+
Ok(_) => {
116+
log::info!("opened {:?}", fp);
117+
}
118+
Err(err) => {
119+
file_opened = false;
120+
log::error!("failed opening {:?}: {:?}", fp, err);
121+
}
122+
};
123+
}
124+
_ => {
125+
file_opened = false;
126+
log::error!("file not supported: {:?} \n Close the file to connect to a spectrometer or open another file.", fp);
127+
continue;
128+
}
97129
}
130+
} else {
131+
file_opened = false;
98132
}
133+
} else {
134+
file_opened = false;
135+
}
136+
137+
if let Ok(mut write_guard) = data_lock.write() {
138+
*write_guard = data.clone();
99139
}
100140

101141
if let Ok(csv_options) = save_rx.recv_timeout(Duration::from_millis(1)) {
@@ -129,6 +169,7 @@ fn main() {
129169
let connected_lock = Arc::new(RwLock::new(false));
130170

131171
let (save_tx, save_rx): (Sender<FileOptions>, Receiver<FileOptions>) = mpsc::channel();
172+
let (load_tx, load_rx): (Sender<PathBuf>, Receiver<PathBuf>) = mpsc::channel();
132173
let (send_tx, send_rx): (Sender<String>, Receiver<String>) = mpsc::channel();
133174
let (clear_tx, clear_rx): (Sender<bool>, Receiver<bool>) = mpsc::channel();
134175
let (raw_data_tx, raw_data_rx): (Sender<Packet>, Receiver<Packet>) = mpsc::channel();
@@ -151,7 +192,14 @@ fn main() {
151192
let main_data_lock = data_lock.clone();
152193

153194
let _main_thread_handler = thread::spawn(|| {
154-
main_thread(sync_tx, main_data_lock, raw_data_rx, save_rx, clear_rx);
195+
main_thread(
196+
sync_tx,
197+
main_data_lock,
198+
raw_data_rx,
199+
save_rx,
200+
load_rx,
201+
clear_rx,
202+
);
155203
});
156204

157205
let options = eframe::NativeOptions {
@@ -196,6 +244,7 @@ fn main() {
196244
gui_connected_lock,
197245
gui_settings,
198246
save_tx,
247+
load_tx,
199248
send_tx,
200249
clear_tx,
201250
)))

0 commit comments

Comments
 (0)