// Platform detection #[cfg(target_os = "linux")] pub const PLATFORM_SUPPORTS_GPIO: bool = true; #[cfg(not(target_os = "linux"))] pub const PLATFORM_SUPPORTS_GPIO: bool = false; mod camera; mod config; mod detection; mod gps; mod hooks; mod overlay; mod sensors; mod storage; mod streaming; mod communication; mod monitoring; mod utils; use anyhow::{Context, Result}; use log::{info, error, warn}; use std::path::PathBuf; use std::sync::{Arc,Mutex as StdMutex}; use gstreamer_rtsp_server::prelude::SettingsExt; use tokio::sync::{Mutex, MutexGuard}; use tokio::signal; use futures::future::join_all; pub use config::Config; use crate::overlay::Watermark; /// Main entry point for the meteor detection system #[tokio::main] async fn main() -> Result<()> { // Create a logger builder with default settings let mut builder = env_logger::Builder::from_env( env_logger::Env::default().filter_or("RUST_LOG", "info") ); // Load configuration let config = config::load_config() .context("Failed to load configuration")?; // Update the logger with configured log level std::env::set_var("RUST_LOG", &config.log_level); builder.parse_env(env_logger::Env::default()); builder.init(); info!("Meteor detection system starting up"); // Check if we're running on a platform that supports GPIO if PLATFORM_SUPPORTS_GPIO { info!("Running on a Linux platform with GPIO support"); } else { info!("Running on a platform without GPIO support (macOS/Windows/etc). Using simulated sensors."); } info!("Loaded configuration with device ID: {}", config.device.id); // Initialize camera subsystem let camera_controller = camera::CameraController::new(&config) .await .context("Failed to initialize camera")?; let camera_controller = Arc::new(Mutex::new(camera_controller)); // Initialize GPS module let gps_controller = gps::GpsController::new(&config) .await .context("Failed to initialize GPS")?; let gps_controller = Arc::new(Mutex::new(gps_controller)); // Initialize sensor controller let sensor_controller = sensors::SensorController::new(&config) .await .context("Failed to initialize sensors")?; let sensor_controller = Arc::new(Mutex::new(sensor_controller)); // Initialize watermark overlay let watermark = { let gps_status = gps_controller.lock().await.get_status(); let env_data = sensor_controller.lock().await.get_current_data(); overlay::watermark::Watermark::new( config.watermark.clone(), Arc::new(StdMutex::new(env_data)), Arc::new(StdMutex::new(gps_status)), ) }; let watermark = Arc::new(Mutex::new(watermark)); // Initialize frame hook manager let hook_manager = hooks::HookManager::new(); let hook_manager = Arc::new(Mutex::new(hook_manager)); // Initialize RTSP streaming server let rtsp_server = streaming::RtspServer::new(config.rtsp.clone()); let rtsp_server = Arc::new(Mutex::new(rtsp_server)); // Initialize detection pipeline let detection_pipeline = detection::DetectionPipeline::new( camera_controller.clone(), &config.clone(), config.detection.pipeline.clone() ).context("Failed to initialize detection pipeline")?; // Initialize storage system let storage_manager = storage::StorageManager::new(&(config.clone())) .await .context("Failed to initialize storage")?; // Initialize communication module let mut comms = communication::CommunicationManager::new( &config, camera_controller.clone(), gps_controller.clone(), ).await.context("Failed to initialize communication")?; // Initialize health monitoring let monitor = monitoring::SystemMonitor::new(&config) .await .context("Failed to initialize system monitor")?; // Start all subsystems info!("All subsystems initialized, starting main processing loop"); // Initialize sensors sensor_controller.lock().await.initialize().await .context("Failed to initialize sensors")?; sensor_controller.lock().await.start().await .context("Failed to start sensors")?; // Initialize GPS gps_controller.lock().await.initialize().await .context("Failed to initialize GPS")?; gps_controller.lock().await.start().await .context("Failed to start GPS")?; // Start RTSP server if enabled if config.rtsp.enabled { rtsp_server.lock().await.start().await .context("Failed to start RTSP server")?; info!("RTSP server started at {}", rtsp_server.lock().await.get_url()); } // Run the main event loop let mut tasks = Vec::new(); // Add watermark hook { let mut manager = hook_manager.lock().await; let watermark_clone = watermark.clone(); manager.register_hook(Box::new(hooks::BasicFrameHook::new( "watermark", "Watermark Overlay", "Adds timestamp, GPS, and sensor data overlay to frames", config.watermark.enabled, move |frame, timestamp| { // Using block_in_place to properly handle async operations in sync context tokio::task::block_in_place(|| { let mut guard = futures::executor::block_on(watermark_clone.lock()); guard.apply(frame, timestamp) }) }, ))); } // Spawn detection pipeline task tasks.push(tokio::spawn(async move { if let Err(e) = detection_pipeline.run().await { error!("Detection pipeline error: {}", e); } })); // Spawn communication manager task tasks.push(tokio::spawn(async move { if let Err(e) = comms.run().await { error!("Communication manager error: {}", e); } })); // Spawn system monitor task tasks.push(tokio::spawn(async move { if let Err(e) = monitor.run().await { error!("System monitor error: {}", e); } })); // Add RTSP streaming task with proper loop to keep it alive let rtsp_config_enabled = config.rtsp.enabled; tasks.push(tokio::spawn(async move { if rtsp_config_enabled { info!("Starting RTSP streaming task"); // Implement a proper continuous loop to keep the task alive loop { // This would normally feed frames to the RTSP server // For now, just sleep to keep the task alive tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; // Add some actual implementation here later } } })); // Wait for the Ctrl+C signal info!("Press Ctrl+C to stop the application"); match signal::ctrl_c().await { Ok(()) => { info!("Shutdown signal received, preparing to exit"); // Here you would add cleanup code } Err(err) => { error!("Error waiting for Ctrl+C: {}", err); } } // Now that we've received a shutdown signal, cancel all tasks for task in tasks { task.abort(); } info!("Meteor detection system shutting down"); Ok(()) }