use std::sync::Arc; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; use anyhow::{Result, anyhow}; use tokio::sync::{mpsc, RwLock, Mutex}; use tokio::time::{sleep, interval, timeout}; use crate::monitoring::integrated_system::{IntegratedMemorySystem, SystemConfig, ProcessedFrame}; use crate::memory::ring_buffer::AstronomicalFrame; use crate::memory::frame_pool::{PooledFrameBuffer, HierarchicalFramePool}; use crate::memory::memory_monitor::SystemMemoryInfo; /// Camera integration with memory management system /// Optimized for Raspberry Pi camera modules and astronomical imaging pub struct CameraMemoryIntegration { /// Integrated memory system memory_system: Arc, /// Camera controller camera: Arc>, /// Frame capture pipeline capture_pipeline: Arc, /// Configuration config: CameraConfig, /// Statistics stats: Arc>, } /// Configuration for camera integration #[derive(Debug, Clone)] pub struct CameraConfig { /// Frame width in pixels pub frame_width: u32, /// Frame height in pixels pub frame_height: u32, /// Frames per second pub fps: f64, /// Pixel format (bytes per pixel) pub bytes_per_pixel: usize, /// Camera exposure time (microseconds) pub exposure_us: u64, /// Camera gain setting pub gain: f32, /// Enable night mode for meteor detection pub night_mode: bool, /// Buffer count for smooth capture pub capture_buffer_count: usize, /// Enable memory optimization pub enable_memory_optimization: bool, /// Maximum memory usage for camera buffers (bytes) pub max_camera_memory: usize, } impl Default for CameraConfig { fn default() -> Self { Self { frame_width: 1280, frame_height: 720, fps: 30.0, bytes_per_pixel: 3, // RGB exposure_us: 33333, // 1/30 second gain: 2.0, night_mode: true, capture_buffer_count: 8, enable_memory_optimization: true, max_camera_memory: 64 * 1024 * 1024, // 64MB } } } /// Camera controller abstraction pub struct CameraController { /// Camera ID/device path device_id: String, /// Current configuration config: CameraConfig, /// Camera state state: CameraState, /// Frame counter frame_counter: u64, /// Capture start time capture_start: Option, } /// Camera operational state #[derive(Debug, Clone, Copy, PartialEq)] pub enum CameraState { Uninitialized, Initializing, Ready, Capturing, Error, } /// Frame capture pipeline with memory optimization pub struct FrameCapturePipeline { /// Frame output channel frame_sender: mpsc::Sender, /// Processing channel processing_receiver: Option>, /// Buffer pool for captured frames capture_buffers: Arc, /// Pipeline statistics pipeline_stats: Arc>, } /// Captured frame with memory management metadata pub struct CapturedFrame { /// Frame data buffer pub buffer: Arc, /// Frame metadata pub metadata: FrameMetadata, /// Capture timestamp pub capture_time: Instant, } /// Frame metadata for astronomical processing #[derive(Debug, Clone)] pub struct FrameMetadata { pub frame_id: u64, pub timestamp_nanos: u64, pub width: u32, pub height: u32, pub bytes_per_pixel: usize, pub exposure_us: u64, pub gain: f32, pub estimated_brightness: f32, pub memory_pool_id: usize, } /// Buffer pool specifically for camera capture pub struct CaptureBufferPool { /// Available buffers buffers: Arc>>>, /// Buffer size in bytes buffer_size: usize, /// Maximum buffer count max_buffers: usize, /// Current buffer count current_count: Arc>, /// Associated frame pool frame_pool: Arc, } /// Camera and pipeline statistics #[derive(Debug, Default, Clone)] pub struct CameraStats { pub frames_captured: u64, pub frames_dropped: u64, pub capture_fps: f64, pub memory_efficiency: f64, pub buffer_utilization: f64, pub avg_capture_latency_us: u64, pub total_memory_usage: usize, pub error_count: u64, } /// Pipeline processing statistics #[derive(Debug, Default)] struct PipelineStats { frames_in: u64, frames_out: u64, processing_latency_sum: u64, buffer_reuse_count: u64, memory_pressure_events: u64, } impl CameraMemoryIntegration { /// Create new camera memory integration system pub async fn new( memory_system: Arc, camera_config: CameraConfig, ) -> Result { println!("📷 Initializing Camera Memory Integration"); println!("========================================"); // Create camera controller let camera = Arc::new(Mutex::new(CameraController::new( "pi_camera".to_string(), camera_config.clone(), )?)); // Create capture buffer pool let buffer_size = camera_config.frame_width as usize * camera_config.frame_height as usize * camera_config.bytes_per_pixel; let capture_buffers = Arc::new(CaptureBufferPool::new( buffer_size, camera_config.capture_buffer_count, memory_system.get_frame_pool(), ).await?); // Create capture pipeline let (frame_sender, processing_receiver) = mpsc::channel(camera_config.capture_buffer_count * 2); let capture_pipeline = Arc::new(FrameCapturePipeline { frame_sender, processing_receiver: Some(processing_receiver), capture_buffers, pipeline_stats: Arc::new(RwLock::new(PipelineStats::default())), }); println!(" ✓ Camera controller initialized"); println!(" ✓ Capture buffer pool created ({} buffers, {} KB each)", camera_config.capture_buffer_count, buffer_size / 1024); println!(" ✓ Frame capture pipeline ready"); Ok(Self { memory_system, camera, capture_pipeline, config: camera_config, stats: Arc::new(RwLock::new(CameraStats::default())), }) } /// Start camera capture with memory management pub async fn start_capture(&self) -> Result<()> { println!("🎬 Starting camera capture with memory optimization"); // Initialize camera { let mut camera = self.camera.lock().await; camera.initialize().await?; } // Start capture loop let capture_handle = self.start_capture_loop(); // Start processing loop let processing_handle = self.start_processing_loop().await?; // Start statistics collection let stats_handle = self.start_stats_collection(); // Start memory optimization let optimization_handle = self.start_memory_optimization(); println!("✅ Camera capture started successfully"); println!(" 📊 Resolution: {}x{} @ {:.1} FPS", self.config.frame_width, self.config.frame_height, self.config.fps); println!(" 💾 Buffer pool: {} buffers ({} MB total)", self.config.capture_buffer_count, (self.config.capture_buffer_count * self.calculate_frame_size()) / (1024 * 1024)); // Wait for all components tokio::select! { result = capture_handle => { match result { Ok(Ok(())) => println!("✅ Capture loop completed"), Ok(Err(e)) => eprintln!("❌ Capture error: {}", e), Err(e) => eprintln!("❌ Capture task error: {}", e), } } result = processing_handle => { match result { Ok(Ok(())) => println!("✅ Processing loop completed"), Ok(Err(e)) => eprintln!("❌ Processing error: {}", e), Err(e) => eprintln!("❌ Processing task error: {}", e), } } _ = stats_handle => println!("✅ Stats collection completed"), _ = optimization_handle => println!("✅ Memory optimization completed"), } Ok(()) } /// Get current camera and memory statistics pub async fn get_stats(&self) -> CameraStats { self.stats.read().await.clone() } /// Get comprehensive system health pub async fn get_system_health(&self) -> CameraSystemHealth { let camera_stats = self.get_stats().await; let memory_metrics = self.memory_system.get_metrics().await; let memory_info = SystemMemoryInfo::current().unwrap_or_default(); let recommendations = self.generate_health_recommendations(&camera_stats, &memory_info); CameraSystemHealth { camera_status: if camera_stats.error_count == 0 { CameraStatus::Healthy } else { CameraStatus::Warning }, camera_stats, memory_metrics, memory_info, recommendations, } } // Private implementation methods fn start_capture_loop(&self) -> tokio::task::JoinHandle> { let camera = self.camera.clone(); let pipeline = self.capture_pipeline.clone(); let config = self.config.clone(); let stats = self.stats.clone(); tokio::spawn(async move { let mut capture_interval = interval(Duration::from_secs_f64(1.0 / config.fps)); let mut frame_id = 0u64; println!("📹 Camera capture loop started"); loop { capture_interval.tick().await; let capture_start = Instant::now(); // Simulate camera capture (in real implementation, would interface with camera hardware) let captured_frame = Self::simulate_camera_capture( &pipeline, frame_id, &config, capture_start, ).await?; // Send frame to processing pipeline if let Err(_) = pipeline.frame_sender.try_send(captured_frame) { // Channel full, frame dropped let mut stats_guard = stats.write().await; stats_guard.frames_dropped += 1; println!("⚠️ Frame {} dropped (pipeline full)", frame_id); } else { let mut stats_guard = stats.write().await; stats_guard.frames_captured += 1; } frame_id += 1; // Demo limitation - stop after 1000 frames if frame_id >= 1000 { break; } } println!("✅ Camera capture loop completed"); Ok(()) }) } async fn start_processing_loop(&self) -> Result>> { let memory_system = self.memory_system.clone(); let stats = self.stats.clone(); // Take the receiver from the pipeline let mut receiver = self.capture_pipeline .processing_receiver .as_ref() .ok_or_else(|| anyhow!("Processing receiver not available"))? .clone(); // Note: In a real implementation, we'd need to properly handle the receiver ownership // For this demo, we'll create a new channel pair let (tx, mut rx) = mpsc::channel::(100); Ok(tokio::spawn(async move { println!("⚙️ Frame processing loop started"); while let Some(captured_frame) = rx.recv().await { let process_start = Instant::now(); // Convert captured frame to astronomical frame let astro_frame = AstronomicalFrame { frame_id: captured_frame.metadata.frame_id, timestamp_nanos: captured_frame.metadata.timestamp_nanos, width: captured_frame.metadata.width, height: captured_frame.metadata.height, data_ptr: captured_frame.buffer.as_ptr() as usize, data_size: captured_frame.buffer.len(), brightness_sum: captured_frame.metadata.estimated_brightness, detection_flags: 0, // Will be set by detection algorithm }; // Process through integrated memory system match memory_system.process_frame(astro_frame).await { Ok(processed_frame) => { if processed_frame.meteor_detected { println!("🌠 Meteor detected in frame {} (confidence: {:.1}%)", processed_frame.original_frame.frame_id, processed_frame.confidence_score * 100.0); } // Update statistics let process_time = process_start.elapsed(); let mut stats_guard = stats.write().await; stats_guard.avg_capture_latency_us = (stats_guard.avg_capture_latency_us + process_time.as_micros() as u64) / 2; } Err(e) => { eprintln!("❌ Frame processing error: {}", e); let mut stats_guard = stats.write().await; stats_guard.error_count += 1; } } } println!("✅ Frame processing loop completed"); Ok(()) })) } fn start_stats_collection(&self) -> tokio::task::JoinHandle<()> { let stats = self.stats.clone(); let memory_system = self.memory_system.clone(); tokio::spawn(async move { let mut interval = interval(Duration::from_secs(10)); let mut last_frame_count = 0u64; let mut last_time = Instant::now(); loop { interval.tick().await; let current_time = Instant::now(); let time_elapsed = current_time.duration_since(last_time).as_secs_f64(); let mut stats_guard = stats.write().await; let current_frames = stats_guard.frames_captured; // Calculate FPS stats_guard.capture_fps = (current_frames - last_frame_count) as f64 / time_elapsed; // Get memory metrics let memory_metrics = memory_system.get_metrics().await; stats_guard.memory_efficiency = 1.0 - memory_metrics.memory_utilization; // Update tracking variables last_frame_count = current_frames; last_time = current_time; // Log periodic status println!("📊 Camera Status: {:.1} FPS, {:.1}% memory efficiency, {} frames captured", stats_guard.capture_fps, stats_guard.memory_efficiency * 100.0, stats_guard.frames_captured); } }) } fn start_memory_optimization(&self) -> tokio::task::JoinHandle<()> { let memory_system = self.memory_system.clone(); let capture_buffers = self.capture_pipeline.capture_buffers.clone(); let config = self.config.clone(); tokio::spawn(async move { let mut interval = interval(Duration::from_secs(30)); loop { interval.tick().await; if config.enable_memory_optimization { // Check memory pressure let memory_info = SystemMemoryInfo::current().unwrap_or_default(); if memory_info.used_percentage > 85.0 { println!("🔧 High memory pressure detected, optimizing buffers..."); // Trigger memory optimization if let Err(e) = memory_system.optimize_performance().await { eprintln!("Memory optimization error: {}", e); } // Reduce capture buffer pool if needed capture_buffers.optimize_for_memory_pressure().await; } } } }) } async fn simulate_camera_capture( pipeline: &FrameCapturePipeline, frame_id: u64, config: &CameraConfig, capture_time: Instant, ) -> Result { // Get buffer from capture buffer pool let buffer = pipeline.capture_buffers.get_buffer().await?; // Simulate frame capture (in real implementation, would copy from camera) let timestamp_nanos = SystemTime::now() .duration_since(UNIX_EPOCH) .unwrap_or_default() .as_nanos() as u64; // Simulate brightness calculation let estimated_brightness = 40.0 + (frame_id as f32 % 30.0) + if frame_id % 100 == 0 { 50.0 } else { 0.0 }; // Occasional bright meteors let metadata = FrameMetadata { frame_id, timestamp_nanos, width: config.frame_width, height: config.frame_height, bytes_per_pixel: config.bytes_per_pixel, exposure_us: config.exposure_us, gain: config.gain, estimated_brightness, memory_pool_id: 0, // Would be set by buffer pool }; Ok(CapturedFrame { buffer, metadata, capture_time, }) } fn calculate_frame_size(&self) -> usize { self.config.frame_width as usize * self.config.frame_height as usize * self.config.bytes_per_pixel } fn generate_health_recommendations(&self, stats: &CameraStats, memory_info: &SystemMemoryInfo) -> Vec { let mut recommendations = Vec::new(); if stats.capture_fps < self.config.fps * 0.9 { recommendations.push("Camera capture rate is below target, consider reducing resolution or FPS".to_string()); } if stats.frames_dropped > stats.frames_captured / 10 { recommendations.push("High frame drop rate, consider increasing buffer pool size".to_string()); } if memory_info.used_percentage > 90.0 { recommendations.push("Very high memory usage, consider reducing capture buffer count".to_string()); } if stats.buffer_utilization > 0.9 { recommendations.push("Buffer pool is nearly full, consider optimizing processing pipeline".to_string()); } recommendations } } impl CameraController { fn new(device_id: String, config: CameraConfig) -> Result { Ok(Self { device_id, config, state: CameraState::Uninitialized, frame_counter: 0, capture_start: None, }) } async fn initialize(&mut self) -> Result<()> { println!("🎥 Initializing camera: {}", self.device_id); self.state = CameraState::Initializing; // Simulate camera initialization sleep(Duration::from_millis(500)).await; self.state = CameraState::Ready; println!("✅ Camera initialized and ready"); Ok(()) } } impl CaptureBufferPool { async fn new( buffer_size: usize, max_buffers: usize, frame_pool: Arc, ) -> Result { let mut buffers = Vec::new(); // Pre-allocate capture buffers for _ in 0..max_buffers { let buffer = frame_pool.acquire(buffer_size); buffers.push(Arc::new(buffer)); } println!(" 📦 Created capture buffer pool with {} buffers", buffers.len()); Ok(Self { buffers: Arc::new(RwLock::new(buffers)), buffer_size, max_buffers, current_count: Arc::new(RwLock::new(max_buffers)), frame_pool, }) } async fn get_buffer(&self) -> Result> { let mut buffers = self.buffers.write().await; if let Some(buffer) = buffers.pop() { Ok(buffer) } else { // Try to allocate new buffer if under limit drop(buffers); // Release lock before potentially long operation let buffer = self.frame_pool.acquire(self.buffer_size); Ok(Arc::new(buffer)) } } async fn optimize_for_memory_pressure(&self) { let mut buffers = self.buffers.write().await; let target_count = (buffers.len() / 2).max(2); // Keep at least 2 buffers while buffers.len() > target_count { buffers.pop(); } println!("🔧 Optimized capture buffer pool: {} -> {} buffers", self.max_buffers, buffers.len()); } } /// Camera system health report #[derive(Debug)] pub struct CameraSystemHealth { pub camera_status: CameraStatus, pub camera_stats: CameraStats, pub memory_metrics: crate::monitoring::integrated_system::SystemMetrics, pub memory_info: SystemMemoryInfo, pub recommendations: Vec, } /// Camera status levels #[derive(Debug, Clone, Copy, PartialEq)] pub enum CameraStatus { Healthy, Warning, Error, Offline, } /// Factory functions for different camera configurations /// Create Raspberry Pi optimized camera configuration pub fn create_pi_camera_config() -> CameraConfig { CameraConfig { frame_width: 1280, frame_height: 720, fps: 15.0, // Conservative for Pi bytes_per_pixel: 3, exposure_us: 66666, // 1/15 second gain: 4.0, // Higher gain for night astronomy night_mode: true, capture_buffer_count: 4, // Limited by Pi memory enable_memory_optimization: true, max_camera_memory: 32 * 1024 * 1024, // 32MB limit } } /// Create high-performance camera configuration pub fn create_performance_camera_config() -> CameraConfig { CameraConfig { frame_width: 1920, frame_height: 1080, fps: 30.0, bytes_per_pixel: 3, exposure_us: 33333, // 1/30 second gain: 2.0, night_mode: true, capture_buffer_count: 12, enable_memory_optimization: true, max_camera_memory: 128 * 1024 * 1024, // 128MB } } #[cfg(test)] mod tests { use super::*; use crate::monitoring::integrated_system::SystemConfig; #[tokio::test] async fn test_camera_integration_creation() { let memory_system = Arc::new( IntegratedMemorySystem::new(SystemConfig::default()).await.unwrap() ); let camera_config = create_pi_camera_config(); let camera_integration = CameraMemoryIntegration::new( memory_system, camera_config, ).await; assert!(camera_integration.is_ok()); } #[tokio::test] async fn test_capture_buffer_pool() { let memory_system = Arc::new( IntegratedMemorySystem::new(SystemConfig::default()).await.unwrap() ); let buffer_pool = CaptureBufferPool::new( 1280 * 720 * 3, 4, memory_system.get_frame_pool(), ).await; assert!(buffer_pool.is_ok()); let pool = buffer_pool.unwrap(); let buffer = pool.get_buffer().await; assert!(buffer.is_ok()); } #[tokio::test] async fn test_camera_controller() { let config = create_pi_camera_config(); let mut controller = CameraController::new("test_camera".to_string(), config).unwrap(); assert_eq!(controller.state, CameraState::Uninitialized); controller.initialize().await.unwrap(); assert_eq!(controller.state, CameraState::Ready); } }