mirror of
https://github.com/hubaldv/bioz-host-rs.git
synced 2025-12-06 05:11:17 +00:00
Added log and automatic reconnect.
This commit is contained in:
93
Cargo.lock
generated
93
Cargo.lock
generated
@@ -435,7 +435,9 @@ dependencies = [
|
|||||||
"defmt",
|
"defmt",
|
||||||
"eframe",
|
"eframe",
|
||||||
"egui_plot",
|
"egui_plot",
|
||||||
|
"log",
|
||||||
"postcard-rpc",
|
"postcard-rpc",
|
||||||
|
"simple_logger",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-serial",
|
"tokio-serial",
|
||||||
]
|
]
|
||||||
@@ -647,6 +649,16 @@ dependencies = [
|
|||||||
"unicode-width",
|
"unicode-width",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colored"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "combine"
|
name = "combine"
|
||||||
version = "4.6.7"
|
version = "4.6.7"
|
||||||
@@ -791,6 +803,15 @@ dependencies = [
|
|||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "deranged"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
|
||||||
|
dependencies = [
|
||||||
|
"powerfmt",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dispatch"
|
name = "dispatch"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@@ -1639,6 +1660,12 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jni"
|
name = "jni"
|
||||||
version = "0.21.1"
|
version = "0.21.1"
|
||||||
@@ -1987,6 +2014,12 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-conv"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.19"
|
version = "0.2.19"
|
||||||
@@ -2019,6 +2052,15 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_threads"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nusb"
|
name = "nusb"
|
||||||
version = "0.1.14"
|
version = "0.1.14"
|
||||||
@@ -2540,6 +2582,12 @@ dependencies = [
|
|||||||
"zerovec",
|
"zerovec",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "powerfmt"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-crate"
|
name = "proc-macro-crate"
|
||||||
version = "3.3.0"
|
version = "3.3.0"
|
||||||
@@ -2872,6 +2920,18 @@ version = "0.3.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simple_logger"
|
||||||
|
version = "5.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e8c5dfa5e08767553704aa0ffd9d9794d527103c736aba9854773851fd7497eb"
|
||||||
|
dependencies = [
|
||||||
|
"colored",
|
||||||
|
"log",
|
||||||
|
"time",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.10"
|
version = "0.4.10"
|
||||||
@@ -3111,6 +3171,39 @@ dependencies = [
|
|||||||
"weezl",
|
"weezl",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time"
|
||||||
|
version = "0.3.41"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
|
||||||
|
dependencies = [
|
||||||
|
"deranged",
|
||||||
|
"itoa",
|
||||||
|
"libc",
|
||||||
|
"num-conv",
|
||||||
|
"num_threads",
|
||||||
|
"powerfmt",
|
||||||
|
"serde",
|
||||||
|
"time-core",
|
||||||
|
"time-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time-core"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time-macros"
|
||||||
|
version = "0.2.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49"
|
||||||
|
dependencies = [
|
||||||
|
"num-conv",
|
||||||
|
"time-core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tiny-skia"
|
name = "tiny-skia"
|
||||||
version = "0.11.4"
|
version = "0.11.4"
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ edition = "2024"
|
|||||||
defmt = { version = "1.0.1" }
|
defmt = { version = "1.0.1" }
|
||||||
eframe = { version = "0.32.0"}
|
eframe = { version = "0.32.0"}
|
||||||
egui_plot = "0.33.0"
|
egui_plot = "0.33.0"
|
||||||
|
log = "0.4.27"
|
||||||
|
simple_logger = "5.0.0"
|
||||||
|
|
||||||
[dependencies.bioz-icd-rs]
|
[dependencies.bioz-icd-rs]
|
||||||
path = "../bioz-icd-rs"
|
path = "../bioz-icd-rs"
|
||||||
|
|||||||
22
src/app.rs
22
src/app.rs
@@ -1,16 +1,16 @@
|
|||||||
use std::sync::{Arc, Mutex, RwLock};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use std::ops::RangeInclusive;
|
use std::ops::RangeInclusive;
|
||||||
|
|
||||||
use tokio::{sync::mpsc::{self, Receiver, Sender}, time::Timeout};
|
use tokio::{sync::mpsc::{Sender}};
|
||||||
|
|
||||||
use eframe::egui::{self, Button, Checkbox, Color32, DragValue, Key, Layout, Modifiers, RichText, Rounding, };
|
use eframe::egui::{self, Color32, DragValue, Key, Layout, Modifiers};
|
||||||
use egui_plot::{Corner, Legend, Line, Plot, PlotPoints, Points, PlotBounds};
|
use egui_plot::{Corner, Legend, Line, Plot, PlotPoints, Points, PlotBounds};
|
||||||
|
|
||||||
use crate::plot::TimeSeriesPlot;
|
use crate::plot::TimeSeriesPlot;
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
interval_ms: u32,
|
frequency: u32,
|
||||||
run_impedancemeter_tx: Sender<u32>,
|
run_impedancemeter_tx: Sender<u32>,
|
||||||
pub magnitude: Arc<Mutex<f32>>,
|
pub magnitude: Arc<Mutex<f32>>,
|
||||||
pub phase: Arc<Mutex<f32>>,
|
pub phase: Arc<Mutex<f32>>,
|
||||||
@@ -21,7 +21,7 @@ pub struct App {
|
|||||||
impl App {
|
impl App {
|
||||||
pub fn new(run_impedancemeter_tx: Sender<u32>) -> Self {
|
pub fn new(run_impedancemeter_tx: Sender<u32>) -> Self {
|
||||||
App {
|
App {
|
||||||
interval_ms: 10, // Default interval
|
frequency: 2, // Default frequency
|
||||||
run_impedancemeter_tx,
|
run_impedancemeter_tx,
|
||||||
magnitude: Arc::new(Mutex::new(0.0)),
|
magnitude: Arc::new(Mutex::new(0.0)),
|
||||||
phase: Arc::new(Mutex::new(0.0)),
|
phase: Arc::new(Mutex::new(0.0)),
|
||||||
@@ -39,18 +39,20 @@ impl eframe::App for App {
|
|||||||
egui::widgets::global_theme_preference_switch(ui);
|
egui::widgets::global_theme_preference_switch(ui);
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
||||||
if ui.add(DragValue::new(&mut self.interval_ms).speed(0.1).range(RangeInclusive::new(0, 50)).update_while_editing(false)).changed() {
|
if ui.add(DragValue::new(&mut self.frequency).speed(0.1).range(RangeInclusive::new(0, 50)).update_while_editing(false)).changed() {
|
||||||
if let Err(e) = self.run_impedancemeter_tx.try_send(0) {
|
if let Err(e) = self.run_impedancemeter_tx.try_send(0) {
|
||||||
eprintln!("Failed to send stop command: {:?}", e);
|
eprintln!("Failed to send stop command: {:?}", e);
|
||||||
}
|
}
|
||||||
// Delay
|
// Delay
|
||||||
if let Err(e) = self.run_impedancemeter_tx.try_send(self.interval_ms) {
|
if let Err(e) = self.run_impedancemeter_tx.try_send(self.frequency) {
|
||||||
eprintln!("Failed to send interval update: {:?}", e);
|
eprintln!("Failed to send frequency update: {:?}", e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ui.separator();
|
||||||
|
|
||||||
if ui.button("Start").clicked() {
|
if ui.button("Start").clicked() {
|
||||||
if let Err(e) = self.run_impedancemeter_tx.try_send(self.interval_ms) {
|
if let Err(e) = self.run_impedancemeter_tx.try_send(self.frequency) {
|
||||||
eprintln!("Failed to send start command: {:?}", e);
|
eprintln!("Failed to send start command: {:?}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -67,7 +69,7 @@ impl eframe::App for App {
|
|||||||
|
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
let available_height = ui.available_height();
|
let available_height = ui.available_height();
|
||||||
let mut half_height = available_height / 4.0;
|
let half_height = available_height / 4.0;
|
||||||
|
|
||||||
let point_pos = vec![[*self.magnitude.lock().unwrap() as f64, *self.phase.lock().unwrap() as f64]];
|
let point_pos = vec![[*self.magnitude.lock().unwrap() as f64, *self.phase.lock().unwrap() as f64]];
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,13 @@ use bioz_host_rs::{client::WorkbookClient, icd, read_line};
|
|||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
println!("Connecting to USB device...");
|
println!("Connecting to USB device...");
|
||||||
let client = WorkbookClient::new();
|
let client = match WorkbookClient::new() {
|
||||||
|
Ok(client) => client,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Failed to connect to USB device: {}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
for i in 0..10 {
|
for i in 0..10 {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use simple_logger::SimpleLogger;
|
||||||
|
use log::info;
|
||||||
use tokio::runtime::Runtime;
|
use tokio::runtime::Runtime;
|
||||||
|
|
||||||
use bioz_host_rs::app::App;
|
use bioz_host_rs::app::App;
|
||||||
@@ -7,6 +9,9 @@ use bioz_host_rs::communication::communicate_with_hardware;
|
|||||||
use tokio::sync::mpsc::{self};
|
use tokio::sync::mpsc::{self};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
SimpleLogger::new().init().expect("Failed to initialize logger");
|
||||||
|
log::set_max_level(log::LevelFilter::Info);
|
||||||
|
info!("Starting Bioz Impedance Visualizer...");
|
||||||
|
|
||||||
let rt = Runtime::new().expect("Unable to create Runtime");
|
let rt = Runtime::new().expect("Unable to create Runtime");
|
||||||
|
|
||||||
|
|||||||
@@ -26,36 +26,17 @@ impl<E> From<HostErr<WireError>> for WorkbookError<E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait FlattenErr {
|
|
||||||
type Good;
|
|
||||||
type Bad;
|
|
||||||
fn flatten(self) -> Result<Self::Good, WorkbookError<Self::Bad>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, E> FlattenErr for Result<T, E> {
|
|
||||||
type Good = T;
|
|
||||||
type Bad = E;
|
|
||||||
fn flatten(self) -> Result<Self::Good, WorkbookError<Self::Bad>> {
|
|
||||||
self.map_err(WorkbookError::Endpoint)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
impl WorkbookClient {
|
impl WorkbookClient {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Result<Self, String> {
|
||||||
let client = HostClient::new_raw_nusb(
|
let client = HostClient::try_new_raw_nusb(
|
||||||
|d| d.product_string() == Some("Bioz Amplifier"),
|
|d| d.product_string() == Some("Bioz Amplifier"),
|
||||||
ERROR_PATH,
|
ERROR_PATH,
|
||||||
8,
|
8,
|
||||||
VarSeqKind::Seq2,
|
VarSeqKind::Seq2,
|
||||||
);
|
)?;
|
||||||
Self { client }
|
Ok(Self { client })
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_serial(port: &str) -> Self {
|
|
||||||
let client = HostClient::new_serial_cobs(port, ERROR_PATH, 8, 9600, VarSeqKind::Seq2);
|
|
||||||
Self { client }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn wait_closed(&self) {
|
pub async fn wait_closed(&self) {
|
||||||
@@ -87,7 +68,6 @@ impl WorkbookClient {
|
|||||||
self.client
|
self.client
|
||||||
.send_resp::<StartImpedanceEndpoint>(&StartImpedance { update_frequency: 60, sinus_frequency: frequency })
|
.send_resp::<StartImpedanceEndpoint>(&StartImpedance { update_frequency: 60, sinus_frequency: frequency })
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,13 +76,6 @@ impl WorkbookClient {
|
|||||||
.client
|
.client
|
||||||
.send_resp::<StopImpedanceEndpoint>(&())
|
.send_resp::<StopImpedanceEndpoint>(&())
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for WorkbookClient {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use log::{error, info};
|
||||||
|
|
||||||
use tokio::select;
|
use tokio::select;
|
||||||
use tokio::sync::mpsc::Receiver;
|
use tokio::sync::mpsc::Receiver;
|
||||||
|
|
||||||
@@ -15,52 +17,78 @@ pub async fn communicate_with_hardware(
|
|||||||
magnitude_series: Arc<Mutex<TimeSeriesPlot>>,
|
magnitude_series: Arc<Mutex<TimeSeriesPlot>>,
|
||||||
phase_series: Arc<Mutex<TimeSeriesPlot>>,
|
phase_series: Arc<Mutex<TimeSeriesPlot>>,
|
||||||
) {
|
) {
|
||||||
let workbook_client = WorkbookClient::new();
|
|
||||||
|
|
||||||
let mut sub = workbook_client
|
|
||||||
.client
|
|
||||||
.subscribe_multi::<icd::ImpedanceTopic>(8)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
tokio::spawn(async move {
|
|
||||||
while let Ok(val) = sub.recv().await {
|
|
||||||
let mut mag_plot = magnitude_series.lock().unwrap();
|
|
||||||
let mut phase_plot = phase_series.lock().unwrap();
|
|
||||||
|
|
||||||
*magnitude.lock().unwrap() = val.magnitude;
|
|
||||||
*phase.lock().unwrap() = val.phase;
|
|
||||||
|
|
||||||
mag_plot.add(val.magnitude as f64);
|
|
||||||
phase_plot.add(val.phase as f64);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
select! {
|
let workbook_client = match WorkbookClient::new() {
|
||||||
Some(run) = run_impedancemeter_rx.recv() => {
|
Ok(client) => {
|
||||||
if run > 0 {
|
info!("Connected to hardware successfully.");
|
||||||
// Start the impedancemeter
|
client
|
||||||
if let Err(e) = workbook_client.start_impedancemeter(run as f32).await {
|
},
|
||||||
eprintln!("Failed to start impedancemeter: {:?}", e);
|
Err(e) => {
|
||||||
|
error!("Failed to connect to hardware: {:?}", e);
|
||||||
|
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut sub = workbook_client
|
||||||
|
.client
|
||||||
|
.subscribe_multi::<icd::ImpedanceTopic>(8)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let data = (magnitude_series.clone(), phase_series.clone(), magnitude.clone(), phase.clone());
|
||||||
|
|
||||||
|
tokio::spawn(async move {
|
||||||
|
while let Ok(val) = sub.recv().await {
|
||||||
|
let mut mag_plot = data.0.lock().unwrap();
|
||||||
|
let mut phase_plot = data.1.lock().unwrap();
|
||||||
|
let mut mag_val = data.2.lock().unwrap();
|
||||||
|
let mut phase_val = data.3.lock().unwrap();
|
||||||
|
|
||||||
|
*mag_val = val.magnitude;
|
||||||
|
*phase_val = val.phase;
|
||||||
|
|
||||||
|
mag_plot.add(val.magnitude as f64);
|
||||||
|
phase_plot.add(val.phase as f64);
|
||||||
|
}
|
||||||
|
info!("ImpedanceTopic subscription ended.");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
loop {
|
||||||
|
select! {
|
||||||
|
Some(run) = run_impedancemeter_rx.recv() => {
|
||||||
|
if run > 0 {
|
||||||
|
// Start the impedancemeter
|
||||||
|
if let Err(e) = workbook_client.start_impedancemeter(run as f32).await {
|
||||||
|
error!("Failed to start impedancemeter: {:?}", e);
|
||||||
|
} else {
|
||||||
|
info!("Impedancemeter started.");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
println!("Impedancemeter started.");
|
// Stop the impedancemeter
|
||||||
}
|
if let Err(e) = workbook_client.stop_impedancemeter().await {
|
||||||
} else {
|
error!("Failed to stop impedancemeter: {:?}", e);
|
||||||
// Stop the impedancemeter
|
} else {
|
||||||
if let Err(e) = workbook_client.stop_impedancemeter().await {
|
info!("Impedancemeter stopped.");
|
||||||
eprintln!("Failed to stop impedancemeter: {:?}", e);
|
}
|
||||||
} else {
|
|
||||||
println!("Impedancemeter stopped.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
_ = workbook_client.wait_closed() => {
|
||||||
|
// Handle client closure
|
||||||
|
info!("Client connection closed.");
|
||||||
|
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
else => {
|
else => {
|
||||||
// All channels closed
|
// All channels closed
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
info!("Communication with hardware ended.");
|
||||||
|
// Wait for a short period before trying to reconnect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user