fixed all warnings and restored original ethercat discovery behaviour

This commit is contained in:
kraemr committed 2025-10-23 20:13:48 +02:00
1 parent 025464ebff
commit e93e10d14d
6 files changed
+200 -138

No files matched your search

@@ -0,0 +1,38 @@
use std::sync::Arc;
use control_core::socketio::namespace::NamespaceCacheingLogic;
use crate::{
app_state::AppState,
socketio::main_namespace::{
MainNamespaceEvents, ethercat_interface_discovery_event::EthercatInterfaceDiscoveryEvent,
},
};
pub async fn send_ethercat_discovering(app_state: Arc<AppState>) {
{
let main_namespace = &mut app_state
.socketio_setup
.namespaces
.write()
.await
.main_namespace;
let event = EthercatInterfaceDiscoveryEvent::Discovering(true).build();
main_namespace.emit(MainNamespaceEvents::EthercatInterfaceDiscoveryEvent(event));
}
}
pub async fn send_ethercat_found(app_state: Arc<AppState>, interface: &str) {
// Notify client via socketio
let interface = interface.to_string();
let app_state_socketio = app_state.clone();
smol::block_on(async move {
let main_namespace = &mut app_state_socketio
.socketio_setup
.namespaces
.write()
.await
.main_namespace;
let event = EthercatInterfaceDiscoveryEvent::Done(interface).build();
main_namespace.emit(MainNamespaceEvents::EthercatInterfaceDiscoveryEvent(event));
});
}
+1
View File
@@ -1,3 +1,4 @@
pub mod config;
pub mod ethercat_discovery_info;
pub mod init;
pub mod setup;
+4 -3
View File
@@ -52,6 +52,7 @@ pub async fn setup_loop(interface: &str, app_state: Arc<AppState>) -> Result<(),
let _ = set_core_affinity(3);
// Set the thread to real-time priority
#[cfg(not(feature = "development-build"))]
let _ = set_realtime_priority();
#[cfg(not(all(target_os = "linux", feature = "io-uring")))]
@@ -85,13 +86,13 @@ pub async fn setup_loop(interface: &str, app_state: Arc<AppState>) -> Result<(),
// Default 30_000us
pdu: Duration::from_micros(30_000),
// Default 10ms
eeprom: Duration::from_millis(100),
eeprom: Duration::from_millis(10),
// Default 0ms
wait_loop_delay: Duration::from_millis(0),
// Default 100ms
mailbox_echo: Duration::from_millis(1000),
mailbox_echo: Duration::from_millis(100),
// Default 1000ms
mailbox_response: Duration::from_millis(10000),
mailbox_response: Duration::from_millis(1000),
},
MainDeviceConfig {
// Default RetryBehaviour::None
+15 -2
View File
@@ -1,4 +1,4 @@
use crate::app_state::AppState;
use crate::{app_state::AppState, ethercat::setup::setup_loop};
use bitvec::prelude::*;
use control_core::machines::connection::MachineConnection;
use control_core::realtime::set_core_affinity;
@@ -9,8 +9,20 @@ use std::time::Instant;
use tracing::{instrument, trace_span};
pub fn start_loop_thread(
interface: &str,
app_state: Arc<AppState>,
) -> Result<std::thread::JoinHandle<()>, std::io::Error> {
let res = smol::block_on(async { setup_loop(interface, app_state.clone()).await });
match res {
Ok(_) => tracing::info!("Successfully initialized EtherCAT network"),
Err(e) => {
tracing::error!(
"[{}::init_loop] Failed to initialize EtherCAT network \n{:?}",
module_path!(),
e
);
}
}
// Start control loop
let res = std::thread::Builder::new()
.name("loop".to_owned())
@@ -43,7 +55,8 @@ pub fn start_loop_thread(
#[cfg(feature = "development-build")]
std::thread::park_timeout(std::time::Duration::from_millis(600));
}
// Exit the entire program if the Loop fails (gets restarted by systemd if running on NixOS)
// Exit the entire program if the Loop fails
// gets restarted by systemd if running on NixOS, or different distro wtih the same sysd service
std::process::exit(1);
});
return res;
+19 -131
View File
@@ -1,34 +1,21 @@
use anyhow::Result;
use control_core::{
machines::identification::MachineIdentificationUnique,
serial::{
SerialDeviceIdentification, SerialDeviceNew, SerialDeviceNewParams,
serial_detection::SerialDetection,
},
socketio::namespace::NamespaceCacheingLogic,
};
use futures::{FutureExt, select};
use machines::{laser::LaserMachine, registry::MACHINE_REGISTRY};
#[cfg(feature = "mock-machine")]
use mock::init::init_mock;
use serialport::UsbPortInfo;
#[cfg(feature = "mock-machine")]
pub mod mock;
use crate::panic::init_panic_handling;
use app_state::AppState;
use ethercat::init::start_interface_discovery;
use ethercat::{
ethercat_discovery_info::{send_ethercat_discovering, send_ethercat_found},
init::start_interface_discovery,
};
use r#loop::start_loop_thread;
use rest::init::start_api_thread;
use serial::{
devices::laser::Laser, init::start_serial_discovery, registry::SERIAL_DEVICE_REGISTRY,
};
use socketio::{
main_namespace::{MainNamespaceEvents, machines_event::MachinesEventBuilder},
queue::start_socketio_queue,
};
use std::{collections::HashMap, sync::Arc};
use serial::init::{handle_serial_device_hotplug, start_serial_discovery};
use socketio::queue::start_socketio_queue;
use std::sync::Arc;
pub mod app_state;
pub mod ethercat;
pub mod logging;
@@ -40,112 +27,6 @@ pub mod rest;
pub mod serial;
pub mod socketio;
// This function handles a disconnection and or reconnection of Laser
// You can easily rewrite it when we have more serialdevices
// TODO: Add A static list of known SeriadeviceIdents
async fn handle_serial_device_hotplug(
app_state: Arc<AppState>,
map: Option<HashMap<String, UsbPortInfo>>,
) {
let laser_ident = SerialDeviceIdentification {
vendor_id: 0x0403,
product_id: 0x6001,
};
let laser = match map {
Some(map) => SerialDetection::get_path_by_id(laser_ident, map),
None => None,
};
let mut unique_ident: Option<MachineIdentificationUnique> = None;
{
let machines = app_state.machines.read_arc_blocking();
for (id, _) in machines.iter() {
if id.machine_identification == LaserMachine::MACHINE_IDENTIFICATION {
unique_ident = Some(id.clone());
break;
}
}
}
// Machine isnt connected, so add it back
if laser.is_some() && unique_ident.is_none() {
let serial_params = SerialDeviceNewParams {
path: laser.unwrap(),
};
let _ = match Laser::new_serial(&serial_params) {
Ok((device_identification, serial_device)) => {
{
let mut machines = app_state.machines.write().await;
machines.add_serial_device(
&device_identification,
serial_device,
&MACHINE_REGISTRY,
app_state.socketio_setup.socket_queue_tx.clone(),
Arc::downgrade(&app_state.machines),
);
}
let app_state_event = app_state.clone();
let main_namespace = &mut app_state_event
.socketio_setup
.namespaces
.write()
.await
.main_namespace;
let event = MachinesEventBuilder().build(app_state_event.clone());
main_namespace.emit(MainNamespaceEvents::MachinesEvent(event));
}
_ => (),
};
} else if laser.is_none() && unique_ident.is_some() {
tracing::info!("hello non existing laser");
let serial_params = SerialDeviceNewParams {
path: "".to_string(),
};
let _ = match Laser::new_serial(&serial_params) {
Ok((device_identification, _)) => {
app_state
.machines
.write()
.await
.remove_serial_device(&device_identification);
drop(app_state.machines.clone());
app_state
.machines
.write_arc()
.await
.serial_machines
.remove(&unique_ident.clone().unwrap());
app_state
.machines
.write_arc()
.await
.ethercat_machines
.remove(&unique_ident.clone().unwrap());
drop(app_state.machines.clone());
let main_namespace = &mut app_state
.socketio_setup
.namespaces
.write()
.await
.main_namespace;
tracing::info!("{:?}", app_state.machines);
let event = MachinesEventBuilder().build(app_state.clone());
main_namespace.emit(MainNamespaceEvents::MachinesEvent(event));
}
_ => (),
};
}
}
fn main() {
logging::init_tracing();
tracing::info!("Tracing initialized successfully");
@@ -154,28 +35,35 @@ fn main() {
let app_state = Arc::new(AppState::new());
let _ = start_api_thread(app_state.clone());
let _ = start_loop_thread(app_state.clone());
let mut socketio_fut = start_socketio_queue(app_state.clone()).fuse();
let mut ethercat_fut = start_interface_discovery().fuse();
let mut serial_fut = start_serial_discovery().fuse();
smol::block_on(async { send_ethercat_discovering(app_state.clone()).await });
smol::block_on(async {
loop {
// lets the async runtime decide which future to run next
select! {
res = ethercat_fut => {
// Should only complete once
tracing::info!("EtherCAT task finished: {:?}", res);
match res {
Ok(interface) =>
{
send_ethercat_found(app_state.clone(), &interface).await;
let _ = start_loop_thread(&interface, app_state.clone());
},
Err(_) => (),
};
},
res = serial_fut => {
// tracing::info!("Serial discovery finished: {:?}", res);
let _ = handle_serial_device_hotplug(app_state.clone(),res).await;
serial_fut = start_serial_discovery().fuse();
},
res = socketio_fut => {
// In theory it should never finish
tracing::info!("SocketIO task finished: {:?}", res);
tracing::warn!("SocketIO task finished: {:?}", res);
},
_ = smol::Timer::after(std::time::Duration::from_millis(250)).fuse() => {} // Nothing to do just sleep
}
+123 -2
View File
@@ -1,7 +1,22 @@
use control_core::serial::serial_detection::SerialDetection;
use control_core::{
machines::identification::MachineIdentificationUnique,
serial::{
SerialDeviceIdentification, SerialDeviceNew, SerialDeviceNewParams,
serial_detection::SerialDetection,
},
socketio::namespace::NamespaceCacheingLogic,
};
use serialport::UsbPortInfo;
use smol::Task;
use std::{collections::HashMap, time::Duration};
use std::{collections::HashMap, sync::Arc, time::Duration};
use crate::{
app_state::AppState,
machines::{laser::LaserMachine, registry::MACHINE_REGISTRY},
socketio::main_namespace::{MainNamespaceEvents, machines_event::MachinesEventBuilder},
};
use super::devices::laser::Laser;
// Async function that runs until at least one serial device is found.
pub async fn find_serial() -> Option<HashMap<String, UsbPortInfo>> {
@@ -18,3 +33,109 @@ pub async fn find_serial() -> Option<HashMap<String, UsbPortInfo>> {
pub fn start_serial_discovery() -> Task<Option<HashMap<String, UsbPortInfo>>> {
smol::spawn(find_serial())
}
// This function handles a disconnection and or reconnection of Laser
// You can easily rewrite it when we have more serialdevices
// TODO: Add A static list of known SeriadeviceIdents
pub async fn handle_serial_device_hotplug(
app_state: Arc<AppState>,
map: Option<HashMap<String, UsbPortInfo>>,
) {
let laser_ident = SerialDeviceIdentification {
vendor_id: 0x0403,
product_id: 0x6001,
};
let laser = match map {
Some(map) => SerialDetection::get_path_by_id(laser_ident, map),
None => None,
};
let mut unique_ident: Option<MachineIdentificationUnique> = None;
{
let machines = app_state.machines.read_arc_blocking();
for (id, _) in machines.iter() {
if id.machine_identification == LaserMachine::MACHINE_IDENTIFICATION {
unique_ident = Some(id.clone());
break;
}
}
}
// Machine isnt connected, so add it back
if laser.is_some() && unique_ident.is_none() {
let serial_params = SerialDeviceNewParams {
path: laser.unwrap(),
};
let _ = match Laser::new_serial(&serial_params) {
Ok((device_identification, serial_device)) => {
{
let mut machines = app_state.machines.write().await;
machines.add_serial_device(
&device_identification,
serial_device,
&MACHINE_REGISTRY,
app_state.socketio_setup.socket_queue_tx.clone(),
Arc::downgrade(&app_state.machines),
);
}
let app_state_event = app_state.clone();
let main_namespace = &mut app_state_event
.socketio_setup
.namespaces
.write()
.await
.main_namespace;
let event = MachinesEventBuilder().build(app_state_event.clone());
main_namespace.emit(MainNamespaceEvents::MachinesEvent(event));
}
_ => (),
};
} else if laser.is_none() && unique_ident.is_some() {
tracing::info!("hello non existing laser");
let serial_params = SerialDeviceNewParams {
path: "".to_string(),
};
let _ = match Laser::new_serial(&serial_params) {
Ok((device_identification, _)) => {
app_state
.machines
.write()
.await
.remove_serial_device(&device_identification);
drop(app_state.machines.clone());
app_state
.machines
.write_arc()
.await
.serial_machines
.remove(&unique_ident.clone().unwrap());
app_state
.machines
.write_arc()
.await
.ethercat_machines
.remove(&unique_ident.clone().unwrap());
drop(app_state.machines.clone());
let main_namespace = &mut app_state
.socketio_setup
.namespaces
.write()
.await
.main_namespace;
tracing::info!("{:?}", app_state.machines);
let event = MachinesEventBuilder().build(app_state.clone());
main_namespace.emit(MainNamespaceEvents::MachinesEvent(event));
}
_ => (),
};
}
}