use crate::constants::{
INITIAL_ENABLE_BATTERY_MONITOR, INITIAL_ENABLE_DISPLAY, INITIAL_ENABLE_DISTS,
INITIAL_ENABLE_EXTRA_IMU_DATA, INITIAL_ENABLE_GAMEPAD, INITIAL_ENABLE_IMU,
MAX_ROBOT_PATH_LENGTH,
};
use crate::grid::standard_grid::StandardGrid;
#[cfg(feature = "std")]
use crate::messages::server_status::ServerStatus;
#[cfg(feature = "std")]
use crate::messages::settings::PacbotSettings;
use crate::names::RobotName;
#[cfg(feature = "std")]
use crate::names::NUM_ROBOT_NAMES;
use crate::robot_definition::RobotDefinition;
#[cfg(feature = "std")]
use crate::util::ColoredStatus;
use core::time::Duration;
use nalgebra::Point2;
#[cfg(feature = "std")]
use nalgebra::Rotation2;
use nalgebra::Vector2;
use pacbot_rs::game_state::GameState;
use pacbot_rs::location::Direction;
use portable_atomic::{AtomicBool, AtomicF32, AtomicI32, AtomicI8};
use serde::{Deserialize, Serialize};
#[cfg(feature = "std")]
pub mod ota;
pub mod robot_tcp;
#[cfg(feature = "std")]
pub mod server_status;
#[cfg(feature = "std")]
pub mod settings;
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg(feature = "std")]
#[allow(clippy::large_enum_variant)]
pub enum GuiToServerMessage {
Settings(PacbotSettings),
GameServerCommand(GameServerCommand),
SimulationCommand(ServerToSimulationMessage),
RobotVelocity(RobotName, VelocityControl),
RobotCommand(RobotName, ServerToRobotMessage),
StartOtaFirmwareUpdate(RobotName),
CancelOtaFirmwareUpdate(RobotName),
ConfirmFirmwareUpdate(RobotName),
ClearFirmwareUpdateHistory(RobotName),
TargetLocation(Point2<i8>),
RestartSimulation,
}
#[derive(Copy, Clone, Debug, Default, PartialOrd, PartialEq, Serialize, Deserialize)]
pub enum VelocityControl {
#[default]
None,
Stop,
LinVelAngVel(Vector2<f32>, f32),
LinVelFixedAng(Vector2<f32>, f32),
LinVelFaceForward(Vector2<f32>),
AssistedDriving(Vector2<f32>),
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg(feature = "std")]
#[allow(clippy::large_enum_variant)]
pub enum ServerToGuiMessage {
Status(ServerStatus),
Settings(PacbotSettings),
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg(feature = "std")]
pub enum SimulationToServerMessage {
RobotPositions([Option<(Point2<f32>, Rotation2<f32>)>; NUM_ROBOT_NAMES]),
RobotDisplay(RobotName, Vec<u128>),
}
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Serialize, Deserialize)]
pub enum RobotButton {
EastA,
SouthB,
NorthX,
WestY,
LeftStart,
RightSelect,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg(feature = "std")]
pub enum ServerToSimulationMessage {
Spawn(RobotName),
Teleport(RobotName, Point2<i8>),
Delete(RobotName),
SetPacman(RobotName),
SetStandardGrid(StandardGrid),
RobotButton(RobotName, (RobotButton, bool)),
RobotJoystick(RobotName, (f32, f32)),
}
#[derive(Clone, Debug, PartialOrd, PartialEq, Serialize, Deserialize)]
pub struct FrequentServerToRobot {
pub grid: StandardGrid,
pub target_velocity: VelocityControl,
pub motors_override: [Option<f32>; 3],
pub pwm_override: [[Option<u16>; 2]; 3],
pub motor_config: [[usize; 2]; 3],
pub encoder_config: [(usize, bool); 3],
pub dist_sensor_config: [usize; 4],
pub pid: [f32; 3],
pub cv_location: Option<Point2<i8>>,
pub target_path: heapless::Vec<Point2<i8>, MAX_ROBOT_PATH_LENGTH>,
pub follow_target_path: bool,
pub angle_offset: f32,
pub lookahead_dist: f32,
pub robot_speed: f32,
pub snapping_dist: f32,
pub cv_error: f32,
pub enable_imu: bool,
pub enable_extra_imu_data: bool,
pub enable_dists: bool,
pub enable_battery_monitor: bool,
pub enable_display: bool,
pub enable_gamepad: bool,
pub display_loop_interval: u64,
}
impl FrequentServerToRobot {
pub fn new(robot: RobotName) -> Self {
let definition = RobotDefinition::new(robot);
Self {
grid: StandardGrid::Pacman,
target_velocity: VelocityControl::None,
motors_override: [None; 3],
pwm_override: [[None; 2]; 3],
motor_config: definition.default_motor_config,
encoder_config: definition.default_encoder_config,
dist_sensor_config: definition.default_dist_sensor_order,
pid: definition.default_pid,
cv_location: Some(Point2::new(1, 1)),
target_path: heapless::Vec::new(),
follow_target_path: false,
angle_offset: 0.0,
lookahead_dist: 0.7,
robot_speed: 2.5,
snapping_dist: 0.3,
cv_error: 1.5,
enable_imu: INITIAL_ENABLE_IMU,
enable_extra_imu_data: INITIAL_ENABLE_EXTRA_IMU_DATA,
enable_dists: INITIAL_ENABLE_DISTS,
enable_battery_monitor: INITIAL_ENABLE_BATTERY_MONITOR,
enable_display: INITIAL_ENABLE_DISPLAY,
enable_gamepad: INITIAL_ENABLE_GAMEPAD,
display_loop_interval: 500,
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[repr(usize)]
pub enum ServerToRobotMessage {
ReadyToStartUpdate = 0,
FirmwareWritePart {
offset: usize,
len: usize,
} = 1,
CalculateFirmwareHash(u32) = 2,
MarkFirmwareUpdated = 3,
IsFirmwareSwapped = 4,
Reboot = 5,
MarkFirmwareBooted = 6,
CancelFirmwareUpdate = 7,
FrequentRobotItems(FrequentServerToRobot) = 8,
Ping = 9,
ExtraOpts(ExtraOptsTypes) = 11,
}
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, PartialOrd, PartialEq)]
pub struct ExtraOptsTypes {
pub opts_bool: [bool; 8],
pub opts_f32: [f32; 4],
pub opts_i8: [i8; 4],
pub opts_i32: [i32; 4],
}
pub type ExtraOptsAtomicTypes = (
[AtomicBool; 8],
[AtomicF32; 8],
[AtomicI8; 8],
[AtomicI32; 8],
);
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
pub struct MotorControlStatus {
pub pwm: [[u16; 2]; 3],
pub speed_set_points: [f32; 3],
pub measured_speeds: [f32; 3],
}
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
pub struct ExtraImuData {
pub accel: ([f32; 3], u8),
pub gyro: ([f32; 3], u8),
pub mag: ([f32; 3], u8),
pub rotation_vector: ([f32; 4], f32, u8),
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[repr(usize)]
pub enum RobotToServerMessage {
ReadyToStartUpdate = 0,
ConfirmFirmwarePart { offset: usize, len: usize } = 1,
MarkedFirmwareUpdated = 2,
FirmwareHash([u8; 32]) = 3,
Rebooting = 4,
FirmwareIsSwapped(bool) = 5,
MarkedFirmwareBooted = 6,
Name(RobotName) = 7,
MotorControlStatus((Duration, MotorControlStatus)) = 8,
Utilization([f32; 3]) = 9,
Sensors(SensorData) = 10,
Pong = 11,
ReceivedExtraOpts(ExtraOptsTypes) = 12,
ExtraIndicators(ExtraOptsTypes) = 13,
ExtraImuData(ExtraImuData) = 14,
}
#[derive(Copy, Clone, Debug)]
#[repr(usize)]
pub enum Task {
Wifi = 0,
Motors = 1,
Peripherals = 2,
}
impl Task {
pub fn get_all() -> [Self; 3] {
[Task::Wifi, Task::Motors, Task::Peripherals]
}
}
pub const MAX_SENSOR_ERR_LEN: usize = 10;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SensorData {
pub angle: Result<f32, heapless::String<MAX_SENSOR_ERR_LEN>>,
pub distances: [Result<Option<f32>, heapless::String<MAX_SENSOR_ERR_LEN>>; 4],
pub location: Option<Point2<f32>>,
pub battery: Result<f32, heapless::String<MAX_SENSOR_ERR_LEN>>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RobotStatus {}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, Default, PartialOrd, PartialEq)]
pub enum NetworkStatus {
#[default]
NotConnected,
ConnectionFailed,
Connecting,
Connected,
}
impl NetworkStatus {
#[cfg(feature = "std")]
pub fn status(&self) -> ColoredStatus {
match self {
NetworkStatus::NotConnected => {
ColoredStatus::NotApplicable(Some("Not connected".to_string()))
}
NetworkStatus::ConnectionFailed => {
ColoredStatus::Error(Some("Connection failed".to_string()))
}
NetworkStatus::Connecting => ColoredStatus::Warn(Some("Connecting".to_string())),
NetworkStatus::Connected => ColoredStatus::Ok(Some("Connected".to_string())),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[allow(clippy::large_enum_variant)]
pub enum GameServerCommand {
Pause,
Unpause,
Reset,
Direction(Direction),
SetState(GameState),
}
impl GameServerCommand {
pub fn text(&self) -> Option<&'static str> {
match self {
GameServerCommand::Pause => Some("p"),
GameServerCommand::Unpause => Some("P"),
GameServerCommand::Reset => Some("r"),
GameServerCommand::Direction(Direction::Up) => Some("w"),
GameServerCommand::Direction(Direction::Left) => Some("a"),
GameServerCommand::Direction(Direction::Down) => Some("s"),
GameServerCommand::Direction(Direction::Right) => Some("d"),
_ => None,
}
}
}