fmi-rs 0.3.0

Functional Mock-up Interface (FMI) for Rust
#![allow(non_snake_case)]

use crate::{
    fmi3::{
        self, FMU3, Implementation,
        log::DefaultLogger,
        native::{NativeLibrary, PLATFORM_TUPLE},
    },
    platform_binary_path,
    sim::SimulationError,
    zip::extract_zip_archive,
};
use std::{
    path::{Path, PathBuf},
    sync::Arc,
};
use tempfile::TempDir;

pub struct FMU3Builder {
    pub unzipdir: TempDir,
    pub model_description: crate::model_description::fmi3::ModelDescription,
    pub visible: bool,
    pub loggingOn: bool,
    pub logFile: Option<PathBuf>,
    pub logCalls: bool,
    pub printMessages: bool,
    pub eventModeUsed: bool,
    pub earlyReturnAllowed: bool,
    pub requiredIntermediateVariables: Vec<u32>,
}

impl FMU3Builder {
    pub fn new<P: AsRef<Path>>(fmu_path: &P) -> Result<Self, SimulationError> {
        let unzipdir = TempDir::new().map_err(SimulationError::io(fmu_path.as_ref()))?;

        extract_zip_archive(fmu_path, &unzipdir)?;

        let model_description = crate::model_description::fmi3::ModelDescription::from_path(
            &unzipdir.path().join("modelDescription.xml"),
        )?;

        Ok(Self {
            unzipdir,
            model_description,
            visible: false,
            loggingOn: false,
            logFile: None,
            logCalls: false,
            printMessages: true,
            eventModeUsed: true,
            earlyReturnAllowed: true,
            requiredIntermediateVariables: vec![],
        })
    }

    pub fn visible(mut self, visible: bool) -> Self {
        self.visible = visible;
        self
    }

    pub fn loggingOn(mut self, loggingOn: bool) -> Self {
        self.loggingOn = loggingOn;
        self
    }

    pub fn logCalls(mut self, logCalls: bool) -> Self {
        self.logCalls = logCalls;
        self
    }

    pub fn printMessages(mut self, printMessages: bool) -> Self {
        self.printMessages = printMessages;
        self
    }

    pub fn instantiate_me(&self, instanceName: &str) -> Result<Arc<FMU3>, SimulationError> {
        if let Some(me) = &self.model_description.modelExchange {
            let logger = Arc::new(if let Some(log_file) = &self.logFile {
                DefaultLogger::from_path(log_file).map_err(SimulationError::io(&log_file))?
            } else {
                DefaultLogger::default()
            });

            let file = platform_binary_path(&self.unzipdir, PLATFORM_TUPLE, &me.modelIdentifier);

            let implementation: Box<dyn Implementation> = Box::new(NativeLibrary::load(file)?);

            let resource_dir = self.unzipdir.path().join("resources");

            let resourcePath = if resource_dir.is_dir() {
                Some(resource_dir.as_path())
            } else {
                None
            };

            fmi3::FMU3::instantiateModelExchange(
                implementation,
                resourcePath,
                instanceName,
                &self.model_description.instantiationToken,
                self.visible,
                self.loggingOn,
                logger,
                self.logCalls,
            )
        } else {
            Err(SimulationError::InterfaceType)
        }
    }

    pub fn instantiate_cs(&self, instanceName: &str) -> Result<Arc<FMU3>, SimulationError> {
        if let Some(cs) = &self.model_description.coSimulation {
            let logger = Arc::new(if let Some(log_file) = &self.logFile {
                DefaultLogger::from_path(log_file).map_err(SimulationError::io(&log_file))?
            } else {
                DefaultLogger::default()
            });

            let file = platform_binary_path(&self.unzipdir, PLATFORM_TUPLE, &cs.modelIdentifier);

            let implementation: Box<dyn Implementation> = Box::new(NativeLibrary::load(file)?);

            let resource_dir = self.unzipdir.path().join("resources");

            let resourcePath = if resource_dir.is_dir() {
                Some(resource_dir.as_path())
            } else {
                None
            };

            FMU3::instantiateCoSimulation(
                implementation,
                resourcePath,
                instanceName,
                &self.model_description.instantiationToken,
                self.visible,
                self.loggingOn,
                self.eventModeUsed,
                self.earlyReturnAllowed,
                logger,
                self.logCalls,
                None,
            )
        } else {
            Err(SimulationError::InterfaceType)
        }
    }
}