use crate::config;
use crate::error::FpgadError;
use crate::platforms::platform::{Fpga, OverlayHandler, Platform, list_fpga_managers};
use crate::platforms::universal_components::universal_fpga::UniversalFPGA;
use crate::platforms::universal_components::universal_overlay_handler::UniversalOverlayHandler;
use crate::system_io::fs_read_dir;
use fpgad_macros::platform;
use log::trace;
use std::sync::OnceLock;
#[platform(compat_string = "universal")]
#[derive(Debug)]
pub struct UniversalPlatform {
fpga: OnceLock<UniversalFPGA>,
overlay_handler: OnceLock<UniversalOverlayHandler>,
}
impl Default for UniversalPlatform {
fn default() -> Self {
Self::new()
}
}
impl UniversalPlatform {
pub fn new() -> Self {
trace!("creating new universal_platform");
UniversalPlatform {
fpga: OnceLock::new(),
overlay_handler: OnceLock::new(),
}
}
}
impl Platform for UniversalPlatform {
fn fpga(&self, device_handle: &str) -> Result<&dyn Fpga, FpgadError> {
Ok(self.fpga.get_or_init(|| UniversalFPGA::new(device_handle)))
}
fn overlay_handler(&self, overlay_handle: &str) -> Result<&dyn OverlayHandler, FpgadError> {
if overlay_handle.is_empty() {
return Err(FpgadError::Argument(
"An overlay handle is required. Provided overlay handle is empty.".into(),
));
}
let handler = self
.overlay_handler
.get_or_init(|| UniversalOverlayHandler::new(overlay_handle));
let parent_path = handler.overlay_fs_path()?.parent().ok_or_else(|| {
FpgadError::Argument(format!(
"The path {:?} has no parent directory.",
handler.overlay_fs_path()
))
})?;
if !parent_path.exists() {
return Err(FpgadError::Argument(format!(
"The overlayfs path {parent_path:?} doesn't seem to exist."
)));
}
Ok(handler)
}
fn status_message(&self) -> Result<String, FpgadError> {
let mut ret_string = String::from(
"---- DEVICES ----\n\
| dev | platform | state |\n",
);
for device in list_fpga_managers()? {
let state = self.fpga(&device)?.state()?;
ret_string += format!(
"| {} | {} | {} |\n",
device,
self.platform_compat_string(),
state
)
.as_str();
}
ret_string += "\n---- OVERLAYS ----\n\
| overlay | status |\n";
for overlay in fs_read_dir(config::OVERLAY_CONTROL_DIR.as_ref())? {
let status = self.overlay_handler(&overlay)?.status()?;
ret_string.push_str(format!("| {overlay} | {status} |\n").as_ref());
}
Ok(ret_string)
}
fn platform_compat_string(&self) -> String {
"universal".into()
}
}