Skip to content

Commit

Permalink
Support state saving and serialisation for FMI2
Browse files Browse the repository at this point in the history
Closes #4.
  • Loading branch information
kyllingstad committed May 30, 2024
1 parent bf6bbba commit 9786484
Show file tree
Hide file tree
Showing 7 changed files with 326 additions and 72 deletions.
4 changes: 4 additions & 0 deletions cppfmu_common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,15 @@ namespace cppfmu
typedef fmiInteger FMIInteger;
typedef fmiBoolean FMIBoolean;
typedef fmiString FMIString;
typedef char FMIByte; // doesn't exist in FMI 1
typedef fmiCallbackFunctions FMICallbackFunctions;
typedef fmiCallbackAllocateMemory FMICallbackAllocateMemory;
typedef fmiCallbackFreeMemory FMICallbackFreeMemory;
typedef fmiCallbackLogger FMICallbackLogger;
typedef fmiComponent FMIComponent;
typedef fmiComponent FMIComponentEnvironment;
typedef fmiStatus FMIStatus;
typedef void* FMIFMUState; // doesn't exist in FMI 1
typedef fmiValueReference FMIValueReference;

const FMIBoolean FMIFalse = fmiFalse;
Expand All @@ -66,12 +68,14 @@ namespace cppfmu
typedef fmi2Integer FMIInteger;
typedef fmi2Boolean FMIBoolean;
typedef fmi2String FMIString;
typedef fmi2Byte FMIByte;
typedef fmi2CallbackFunctions FMICallbackFunctions;
typedef fmi2CallbackAllocateMemory FMICallbackAllocateMemory;
typedef fmi2CallbackFreeMemory FMICallbackFreeMemory;
typedef fmi2CallbackLogger FMICallbackLogger;
typedef fmi2Component FMIComponent;
typedef fmi2ComponentEnvironment FMIComponentEnvironment;
typedef fmi2FMUstate FMIFMUState;
typedef fmi2Status FMIStatus;
typedef fmi2ValueReference FMIValueReference;

Expand Down
42 changes: 42 additions & 0 deletions cppfmu_cs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,48 @@ void SlaveInstance::GetString(
}


void SlaveInstance::GetFMUState(FMIFMUState* state)
{
throw std::logic_error("Operation not supported: get FMU state");
}


void SlaveInstance::SetFMUState(FMIFMUState state)
{
throw std::logic_error("Operation not supported: set FMU state");
}


void SlaveInstance::FreeFMUState(FMIFMUState state)
{
throw std::logic_error("Operation not supported: free FMU state");
}


std::size_t SlaveInstance::SerializedFMUStateSize(FMIFMUState state)
{
throw std::logic_error("Operation not supported: get serialized FMU state size");
}


void SlaveInstance::SerializeFMUState(
FMIFMUState state,
FMIByte data[],
std::size_t size)
{
throw std::logic_error("Operation not supported: serialize FMU state");
}


FMIFMUState SlaveInstance::DeserializeFMUState(
const FMIByte data[],
std::size_t size)
{
throw std::logic_error("Operation not supported: deserialize FMU state");
}



SlaveInstance::~SlaveInstance() CPPFMU_NOEXCEPT
{
// Do nothing
Expand Down
41 changes: 41 additions & 0 deletions cppfmu_cs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,47 @@ class SlaveInstance
std::size_t nvr,
FMIString value[]) const;

/* Called from fmi2GetFMUState().
* Never called with FMI 1.x.
* Throws std::logic_error by default.
*/
virtual void GetFMUState(FMIFMUState* state);

/* Called from fmi2SetFMUstate().
* Never called with FMI 1.x.
* Throws std::logic_error by default.
*/
virtual void SetFMUState(FMIFMUState state);

/* Called from fmi2FreeFMUstate().
* Never called with FMI 1.x.
* Throws std::logic_error by default.
*/
virtual void FreeFMUState(FMIFMUState state);

/* Called from fmi2SerializedFMUstateSize().
* Never called with FMI 1.x.
* Throws std::logic_error by default.
*/
virtual std::size_t SerializedFMUStateSize(FMIFMUState state);

