Skip to content

Commit d665e7e

Browse files
committed
Making subscription working with fake data generator, no can communication at this point
1 parent ac1ea67 commit d665e7e

4 files changed

Lines changed: 176 additions & 8 deletions

File tree

Cargo.lock

Lines changed: 110 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ rfd = "0.15.4"
1010
egui_plot = "0.31.0"
1111
image = "0.25.1"
1212
chrono = "0.4.41"
13+
tokio = { version = "1.47.1", features = ["full"] }
14+
rand = "0.9.2"

src/communication.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use std::sync::mpsc::{Receiver, Sender};
22
use std::path::PathBuf;
33
use configparser::ini::Ini;
4-
use std::collections::BTreeMap;
4+
use std::collections::{BTreeMap, HashMap};
5+
use rand::Rng;
6+
use tokio::{sync::{mpsc as tokio_mpsc, oneshot}, task::JoinHandle};
57

68

79
#[derive(Debug, Clone)]
@@ -47,6 +49,22 @@ pub enum Update {
4749
},
4850
}
4951

52+
async fn simulation_task(address: SdoAddress, interval_ms: u64, update_tx: Sender<Update>) {
53+
println!("Starting simulation task for address {:?} with interval {} ms", &address, interval_ms);
54+
let mut interval = tokio::time::interval(std::time::Duration::from_millis(interval_ms));
55+
56+
57+
loop {
58+
interval.tick().await;
59+
let mut rng = rand::thread_rng();
60+
let random_value = rng.gen_range(0..100);
61+
let _ = update_tx.send(Update::SdoData {
62+
address: address.clone(),
63+
value: format!("{}", random_value),
64+
});
65+
}
66+
}
67+
5068
// Make the main function for the thread public as well.
5169
pub fn communication_thread_main(
5270
command_rx: Receiver<Command>,
@@ -56,9 +74,12 @@ pub fn communication_thread_main(
5674
eds_file: Option<PathBuf>,
5775
) {
5876

77+
let rt = tokio::runtime::Runtime::new().unwrap();
78+
let mut subscription_handles: HashMap<SdoAddress, JoinHandle<()>> = HashMap::new();
5979

6080
for command in command_rx {
6181
match command {
82+
Command::Connect => {},
6283
Command::FetchSdos => {
6384
if let Some(path) = eds_file.as_ref() {
6485
match search_for_readable_sdo(path.clone()) {
@@ -74,7 +95,19 @@ pub fn communication_thread_main(
7495
let _ = update_tx.send(Update::SdoList(BTreeMap::new()));
7596
}
7697
},
77-
Command::Connect => {},
98+
Command::Subscribe { address, interval_ms } => {
99+
println!("Subscribing to address {:?} with interval {} ms", &address, interval_ms);
100+
let update_tx_clone = update_tx.clone();
101+
let subscription_handle = rt.spawn(simulation_task(address.clone(), interval_ms, update_tx_clone));
102+
subscription_handles.insert(address, subscription_handle);
103+
},
104+
Command::Unsubscribe(address) => {
105+
println!("Unsubscribing from address {:?}", &address);
106+
let subscription_handle = subscription_handles.remove(&address);
107+
if let Some(subscription_handle) = subscription_handle {
108+
subscription_handle.abort();
109+
}
110+
}
78111
_ => {}
79112
}
80113
}

src/main.rs

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
mod communication;
44

5-
use std::collections::{BTreeMap, HashMap};
5+
use std::collections::{BTreeMap, HashMap, VecDeque};
66
use std::ops::Deref;
77
use communication::{Command, Update, SdoAddress, SdoObject};
88

@@ -14,6 +14,8 @@ use egui_plot::{Plot, PlotPoints, Line};
1414
use chrono::Local;
1515
use std::sync::Arc;
1616

17+
const PLOT_BUFFER_SIZE: usize = 500;
18+
1719
enum AppView {
1820
SelectInterface,
1921
SelectNodeId,
@@ -24,7 +26,7 @@ enum AppView {
2426
#[derive(Debug, Clone)]
2527
struct SdoSubscription{
2628
interval_ms: u64,
27-
plot_data: Vec<[f64; 2]>,
29+
plot_data: VecDeque<[f64; 2]>,
2830
}
2931
struct ScreenshotInfo {
3032
filename: String,
@@ -98,6 +100,21 @@ impl eframe::App for MyApp {
98100
match update{
99101
Update::SdoList(map) => {
100102
self.sdo_data = Some(map);
103+
},
104+
105+
Update::SdoData { address, value } => {
106+
// 1. Try to parse the incoming string value into a number.
107+
if let Ok(number_value) = value.parse::<f64>() {
108+
// 2. Find the subscription this data belongs to.
109+
if let Some(subscription) = self.subscriptions.get_mut(&address) {
110+
111+
if subscription.plot_data.len() >= PLOT_BUFFER_SIZE {
112+
subscription.plot_data.pop_front();
113+
}
114+
let time = subscription.plot_data.back().map_or(0.0, |p| p[0] + 1.0);
115+
subscription.plot_data.push_back([time, number_value]);
116+
}
117+
}
101118
}
102119
_ => {
103120

@@ -125,6 +142,8 @@ impl eframe::App for MyApp {
125142
AppView::Main => self.draw_main_view(ui),
126143
}
127144
});
145+
146+
ctx.request_repaint();
128147
}
129148
}
130149

@@ -376,6 +395,8 @@ impl MyApp {
376395
.allow_scroll(false)
377396
.height(250.0)
378397
.width(ui.available_width())
398+
.x_axis_label("Sample No")
399+
.y_axis_label("Value")
379400
.show(ui, |plot_ui| {
380401
// 2. Generate a unique color for the line based on its address.
381402
let color = Color32::from_rgb(
@@ -384,10 +405,12 @@ impl MyApp {
384405
(address.index as u8 ^ address.sub_index as u8).wrapping_mul(30),
385406
);
386407

387-
let line = Line::new(PlotPoints::from(subscription.plot_data.clone()))
388-
.name(&plot_title) // Use the title for the legend as well
389-
.color(color);
408+
let points_vec: Vec<[f64; 2]> = subscription.plot_data.iter().cloned().collect();
390409

410+
let line = Line::new(PlotPoints::from(points_vec))
411+
.name(&plot_title)
412+
.color(color);
413+
391414
plot_ui.line(line);
392415
});
393416

@@ -439,7 +462,7 @@ impl MyApp {
439462
}
440463
self.subscriptions.insert(address.clone(), SdoSubscription {
441464
interval_ms,
442-
plot_data: Vec::new(),
465+
plot_data: VecDeque::new(),
443466
});
444467
self.modal_open_for = None; // Close the modal
445468
}

0 commit comments

Comments
 (0)