use std::ffi::CString;
use super::{CallbackFunctions, Instance, binding, traits::ModelExchange};
use crate::{
Error, EventFlags, ME,
fmi2::{Fmi2Error, Fmi2Res, Fmi2Status, import},
traits::{FmiEventHandler, FmiImport, FmiModelExchange, FmiStatus},
};
impl Instance<ME> {
pub fn new(
import: &import::Fmi2Import,
instance_name: &str,
visible: bool,
logging_on: bool,
) -> Result<Self, Error> {
let schema = import.model_description();
let model_exchange = schema
.model_exchange
.as_ref()
.ok_or(Error::UnsupportedFmuType("ModelExchange".to_owned()))?;
let binding = import.binding(&model_exchange.model_identifier)?;
let callbacks = Box::<CallbackFunctions>::default();
let name = instance_name.to_owned();
let instance_name = CString::new(instance_name).expect("Error building CString");
let guid = CString::new(schema.guid.as_bytes()).expect("Error building CString");
let resource_url =
CString::new(import.canonical_resource_path_string()).expect("Invalid resource path");
let component = unsafe {
let callback_functions = &*callbacks as *const CallbackFunctions;
binding.fmi2Instantiate(
instance_name.as_ptr(),
binding::fmi2Type_fmi2ModelExchange,
guid.as_ptr(), resource_url.as_ptr(), callback_functions as _, visible as binding::fmi2Boolean, logging_on as binding::fmi2Boolean, )
};
if component.is_null() {
return Err(Error::Instantiation);
}
log::trace!("Created FMI2.0 ME component {component:?}");
Ok(Self {
binding,
component,
callbacks,
name,
saved_states: Vec::new(),
_tag: std::marker::PhantomData,
})
}
}
impl ModelExchange for Instance<ME> {
fn enter_continuous_time_mode(&mut self) -> Result<Fmi2Res, Fmi2Error> {
Fmi2Status::from(unsafe { self.binding.fmi2EnterContinuousTimeMode(self.component) }).ok()
}
fn enter_event_mode(&mut self) -> Result<Fmi2Res, Fmi2Error> {
Fmi2Status::from(unsafe { self.binding.fmi2EnterEventMode(self.component) }).ok()
}
fn new_discrete_states(&mut self, event_flags: &mut EventFlags) -> Result<Fmi2Res, Fmi2Error> {
let mut event_info = binding::fmi2EventInfo::default();
let result = Fmi2Status::from(unsafe {
self.binding
.fmi2NewDiscreteStates(self.component, &mut event_info)
})
.ok()?;
event_flags.update_from_fmi2_event_info(event_info);
Ok(result)
}
fn completed_integrator_step(
&mut self,
no_set_fmu_state_prior: bool,
enter_event_mode: &mut bool,
terminate_simulation: &mut bool,
) -> Result<Fmi2Res, Fmi2Error> {
let mut _enter_event_mode = 0;
let mut _terminate_simulation = 0;
let result = Fmi2Status::from(unsafe {
self.binding.fmi2CompletedIntegratorStep(
self.component,
no_set_fmu_state_prior as _,
&mut _enter_event_mode,
&mut _terminate_simulation,
)
})
.ok();
*enter_event_mode = _enter_event_mode != 0;
*terminate_simulation = _terminate_simulation != 0;
result
}
fn set_time(&mut self, time: f64) -> Result<Fmi2Res, Fmi2Error> {
Fmi2Status::from(unsafe { self.binding.fmi2SetTime(self.component, time) }).ok()
}
fn get_continuous_states(
&mut self,
continuous_states: &mut [f64],
) -> Result<Fmi2Res, Fmi2Error> {
Fmi2Status::from(unsafe {
self.binding.fmi2GetContinuousStates(
self.component,
continuous_states.as_mut_ptr(),
continuous_states.len(),
)
})
.ok()
}
fn set_continuous_states(&mut self, states: &[f64]) -> Result<Fmi2Res, Fmi2Error> {
Fmi2Status::from(unsafe {
self.binding
.fmi2SetContinuousStates(self.component, states.as_ptr(), states.len())
})
.ok()
}
fn get_derivatives(&mut self, derivatives: &mut [f64]) -> Result<Fmi2Res, Fmi2Error> {
Fmi2Status::from(unsafe {
self.binding.fmi2GetDerivatives(
self.component,
derivatives.as_mut_ptr(),
derivatives.len(),
)
})
.ok()
}
fn get_nominals_of_continuous_states(
&mut self,
nominals: &mut [f64],
) -> Result<Fmi2Res, Fmi2Error> {
Fmi2Status::from(unsafe {
self.binding.fmi2GetNominalsOfContinuousStates(
self.component,
nominals.as_mut_ptr(),
nominals.len(),
)
})
.ok()
}
fn get_event_indicators(&mut self, event_indicators: &mut [f64]) -> Result<bool, Fmi2Error> {
let status = unsafe {
self.binding.fmi2GetEventIndicators(
self.component,
event_indicators.as_mut_ptr(),
event_indicators.len(),
)
};
match Fmi2Status::from(status).ok() {
Ok(_) => Ok(true), Err(Fmi2Error::Discard) => {
Ok(false)
}
Err(e) => Err(e), }
}
}
impl FmiModelExchange for Instance<ME> {
fn enter_continuous_time_mode(&mut self) -> Result<Fmi2Res, Fmi2Error> {
ModelExchange::enter_continuous_time_mode(self)
}
fn enter_event_mode(&mut self) -> Result<Fmi2Res, Fmi2Error> {
ModelExchange::enter_event_mode(self)
}
fn update_discrete_states(
&mut self,
event_flags: &mut EventFlags,
) -> Result<Fmi2Res, Fmi2Error> {
ModelExchange::new_discrete_states(self, event_flags)
}
fn completed_integrator_step(
&mut self,
no_set_fmu_state_prior: bool,
enter_event_mode: &mut bool,
terminate_simulation: &mut bool,
) -> Result<Fmi2Res, Fmi2Error> {
ModelExchange::completed_integrator_step(
self,
no_set_fmu_state_prior,
enter_event_mode,
terminate_simulation,
)
}
fn set_time(&mut self, time: f64) -> Result<Fmi2Res, Fmi2Error> {
ModelExchange::set_time(self, time)
}
fn get_continuous_states(
&mut self,
continuous_states: &mut [f64],
) -> Result<Fmi2Res, Fmi2Error> {
ModelExchange::get_continuous_states(self, continuous_states)
}
fn set_continuous_states(&mut self, states: &[f64]) -> Result<Fmi2Res, Fmi2Error> {
ModelExchange::set_continuous_states(self, states)
}
fn get_continuous_state_derivatives(
&mut self,
derivatives: &mut [f64],
) -> Result<Fmi2Res, Fmi2Error> {
ModelExchange::get_derivatives(self, derivatives)
}
fn get_nominals_of_continuous_states(
&mut self,
nominals: &mut [f64],
) -> Result<Fmi2Res, Fmi2Error> {
ModelExchange::get_nominals_of_continuous_states(self, nominals)
}
fn get_event_indicators(
&mut self,
event_indicators: &mut [f64],
) -> Result<bool, <Self::Status as crate::traits::FmiStatus>::Err> {
ModelExchange::get_event_indicators(self, event_indicators)
}
}
impl FmiEventHandler for Instance<ME> {
fn enter_event_mode(&mut self) -> Result<Fmi2Res, Fmi2Error> {
ModelExchange::enter_event_mode(self)
}
fn update_discrete_states(
&mut self,
event_flags: &mut EventFlags,
) -> Result<Fmi2Res, Fmi2Error> {
ModelExchange::new_discrete_states(self, event_flags)
}
}