Compare commits
No commits in common. "8a997a3d4ce0fcf3bd0e058370b83502b52ccbbd" and "362538c0019c1ac1fd8fb8500b7a13a55fbd6127" have entirely different histories.
8a997a3d4c
...
362538c001
9 changed files with 145 additions and 171 deletions
|
@ -1,6 +1,5 @@
|
||||||
camera_ip = "10.0.0.33"
|
camera_ip = "localhost"
|
||||||
camera_port = 8765
|
camera_port = 8765
|
||||||
tracker_ip = "localhost"
|
tracker_ip = "localhost"
|
||||||
tracker_port = 6543
|
tracker_port = 6543
|
||||||
tracker_refresh_rate_millis = 10
|
tracker_refresh_rate_millis = 100
|
||||||
tracker_jpeg_quality = 80
|
|
||||||
|
|
|
@ -13,7 +13,6 @@ pub struct AppConfig {
|
||||||
pub tracker_ip: String,
|
pub tracker_ip: String,
|
||||||
pub tracker_port: u32,
|
pub tracker_port: u32,
|
||||||
pub tracker_refresh_rate_millis: u32,
|
pub tracker_refresh_rate_millis: u32,
|
||||||
pub tracker_jpeg_quality: i32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for AppConfig {
|
impl Default for AppConfig {
|
||||||
|
@ -25,7 +24,6 @@ impl Default for AppConfig {
|
||||||
tracker_ip: "10.0.0.210".to_string(),
|
tracker_ip: "10.0.0.210".to_string(),
|
||||||
tracker_port: 6543,
|
tracker_port: 6543,
|
||||||
tracker_refresh_rate_millis: 100,
|
tracker_refresh_rate_millis: 100,
|
||||||
tracker_jpeg_quality: 50,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
use std::sync::Mutex;
|
||||||
use std::sync::{
|
use std::sync::{
|
||||||
atomic::{AtomicBool, Ordering},
|
atomic::{AtomicBool, Ordering},
|
||||||
Arc,
|
Arc,
|
||||||
|
@ -32,7 +33,7 @@ pub struct SocketState {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CoordState<'a> {
|
pub struct CoordState<'a> {
|
||||||
pub settings: Arc<RwLock<AppConfig>>,
|
pub settings: Arc<RwLock<AppConfig>>,
|
||||||
pub tracker_metrics: TrackerMetrics,
|
pub tracker_metrics: Arc<tokio::sync::Mutex<TrackerMetrics>>,
|
||||||
|
|
||||||
pub sck_outbound: Option<SplitSink<WebSocketStream<MaybeTlsStream<TcpStream>>, Message>>,
|
pub sck_outbound: Option<SplitSink<WebSocketStream<MaybeTlsStream<TcpStream>>, Message>>,
|
||||||
pub remote_sources_state: Arc<SocketState>,
|
pub remote_sources_state: Arc<SocketState>,
|
||||||
|
@ -49,7 +50,7 @@ pub struct CoordState<'a> {
|
||||||
|
|
||||||
pub pipeline: gstreamer_pipeline::WebcamPipeline,
|
pub pipeline: gstreamer_pipeline::WebcamPipeline,
|
||||||
|
|
||||||
pub tracker_state: TrackerState,
|
pub tracker_state: Arc<Mutex<TrackerState>>,
|
||||||
pub tracker_connection_state: Arc<SocketState>,
|
pub tracker_connection_state: Arc<SocketState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,12 +60,13 @@ impl<'a> CoordState<'a> {
|
||||||
to_mec: Sender<ApplicationEvent>,
|
to_mec: Sender<ApplicationEvent>,
|
||||||
to_gui: Sender<GuiUpdate>,
|
to_gui: Sender<GuiUpdate>,
|
||||||
rt: Handle,
|
rt: Handle,
|
||||||
|
tracker_state: Arc<Mutex<TrackerState>>,
|
||||||
settings: Arc<RwLock<AppConfig>>,
|
settings: Arc<RwLock<AppConfig>>,
|
||||||
jpeg_quality: i32,
|
tracker_header: Arc<std::sync::RwLock<String>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let this = CoordState {
|
let this = CoordState {
|
||||||
settings,
|
settings,
|
||||||
tracker_metrics: TrackerMetrics::new(to_gui.clone()),
|
tracker_metrics: Arc::new(tokio::sync::Mutex::new(TrackerMetrics::new(tracker_header))),
|
||||||
|
|
||||||
sck_outbound: None,
|
sck_outbound: None,
|
||||||
stay_alive_sck_recvr: Arc::new(AtomicBool::new(false)),
|
stay_alive_sck_recvr: Arc::new(AtomicBool::new(false)),
|
||||||
|
@ -82,17 +84,9 @@ impl<'a> CoordState<'a> {
|
||||||
to_gui,
|
to_gui,
|
||||||
rt,
|
rt,
|
||||||
|
|
||||||
pipeline: gstreamer_pipeline::WebcamPipeline::new(jpeg_quality).unwrap(),
|
pipeline: gstreamer_pipeline::WebcamPipeline::new().unwrap(),
|
||||||
|
|
||||||
tracker_state: TrackerState{
|
tracker_state,
|
||||||
tracking_id: 0,
|
|
||||||
highlighted_id: None,
|
|
||||||
last_detect: Instant::now(),
|
|
||||||
enabled: true,
|
|
||||||
|
|
||||||
identity_boxes: vec![],
|
|
||||||
update_ids: false,
|
|
||||||
},
|
|
||||||
tracker_connection_state: Arc::new(SocketState {
|
tracker_connection_state: Arc::new(SocketState {
|
||||||
stay_connected: AtomicBool::new(false),
|
stay_connected: AtomicBool::new(false),
|
||||||
is_connected: AtomicBool::new(false),
|
is_connected: AtomicBool::new(false),
|
||||||
|
@ -231,6 +225,7 @@ impl<'a> CoordState<'a> {
|
||||||
self.rt.clone(),
|
self.rt.clone(),
|
||||||
self.to_mec.clone(),
|
self.to_mec.clone(),
|
||||||
self.remote_sources_state.clone(),
|
self.remote_sources_state.clone(),
|
||||||
|
self.tracker_state.clone(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use std::pin::pin;
|
use std::pin::pin;
|
||||||
|
use std::sync::Mutex;
|
||||||
use std::sync::{
|
use std::sync::{
|
||||||
atomic::{AtomicBool, Ordering},
|
atomic::{AtomicBool, Ordering},
|
||||||
Arc,
|
Arc,
|
||||||
|
@ -24,6 +25,7 @@ pub mod tracker_state;
|
||||||
use crate::config::AppConfig;
|
use crate::config::AppConfig;
|
||||||
use crate::ui::{GuiUpdate, NormalizedBoxCoords};
|
use crate::ui::{GuiUpdate, NormalizedBoxCoords};
|
||||||
pub use coord_state::{CoordState, SocketState};
|
pub use coord_state::{CoordState, SocketState};
|
||||||
|
use tracker_state::TrackerState;
|
||||||
|
|
||||||
const PRIORITY_TIMEOUT: Duration = Duration::from_secs(2);
|
const PRIORITY_TIMEOUT: Duration = Duration::from_secs(2);
|
||||||
|
|
||||||
|
@ -44,14 +46,12 @@ pub enum TrackerUpdate {
|
||||||
Clear,
|
Clear,
|
||||||
Fail,
|
Fail,
|
||||||
Update(TrackerUpdatePackage),
|
Update(TrackerUpdatePackage),
|
||||||
HeaderUpdate(String),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct TrackerUpdatePackage {
|
pub struct TrackerUpdatePackage {
|
||||||
pub boxes: Vec<NormalizedBoxCoords>,
|
boxes: Vec<NormalizedBoxCoords>,
|
||||||
pub time: Instant,
|
time: Instant,
|
||||||
pub request_duration: Duration,
|
request_duration: Duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ApplicationEvent {
|
pub enum ApplicationEvent {
|
||||||
|
@ -59,7 +59,6 @@ pub enum ApplicationEvent {
|
||||||
SocketMessage(Message),
|
SocketMessage(Message),
|
||||||
MoveEvent(MoveEvent, ConnectionType),
|
MoveEvent(MoveEvent, ConnectionType),
|
||||||
TrackerUpdate(TrackerUpdate),
|
TrackerUpdate(TrackerUpdate),
|
||||||
ChangeTracking(u32),
|
|
||||||
EnableAutomatic(bool),
|
EnableAutomatic(bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,21 +69,22 @@ pub async fn start_coordinator(
|
||||||
to_mec: Sender<ApplicationEvent>,
|
to_mec: Sender<ApplicationEvent>,
|
||||||
to_gui: Sender<GuiUpdate>,
|
to_gui: Sender<GuiUpdate>,
|
||||||
runtime: Handle,
|
runtime: Handle,
|
||||||
|
tracker_state: Arc<Mutex<TrackerState>>,
|
||||||
settings: Arc<RwLock<AppConfig>>,
|
settings: Arc<RwLock<AppConfig>>,
|
||||||
|
tracker_header: Arc<std::sync::RwLock<String>>,
|
||||||
) {
|
) {
|
||||||
info!("Starting coordinator!");
|
info!("Starting coordinator!");
|
||||||
|
|
||||||
let mec = pin!(mec);
|
let mec = pin!(mec);
|
||||||
|
|
||||||
let jpeg_quality = settings.read().await.tracker_jpeg_quality.clone();
|
|
||||||
|
|
||||||
let mut state = CoordState::new(
|
let mut state = CoordState::new(
|
||||||
mec,
|
mec,
|
||||||
to_mec,
|
to_mec,
|
||||||
to_gui,
|
to_gui,
|
||||||
runtime,
|
runtime,
|
||||||
|
tracker_state,
|
||||||
settings,
|
settings,
|
||||||
jpeg_quality,
|
tracker_header,
|
||||||
);
|
);
|
||||||
|
|
||||||
state
|
state
|
||||||
|
@ -119,16 +119,16 @@ pub async fn start_coordinator(
|
||||||
ApplicationEvent::SocketMessage(socket_message) => {
|
ApplicationEvent::SocketMessage(socket_message) => {
|
||||||
state.socket_send(socket_message).await;
|
state.socket_send(socket_message).await;
|
||||||
}
|
}
|
||||||
ApplicationEvent::ChangeTracking(new_id) => {
|
|
||||||
state.tracker_state.tracking_id = new_id;
|
|
||||||
}
|
|
||||||
ApplicationEvent::EnableAutomatic(do_enable) => {
|
ApplicationEvent::EnableAutomatic(do_enable) => {
|
||||||
state.tracker_state.enabled = do_enable;
|
#[cfg(feature = "tracker-state-debug")]
|
||||||
state
|
debug!("Trying to get lock on tracker_state for enable automatic");
|
||||||
.tracker_connection_state
|
if let Ok(mut ts) = state.tracker_state.lock() {
|
||||||
.stay_connected
|
ts.enabled = do_enable;
|
||||||
.store(do_enable, Ordering::SeqCst);
|
state
|
||||||
|
.tracker_connection_state
|
||||||
|
.stay_connected
|
||||||
|
.store(do_enable, Ordering::SeqCst);
|
||||||
|
}
|
||||||
state.check_states().await;
|
state.check_states().await;
|
||||||
}
|
}
|
||||||
ApplicationEvent::MoveEvent(coord, priority) => {
|
ApplicationEvent::MoveEvent(coord, priority) => {
|
||||||
|
@ -157,43 +157,36 @@ pub async fn start_coordinator(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ApplicationEvent::TrackerUpdate(update) => match update {
|
ApplicationEvent::TrackerUpdate(update) => match update {
|
||||||
TrackerUpdate::HeaderUpdate(_) => {}
|
|
||||||
TrackerUpdate::Clear => {
|
TrackerUpdate::Clear => {
|
||||||
state.tracker_state.clear();
|
if let Ok(mut ts) = state.tracker_state.lock() {
|
||||||
state.tracker_metrics.clear_times();
|
ts.clear();
|
||||||
if let Err(e) = state.to_gui.send(GuiUpdate::TrackerUpdate(TrackerUpdate::Clear)).await {
|
}
|
||||||
error!("Could not send message to GUI: {e}");
|
{
|
||||||
break;
|
let mut tm = state.tracker_metrics.lock().await;
|
||||||
|
tm.clear_times();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TrackerUpdate::Fail => {
|
TrackerUpdate::Fail => {
|
||||||
let fail_count: usize = state.tracker_metrics.fail_count + 1;
|
let mut tm = state.tracker_metrics.lock().await;
|
||||||
state.tracker_metrics.starting_connection(Some(fail_count));
|
let fail_count: usize = tm.fail_count + 1;
|
||||||
|
tm.starting_connection(Some(fail_count));
|
||||||
}
|
}
|
||||||
TrackerUpdate::Update(update) => {
|
TrackerUpdate::Update(update) => {
|
||||||
let mut x_adj: i32 = 0;
|
let mut x_adj: i32 = 0;
|
||||||
let mut y_adj: i32 = 0;
|
let mut y_adj: i32 = 0;
|
||||||
|
|
||||||
if let Err(e) = state.to_gui
|
if let Ok(mut ts) = state.tracker_state.lock() {
|
||||||
.send(GuiUpdate::TrackerUpdate(TrackerUpdate::Update(
|
ts.update_from_boxes(update.boxes);
|
||||||
update.clone(),
|
ts.last_detect = update.time;
|
||||||
)))
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
error!("Could not send message to the GUI: {e}");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.tracker_state.update_from_boxes(update.boxes);
|
match ts.calculate_tracking() {
|
||||||
state.tracker_state.last_detect = update.time;
|
Ok((x, y, _tracker_enabled)) => {
|
||||||
|
x_adj = x;
|
||||||
match state.tracker_state.calculate_tracking() {
|
y_adj = y;
|
||||||
Ok((x, y, _tracker_enabled)) => {
|
}
|
||||||
x_adj = x;
|
Err(e) => {
|
||||||
y_adj = y;
|
error!("Could not calculate the tracking!: {e}");
|
||||||
}
|
}
|
||||||
Err(e) => {
|
|
||||||
error!("Could not calculate the tracking!: {e}");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,7 +204,10 @@ pub async fn start_coordinator(
|
||||||
if let Err(e) = state.to_gui.send(GuiUpdate::MoveEvent(me)).await {
|
if let Err(e) = state.to_gui.send(GuiUpdate::MoveEvent(me)).await {
|
||||||
error!("Could not send to MEC... even though in the MEC?! {e}");
|
error!("Could not send to MEC... even though in the MEC?! {e}");
|
||||||
}
|
}
|
||||||
state.tracker_metrics.insert_time(update.request_duration);
|
{
|
||||||
|
let mut tm = state.tracker_metrics.lock().await;
|
||||||
|
tm.insert_time(update.request_duration);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,59 +1,48 @@
|
||||||
use std::{collections::VecDeque, time::Duration};
|
use std::{collections::VecDeque, sync, time::Duration};
|
||||||
|
|
||||||
use async_channel::Sender;
|
|
||||||
use tracing::error;
|
|
||||||
|
|
||||||
use crate::ui::GuiUpdate;
|
|
||||||
|
|
||||||
const MAX_RECORDED_TIMES: usize = 10;
|
const MAX_RECORDED_TIMES: usize = 10;
|
||||||
const DEGRADED_TRACKER_TIME: u128 = 150;
|
const DEGRADED_TRACKER_TIME: u128 = 150;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TrackerMetrics {
|
pub struct TrackerMetrics {
|
||||||
pub header_text: String,
|
pub header_text: sync::Arc<sync::RwLock<String>>,
|
||||||
pub fail_count: usize,
|
pub fail_count: usize,
|
||||||
tracker_times: VecDeque<u128>,
|
tracker_times: VecDeque<u128>,
|
||||||
to_gui: Sender<GuiUpdate>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TrackerMetrics {
|
impl TrackerMetrics {
|
||||||
pub fn new(to_gui: Sender<GuiUpdate>) -> Self {
|
pub fn new(text_reference: sync::Arc<sync::RwLock<String>>) -> Self {
|
||||||
let mut ret = TrackerMetrics {
|
let mut ret = TrackerMetrics {
|
||||||
header_text: String::from(""),
|
header_text: text_reference,
|
||||||
fail_count: 0,
|
fail_count: 0,
|
||||||
|
|
||||||
tracker_times: VecDeque::with_capacity(MAX_RECORDED_TIMES),
|
tracker_times: VecDeque::with_capacity(MAX_RECORDED_TIMES),
|
||||||
to_gui,
|
|
||||||
};
|
};
|
||||||
ret.clear_times();
|
ret.clear_times();
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_gui(&mut self) {
|
|
||||||
if let Err(e) = self.to_gui.send_blocking(GuiUpdate::TrackerUpdate(super::TrackerUpdate::HeaderUpdate(self.header_text.clone()))) {
|
|
||||||
error!("TrackerMetrics couldnt' send update to GUI: {e}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn starting_connection(&mut self, fail_count: Option<usize>) {
|
pub fn starting_connection(&mut self, fail_count: Option<usize>) {
|
||||||
self.clear_times();
|
self.clear_times();
|
||||||
|
|
||||||
self.header_text.clear();
|
if let Ok(mut writer) = self.header_text.write() {
|
||||||
match fail_count {
|
writer.clear();
|
||||||
None => self.header_text.push_str("Status: Connecting ..."),
|
match fail_count {
|
||||||
Some(v) => self.header_text.push_str(&format!("Status: Attempt {}/5", v)),
|
None => writer.push_str("Status: Connecting ..."),
|
||||||
|
Some(v) => writer.push_str(&format!("Status: Attempt {}/5", v)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.update_gui();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_times(&mut self) {
|
pub fn clear_times(&mut self) {
|
||||||
for _ in 0..10 {
|
for _ in 0..10 {
|
||||||
self.tracker_times.pop_front();
|
self.tracker_times.pop_front();
|
||||||
}
|
}
|
||||||
self.header_text = "Status: Disconnected".to_string();
|
// self.insert_time(Duration::new(0, 0));
|
||||||
|
if let Ok(mut writer) = self.header_text.write() {
|
||||||
self.update_gui();
|
writer.clear();
|
||||||
|
writer.push_str("Status: Disconnected");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_time(&mut self, new_measurement: Duration) {
|
pub fn insert_time(&mut self, new_measurement: Duration) {
|
||||||
|
@ -65,24 +54,31 @@ impl TrackerMetrics {
|
||||||
let avg_time = self.tracker_times.iter().sum::<u128>() / self.tracker_times.len() as u128;
|
let avg_time = self.tracker_times.iter().sum::<u128>() / self.tracker_times.len() as u128;
|
||||||
|
|
||||||
if avg_time == 0 {
|
if avg_time == 0 {
|
||||||
self.header_text = format!(
|
if let Ok(mut writer) = self.header_text.write() {
|
||||||
"Status: Failed Avg Response: {} ms",
|
writer.clear();
|
||||||
avg_time.to_string()
|
writer.push_str(&format!(
|
||||||
);
|
"Status: Failed Avg Response: {} ms",
|
||||||
|
avg_time.to_string()
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if avg_time > DEGRADED_TRACKER_TIME {
|
if avg_time > DEGRADED_TRACKER_TIME {
|
||||||
self.header_text = format!(
|
if let Ok(mut writer) = self.header_text.write() {
|
||||||
"Status: Degraded Avg Response: {} ms",
|
writer.clear();
|
||||||
avg_time.to_string()
|
writer.push_str(&format!(
|
||||||
);
|
"Status: Degraded Avg Response: {} ms",
|
||||||
|
avg_time.to_string()
|
||||||
|
));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.header_text = format!(
|
if let Ok(mut writer) = self.header_text.write() {
|
||||||
"Status: Nominal Avg Response: {} ms",
|
writer.clear();
|
||||||
avg_time.to_string()
|
writer.push_str(&format!(
|
||||||
);
|
"Status: Nominal Avg Response: {} ms",
|
||||||
|
avg_time.to_string()
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.update_gui();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@ use snafu::prelude::*;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
pub const JPEG_QUALITY: i32 = 40;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct WebcamPipeline {
|
pub struct WebcamPipeline {
|
||||||
pub pipeline: Pipeline,
|
pub pipeline: Pipeline,
|
||||||
|
@ -16,7 +18,7 @@ pub struct WebcamPipeline {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WebcamPipeline {
|
impl WebcamPipeline {
|
||||||
pub fn new(jpeg_quality: i32) -> Result<WebcamPipeline, PipelineError> {
|
pub fn new() -> Result<WebcamPipeline, PipelineError> {
|
||||||
let pipeline = Pipeline::with_name("webcam_pipeline");
|
let pipeline = Pipeline::with_name("webcam_pipeline");
|
||||||
|
|
||||||
// All of the following errors are unrecoverable
|
// All of the following errors are unrecoverable
|
||||||
|
@ -76,7 +78,7 @@ impl WebcamPipeline {
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let jpeg_enc = ElementFactory::make("jpegenc")
|
let jpeg_enc = ElementFactory::make("jpegenc")
|
||||||
.property("quality", jpeg_quality)
|
.property("quality", JPEG_QUALITY)
|
||||||
.build()
|
.build()
|
||||||
.context(BuildSnafu { element: "jpegenc" })?;
|
.context(BuildSnafu { element: "jpegenc" })?;
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ use tracing::instrument;
|
||||||
mod remote_source;
|
mod remote_source;
|
||||||
|
|
||||||
use crate::coordinator::{
|
use crate::coordinator::{
|
||||||
ApplicationEvent, ConnectionType, SocketState,
|
tracker_state::TrackerState, ApplicationEvent, ConnectionType, SocketState,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[instrument(skip(rt, mec))]
|
#[instrument(skip(rt, mec))]
|
||||||
|
@ -28,6 +28,7 @@ pub async fn start_socketserver(
|
||||||
rt: Handle,
|
rt: Handle,
|
||||||
mec: Sender<ApplicationEvent>,
|
mec: Sender<ApplicationEvent>,
|
||||||
connection_state: Arc<SocketState>,
|
connection_state: Arc<SocketState>,
|
||||||
|
tracker_state: Arc<Mutex<TrackerState>>,
|
||||||
) {
|
) {
|
||||||
let addr = "127.0.0.1:9002";
|
let addr = "127.0.0.1:9002";
|
||||||
let listener = TcpListener::bind(&addr).await.expect("Can't listen");
|
let listener = TcpListener::bind(&addr).await.expect("Can't listen");
|
||||||
|
@ -48,6 +49,7 @@ pub async fn start_socketserver(
|
||||||
peer,
|
peer,
|
||||||
stream,
|
stream,
|
||||||
mec.clone(),
|
mec.clone(),
|
||||||
|
tracker_state.clone(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,8 +61,9 @@ async fn accept_connection(
|
||||||
peer: SocketAddr,
|
peer: SocketAddr,
|
||||||
stream: TcpStream,
|
stream: TcpStream,
|
||||||
mec: Sender<ApplicationEvent>,
|
mec: Sender<ApplicationEvent>,
|
||||||
|
tracker_state: Arc<Mutex<TrackerState>>,
|
||||||
) {
|
) {
|
||||||
if let Err(e) = handle_connection(peer, stream, mec.clone()).await {
|
if let Err(e) = handle_connection(peer, stream, mec.clone(), tracker_state).await {
|
||||||
match e {
|
match e {
|
||||||
Error::ConnectionClosed | Error::Protocol(_) | Error::Utf8 => (),
|
Error::ConnectionClosed | Error::Protocol(_) | Error::Utf8 => (),
|
||||||
err => error!("Error processing connection: {}", err),
|
err => error!("Error processing connection: {}", err),
|
||||||
|
@ -73,6 +76,7 @@ async fn handle_connection(
|
||||||
peer: SocketAddr,
|
peer: SocketAddr,
|
||||||
stream: TcpStream,
|
stream: TcpStream,
|
||||||
mec: Sender<ApplicationEvent>,
|
mec: Sender<ApplicationEvent>,
|
||||||
|
tracker_state: Arc<Mutex<TrackerState>>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut ws_stream = accept_async(stream).await.expect("Failed to accept");
|
let mut ws_stream = accept_async(stream).await.expect("Failed to accept");
|
||||||
info!("New WebSocket connection: {}", peer);
|
info!("New WebSocket connection: {}", peer);
|
||||||
|
|
|
@ -3,14 +3,13 @@ use std::{
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use async_channel::Sender;
|
|
||||||
use gtk::{
|
use gtk::{
|
||||||
gdk::Paintable,
|
gdk::Paintable,
|
||||||
prelude::{BoxExt, GestureExt, WidgetExt},
|
prelude::{BoxExt, GestureExt, WidgetExt},
|
||||||
AspectFrame, Box, DrawingArea, EventControllerMotion, GestureClick, Label, Overlay, Picture,
|
AspectFrame, Box, DrawingArea, EventControllerMotion, GestureClick, Label, Overlay, Picture,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::coordinator::{tracker_state::TrackerState, ApplicationEvent};
|
use crate::coordinator::tracker_state::TrackerState;
|
||||||
|
|
||||||
use super::NormalizedBoxCoords;
|
use super::NormalizedBoxCoords;
|
||||||
|
|
||||||
|
@ -25,7 +24,7 @@ pub struct LiveViewPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LiveViewPanel {
|
impl LiveViewPanel {
|
||||||
pub fn new(tracker_state: Arc<Mutex<TrackerState>>, to_mec: Sender<ApplicationEvent>) -> Self {
|
pub fn new(tracker_state: Arc<Mutex<TrackerState>>) -> Self {
|
||||||
let right_box = gtk::Box::builder()
|
let right_box = gtk::Box::builder()
|
||||||
.orientation(gtk::Orientation::Vertical)
|
.orientation(gtk::Orientation::Vertical)
|
||||||
.hexpand(true)
|
.hexpand(true)
|
||||||
|
@ -75,7 +74,7 @@ impl LiveViewPanel {
|
||||||
|
|
||||||
click_handler.connect_pressed(move |gesture, _id, x, y| {
|
click_handler.connect_pressed(move |gesture, _id, x, y| {
|
||||||
gesture.set_state(gtk::EventSequenceState::Claimed);
|
gesture.set_state(gtk::EventSequenceState::Claimed);
|
||||||
LiveViewPanel::click_gesture_callback(&handler_picture, &tracker_state, &to_mec, x, y)
|
LiveViewPanel::click_gesture_callback(&handler_picture, &tracker_state, x, y)
|
||||||
});
|
});
|
||||||
|
|
||||||
overlay_box.add_controller(click_handler);
|
overlay_box.add_controller(click_handler);
|
||||||
|
@ -105,7 +104,6 @@ impl LiveViewPanel {
|
||||||
fn click_gesture_callback(
|
fn click_gesture_callback(
|
||||||
overlay: &Picture,
|
overlay: &Picture,
|
||||||
tracker_state: &Arc<Mutex<TrackerState>>,
|
tracker_state: &Arc<Mutex<TrackerState>>,
|
||||||
to_mec: &Sender<ApplicationEvent>,
|
|
||||||
x_coord: f64,
|
x_coord: f64,
|
||||||
y_coord: f64,
|
y_coord: f64,
|
||||||
) {
|
) {
|
||||||
|
@ -117,9 +115,6 @@ impl LiveViewPanel {
|
||||||
if let Ok(mut ts) = tracker_state.lock() {
|
if let Ok(mut ts) = tracker_state.lock() {
|
||||||
if let Some(v) = calc_box_under_mouse(&ts.identity_boxes, x_coord, y_coord) {
|
if let Some(v) = calc_box_under_mouse(&ts.identity_boxes, x_coord, y_coord) {
|
||||||
ts.tracking_id = v;
|
ts.tracking_id = v;
|
||||||
if let Err(e) = to_mec.send_blocking(ApplicationEvent::ChangeTracking(v)) {
|
|
||||||
panic!("Could not send message to MEC, unrecoverable: {e}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ use tokio::sync::RwLock;
|
||||||
|
|
||||||
use crate::config::AppConfig;
|
use crate::config::AppConfig;
|
||||||
use crate::coordinator::tracker_state::TrackerState;
|
use crate::coordinator::tracker_state::TrackerState;
|
||||||
use crate::coordinator::{start_coordinator, ApplicationEvent, MoveEvent, TrackerUpdate};
|
use crate::coordinator::{start_coordinator, ApplicationEvent, MoveEvent};
|
||||||
|
|
||||||
mod control_panel;
|
mod control_panel;
|
||||||
mod liveview_panel;
|
mod liveview_panel;
|
||||||
|
@ -28,7 +28,6 @@ pub enum GuiUpdate {
|
||||||
SocketConnected,
|
SocketConnected,
|
||||||
MoveEvent(MoveEvent),
|
MoveEvent(MoveEvent),
|
||||||
UpdatePaintable(gstreamer::Element),
|
UpdatePaintable(gstreamer::Element),
|
||||||
TrackerUpdate(TrackerUpdate),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
@ -159,12 +158,16 @@ pub fn build_ui(app: &Application, config: Arc<RwLock<AppConfig>>, runtime: Hand
|
||||||
|
|
||||||
let coord_config = config.clone();
|
let coord_config = config.clone();
|
||||||
|
|
||||||
|
let tracker_header = Arc::new(std::sync::RwLock::new(String::new()));
|
||||||
|
|
||||||
runtime.spawn(start_coordinator(
|
runtime.spawn(start_coordinator(
|
||||||
mec,
|
mec,
|
||||||
to_mec.clone(),
|
to_mec.clone(),
|
||||||
to_gui,
|
to_gui,
|
||||||
runtime.clone(),
|
runtime.clone(),
|
||||||
|
tracker_state.clone(),
|
||||||
coord_config,
|
coord_config,
|
||||||
|
tracker_header.clone(),
|
||||||
));
|
));
|
||||||
|
|
||||||
let control_panel = ControlPanel::new(tracker_state.clone());
|
let control_panel = ControlPanel::new(tracker_state.clone());
|
||||||
|
@ -174,7 +177,7 @@ pub fn build_ui(app: &Application, config: Arc<RwLock<AppConfig>>, runtime: Hand
|
||||||
|
|
||||||
main_box.append(&left_box);
|
main_box.append(&left_box);
|
||||||
|
|
||||||
let liveview_panel = LiveViewPanel::new(tracker_state.clone(), to_mec.clone());
|
let liveview_panel = LiveViewPanel::new(tracker_state.clone());
|
||||||
main_box.append(liveview_panel.get_top_level());
|
main_box.append(liveview_panel.get_top_level());
|
||||||
|
|
||||||
let drawable = gtk::DrawingArea::builder().build();
|
let drawable = gtk::DrawingArea::builder().build();
|
||||||
|
@ -193,8 +196,6 @@ pub fn build_ui(app: &Application, config: Arc<RwLock<AppConfig>>, runtime: Hand
|
||||||
.model()
|
.model()
|
||||||
.expect("The list view should have a model!");
|
.expect("The list view should have a model!");
|
||||||
|
|
||||||
let tracker_state_2 = tracker_state.clone();
|
|
||||||
|
|
||||||
glib::timeout_add_local(Duration::from_millis(500), move || {
|
glib::timeout_add_local(Duration::from_millis(500), move || {
|
||||||
#[cfg(feature = "tracker-state-debug")]
|
#[cfg(feature = "tracker-state-debug")]
|
||||||
debug!("Getting lock on tracker state for checking identity boxes");
|
debug!("Getting lock on tracker state for checking identity boxes");
|
||||||
|
@ -258,12 +259,47 @@ pub fn build_ui(app: &Application, config: Arc<RwLock<AppConfig>>, runtime: Hand
|
||||||
glib::ControlFlow::Continue
|
glib::ControlFlow::Continue
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut tracker_status_label = liveview_panel.tracker_status_label.clone();
|
let tracker_status_label = liveview_panel.tracker_status_label.clone();
|
||||||
let mut tracker_enable_toggle = control_panel
|
let tracker_enable_toggle = control_panel
|
||||||
.connection_buttons
|
.connection_buttons
|
||||||
.tracker_enable_toggle
|
.tracker_enable_toggle
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
|
glib::timeout_add_seconds_local(1, move || {
|
||||||
|
if let Ok(reader) = tracker_header.read() {
|
||||||
|
tracker_status_label.set_text(reader.as_str());
|
||||||
|
if reader.contains("Failed") || reader.contains("Disconnected") {
|
||||||
|
tracker_status_label.set_css_classes(&["NoConnection"]);
|
||||||
|
|
||||||
|
tracker_enable_toggle.set_label("Connect to Tracker Computer");
|
||||||
|
tracker_enable_toggle.set_active(false);
|
||||||
|
tracker_enable_toggle.set_sensitive(true);
|
||||||
|
} else if reader.contains("Degraded") {
|
||||||
|
tracker_status_label.set_css_classes(&["LoadingConnection"]);
|
||||||
|
|
||||||
|
tracker_enable_toggle.set_label("Disconnect Tracker Computer");
|
||||||
|
tracker_enable_toggle.set_active(true);
|
||||||
|
tracker_enable_toggle.set_sensitive(true);
|
||||||
|
} else if reader.contains("Connecting") {
|
||||||
|
tracker_status_label.set_css_classes(&["LoadingConnection"]);
|
||||||
|
|
||||||
|
tracker_enable_toggle.set_label("Please Wait");
|
||||||
|
tracker_enable_toggle.set_active(false);
|
||||||
|
tracker_enable_toggle.set_sensitive(false);
|
||||||
|
} else if reader.contains("Nominal") {
|
||||||
|
tracker_status_label.set_css_classes(&["YesConnection"]);
|
||||||
|
|
||||||
|
tracker_enable_toggle.set_label("Disconnect Tracker Computer");
|
||||||
|
tracker_enable_toggle.set_active(true);
|
||||||
|
tracker_enable_toggle.set_sensitive(true);
|
||||||
|
}
|
||||||
|
glib::ControlFlow::Continue
|
||||||
|
} else {
|
||||||
|
error!("Couldn't get rwlock on metrics");
|
||||||
|
glib::ControlFlow::Break
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
glib::spawn_future_local(glib::clone!(@weak drawable => async move {
|
glib::spawn_future_local(glib::clone!(@weak drawable => async move {
|
||||||
while let Ok(d) = gui_recv.recv().await {
|
while let Ok(d) = gui_recv.recv().await {
|
||||||
drawable.queue_draw();
|
drawable.queue_draw();
|
||||||
|
@ -301,23 +337,6 @@ pub fn build_ui(app: &Application, config: Arc<RwLock<AppConfig>>, runtime: Hand
|
||||||
|
|
||||||
liveview_panel.set_paintable(&paintable);
|
liveview_panel.set_paintable(&paintable);
|
||||||
}
|
}
|
||||||
GuiUpdate::TrackerUpdate(update) => match update {
|
|
||||||
TrackerUpdate::Fail => {}
|
|
||||||
TrackerUpdate::HeaderUpdate(new_header) => {
|
|
||||||
update_tracker_header(new_header, &mut tracker_status_label, &mut tracker_enable_toggle)
|
|
||||||
}
|
|
||||||
TrackerUpdate::Clear => {
|
|
||||||
if let Ok(mut ts) = tracker_state_2.lock() {
|
|
||||||
ts.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TrackerUpdate::Update(update) => {
|
|
||||||
if let Ok(mut ts) = tracker_state_2.lock() {
|
|
||||||
ts.update_from_boxes(update.boxes);
|
|
||||||
ts.last_detect = update.time;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
info!("Closing update loop");
|
info!("Closing update loop");
|
||||||
|
@ -329,36 +348,6 @@ pub fn build_ui(app: &Application, config: Arc<RwLock<AppConfig>>, runtime: Hand
|
||||||
window.present();
|
window.present();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_tracker_header(new_header: String, tracker_status_label: &mut gtk::Label, tracker_enable_toggle: &mut gtk::ToggleButton) {
|
|
||||||
tracker_status_label.set_text(&new_header);
|
|
||||||
if new_header.contains("Failed") || new_header.contains("Disconnected") {
|
|
||||||
tracker_status_label.set_css_classes(&["NoConnection"]);
|
|
||||||
|
|
||||||
tracker_enable_toggle.set_label("Connect to Tracker Computer");
|
|
||||||
tracker_enable_toggle.set_active(false);
|
|
||||||
tracker_enable_toggle.set_sensitive(true);
|
|
||||||
} else if new_header.contains("Degraded") {
|
|
||||||
tracker_status_label.set_css_classes(&["LoadingConnection"]);
|
|
||||||
|
|
||||||
tracker_enable_toggle.set_label("Disconnect Tracker Computer");
|
|
||||||
tracker_enable_toggle.set_active(true);
|
|
||||||
tracker_enable_toggle.set_sensitive(true);
|
|
||||||
} else if new_header.contains("Connecting") {
|
|
||||||
tracker_status_label.set_css_classes(&["LoadingConnection"]);
|
|
||||||
|
|
||||||
tracker_enable_toggle.set_label("Please Wait");
|
|
||||||
tracker_enable_toggle.set_active(false);
|
|
||||||
tracker_enable_toggle.set_sensitive(false);
|
|
||||||
} else if new_header.contains("Nominal") {
|
|
||||||
tracker_status_label.set_css_classes(&["YesConnection"]);
|
|
||||||
|
|
||||||
tracker_enable_toggle.set_label("Disconnect Tracker Computer");
|
|
||||||
tracker_enable_toggle.set_active(true);
|
|
||||||
tracker_enable_toggle.set_sensitive(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw_boxes(width: i32, height: i32, ctx: &Context, tracker_state: &Arc<Mutex<TrackerState>>) {
|
fn draw_boxes(width: i32, height: i32, ctx: &Context, tracker_state: &Arc<Mutex<TrackerState>>) {
|
||||||
ctx.set_line_width(5.0);
|
ctx.set_line_width(5.0);
|
||||||
ctx.select_font_face(
|
ctx.select_font_face(
|
||||||
|
|
Loading…
Reference in a new issue