1use crate::{
8 args::Args,
9 fpga::{InterruptHandler, IpCore},
10 httpd::{self, RecorderFinishWaiter, RecorderState},
11 iio::Ad9361,
12 spectrometer::{Spectrometer, SpectrometerConfig},
13};
14use anyhow::Result;
15use std::sync::{Arc, Mutex};
16use tokio::sync::broadcast;
17
18#[derive(Debug)]
23pub struct App {
24 httpd: httpd::Server,
25 interrupt_handler: InterruptHandler,
26 recorder_finish: RecorderFinishWaiter,
27 spectrometer: Spectrometer,
28}
29
30impl App {
31 #[tracing::instrument(name = "App::new", level = "debug")]
33 pub async fn new(args: &Args) -> Result<App> {
34 let (ip_core, interrupt_handler) = IpCore::take().await?;
36 let ip_core = std::sync::Mutex::new(ip_core);
37 let ad9361 = tokio::sync::Mutex::new(Ad9361::new().await?);
38 let recorder = RecorderState::new(&ad9361, &ip_core).await?;
39 let state = AppState(Arc::new(State {
40 ad9361,
41 ip_core,
42 geolocation: std::sync::Mutex::new(None),
43 recorder,
44 spectrometer_config: Default::default(),
45 }));
46 state.spectrometer_config().set_samp_rate_mode(
48 state.ad9361().lock().await.get_sampling_frequency().await? as f32,
49 state.ip_core().lock().unwrap().spectrometer_mode(),
50 );
51
52 let (waterfall_sender, _) = broadcast::channel(16);
55 let spectrometer = Spectrometer::new(
56 state.clone(),
57 interrupt_handler.waiter_spectrometer(),
58 waterfall_sender.clone(),
59 );
60
61 let recorder_finish =
62 RecorderFinishWaiter::new(state.clone(), interrupt_handler.waiter_recorder());
63
64 let httpd = httpd::Server::new(
65 args.listen,
66 args.listen_https,
67 args.ssl_cert.as_ref(),
68 args.ssl_key.as_ref(),
69 args.ca_cert.as_ref(),
70 state,
71 waterfall_sender,
72 )
73 .await?;
74
75 Ok(App {
76 httpd,
77 interrupt_handler,
78 recorder_finish,
79 spectrometer,
80 })
81 }
82
83 #[tracing::instrument(name = "App::run", level = "debug", skip_all)]
87 pub async fn run(self) -> Result<()> {
88 tokio::select! {
89 ret = self.httpd.run() => ret,
90 ret = self.interrupt_handler.run() => ret,
91 ret = self.recorder_finish.run() => ret,
92 ret = self.spectrometer.run() => ret,
93 }
94 }
95}
96
97#[derive(Debug, Clone)]
104pub struct AppState(Arc<State>);
105
106#[derive(Debug)]
107struct State {
108 ad9361: tokio::sync::Mutex<Ad9361>,
109 ip_core: Mutex<IpCore>,
110 geolocation: Mutex<Option<maia_json::Geolocation>>,
111 recorder: RecorderState,
112 spectrometer_config: SpectrometerConfig,
113}
114
115impl AppState {
116 pub fn ad9361(&self) -> &tokio::sync::Mutex<Ad9361> {
118 &self.0.ad9361
119 }
120
121 pub fn ip_core(&self) -> &Mutex<IpCore> {
123 &self.0.ip_core
124 }
125
126 pub fn geolocation(&self) -> &Mutex<Option<maia_json::Geolocation>> {
131 &self.0.geolocation
132 }
133
134 pub fn recorder(&self) -> &RecorderState {
136 &self.0.recorder
137 }
138
139 pub fn spectrometer_config(&self) -> &SpectrometerConfig {
141 &self.0.spectrometer_config
142 }
143
144 pub async fn ad9361_samp_rate(&self) -> Result<f64> {
146 Ok(self.ad9361().lock().await.get_sampling_frequency().await? as f64)
147 }
148}