use std::{ sync::Arc, time::{Duration, SystemTime}, }; use ddc_hi::Display; use paris::{error, info, warn}; use tokio::{sync::{watch, OnceCell, RwLock}, task::yield_now}; use crate::rpc::{BoardMessageChannels, DisplaySetting}; use super::{display_handler::DisplayHandler, display_state::DisplayState}; pub struct DisplayManager { displays: Arc<RwLock<Vec<Arc<RwLock<DisplayHandler>>>>>, setting_request_handler: Option<tokio::task::JoinHandle<()>>, displays_changed_sender: Arc<watch::Sender<Vec<DisplayState>>>, } impl DisplayManager { pub async fn global() -> &'static Self { static DISPLAY_MANAGER: OnceCell<DisplayManager> = OnceCell::const_new(); DISPLAY_MANAGER.get_or_init(|| Self::create()).await } pub async fn create() -> Self { let (displays_changed_sender, _) = watch::channel(Vec::new()); let displays_changed_sender = Arc::new(displays_changed_sender); let mut instance = Self { displays: Arc::new(RwLock::new(Vec::new())), setting_request_handler: None, displays_changed_sender, }; instance.fetch_displays().await; instance.subscribe_setting_request(); instance } async fn fetch_displays(&self) { let mut displays = self.displays.write().await; displays.clear(); let controllers = Display::enumerate(); for display in controllers { let controller = Arc::new(RwLock::new(display)); let state = Arc::new(RwLock::new(DisplayState::default())); let handler = DisplayHandler { state: state.clone(), controller: controller.clone(), }; handler.fetch_state().await; displays.push(Arc::new(RwLock::new(handler))); } } pub async fn get_displays(&self) -> Vec<DisplayState> { let displays = self.displays.read().await; let mut states = Vec::new(); for display in displays.iter() { let state = display.read().await.state.read().await.clone(); states.push(state); } states } fn subscribe_setting_request(&mut self) { let displays = self.displays.clone(); let displays_changed_sender = self.displays_changed_sender.clone(); log::info!("start display setting request handler"); let handler = tokio::spawn(async move { let channels = BoardMessageChannels::global().await; let mut request_rx = channels.display_setting_request_sender.subscribe(); log::info!("display setting request handler started"); while let Ok(message) = request_rx.recv().await { let displays = displays.write().await; let display = displays.get(message.display_index); if display.is_none() { warn!("display#{} not found", message.display_index); continue; } log::info!("display setting request received. {:?}", message); let display = display.unwrap().write().await; match message.setting { DisplaySetting::Brightness(value) => display.set_brightness(value as u16).await, DisplaySetting::Contrast(value) => display.set_contrast(value as u16).await, DisplaySetting::Mode(value) => display.set_mode(value as u16).await, } drop(display); log::info!("display setting request handled. {:?}", message); let mut states = Vec::new(); for display in displays.iter() { let state = display.read().await.state.read().await.clone(); states.push(state); } if let Err(err) = displays_changed_sender.send(states) { error!("failed to send displays changed event: {}", err); } yield_now().await; } }); self.setting_request_handler = Some(handler); } pub fn subscribe_displays_changed(&self) -> watch::Receiver<Vec<DisplayState>> { self.displays_changed_sender.subscribe() } // fn read_display_config_by_ddc(index: usize) -> anyhow::Result<DisplayState> { // let mut displays = Display::enumerate(); // match displays.get_mut(index) { // Some(display) => { // let mut config = DisplayState::default(index); // match display.handle.get_vcp_feature(0x10) { // Ok(value) => { // config.max_brightness = value.maximum(); // config.min_brightness = 0; // config.brightness = value.value(); // } // Err(_) => {} // }; // match display.handle.get_vcp_feature(0x12) { // Ok(value) => { // config.max_contrast = value.maximum(); // config.min_contrast = 0; // config.contrast = value.value(); // } // Err(_) => {} // }; // match display.handle.get_vcp_feature(0xdc) { // Ok(value) => { // config.max_mode = value.maximum(); // config.min_mode = 0; // config.mode = value.value(); // } // Err(_) => {} // }; // Ok(config) // } // None => anyhow::bail!("display#{} is missed.", index), // } // } // async fn get_display(&self, index: usize) -> anyhow::Result<OwnedMutexGuard<DisplayState>> { // let mut displays = self.displays.lock().await; // match displays.get_mut(&index) { // Some(config) => { // let mut config = config.to_owned().lock_owned().await; // if config.last_modified_at > SystemTime::now().sub(Duration::from_secs(10)) { // info!("cached"); // return Ok(config); // } // return match Self::read_display_config_by_ddc(index) { // Ok(config) => { // let id = config.id; // let value = Arc::new(Mutex::new(config)); // let valueGuard = value.clone().lock_owned().await; // displays.insert(id, value); // info!("read form ddc"); // Ok(valueGuard) // } // Err(err) => { // warn!( // "can not read config from display by ddc, use CACHED value. {:?}", // err // ); // config.last_modified_at = SystemTime::now(); // Ok(config) // } // }; // } // None => { // let config = Self::read_display_config_by_ddc(index).map_err(|err| { // anyhow::anyhow!( // "can not read config from display by ddc,use DEFAULT value. {:?}", // err // ) // })?; // let id = config.id; // let value = Arc::new(Mutex::new(config)); // let valueGuard = value.clone().lock_owned().await; // displays.insert(id, value); // Ok(valueGuard) // } // } // } // pub async fn set_display_brightness( // &self, // display_brightness: DisplayBrightness, // ) -> anyhow::Result<()> { // match Display::enumerate().get_mut(display_brightness.display_index) { // Some(display) => { // match self.get_display(display_brightness.display_index).await { // Ok(mut config) => { // let curr = config.brightness; // info!("curr_brightness: {:?}", curr); // let mut target = match display_brightness.brightness { // Brightness::Relative(v) => curr.wrapping_add_signed(v), // Brightness::Absolute(v) => v, // }; // if target.gt(&config.max_brightness) { // target = config.max_brightness; // } else if target.lt(&config.min_brightness) { // target = config.min_brightness; // } // config.brightness = target; // display // .handle // .set_vcp_feature(0x10, target as u16) // .map_err(|err| anyhow::anyhow!("can not set brightness. {:?}", err))?; // let rpc = rpc::Manager::global().await; // rpc.publish_desktop_cmd( // format!("display{}/brightness", display_brightness.display_index) // .as_str(), // target.to_be_bytes().to_vec(), // ) // .await; // } // Err(err) => { // info!( // "can not get display#{} brightness. {:?}", // display_brightness.display_index, err // ); // if let Brightness::Absolute(v) = display_brightness.brightness { // display.handle.set_vcp_feature(0x10, v).map_err(|err| { // anyhow::anyhow!("can not set brightness. {:?}", err) // })?; // }; // } // }; // } // None => { // warn!("display#{} is not found.", display_brightness.display_index); // } // } // Ok(()) // } } impl Drop for DisplayManager { fn drop(&mut self) { if let Some(handler) = self.setting_request_handler.take() { handler.abort(); } } }