use crate::{
CS, ME,
fmi2::Fmi2Res,
traits::{FmiImport, FmiInstance, FmiStatus, InstanceTag},
};
use super::{CallbackFunctions, Fmi2Error, Fmi2Status, binding, import::Fmi2Import, schema};
mod co_simulation;
mod common;
mod model_exchange;
mod traits;
pub use traits::{CoSimulation, Common, ModelExchange};
pub type InstanceME = Instance<ME>;
pub type InstanceCS = Instance<CS>;
pub struct FmuState(usize);
pub struct Instance<Tag> {
name: String,
binding: binding::Fmi2Binding,
component: binding::fmi2Component,
#[allow(dead_code)]
callbacks: Box<CallbackFunctions>,
saved_states: Vec<binding::fmi2FMUstate>,
_tag: std::marker::PhantomData<Tag>,
}
impl<Tag> Drop for Instance<Tag> {
fn drop(&mut self) {
log::trace!("Freeing component {:?}", self.component);
unsafe {
for state in &mut self.saved_states {
self.binding.fmi2FreeFMUstate(self.component, state);
}
self.binding.fmi2FreeInstance(self.component)
};
}
}
impl<Tag: InstanceTag> FmiInstance for Instance<Tag> {
type ModelDescription = schema::Fmi2ModelDescription;
type ValueRef = <Fmi2Import as FmiImport>::ValueRef;
type Status = Fmi2Status;
fn name(&self) -> &str {
&self.name
}
fn get_version(&self) -> &str {
Common::get_version(self)
}
fn interface_type(&self) -> crate::InterfaceType {
Tag::TYPE
}
fn set_debug_logging(
&mut self,
logging_on: bool,
categories: &[&str],
) -> Result<Fmi2Res, Fmi2Error> {
Common::set_debug_logging(self, logging_on, categories)
}
fn enter_initialization_mode(
&mut self,
tolerance: Option<f64>,
start_time: f64,
stop_time: Option<f64>,
) -> Result<Fmi2Res, Fmi2Error> {
Common::setup_experiment(self, tolerance, start_time, stop_time)?;
Common::enter_initialization_mode(self)
}
fn exit_initialization_mode(&mut self) -> Result<Fmi2Res, Fmi2Error> {
Common::exit_initialization_mode(self)
}
fn terminate(&mut self) -> Result<Fmi2Res, Fmi2Error> {
Common::terminate(self)
}
fn reset(&mut self) -> Result<Fmi2Res, Fmi2Error> {
Common::reset(self)
}
}
impl Default for CallbackFunctions {
fn default() -> Self {
CallbackFunctions {
logger: Some(super::binding::logger::callback_logger_handler as _),
allocate_memory: Some(libc::calloc),
free_memory: Some(libc::free),
step_finished: None,
component_environment: std::ptr::null_mut::<std::os::raw::c_void>(),
}
}
}
impl<Tag: InstanceTag> Instance<Tag> {
pub fn get_fmu_state(&mut self) -> Result<FmuState, Fmi2Error> {
let mut state = std::ptr::null_mut();
Fmi2Status(unsafe { self.binding.fmi2GetFMUstate(self.component, &mut state) }).ok()?;
if state.is_null() {
log::error!("FMU returned a null state");
Err(Fmi2Error::Fatal)
} else {
self.saved_states.push(state);
Ok(FmuState(self.saved_states.len() - 1))
}
}
pub fn set_fmu_state(&mut self, state: &FmuState) -> Fmi2Status {
let state = self.saved_states.get(state.0).unwrap();
unsafe { self.binding.fmi2SetFMUstate(self.component, *state) }.into()
}
pub fn update_fmu_state(&mut self, state: &FmuState) -> Fmi2Status {
let state = self.saved_states.get_mut(state.0).unwrap();
unsafe { self.binding.fmi2GetFMUstate(self.component, state) }.into()
}
pub fn serialize_fmu_state(&mut self, state: &FmuState) -> Result<Vec<u8>, Fmi2Error> {
let state = self.saved_states.get_mut(state.0).unwrap();
let mut size = 0;
Fmi2Status(unsafe {
self.binding
.fmi2SerializedFMUstateSize(self.component, *state, &mut size)
})
.ok()?;
let mut buffer: Vec<u8> = vec![0; size];
Fmi2Status(unsafe {
self.binding.fmi2SerializeFMUstate(
self.component,
*state,
buffer.as_mut_ptr() as _,
size,
)
})
.ok()?;
Ok(buffer)
}
pub fn deserialize_fmu_state(&mut self, buffer: &[u8]) -> Result<FmuState, Fmi2Error> {
let mut state = std::ptr::null_mut();
Fmi2Status(unsafe {
self.binding.fmi2DeSerializeFMUstate(
self.component,
buffer.as_ptr() as _,
buffer.len() as _,
&mut state,
)
})
.ok()?;
if state.is_null() {
log::error!("FMU returned a null state");
Err(Fmi2Error::Fatal)
} else {
self.saved_states.push(state);
Ok(FmuState(self.saved_states.len() - 1))
}
}
}
impl<A> std::fmt::Debug for Instance<A> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Instance {} {{{:?}}}", self.name, self.component,)
}
}