core_pb/messages/
server_status.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use crate::messages::ota::{OverTheAirStep, OverTheAirStepCompletion};
use crate::messages::{ExtraImuData, ExtraOptsTypes, MotorControlStatus, NetworkStatus};
use crate::names::{RobotName, NUM_ROBOT_NAMES};
use crate::util::ColoredStatus;
use nalgebra::{Point2, Rotation2};
use pacbot_rs::game_state::GameState;
use serde::{Deserialize, Serialize};
use std::time::Duration;

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ServerStatus {
    pub utilization: ColoredStatus,
    pub inference_time: ColoredStatus,

    pub simulation_connection: NetworkStatus,

    pub game_state: GameState,
    pub game_server_connection: NetworkStatus,
    pub advanced_game_server: bool,

    pub cv_location: Option<Point2<i8>>,
    pub target_path: Vec<Point2<i8>>,

    pub gui_clients: usize,
    pub robots: [RobotStatus; NUM_ROBOT_NAMES],
}

impl Default for ServerStatus {
    fn default() -> Self {
        Self {
            utilization: ColoredStatus::Ok(Some("Loading...".to_string())),
            inference_time: ColoredStatus::NotApplicable(Some("N/A".to_string())),

            simulation_connection: NetworkStatus::default(),

            game_state: GameState::default(),
            game_server_connection: NetworkStatus::default(),
            advanced_game_server: false,

            cv_location: None,
            target_path: vec![],

            gui_clients: 0,
            robots: RobotName::get_all().map(RobotStatus::new),
        }
    }
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RobotStatus {
    pub name: RobotName,
    pub connection: NetworkStatus,
    pub ping: Option<Duration>,

    pub ota_current: OverTheAirStep,
    pub ota_completed: Vec<OverTheAirStepCompletion>,

    pub last_motor_status: (Duration, MotorControlStatus),
    pub utilization: [f32; 3],

    pub sim_position: Option<(Point2<f32>, Rotation2<f32>)>,

    pub imu_angle: Result<f32, String>,
    pub distance_sensors: [Result<Option<f32>, String>; 4],
    pub estimated_location: Option<Point2<f32>>,
    pub battery: Result<f32, ()>,

    pub display: Option<Vec<u128>>,

    pub received_extra_opts: Option<ExtraOptsTypes>,
    pub extra_indicators: Option<ExtraOptsTypes>,
    pub extra_imu_data: Option<ExtraImuData>,
}

impl RobotStatus {
    pub fn new(name: RobotName) -> Self {
        Self {
            name,
            connection: NetworkStatus::default(),
            ping: None,

            ota_current: OverTheAirStep::GuiRequest,
            ota_completed: vec![],

            last_motor_status: Default::default(),
            utilization: [0.0; 3],

            sim_position: None,

            imu_angle: Err(String::new()),
            distance_sensors: [const { Err(String::new()) }; 4],
            estimated_location: None,
            battery: Err(()),

            display: None,

            received_extra_opts: None,
            extra_indicators: None,
            extra_imu_data: None,
        }
    }
}

impl RobotStatus {
    #[cfg(feature = "egui-phosphor")]
    pub fn battery_status(&self) -> ColoredStatus {
        if self.connection != NetworkStatus::Connected {
            ColoredStatus::NotApplicable(Some("Not connected".to_string()))
        } else if let Ok(battery) = self.battery {
            let battery_percent = f32::min(1.0, (battery - 7.0).max(0.0) / (8.35 - 7.0));
            let msg = Some(format!("{:.2}V {:.1}%", battery, battery_percent * 100.0));
            if battery_percent > 0.5 {
                ColoredStatus::Ok(msg)
            } else if battery_percent > 0.25 {
                ColoredStatus::Warn(msg)
            } else {
                ColoredStatus::Error(msg)
            }
        } else {
            ColoredStatus::Error(Some("ERR".to_string()))
        }
    }
}