/* Called from fmi2SerializeFMUstate().
* Never called with FMI 1.x.
* Throws std::logic_error by default.
*/
virtual void SerializeFMUState(
FMIFMUState state,
FMIByte data[],
std::size_t size);

/* Called from fmi2DeSerializeFMUstate().
* Never called with FMI 1.x.
* Throws std::logic_error by default.
*/
virtual FMIFMUState DeserializeFMUState(
const FMIByte data[],
std::size_t size);

// Called from fmi2DoStep()/fmiDoStep(). Must be implemented in model code.
virtual bool DoStep(
FMIReal currentCommunicationPoint,
Expand Down
122 changes: 80 additions & 42 deletions fmi_functions.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright 2016-2019, SINTEF Ocean.
/* Copyright 2016-2024, SINTEF Ocean.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
Expand Down Expand Up @@ -798,73 +798,111 @@ fmi2Status fmi2SetString(

fmi2Status fmi2GetFMUstate(
fmi2Component c,
fmi2FMUstate*)
fmi2FMUstate* state)
{
reinterpret_cast<Component*>(c)->logger.Log(
fmi2Error,
"cppfmu",
"FMI function not supported: fmi2GetFMUstate");
return fmi2Error;
const auto component = reinterpret_cast<Component*>(c);
try {
component->slave->GetFMUState(state);
return fmi2OK;
} catch (const cppfmu::FatalError& e) {
component->logger.Log(fmi2Fatal, "", e.what());
return fmi2Fatal;
} catch (const std::exception& e) {
component->logger.Log(fmi2Error, "", e.what());
return fmi2Error;
}
}

fmi2Status fmi2SetFMUstate(
fmi2Component c,
fmi2FMUstate)
fmi2FMUstate state)
{
reinterpret_cast<Component*>(c)->logger.Log(
fmi2Error,
"cppfmu",
"FMI function not supported: fmi2SetFMUstate");
return fmi2Error;
const auto component = reinterpret_cast<Component*>(c);
try {
component->slave->SetFMUState(state);
return fmi2OK;
} catch (const cppfmu::FatalError& e) {
component->logger.Log(fmi2Fatal, "", e.what());
return fmi2Fatal;
} catch (const std::exception& e) {
component->logger.Log(fmi2Error, "", e.what());
return fmi2Error;
}
}

fmi2Status fmi2FreeFMUstate(
fmi2Component c,
fmi2FMUstate*)
fmi2FMUstate* state)
{
reinterpret_cast<Component*>(c)->logger.Log(
fmi2Error,
"cppfmu",
"FMI function not supported: fmi2FreeFMUstate");
return fmi2Error;
if (state == nullptr) return fmi2OK;
const auto component = reinterpret_cast<Component*>(c);
try {
component->slave->FreeFMUState(*state);
*state = nullptr;
return fmi2OK;
} catch (const cppfmu::FatalError& e) {
component->logger.Log(fmi2Fatal, "", e.what());
return fmi2Fatal;
} catch (const std::exception& e) {
component->logger.Log(fmi2Error, "", e.what());
return fmi2Error;
}
}

fmi2Status fmi2SerializedFMUstateSize(
fmi2Component c,
fmi2FMUstate,
size_t*)
fmi2FMUstate state,
size_t* size)
{
reinterpret_cast<Component*>(c)->logger.Log(
fmi2Error,
"cppfmu",
"FMI function not supported: fmi2SerializedFMUstateSize");
return fmi2Error;
const auto component = reinterpret_cast<Component*>(c);
try {
*size = component->slave->SerializedFMUStateSize(state);
return fmi2OK;
} catch (const cppfmu::FatalError& e) {
component->logger.Log(fmi2Fatal, "", e.what());
return fmi2Fatal;
} catch (const std::exception& e) {
component->logger.Log(fmi2Error, "", e.what());
return fmi2Error;
}
}

fmi2Status fmi2SerializeFMUstate(
fmi2Component c,
fmi2FMUstate,
fmi2Byte[],
size_t)
fmi2FMUstate state,
fmi2Byte data[],
size_t size)
{
reinterpret_cast<Component*>(c)->logger.Log(
fmi2Error,
"cppfmu",
"FMI function not supported: fmi2SerializeFMUstate");
return fmi2Error;
const auto component = reinterpret_cast<Component*>(c);
try {
component->slave->SerializeFMUState(state, data, size);
return fmi2OK;
} catch (const cppfmu::FatalError& e) {
component->logger.Log(fmi2Fatal, "", e.what());
return fmi2Fatal;
} catch (const std::exception& e) {
component->logger.Log(fmi2Error, "", e.what());
return fmi2Error;
}
}

fmi2Status fmi2DeSerializeFMUstate(
fmi2Component c,
const fmi2Byte[],
size_t,
fmi2FMUstate*)
const fmi2Byte data[],
size_t size,
fmi2FMUstate* state)
{
reinterpret_cast<Component*>(c)->logger.Log(
fmi2Error,
"cppfmu",
"FMI function not supported: fmi2DeSerializeFMUstate");
return fmi2Error;
const auto component = reinterpret_cast<Component*>(c);
try {
*state = component->slave->DeserializeFMUState(data, size);
return fmi2OK;
} catch (const cppfmu::FatalError& e) {
component->logger.Log(fmi2Fatal, "", e.what());
return fmi2Fatal;
} catch (const std::exception& e) {
component->logger.Log(fmi2Error, "", e.what());
return fmi2Error;
}
}


Expand Down
53 changes: 52 additions & 1 deletion tests/cs_slave.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
#include <cppfmu_cs.hpp>

#include <cstring>
#include <stdexcept>


class TestSlave : public cppfmu::SlaveInstance
{
public:
explicit TestSlave(cppfmu::Memory memory)
: memory_(memory)
{
}

void SetReal(
const cppfmu::FMIValueReference vr[],
std::size_t nvr,
Expand Down Expand Up @@ -34,6 +40,50 @@ class TestSlave : public cppfmu::SlaveInstance
}
}

void GetFMUState(cppfmu::FMIFMUState* state) override
{
auto s = (*state == nullptr)
? cppfmu::New<cppfmu::FMIReal>(memory_)
: static_cast<cppfmu::FMIReal*>(*state);
*s = value_;
*state = s;
}

void SetFMUState(cppfmu::FMIFMUState state) override
{
auto s = static_cast<cppfmu::FMIReal*>(state);
value_ = *s;
}

void FreeFMUState(cppfmu::FMIFMUState state) override
{
auto s = static_cast<cppfmu::FMIReal*>(state);
cppfmu::Delete(memory_, s);
}

std::size_t SerializedFMUStateSize(cppfmu::FMIFMUState) override
{
return sizeof(cppfmu::FMIReal);
}

void SerializeFMUState(
cppfmu::FMIFMUState state,
cppfmu::FMIByte data[],
std::size_t size) override
{
auto s = static_cast<cppfmu::FMIReal*>(state);
std::memcpy(data, s, sizeof *s);
}

cppfmu::FMIFMUState DeserializeFMUState(
const cppfmu::FMIByte data[],
std::size_t size) override
{
auto s = cppfmu::New<cppfmu::FMIReal>(memory_);
std::memcpy(s, data, sizeof *s);
return s;
}

bool DoStep(
cppfmu::FMIReal currentCommunicationPoint,
cppfmu::FMIReal communicationStepSize,
Expand All @@ -44,6 +94,7 @@ class TestSlave : public cppfmu::SlaveInstance
}

private:
cppfmu::Memory memory_;
cppfmu::FMIReal value_ = 0.0;
};

Expand All @@ -59,6 +110,6 @@ cppfmu::UniquePtr<cppfmu::SlaveInstance> CppfmuInstantiateSlave(
cppfmu::Memory memory,
cppfmu::Logger logger)
{
return cppfmu::AllocateUnique<TestSlave>(memory);
return cppfmu::AllocateUnique<TestSlave>(memory, memory);
}

Loading

0 comments on commit 9786484

Please sign in to comment.