adds initial rcs implementation
This commit is contained in:
@@ -7,7 +7,7 @@ edition = "2024"
|
||||
anyhow = { workspace = true }
|
||||
chrono = { workspace = true }
|
||||
ctrlc = { workspace = true }
|
||||
derive_more = {workspace = true, features = ["display", "from"]}
|
||||
derive_more = {workspace = true, features = ["display", "from", "add", "add_assign", "not"]}
|
||||
fern = { workspace = true }
|
||||
log = { workspace = true }
|
||||
postcard = { workspace = true }
|
||||
|
||||
@@ -1,48 +1,10 @@
|
||||
use chrono::serde::ts_nanoseconds;
|
||||
use chrono::{DateTime, TimeDelta, Utc};
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::time::Instant;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct SetPin {
|
||||
pub pin: u8,
|
||||
pub value: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct ValidPriorityCommand<T>
|
||||
where
|
||||
T: Clone + Debug,
|
||||
{
|
||||
pub inner: T,
|
||||
#[serde(with = "ts_nanoseconds")]
|
||||
pub valid_until: DateTime<Utc>,
|
||||
pub priority: u8,
|
||||
}
|
||||
|
||||
impl<T> ValidPriorityCommand<T>
|
||||
where
|
||||
T: Clone + Debug,
|
||||
{
|
||||
/// Get the valid until time as an Instant
|
||||
///
|
||||
/// # Panics
|
||||
/// While this theoretically could panic, there are checks to prevent this.
|
||||
pub fn get_valid_until_instant(&self) -> Instant {
|
||||
let delta = self.valid_until.signed_duration_since(Utc::now());
|
||||
let now = Instant::now();
|
||||
if delta >= TimeDelta::zero() {
|
||||
// Unwrap is safe because we checked that it is not negative
|
||||
now + delta.to_std().unwrap()
|
||||
} else {
|
||||
// Unwrap is safe because we converted the negative to a positive
|
||||
now.checked_sub((-delta).to_std().unwrap()).unwrap_or(now)
|
||||
}
|
||||
}
|
||||
}
|
||||
pub mod set_pin;
|
||||
pub mod set_rcs;
|
||||
pub mod valid_priority_command;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct CommandHeader<'a> {
|
||||
@@ -59,26 +21,3 @@ pub struct OwnedCommandHeader {
|
||||
pub trait Command: Serialize + DeserializeOwned {}
|
||||
|
||||
impl Command for () {}
|
||||
|
||||
impl Command for SetPin {}
|
||||
|
||||
impl<T: Clone + Debug + Command + Serialize + DeserializeOwned> Command
|
||||
for ValidPriorityCommand<T>
|
||||
{
|
||||
}
|
||||
|
||||
impl<T: Clone + Debug + Command + Serialize + DeserializeOwned> Deref for ValidPriorityCommand<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone + Debug + Command + Serialize + DeserializeOwned> DerefMut
|
||||
for ValidPriorityCommand<T>
|
||||
{
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
|
||||
10
common/src/command/set_pin.rs
Normal file
10
common/src/command/set_pin.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
use crate::command::Command;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct SetPin {
|
||||
pub pin: u8,
|
||||
pub value: bool,
|
||||
}
|
||||
|
||||
impl Command for SetPin {}
|
||||
11
common/src/command/set_rcs.rs
Normal file
11
common/src/command/set_rcs.rs
Normal file
@@ -0,0 +1,11 @@
|
||||
use crate::command::Command;
|
||||
use crate::math::Vector;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct SetRcs {
|
||||
pub translation: Vector,
|
||||
pub rotation: Vector,
|
||||
}
|
||||
|
||||
impl Command for SetRcs {}
|
||||
61
common/src/command/valid_priority_command.rs
Normal file
61
common/src/command/valid_priority_command.rs
Normal file
@@ -0,0 +1,61 @@
|
||||
use crate::command::Command;
|
||||
use chrono::serde::ts_nanoseconds;
|
||||
use chrono::{DateTime, TimeDelta, Utc};
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::time::Instant;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct ValidPriorityCommand<T>
|
||||
where
|
||||
T: Clone + Debug,
|
||||
{
|
||||
pub inner: T,
|
||||
#[serde(with = "ts_nanoseconds")]
|
||||
pub valid_until: DateTime<Utc>,
|
||||
pub priority: u8,
|
||||
}
|
||||
|
||||
impl<T: Clone + Debug + Command + Serialize + DeserializeOwned> Command
|
||||
for ValidPriorityCommand<T>
|
||||
{
|
||||
}
|
||||
|
||||
impl<T> ValidPriorityCommand<T>
|
||||
where
|
||||
T: Clone + Debug,
|
||||
{
|
||||
/// Get the valid until time as an Instant
|
||||
///
|
||||
/// # Panics
|
||||
/// While this theoretically could panic, there are checks to prevent this.
|
||||
pub fn get_valid_until_instant(&self) -> Instant {
|
||||
let delta = self.valid_until.signed_duration_since(Utc::now());
|
||||
let now = Instant::now();
|
||||
if delta >= TimeDelta::zero() {
|
||||
// Unwrap is safe because we checked that it is not negative
|
||||
now + delta.to_std().unwrap()
|
||||
} else {
|
||||
// Unwrap is safe because we converted the negative to a positive
|
||||
now.checked_sub((-delta).to_std().unwrap()).unwrap_or(now)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone + Debug + Command + Serialize + DeserializeOwned> Deref for ValidPriorityCommand<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone + Debug + Command + Serialize + DeserializeOwned> DerefMut
|
||||
for ValidPriorityCommand<T>
|
||||
{
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ use log::info;
|
||||
|
||||
pub mod command;
|
||||
pub mod logger;
|
||||
pub mod math;
|
||||
pub mod on_drop;
|
||||
pub mod telemetry;
|
||||
pub mod udp;
|
||||
|
||||
@@ -43,12 +43,13 @@ pub fn setup_logger(package_name: &'static str) -> Result<()> {
|
||||
target = record.target(),
|
||||
));
|
||||
})
|
||||
.level_for("tungstenite", LevelFilter::Warn)
|
||||
.level_for("tokio_tungstenite", LevelFilter::Warn)
|
||||
.level_for("microlp", LevelFilter::Warn)
|
||||
.level_for("api", LevelFilter::Info)
|
||||
.chain(
|
||||
fern::Dispatch::new()
|
||||
.level(log_level)
|
||||
.level_for("tungstenite", LevelFilter::Warn)
|
||||
.level_for("tokio_tungstenite", LevelFilter::Warn)
|
||||
.level_for("api", LevelFilter::Info)
|
||||
.chain(std::io::stdout()),
|
||||
)
|
||||
.chain(fern::log_file(log_file.clone())?)
|
||||
|
||||
196
common/src/math/mod.rs
Normal file
196
common/src/math/mod.rs
Normal file
@@ -0,0 +1,196 @@
|
||||
use derive_more::{Add, AddAssign, Display, Neg, Sub, SubAssign};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::ops::{Div, DivAssign, Mul, MulAssign};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Copy,
|
||||
Clone,
|
||||
Add,
|
||||
AddAssign,
|
||||
Sub,
|
||||
SubAssign,
|
||||
PartialEq,
|
||||
Display,
|
||||
Neg,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[display("({x}, {y}, {z})")]
|
||||
pub struct Vector {
|
||||
pub x: f64,
|
||||
pub y: f64,
|
||||
pub z: f64,
|
||||
}
|
||||
|
||||
impl Vector {
|
||||
pub const ZERO: Vector = Vector {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.0,
|
||||
};
|
||||
pub const X: Vector = Vector {
|
||||
x: 1.0,
|
||||
y: 0.0,
|
||||
z: 0.0,
|
||||
};
|
||||
pub const Y: Vector = Vector {
|
||||
x: 0.0,
|
||||
y: 1.0,
|
||||
z: 0.0,
|
||||
};
|
||||
pub const Z: Vector = Vector {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 1.0,
|
||||
};
|
||||
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub const fn new(x: f64, y: f64, z: f64) -> Self {
|
||||
Self { x, y, z }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub const fn dot_product(self, rhs: Self) -> f64 {
|
||||
self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub const fn cross_product(self, rhs: Self) -> Self {
|
||||
Self {
|
||||
x: self.y * rhs.z - self.z * rhs.y,
|
||||
y: self.z * rhs.x - self.x * rhs.z,
|
||||
z: self.x * rhs.y - self.y * rhs.x,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub const fn length2(self) -> f64 {
|
||||
self.dot_product(self)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn length(self) -> f64 {
|
||||
self.length2().sqrt()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn normalize(self) -> Self {
|
||||
self / self.length()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn with_length(self, length: f64) -> Self {
|
||||
self.normalize() * length
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub const fn project_onto_vector(self, vector: Self) -> Self {
|
||||
let scale_factor = self.dot_product(vector) / vector.length2();
|
||||
// Manual multiplication to allow const-ification
|
||||
Self {
|
||||
x: vector.x * scale_factor,
|
||||
y: vector.y * scale_factor,
|
||||
z: vector.z * scale_factor,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn project_onto_plane(self, vector: Self) -> Self {
|
||||
self - self.project_onto_vector(vector)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Vector {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self::ZERO
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Mul<T> for Vector
|
||||
where
|
||||
f64: Mul<T, Output = f64>,
|
||||
T: Copy,
|
||||
{
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn mul(self, rhs: T) -> Self::Output {
|
||||
Self::Output {
|
||||
x: self.x * rhs,
|
||||
y: self.y * rhs,
|
||||
z: self.z * rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> MulAssign<T> for Vector
|
||||
where
|
||||
f64: MulAssign<T>,
|
||||
T: Copy,
|
||||
{
|
||||
#[inline]
|
||||
fn mul_assign(&mut self, rhs: T) {
|
||||
self.x *= rhs;
|
||||
self.y *= rhs;
|
||||
self.z *= rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Vector> for f64 {
|
||||
type Output = Vector;
|
||||
|
||||
#[inline]
|
||||
fn mul(self, rhs: Vector) -> Self::Output {
|
||||
rhs * self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Div<T> for Vector
|
||||
where
|
||||
f64: Div<T, Output = f64>,
|
||||
T: Copy,
|
||||
{
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn div(self, rhs: T) -> Self::Output {
|
||||
Self::Output {
|
||||
x: self.x / rhs,
|
||||
y: self.y / rhs,
|
||||
z: self.z / rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DivAssign<T> for Vector
|
||||
where
|
||||
f64: DivAssign<T>,
|
||||
T: Copy,
|
||||
{
|
||||
#[inline]
|
||||
fn div_assign(&mut self, rhs: T) {
|
||||
self.x /= rhs;
|
||||
self.y /= rhs;
|
||||
self.z /= rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul for Vector {
|
||||
type Output = f64;
|
||||
|
||||
#[inline]
|
||||
fn mul(self, rhs: Self) -> f64 {
|
||||
self.dot_product(rhs)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user