chalkydri/subsystems/
mod.rs1use std::{fmt::Debug, marker::PhantomData};
2
3use minint::NtConn;
4use tokio::sync::watch;
5
6use crate::{cameras::pipeline::Preprocessor, config};
7
8#[cfg(feature = "apriltags")]
9pub mod apriltags;
10#[cfg(feature = "capriltags")]
11pub mod capriltags;
12#[cfg(feature = "ml")]
14pub mod ml;
15#[cfg(feature = "python")]
16pub mod python;
17
18pub trait Subsystem: Sized {
31 const NAME: &'static str;
32
33 type Config: Debug + Send + Sync + Clone + 'static;
34 type Preproc: Preprocessor;
35 type Output: Send + 'static;
36 type Error: Debug + Send + 'static;
37
38 async fn init() -> Result<Self, Self::Error>;
40
41 async fn process(
43 &self,
44 nt: NtConn,
45 cam_config: config::Camera,
46 rx: watch::Receiver<Option<<<Self as Subsystem>::Preproc as Preprocessor>::Frame>>,
47 ) -> Result<Self::Output, Self::Error>;
48}
49
50pub struct NoopSubsys<P: Preprocessor>(PhantomData<P>);
51impl<P: Preprocessor> NoopSubsys<P> {
52 #[inline(always)]
53 pub const fn new() -> Self {
54 Self(PhantomData)
55 }
56}
57impl<P: Preprocessor> Subsystem for NoopSubsys<P> {
58 const NAME: &'static str = "noop";
59
60 type Config = ();
61 type Preproc = P;
62 type Output = ();
63 type Error = ();
64
65 async fn init() -> Result<Self, Self::Error> {
66 Ok(Self::new())
67 }
68 async fn process(
69 &self,
70 _nt: NtConn,
71 _cam_config: config::Camera,
72 _rx: watch::Receiver<Option<<<Self as Subsystem>::Preproc as Preprocessor>::Frame>>,
73 ) -> Result<Self::Output, Self::Error> {
74 Ok(())
75 }
76}
77
78pub async fn frame_proc_loop<P: Preprocessor, F: AsyncFnMut(P::Frame) + Sync + Send + 'static>(
80 mut rx: watch::Receiver<Option<P::Frame>>,
81 mut func: F,
82) {
83 loop {
84 'inner: loop {
85 match rx.changed().await {
86 Ok(()) => match rx.borrow_and_update().clone() {
87 Some(frame) => {
88 futures_executor::block_on(async { func(frame).await });
89 }
90 None => {
91 warn!("waiting on first frame...");
92 }
93 },
94 Err(err) => {
95 error!("error waiting for new frame: {err:?}");
96 break 'inner;
97 }
98 }
99 }
100 tokio::task::yield_now().await;
101 }
102}