improved integration with telem viz
This commit is contained in:
48
Cargo.lock
generated
48
Cargo.lock
generated
@@ -20,7 +20,7 @@ checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "api"
|
name = "api"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://gitea.sergeysav.com/sergeysav/telemetry_visualization.git?rev=458c94c2ad362b1a6c31c2b1ee606a9f40605e06#458c94c2ad362b1a6c31c2b1ee606a9f40605e06"
|
source = "git+https://gitea.sergeysav.com/sergeysav/telemetry_visualization.git?rev=44862f65d2388e19b70a03409f1c16195e8f9342#44862f65d2388e19b70a03409f1c16195e8f9342"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"api-core",
|
"api-core",
|
||||||
"api-proc-macro",
|
"api-proc-macro",
|
||||||
@@ -40,7 +40,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "api-core"
|
name = "api-core"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://gitea.sergeysav.com/sergeysav/telemetry_visualization.git?rev=458c94c2ad362b1a6c31c2b1ee606a9f40605e06#458c94c2ad362b1a6c31c2b1ee606a9f40605e06"
|
source = "git+https://gitea.sergeysav.com/sergeysav/telemetry_visualization.git?rev=44862f65d2388e19b70a03409f1c16195e8f9342#44862f65d2388e19b70a03409f1c16195e8f9342"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
@@ -51,7 +51,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "api-proc-macro"
|
name = "api-proc-macro"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://gitea.sergeysav.com/sergeysav/telemetry_visualization.git?rev=458c94c2ad362b1a6c31c2b1ee606a9f40605e06#458c94c2ad362b1a6c31c2b1ee606a9f40605e06"
|
source = "git+https://gitea.sergeysav.com/sergeysav/telemetry_visualization.git?rev=44862f65d2388e19b70a03409f1c16195e8f9342#44862f65d2388e19b70a03409f1c16195e8f9342"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"api-core",
|
"api-core",
|
||||||
"proc-macro-error",
|
"proc-macro-error",
|
||||||
@@ -80,6 +80,15 @@ dependencies = [
|
|||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block2"
|
||||||
|
version = "0.6.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5"
|
||||||
|
dependencies = [
|
||||||
|
"objc2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.17.0"
|
version = "3.17.0"
|
||||||
@@ -213,11 +222,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ctrlc"
|
name = "ctrlc"
|
||||||
version = "3.5.0"
|
version = "3.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "881c5d0a13b2f1498e2306e82cbada78390e152d4b1378fb28a84f4dcd0dc4f3"
|
checksum = "73736a89c4aff73035ba2ed2e565061954da00d4970fc9ac25dcc85a2a20d790"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dispatch",
|
"dispatch2",
|
||||||
"nix",
|
"nix",
|
||||||
"windows-sys 0.61.1",
|
"windows-sys 0.61.1",
|
||||||
]
|
]
|
||||||
@@ -262,10 +271,16 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dispatch"
|
name = "dispatch2"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
|
checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"block2",
|
||||||
|
"libc",
|
||||||
|
"objc2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
@@ -714,6 +729,21 @@ dependencies = [
|
|||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc2"
|
||||||
|
version = "0.6.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05"
|
||||||
|
dependencies = [
|
||||||
|
"objc2-encode",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc2-encode"
|
||||||
|
version = "4.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.21.3"
|
version = "1.21.3"
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ members = ["common", "ground", "flight"]
|
|||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
anyhow = "1.0.100"
|
anyhow = "1.0.100"
|
||||||
api = { git = "https://gitea.sergeysav.com/sergeysav/telemetry_visualization.git", rev = "458c94c2ad362b1a6c31c2b1ee606a9f40605e06" }
|
api = { git = "https://gitea.sergeysav.com/sergeysav/telemetry_visualization.git", rev = "44862f65d2388e19b70a03409f1c16195e8f9342" }
|
||||||
chrono = { version = "0.4.42", features = ["serde"] }
|
chrono = { version = "0.4.42", features = ["serde"] }
|
||||||
crc = "3.4.0"
|
crc = "3.4.0"
|
||||||
ctrlc = "3.5.0"
|
ctrlc = "3.5.1"
|
||||||
derive_more = "2.1.1"
|
derive_more = "2.1.1"
|
||||||
embedded-hal = "1.0.0"
|
embedded-hal = "1.0.0"
|
||||||
embedded-hal-bus = "0.3.0"
|
embedded-hal-bus = "0.3.0"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ edition = "2024"
|
|||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
chrono = { workspace = true }
|
chrono = { workspace = true }
|
||||||
ctrlc = { workspace = true }
|
ctrlc = { workspace = true }
|
||||||
derive_more = {workspace = true, features = ["display"]}
|
derive_more = {workspace = true, features = ["display", "from"]}
|
||||||
fern = { workspace = true }
|
fern = { workspace = true }
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
postcard = { workspace = true }
|
postcard = { workspace = true }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use chrono::serde::ts_nanoseconds;
|
use chrono::serde::ts_nanoseconds;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use derive_more::Display;
|
use derive_more::{Display, From};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
@@ -16,10 +16,21 @@ pub enum SwitchBank {
|
|||||||
B,
|
B,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize, From)]
|
||||||
pub enum TelemetryMessage {
|
pub enum TelemetryMessage {
|
||||||
SwitchState {
|
SwitchState {
|
||||||
bank: SwitchBank,
|
bank: SwitchBank,
|
||||||
switches: [bool; 16],
|
switches: [bool; 16],
|
||||||
},
|
},
|
||||||
|
CommsState(CommsState),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||||
|
pub struct CommsState {
|
||||||
|
pub tx_packets: u32,
|
||||||
|
pub rx_packets: u32,
|
||||||
|
pub tx_bytes: u32,
|
||||||
|
pub rx_bytes: u32,
|
||||||
|
pub tx_errors: u32,
|
||||||
|
pub rx_errors: u32,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ use thiserror::Error;
|
|||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum UdpRecvPostcardError {
|
pub enum UdpRecvPostcardError {
|
||||||
#[error("IO Error")]
|
#[error("IO Error: {0}")]
|
||||||
Io(#[from] std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
#[error("Deserialization Error")]
|
#[error("Deserialization Error: {0}")]
|
||||||
Deserialization(#[from] postcard::Error),
|
Deserialization(#[from] postcard::Error),
|
||||||
#[error("Extra Data")]
|
#[error("Extra Data: {amount}")]
|
||||||
ExtraData { amount: usize },
|
ExtraData { amount: usize },
|
||||||
#[error("No Data")]
|
#[error("No Data")]
|
||||||
NoData,
|
NoData,
|
||||||
@@ -20,11 +20,11 @@ pub enum UdpRecvPostcardError {
|
|||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum UdpSendPostcardError {
|
pub enum UdpSendPostcardError {
|
||||||
#[error("IO Error")]
|
#[error("IO Error: {0}")]
|
||||||
Io(#[from] std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
#[error("Serialization Error")]
|
#[error("Serialization Error: {0}")]
|
||||||
Serialization(#[from] postcard::Error),
|
Serialization(#[from] postcard::Error),
|
||||||
#[error("Length Mismatch")]
|
#[error("Length Mismatch: {expected} expected. {actual} actual")]
|
||||||
LengthMismatch { expected: usize, actual: usize },
|
LengthMismatch { expected: usize, actual: usize },
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ pub trait UdpSocketExt {
|
|||||||
fn recv_postcard<'de, T: Deserialize<'de>>(
|
fn recv_postcard<'de, T: Deserialize<'de>>(
|
||||||
&self,
|
&self,
|
||||||
buffer: &'de mut [u8],
|
buffer: &'de mut [u8],
|
||||||
) -> Result<(T, SocketAddr), UdpRecvPostcardError>;
|
) -> Result<(T, SocketAddr, usize), UdpRecvPostcardError>;
|
||||||
|
|
||||||
/// Send a CBOR encoded message to an address using this socket
|
/// Send a CBOR encoded message to an address using this socket
|
||||||
///
|
///
|
||||||
@@ -48,7 +48,7 @@ pub trait UdpSocketExt {
|
|||||||
data: &T,
|
data: &T,
|
||||||
buffer: &mut [u8],
|
buffer: &mut [u8],
|
||||||
addr: A,
|
addr: A,
|
||||||
) -> Result<(), UdpSendPostcardError>;
|
) -> Result<usize, UdpSendPostcardError>;
|
||||||
|
|
||||||
/// Send a command message to an address using this socket
|
/// Send a command message to an address using this socket
|
||||||
///
|
///
|
||||||
@@ -59,20 +59,20 @@ pub trait UdpSocketExt {
|
|||||||
name: &str,
|
name: &str,
|
||||||
data: &T,
|
data: &T,
|
||||||
addr: A,
|
addr: A,
|
||||||
) -> Result<(), UdpSendPostcardError>;
|
) -> Result<usize, UdpSendPostcardError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recv_postcard_inner<'de, T: Deserialize<'de>>(
|
fn recv_postcard_inner<'de, T: Deserialize<'de>>(
|
||||||
result: std::io::Result<(usize, SocketAddr)>,
|
result: std::io::Result<(usize, SocketAddr)>,
|
||||||
buffer: &'de mut [u8],
|
buffer: &'de mut [u8],
|
||||||
) -> Result<(T, SocketAddr), UdpRecvPostcardError> {
|
) -> Result<(T, SocketAddr, usize), UdpRecvPostcardError> {
|
||||||
match result {
|
match result {
|
||||||
Ok((size, addr)) => match postcard::take_from_bytes::<T>(&buffer[..size]) {
|
Ok((size, addr)) => match postcard::take_from_bytes::<T>(&buffer[..size]) {
|
||||||
Ok((res, rem)) => {
|
Ok((res, rem)) => {
|
||||||
if !rem.is_empty() {
|
if !rem.is_empty() {
|
||||||
return Err(ExtraData { amount: rem.len() });
|
return Err(ExtraData { amount: rem.len() });
|
||||||
}
|
}
|
||||||
Ok((res, addr))
|
Ok((res, addr, size))
|
||||||
}
|
}
|
||||||
Err(err) => Err(err.into()),
|
Err(err) => Err(err.into()),
|
||||||
},
|
},
|
||||||
@@ -86,7 +86,7 @@ fn recv_postcard_inner<'de, T: Deserialize<'de>>(
|
|||||||
fn send_inner(
|
fn send_inner(
|
||||||
send_result: Result<usize, std::io::Error>,
|
send_result: Result<usize, std::io::Error>,
|
||||||
expected_size: usize,
|
expected_size: usize,
|
||||||
) -> Result<(), UdpSendPostcardError> {
|
) -> Result<usize, UdpSendPostcardError> {
|
||||||
match send_result {
|
match send_result {
|
||||||
Ok(size_sent) => {
|
Ok(size_sent) => {
|
||||||
if expected_size != size_sent {
|
if expected_size != size_sent {
|
||||||
@@ -95,7 +95,7 @@ fn send_inner(
|
|||||||
actual: size_sent,
|
actual: size_sent,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(size_sent)
|
||||||
}
|
}
|
||||||
Err(e) => Err(e.into()),
|
Err(e) => Err(e.into()),
|
||||||
}
|
}
|
||||||
@@ -105,7 +105,7 @@ impl UdpSocketExt for UdpSocket {
|
|||||||
fn recv_postcard<'de, T: Deserialize<'de>>(
|
fn recv_postcard<'de, T: Deserialize<'de>>(
|
||||||
&self,
|
&self,
|
||||||
buffer: &'de mut [u8],
|
buffer: &'de mut [u8],
|
||||||
) -> Result<(T, SocketAddr), UdpRecvPostcardError> {
|
) -> Result<(T, SocketAddr, usize), UdpRecvPostcardError> {
|
||||||
recv_postcard_inner(self.recv_from(buffer), buffer)
|
recv_postcard_inner(self.recv_from(buffer), buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +114,7 @@ impl UdpSocketExt for UdpSocket {
|
|||||||
data: &T,
|
data: &T,
|
||||||
buffer: &mut [u8],
|
buffer: &mut [u8],
|
||||||
addr: A,
|
addr: A,
|
||||||
) -> Result<(), UdpSendPostcardError> {
|
) -> Result<usize, UdpSendPostcardError> {
|
||||||
let result = postcard::to_slice(data, buffer)?;
|
let result = postcard::to_slice(data, buffer)?;
|
||||||
let size_encoded = result.len();
|
let size_encoded = result.len();
|
||||||
send_inner(self.send_to(result, addr), size_encoded)
|
send_inner(self.send_to(result, addr), size_encoded)
|
||||||
@@ -125,7 +125,7 @@ impl UdpSocketExt for UdpSocket {
|
|||||||
name: &str,
|
name: &str,
|
||||||
data: &T,
|
data: &T,
|
||||||
addr: A,
|
addr: A,
|
||||||
) -> Result<(), UdpSendPostcardError> {
|
) -> Result<usize, UdpSendPostcardError> {
|
||||||
let mut inner_buffer = [0u8; 512];
|
let mut inner_buffer = [0u8; 512];
|
||||||
let inner_buffer = postcard::to_slice(data, &mut inner_buffer)?;
|
let inner_buffer = postcard::to_slice(data, &mut inner_buffer)?;
|
||||||
let mut buffer = [0u8; 512];
|
let mut buffer = [0u8; 512];
|
||||||
@@ -158,7 +158,7 @@ pub mod tokio {
|
|||||||
fn recv_postcard<'de, T: Deserialize<'de>>(
|
fn recv_postcard<'de, T: Deserialize<'de>>(
|
||||||
&self,
|
&self,
|
||||||
buffer: &'de mut [u8],
|
buffer: &'de mut [u8],
|
||||||
) -> impl Future<Output = Result<(T, SocketAddr), UdpRecvPostcardError>>;
|
) -> impl Future<Output = Result<(T, SocketAddr, usize), UdpRecvPostcardError>>;
|
||||||
|
|
||||||
/// Send a CBOR encoded message to an address using this socket
|
/// Send a CBOR encoded message to an address using this socket
|
||||||
///
|
///
|
||||||
@@ -169,7 +169,7 @@ pub mod tokio {
|
|||||||
data: &T,
|
data: &T,
|
||||||
buffer: &mut [u8],
|
buffer: &mut [u8],
|
||||||
addr: A,
|
addr: A,
|
||||||
) -> impl Future<Output = Result<(), UdpSendPostcardError>>;
|
) -> impl Future<Output = Result<usize, UdpSendPostcardError>>;
|
||||||
|
|
||||||
/// Send a command message to an address using this socket
|
/// Send a command message to an address using this socket
|
||||||
///
|
///
|
||||||
@@ -180,14 +180,14 @@ pub mod tokio {
|
|||||||
name: &str,
|
name: &str,
|
||||||
data: &T,
|
data: &T,
|
||||||
addr: A,
|
addr: A,
|
||||||
) -> impl Future<Output = Result<(), UdpSendPostcardError>>;
|
) -> impl Future<Output = Result<usize, UdpSendPostcardError>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsyncUdpSocketExt for UdpSocket {
|
impl AsyncUdpSocketExt for UdpSocket {
|
||||||
async fn recv_postcard<'de, T: Deserialize<'de>>(
|
async fn recv_postcard<'de, T: Deserialize<'de>>(
|
||||||
&self,
|
&self,
|
||||||
buffer: &'de mut [u8],
|
buffer: &'de mut [u8],
|
||||||
) -> Result<(T, SocketAddr), UdpRecvPostcardError> {
|
) -> Result<(T, SocketAddr, usize), UdpRecvPostcardError> {
|
||||||
recv_postcard_inner(self.recv_from(buffer).await, buffer)
|
recv_postcard_inner(self.recv_from(buffer).await, buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,7 +196,7 @@ pub mod tokio {
|
|||||||
data: &T,
|
data: &T,
|
||||||
buffer: &mut [u8],
|
buffer: &mut [u8],
|
||||||
addr: A,
|
addr: A,
|
||||||
) -> Result<(), UdpSendPostcardError> {
|
) -> Result<usize, UdpSendPostcardError> {
|
||||||
let result = postcard::to_slice(data, buffer)?;
|
let result = postcard::to_slice(data, buffer)?;
|
||||||
let size_encoded = result.len();
|
let size_encoded = result.len();
|
||||||
send_inner(self.send_to(result, addr).await, size_encoded)
|
send_inner(self.send_to(result, addr).await, size_encoded)
|
||||||
@@ -207,7 +207,7 @@ pub mod tokio {
|
|||||||
name: &str,
|
name: &str,
|
||||||
data: &T,
|
data: &T,
|
||||||
addr: A,
|
addr: A,
|
||||||
) -> Result<(), UdpSendPostcardError> {
|
) -> Result<usize, UdpSendPostcardError> {
|
||||||
let mut inner_buffer = [0u8; 512];
|
let mut inner_buffer = [0u8; 512];
|
||||||
let inner_buffer = postcard::to_slice(data, &mut inner_buffer)?;
|
let inner_buffer = postcard::to_slice(data, &mut inner_buffer)?;
|
||||||
let mut buffer = [0u8; 512];
|
let mut buffer = [0u8; 512];
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
use crate::scheduler::{CyclicTask, TaskHandle};
|
use crate::scheduler::{CyclicTask, TaskHandle};
|
||||||
|
use crate::state_vector::{SectionIdentifier, SectionWriter, StateVector};
|
||||||
use anyhow::{Result, ensure};
|
use anyhow::{Result, ensure};
|
||||||
use log::{error, trace, warn};
|
use log::{error, trace, warn};
|
||||||
use nautilus_common::command::{Command, CommandHeader};
|
use nautilus_common::command::{Command, CommandHeader};
|
||||||
use nautilus_common::telemetry::{Telemetry, TelemetryMessage};
|
pub(crate) use nautilus_common::telemetry::{CommsState, Telemetry, TelemetryMessage};
|
||||||
use nautilus_common::udp::{UdpRecvPostcardError, UdpSocketExt};
|
use nautilus_common::udp::{UdpRecvPostcardError, UdpSocketExt};
|
||||||
use std::any::type_name;
|
use std::any::type_name;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@@ -11,7 +12,7 @@ use std::net::{IpAddr, Ipv4Addr, SocketAddr, ToSocketAddrs, UdpSocket};
|
|||||||
use std::sync::mpsc::Receiver;
|
use std::sync::mpsc::Receiver;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
pub type TelemetrySender = TaskHandle<Telemetry, ()>;
|
pub type TelemetrySender = TaskHandle<Telemetry, SectionIdentifier>;
|
||||||
|
|
||||||
impl TelemetrySender {
|
impl TelemetrySender {
|
||||||
pub fn send(&self, telemetry_message: TelemetryMessage) {
|
pub fn send(&self, telemetry_message: TelemetryMessage) {
|
||||||
@@ -33,6 +34,7 @@ where
|
|||||||
udp: UdpSocket,
|
udp: UdpSocket,
|
||||||
ground_address: A,
|
ground_address: A,
|
||||||
command_callbacks: HashMap<String, CommandCallback<'a>>,
|
command_callbacks: HashMap<String, CommandCallback<'a>>,
|
||||||
|
section_writer: SectionWriter<'a, CommsState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A> Debug for CommsTask<'_, A>
|
impl<A> Debug for CommsTask<'_, A>
|
||||||
@@ -52,7 +54,7 @@ impl<'a, A> CommsTask<'a, A>
|
|||||||
where
|
where
|
||||||
A: ToSocketAddrs + Debug,
|
A: ToSocketAddrs + Debug,
|
||||||
{
|
{
|
||||||
pub fn new(local_port: u16, ground_address: A) -> Result<Self> {
|
pub fn new(local_port: u16, ground_address: A, state_vector: &'a StateVector) -> Result<Self> {
|
||||||
trace!(
|
trace!(
|
||||||
"CommsTask::new<A={}>(local_port: {local_port}, ground_address: {ground_address:?})",
|
"CommsTask::new<A={}>(local_port: {local_port}, ground_address: {ground_address:?})",
|
||||||
type_name::<A>()
|
type_name::<A>()
|
||||||
@@ -61,10 +63,13 @@ where
|
|||||||
// let bind_addr = SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), local_port);
|
// let bind_addr = SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), local_port);
|
||||||
let udp = UdpSocket::bind(bind_addr)?;
|
let udp = UdpSocket::bind(bind_addr)?;
|
||||||
udp.set_nonblocking(true)?;
|
udp.set_nonblocking(true)?;
|
||||||
|
|
||||||
|
let section_writer = state_vector.create_section(CommsState::default());
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
udp,
|
udp,
|
||||||
ground_address,
|
ground_address,
|
||||||
command_callbacks: HashMap::new(),
|
command_callbacks: HashMap::new(),
|
||||||
|
section_writer,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,13 +105,15 @@ where
|
|||||||
A: ToSocketAddrs + Debug,
|
A: ToSocketAddrs + Debug,
|
||||||
{
|
{
|
||||||
type Message = Telemetry;
|
type Message = Telemetry;
|
||||||
type Data = ();
|
type Data = SectionIdentifier;
|
||||||
|
|
||||||
fn get_data(&self) -> Self::Data {
|
fn get_data(&self) -> Self::Data {
|
||||||
trace!(
|
trace!(
|
||||||
"CommsTask<A={}>::get_data(self: {self:?})",
|
"CommsTask<A={}>::get_data(self: {self:?})",
|
||||||
type_name::<A>()
|
type_name::<A>()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
self.section_writer.get_identifier()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn step(&mut self, receiver: &Receiver<Self::Message>, step_time: Instant) {
|
fn step(&mut self, receiver: &Receiver<Self::Message>, step_time: Instant) {
|
||||||
@@ -117,7 +124,14 @@ where
|
|||||||
let mut buffer = [0u8; 512];
|
let mut buffer = [0u8; 512];
|
||||||
|
|
||||||
match self.udp.recv_postcard::<CommandHeader>(&mut buffer) {
|
match self.udp.recv_postcard::<CommandHeader>(&mut buffer) {
|
||||||
Ok((cmd, _)) => match self.command_callbacks.get(cmd.name) {
|
Ok((cmd, _, size)) => {
|
||||||
|
self.section_writer.update(|state| {
|
||||||
|
state.rx_packets = state.rx_packets.wrapping_add(1);
|
||||||
|
state.rx_bytes = state
|
||||||
|
.rx_bytes
|
||||||
|
.wrapping_add(u32::try_from(size % (u32::MAX as usize)).unwrap_or(0));
|
||||||
|
});
|
||||||
|
match self.command_callbacks.get(cmd.name) {
|
||||||
Some(handler) => {
|
Some(handler) => {
|
||||||
if let Err(e) = handler(cmd.data) {
|
if let Err(e) = handler(cmd.data) {
|
||||||
error!("Command Error: {e}");
|
error!("Command Error: {e}");
|
||||||
@@ -126,20 +140,35 @@ where
|
|||||||
None => {
|
None => {
|
||||||
warn!("Unknown Command: {}", cmd.name);
|
warn!("Unknown Command: {}", cmd.name);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
}
|
||||||
Err(UdpRecvPostcardError::NoData) => {}
|
Err(UdpRecvPostcardError::NoData) => {}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("Rx error: {err}");
|
error!("Rx error: {err}");
|
||||||
|
self.section_writer.update(|state| {
|
||||||
|
state.rx_errors = state.rx_errors.wrapping_add(1);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intentionally ignore Err case
|
// Intentionally ignore Err case
|
||||||
while let Ok(tlm) = receiver.try_recv() {
|
while let Ok(tlm) = receiver.try_recv() {
|
||||||
if let Err(err) = self
|
match self
|
||||||
.udp
|
.udp
|
||||||
.send_postcard(&tlm, &mut buffer, &self.ground_address)
|
.send_postcard(&tlm, &mut buffer, &self.ground_address)
|
||||||
{
|
{
|
||||||
|
Ok(bytes_sent) => self.section_writer.update(|state| {
|
||||||
|
state.tx_packets = state.tx_packets.wrapping_add(1);
|
||||||
|
state.tx_bytes = state
|
||||||
|
.tx_bytes
|
||||||
|
.wrapping_add(u32::try_from(bytes_sent % (u32::MAX as usize)).unwrap_or(0));
|
||||||
|
}),
|
||||||
|
Err(err) => {
|
||||||
error!("Tx Error: {err}");
|
error!("Tx Error: {err}");
|
||||||
|
self.section_writer.update(|state| {
|
||||||
|
state.tx_errors = state.tx_errors.wrapping_add(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ pub struct Mcp23017Data {
|
|||||||
|
|
||||||
impl Mcp23017Data {
|
impl Mcp23017Data {
|
||||||
pub fn get_id(&self) -> SectionIdentifier {
|
pub fn get_id(&self) -> SectionIdentifier {
|
||||||
self.id.clone()
|
self.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,9 +216,10 @@ impl<M: Mcp23017 + Debug> CyclicTask for Mcp23017Task<'_, M> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for pin in 0u8..16u8 {
|
for pin in 0u8..16u8 {
|
||||||
let state = self.pins.pins[pin as usize].value;
|
let current_pin = &mut self.pins.pins[pin as usize];
|
||||||
if self.pins.pins[pin as usize].changed {
|
let state = current_pin.value;
|
||||||
self.pins.pins[pin as usize].changed = false;
|
if current_pin.changed {
|
||||||
|
current_pin.changed = false;
|
||||||
// This shouldn't be able to fail
|
// This shouldn't be able to fail
|
||||||
// TODO: handle error case
|
// TODO: handle error case
|
||||||
let _ = self.mcp23017.set_pin(pin, state);
|
let _ = self.mcp23017.set_pin(pin, state);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#![warn(clippy::all, clippy::pedantic)]
|
#![warn(clippy::all, clippy::pedantic)]
|
||||||
use crate::comms::CommsTask;
|
|
||||||
|
use crate::comms::{CommsState, CommsTask};
|
||||||
use crate::hardware::Hardware;
|
use crate::hardware::Hardware;
|
||||||
use crate::hardware::initialize;
|
use crate::hardware::initialize;
|
||||||
use crate::hardware::mcp23017::{Mcp23017, Mcp23017State, Mcp23017Task};
|
use crate::hardware::mcp23017::{Mcp23017, Mcp23017State, Mcp23017Task};
|
||||||
@@ -10,12 +11,12 @@ use crate::state_vector::StateVector;
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use embedded_hal::pwm::SetDutyCycle;
|
use embedded_hal::pwm::SetDutyCycle;
|
||||||
use log::info;
|
use log::info;
|
||||||
|
use nautilus_common::add_ctrlc_handler_arc;
|
||||||
use nautilus_common::telemetry::{SwitchBank, TelemetryMessage};
|
use nautilus_common::telemetry::{SwitchBank, TelemetryMessage};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::thread::sleep;
|
use std::thread::sleep;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use nautilus_common::add_ctrlc_handler_arc;
|
|
||||||
|
|
||||||
mod hardware;
|
mod hardware;
|
||||||
|
|
||||||
@@ -69,30 +70,34 @@ pub fn run() -> Result<()> {
|
|||||||
)?;
|
)?;
|
||||||
let b_id = task_b.get_id();
|
let b_id = task_b.get_id();
|
||||||
|
|
||||||
let mut comms = CommsTask::new(15000, "nautilus-ground:14000")?;
|
let mut comms = CommsTask::new(15000, "nautilus-ground:14000", &state_vector)?;
|
||||||
comms.add_command_handler("/shutdown", new_shutdown_handler(&running))?;
|
comms.add_command_handler("/shutdown", new_shutdown_handler(&running))?;
|
||||||
comms.add_command_handler("/mcp23017a/set", task_a.new_set_pin_callback())?;
|
comms.add_command_handler("/mcp23017a/set", task_a.new_set_pin_callback())?;
|
||||||
comms.add_command_handler("/mcp23017b/set", task_b.new_set_pin_callback())?;
|
comms.add_command_handler("/mcp23017b/set", task_b.new_set_pin_callback())?;
|
||||||
let comms = s.run_cyclic("comms-task", comms, 10)?;
|
let comms = s.run_cyclic("comms-task", comms, 10)?;
|
||||||
|
let comms_id = *comms;
|
||||||
|
|
||||||
let sv = &state_vector;
|
let sv = &state_vector;
|
||||||
s.run_cyclic(
|
s.run_cyclic(
|
||||||
"telemetry-producer",
|
"telemetry-producer",
|
||||||
move || {
|
move || {
|
||||||
sv.access_section(&a_id, |state: &Mcp23017State| {
|
sv.access_section(a_id, |state: &Mcp23017State| {
|
||||||
comms.send(TelemetryMessage::SwitchState {
|
comms.send(TelemetryMessage::SwitchState {
|
||||||
bank: SwitchBank::A,
|
bank: SwitchBank::A,
|
||||||
switches: state.pins,
|
switches: state.pins,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
sv.access_section(&b_id, |state: &Mcp23017State| {
|
sv.access_section(b_id, |state: &Mcp23017State| {
|
||||||
comms.send(TelemetryMessage::SwitchState {
|
comms.send(TelemetryMessage::SwitchState {
|
||||||
bank: SwitchBank::B,
|
bank: SwitchBank::B,
|
||||||
switches: state.pins,
|
switches: state.pins,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
sv.access_section(comms_id, |state: &CommsState| {
|
||||||
|
comms.send(state.clone().into());
|
||||||
|
});
|
||||||
},
|
},
|
||||||
10,
|
1,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
info!("Starting Main Loop");
|
info!("Starting Main Loop");
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ pub struct StateVector {
|
|||||||
sections: RwLock<HashMap<SectionIdentifier, Box<RwLock<dyn Any + Send + Sync>>>>,
|
sections: RwLock<HashMap<SectionIdentifier, Box<RwLock<dyn Any + Send + Sync>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
|
||||||
pub struct SectionIdentifier(usize);
|
pub struct SectionIdentifier(usize);
|
||||||
|
|
||||||
pub struct SectionWriter<'a, T> {
|
pub struct SectionWriter<'a, T> {
|
||||||
@@ -39,7 +39,7 @@ impl<T: 'static> SectionWriter<'_, T> {
|
|||||||
"SectionWriter<T={}>::get_identifier(self: {self:?})",
|
"SectionWriter<T={}>::get_identifier(self: {self:?})",
|
||||||
type_name::<T>()
|
type_name::<T>()
|
||||||
);
|
);
|
||||||
self.id.clone()
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update<F, R>(&self, f: F) -> R
|
pub fn update<F, R>(&self, f: F) -> R
|
||||||
@@ -81,9 +81,7 @@ impl StateVector {
|
|||||||
|
|
||||||
self.sections.clear_poison();
|
self.sections.clear_poison();
|
||||||
let mut sections = self.sections.write().unwrap();
|
let mut sections = self.sections.write().unwrap();
|
||||||
if !sections.contains_key(&id) {
|
sections.entry(id).or_insert(lock);
|
||||||
sections.insert(id.clone(), lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
drop(sections);
|
drop(sections);
|
||||||
|
|
||||||
@@ -94,7 +92,7 @@ impl StateVector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn access_section<T, F, R>(&self, id: &SectionIdentifier, f: F) -> Option<R>
|
pub fn access_section<T, F, R>(&self, id: SectionIdentifier, f: F) -> Option<R>
|
||||||
where
|
where
|
||||||
T: 'static,
|
T: 'static,
|
||||||
F: FnOnce(&T) -> R,
|
F: FnOnce(&T) -> R,
|
||||||
@@ -109,7 +107,7 @@ impl StateVector {
|
|||||||
let Ok(sections) = self.sections.read() else {
|
let Ok(sections) = self.sections.read() else {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
let section = sections.get(id)?;
|
let section = sections.get(&id)?;
|
||||||
section.clear_poison();
|
section.clear_poison();
|
||||||
let Ok(data) = section.read() else {
|
let Ok(data) = section.read() else {
|
||||||
return None;
|
return None;
|
||||||
@@ -148,14 +146,14 @@ mod tests {
|
|||||||
|
|
||||||
let id_1 = section_1.get_identifier();
|
let id_1 = section_1.get_identifier();
|
||||||
|
|
||||||
state_vector.access_section(&id_1, |s: &TestType| {
|
state_vector.access_section(id_1, |s: &TestType| {
|
||||||
assert_eq!(1, s.value1);
|
assert_eq!(1, s.value1);
|
||||||
assert_eq!(2, s.value2);
|
assert_eq!(2, s.value2);
|
||||||
});
|
});
|
||||||
|
|
||||||
let id_2 = section_2.get_identifier();
|
let id_2 = section_2.get_identifier();
|
||||||
|
|
||||||
state_vector.access_section(&id_2, |s: &TestType| {
|
state_vector.access_section(id_2, |s: &TestType| {
|
||||||
assert_eq!(3, s.value1);
|
assert_eq!(3, s.value1);
|
||||||
assert_eq!(4, s.value2);
|
assert_eq!(4, s.value2);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
use anyhow::bail;
|
||||||
use api::client::Client;
|
use api::client::Client;
|
||||||
use api::client::command::CommandRegistry;
|
use api::client::command::CommandRegistry;
|
||||||
use api::macros::IntoCommandDefinition;
|
use api::macros::IntoCommandDefinition;
|
||||||
use chrono::TimeDelta;
|
use chrono::{DateTime, Utc};
|
||||||
use itertools::Itertools;
|
|
||||||
use log::{error, trace};
|
use log::{error, trace};
|
||||||
use nautilus_common::command::{Command, OwnedCommandHeader, SetPin, ValidPriorityCommand};
|
use nautilus_common::command::{Command, OwnedCommandHeader, SetPin, ValidPriorityCommand};
|
||||||
use nautilus_common::udp::tokio::AsyncUdpSocketExt;
|
use nautilus_common::udp::tokio::AsyncUdpSocketExt;
|
||||||
@@ -15,6 +15,8 @@ use tokio::sync::RwLock;
|
|||||||
use tokio::sync::mpsc::{Sender, channel};
|
use tokio::sync::mpsc::{Sender, channel};
|
||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
|
|
||||||
|
const MAX_DATETIME: DateTime<Utc> = DateTime::from_timestamp_nanos(i64::MAX);
|
||||||
|
|
||||||
pub struct CommandHandler<'a> {
|
pub struct CommandHandler<'a> {
|
||||||
cmd: CommandRegistry,
|
cmd: CommandRegistry,
|
||||||
flight_addr: &'a RwLock<SocketAddr>,
|
flight_addr: &'a RwLock<SocketAddr>,
|
||||||
@@ -24,6 +26,7 @@ pub struct CommandHandler<'a> {
|
|||||||
|
|
||||||
#[derive(IntoCommandDefinition)]
|
#[derive(IntoCommandDefinition)]
|
||||||
struct SetPinCommand {
|
struct SetPinCommand {
|
||||||
|
index: u8,
|
||||||
state: bool,
|
state: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,23 +53,27 @@ impl<'a> CommandHandler<'a> {
|
|||||||
runtime.block_on(async move {
|
runtime.block_on(async move {
|
||||||
let (outgoing_commands_tx, mut outgoing_commands_rx) = channel::<OwnedCommandHeader>(16);
|
let (outgoing_commands_tx, mut outgoing_commands_rx) = channel::<OwnedCommandHeader>(16);
|
||||||
|
|
||||||
let commands = ["a", "b"].iter().cartesian_product(0..16)
|
let mut commands = ["a", "b"].iter()
|
||||||
.map(|(bank, i)| {
|
.map(|bank| {
|
||||||
let command_name = format!("/mcp23017{bank}/set");
|
let command_name = format!("/mcp23017{bank}/set");
|
||||||
let outgoing_commands_tx = outgoing_commands_tx.clone();
|
let outgoing_commands_tx = outgoing_commands_tx.clone();
|
||||||
self.cmd.register_handler(
|
self.cmd.register_handler(
|
||||||
format!("switch.{bank}.{i}.set"),
|
format!("switch.{bank}.set"),
|
||||||
move |header, cmd: SetPinCommand| -> anyhow::Result<_> {
|
move |_, cmd: SetPinCommand| -> anyhow::Result<_> {
|
||||||
trace!("Setting Switch {bank} {i}");
|
trace!("Setting Switch {bank} {}", cmd.index);
|
||||||
|
|
||||||
|
if cmd.index >= 16 {
|
||||||
|
bail!("Invalid Pin Number: {}", cmd.index)
|
||||||
|
}
|
||||||
|
|
||||||
outgoing_commands_tx.try_send_command(
|
outgoing_commands_tx.try_send_command(
|
||||||
&command_name,
|
&command_name,
|
||||||
&ValidPriorityCommand {
|
&ValidPriorityCommand {
|
||||||
inner: SetPin {
|
inner: SetPin {
|
||||||
pin: i,
|
pin: cmd.index,
|
||||||
value: cmd.state,
|
value: cmd.state,
|
||||||
},
|
},
|
||||||
valid_until: header.timestamp + TimeDelta::seconds(5),
|
valid_until: MAX_DATETIME, // header.timestamp + TimeDelta::seconds(5),
|
||||||
priority: 0,
|
priority: 0,
|
||||||
}
|
}
|
||||||
)?;
|
)?;
|
||||||
@@ -77,6 +84,14 @@ impl<'a> CommandHandler<'a> {
|
|||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
commands.push(self.cmd.register_handler("shutdown", move |_, ()| -> anyhow::Result<_> {
|
||||||
|
trace!("Shutting Down Flight");
|
||||||
|
|
||||||
|
outgoing_commands_tx.try_send_command("/shutdown", &())?;
|
||||||
|
|
||||||
|
Ok("Command Executed Successfully".to_string())
|
||||||
|
}));
|
||||||
|
|
||||||
let mut buffer = [0u8; 512];
|
let mut buffer = [0u8; 512];
|
||||||
while !self.cancel.is_cancelled() {
|
while !self.cancel.is_cancelled() {
|
||||||
select! {
|
select! {
|
||||||
@@ -86,7 +101,7 @@ impl<'a> CommandHandler<'a> {
|
|||||||
None => break,
|
None => break,
|
||||||
Some(outgoing) => {
|
Some(outgoing) => {
|
||||||
match self.udp.send_postcard(&outgoing, &mut buffer, *self.flight_addr.read().await).await {
|
match self.udp.send_postcard(&outgoing, &mut buffer, *self.flight_addr.read().await).await {
|
||||||
Ok(()) => {},
|
Ok(_) => {},
|
||||||
Err(err) => error!("Failed to Send Outgoing {err}"),
|
Err(err) => error!("Failed to Send Outgoing {err}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#![warn(clippy::all, clippy::pedantic)]
|
#![warn(clippy::all, clippy::pedantic)]
|
||||||
|
|
||||||
use nautilus_common::udp::tokio::AsyncUdpSocketExt;
|
|
||||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||||
mod command;
|
mod command;
|
||||||
mod telemetry;
|
mod telemetry;
|
||||||
@@ -94,11 +93,7 @@ pub fn run() -> Result<()> {
|
|||||||
Ok(()) as Result<()>
|
Ok(()) as Result<()>
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
info!("Sending Shutdown Command");
|
info!("Shutting Down");
|
||||||
|
|
||||||
if let Ok(flight_addr) = flight_addr.try_read() {
|
|
||||||
block_on(async { udp.send_command("/shutdown", &(), *flight_addr).await })?;
|
|
||||||
}
|
|
||||||
|
|
||||||
udp_shutdown.cancel();
|
udp_shutdown.cancel();
|
||||||
udp_thread.join().map_err(|e| anyhow!("{e:?}"))??;
|
udp_thread.join().map_err(|e| anyhow!("{e:?}"))??;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use futures::TryFutureExt;
|
|||||||
use futures::future::join_all;
|
use futures::future::join_all;
|
||||||
use log::{error, trace};
|
use log::{error, trace};
|
||||||
use nautilus_common::on_drop::on_drop;
|
use nautilus_common::on_drop::on_drop;
|
||||||
use nautilus_common::telemetry::{SwitchBank, Telemetry, TelemetryMessage};
|
use nautilus_common::telemetry::{CommsState, SwitchBank, Telemetry, TelemetryMessage};
|
||||||
use nautilus_common::udp::UdpRecvPostcardError;
|
use nautilus_common::udp::UdpRecvPostcardError;
|
||||||
use nautilus_common::udp::tokio::AsyncUdpSocketExt;
|
use nautilus_common::udp::tokio::AsyncUdpSocketExt;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
@@ -12,7 +12,7 @@ use std::sync::Arc;
|
|||||||
use tokio::net::UdpSocket;
|
use tokio::net::UdpSocket;
|
||||||
use tokio::sync::{RwLock, RwLockWriteGuard};
|
use tokio::sync::{RwLock, RwLockWriteGuard};
|
||||||
use tokio::task::yield_now;
|
use tokio::task::yield_now;
|
||||||
use tokio::{join, pin, select};
|
use tokio::{join, pin, select, try_join};
|
||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
|
|
||||||
pub struct TelemetryHandler<'a> {
|
pub struct TelemetryHandler<'a> {
|
||||||
@@ -61,7 +61,7 @@ impl<'a> TelemetryHandler<'a> {
|
|||||||
() = self.cancel.cancelled() => {},
|
() = self.cancel.cancelled() => {},
|
||||||
incoming = self.udp.recv_postcard::<Telemetry>(&mut buffer) => {
|
incoming = self.udp.recv_postcard::<Telemetry>(&mut buffer) => {
|
||||||
match incoming {
|
match incoming {
|
||||||
Ok((tlm, addr)) => {
|
Ok((tlm, addr, _)) => {
|
||||||
trace!("{tlm:?}");
|
trace!("{tlm:?}");
|
||||||
|
|
||||||
let flight_addr_update = async {
|
let flight_addr_update = async {
|
||||||
@@ -107,16 +107,38 @@ impl<'a> TelemetryHandler<'a> {
|
|||||||
struct TelemetryContext {
|
struct TelemetryContext {
|
||||||
bank_a: Vec<TelemetryHandle<bool>>,
|
bank_a: Vec<TelemetryHandle<bool>>,
|
||||||
bank_b: Vec<TelemetryHandle<bool>>,
|
bank_b: Vec<TelemetryHandle<bool>>,
|
||||||
|
tx_packets: TelemetryHandle<u32>,
|
||||||
|
rx_packets: TelemetryHandle<u32>,
|
||||||
|
tx_bytes: TelemetryHandle<u32>,
|
||||||
|
rx_bytes: TelemetryHandle<u32>,
|
||||||
|
tx_errors: TelemetryHandle<u32>,
|
||||||
|
rx_errors: TelemetryHandle<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TelemetryContext {
|
impl TelemetryContext {
|
||||||
async fn new(tlm: &TelemetryHandler<'_>) -> Self {
|
async fn new(tlm: &TelemetryHandler<'_>) -> Self {
|
||||||
let bank_a =
|
let bank_a =
|
||||||
join_all((0..16).map(|i| tlm.tlm.register::<bool>(format!("switch.bank_a.{i}")))).await;
|
join_all((0..16).map(|i| tlm.tlm.register(format!("switch.bank_a.{i}")))).await;
|
||||||
let bank_b =
|
let bank_b =
|
||||||
join_all((0..16).map(|i| tlm.tlm.register::<bool>(format!("switch.bank_b.{i}")))).await;
|
join_all((0..16).map(|i| tlm.tlm.register(format!("switch.bank_b.{i}")))).await;
|
||||||
|
|
||||||
Self { bank_a, bank_b }
|
let tx_packets = tlm.tlm.register("comms.tx_packets").await;
|
||||||
|
let rx_packets = tlm.tlm.register("comms.rx_packets").await;
|
||||||
|
let tx_bytes = tlm.tlm.register("comms.tx_bytes").await;
|
||||||
|
let rx_bytes = tlm.tlm.register("comms.rx_bytes").await;
|
||||||
|
let tx_errors = tlm.tlm.register("comms.tx_errors").await;
|
||||||
|
let rx_errors = tlm.tlm.register("comms.rx_errors").await;
|
||||||
|
|
||||||
|
Self {
|
||||||
|
bank_a,
|
||||||
|
bank_b,
|
||||||
|
tx_packets,
|
||||||
|
rx_packets,
|
||||||
|
tx_bytes,
|
||||||
|
rx_bytes,
|
||||||
|
tx_errors,
|
||||||
|
rx_errors,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn step(&mut self, tlm: Telemetry) {
|
async fn step(&mut self, tlm: Telemetry) {
|
||||||
@@ -137,6 +159,25 @@ impl TelemetryContext {
|
|||||||
}))
|
}))
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
TelemetryMessage::CommsState(CommsState {
|
||||||
|
tx_packets,
|
||||||
|
rx_packets,
|
||||||
|
tx_bytes,
|
||||||
|
rx_bytes,
|
||||||
|
tx_errors,
|
||||||
|
rx_errors,
|
||||||
|
}) => {
|
||||||
|
if let Err(e) = try_join!(
|
||||||
|
self.tx_packets.publish(tx_packets, tlm.timestamp),
|
||||||
|
self.rx_packets.publish(rx_packets, tlm.timestamp),
|
||||||
|
self.tx_bytes.publish(tx_bytes, tlm.timestamp),
|
||||||
|
self.rx_bytes.publish(rx_bytes, tlm.timestamp),
|
||||||
|
self.tx_errors.publish(tx_errors, tlm.timestamp),
|
||||||
|
self.rx_errors.publish(rx_errors, tlm.timestamp),
|
||||||
|
) {
|
||||||
|
error!("Failed to publish comms telemetry: {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user