Skip to content

Commit b106a5e

Browse files
authored
Merge pull request #12 from viproma/feature/4-support-serialisation
Support state saving and serialisation for FMI2
2 parents 21f32d6 + 9786484 commit b106a5e

File tree

7 files changed

+326
-72
lines changed

7 files changed

+326
-72
lines changed

cppfmu_common.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,15 @@ namespace cppfmu
4343
typedef fmiInteger FMIInteger;
4444
typedef fmiBoolean FMIBoolean;
4545
typedef fmiString FMIString;
46+
typedef char FMIByte; // doesn't exist in FMI 1
4647
typedef fmiCallbackFunctions FMICallbackFunctions;
4748
typedef fmiCallbackAllocateMemory FMICallbackAllocateMemory;
4849
typedef fmiCallbackFreeMemory FMICallbackFreeMemory;
4950
typedef fmiCallbackLogger FMICallbackLogger;
5051
typedef fmiComponent FMIComponent;
5152
typedef fmiComponent FMIComponentEnvironment;
5253
typedef fmiStatus FMIStatus;
54+
typedef void* FMIFMUState; // doesn't exist in FMI 1
5355
typedef fmiValueReference FMIValueReference;
5456

5557
const FMIBoolean FMIFalse = fmiFalse;
@@ -66,12 +68,14 @@ namespace cppfmu
6668
typedef fmi2Integer FMIInteger;
6769
typedef fmi2Boolean FMIBoolean;
6870
typedef fmi2String FMIString;
71+
typedef fmi2Byte FMIByte;
6972
typedef fmi2CallbackFunctions FMICallbackFunctions;
7073
typedef fmi2CallbackAllocateMemory FMICallbackAllocateMemory;
7174
typedef fmi2CallbackFreeMemory FMICallbackFreeMemory;
7275
typedef fmi2CallbackLogger FMICallbackLogger;
7376
typedef fmi2Component FMIComponent;
7477
typedef fmi2ComponentEnvironment FMIComponentEnvironment;
78+
typedef fmi2FMUstate FMIFMUState;
7579
typedef fmi2Status FMIStatus;
7680
typedef fmi2ValueReference FMIValueReference;
7781

cppfmu_cs.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,48 @@ void SlaveInstance::GetString(
139139
}
140140

141141

142+
void SlaveInstance::GetFMUState(FMIFMUState* state)
143+
{
144+
throw std::logic_error("Operation not supported: get FMU state");
145+
}
146+
147+
148+
void SlaveInstance::SetFMUState(FMIFMUState state)
149+
{
150+
throw std::logic_error("Operation not supported: set FMU state");
151+
}
152+
153+
154+
void SlaveInstance::FreeFMUState(FMIFMUState state)
155+
{
156+
throw std::logic_error("Operation not supported: free FMU state");
157+
}
158+
159+
160+
std::size_t SlaveInstance::SerializedFMUStateSize(FMIFMUState state)
161+
{
162+
throw std::logic_error("Operation not supported: get serialized FMU state size");
163+
}
164+
165+
166+
void SlaveInstance::SerializeFMUState(
167+
FMIFMUState state,
168+
FMIByte data[],
169+
std::size_t size)
170+
{
171+
throw std::logic_error("Operation not supported: serialize FMU state");
172+
}
173+
174+
175+
FMIFMUState SlaveInstance::DeserializeFMUState(
176+
const FMIByte data[],
177+
std::size_t size)
178+
{
179+
throw std::logic_error("Operation not supported: deserialize FMU state");
180+
}
181+
182+
183+
142184
SlaveInstance::~SlaveInstance() CPPFMU_NOEXCEPT
143185
{
144186
// Do nothing

cppfmu_cs.hpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,47 @@ class SlaveInstance
103103
std::size_t nvr,
104104
FMIString value[]) const;
105105

106+
/* Called from fmi2GetFMUState().
107+
* Never called with FMI 1.x.
108+
* Throws std::logic_error by default.
109+
*/
110+
virtual void GetFMUState(FMIFMUState* state);
111+
112+
/* Called from fmi2SetFMUstate().
113+
* Never called with FMI 1.x.
114+
* Throws std::logic_error by default.
115+
*/
116+
virtual void SetFMUState(FMIFMUState state);
117+
118+
/* Called from fmi2FreeFMUstate().
119+
* Never called with FMI 1.x.
120+
* Throws std::logic_error by default.
121+
*/
122+
virtual void FreeFMUState(FMIFMUState state);
123+
124+
/* Called from fmi2SerializedFMUstateSize().
125+
* Never called with FMI 1.x.
126+
* Throws std::logic_error by default.
127+
*/
128+
virtual std::size_t SerializedFMUStateSize(FMIFMUState state);
129+
130+
/* Called from fmi2SerializeFMUstate().
131+
* Never called with FMI 1.x.
132+
* Throws std::logic_error by default.
133+
*/
134+
virtual void SerializeFMUState(
135+
FMIFMUState state,
136+
FMIByte data[],
137+
std::size_t size);
138+
139+
/* Called from fmi2DeSerializeFMUstate().
140+
* Never called with FMI 1.x.
141+
* Throws std::logic_error by default.
142+
*/
143+
virtual FMIFMUState DeserializeFMUState(
144+
const FMIByte data[],
145+
std::size_t size);
146+
106147
// Called from fmi2DoStep()/fmiDoStep(). Must be implemented in model code.
107148
virtual bool DoStep(
108149
FMIReal currentCommunicationPoint,

fmi_functions.cpp

Lines changed: 80 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright 2016-2019, SINTEF Ocean.
1+
/* Copyright 2016-2024, SINTEF Ocean.
22
* This Source Code Form is subject to the terms of the Mozilla Public
33
* License, v. 2.0. If a copy of the MPL was not distributed with this
44
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -798,73 +798,111 @@ fmi2Status fmi2SetString(
798798

799799
fmi2Status fmi2GetFMUstate(
800800
fmi2Component c,
801-
fmi2FMUstate*)
801+
fmi2FMUstate* state)
802802
{
803-
reinterpret_cast<Component*>(c)->logger.Log(
804-
fmi2Error,
805-
"cppfmu",
806-
"FMI function not supported: fmi2GetFMUstate");
807-
return fmi2Error;
803+
const auto component = reinterpret_cast<Component*>(c);
804+
try {
805+
component->slave->GetFMUState(state);
806+
return fmi2OK;
807+
} catch (const cppfmu::FatalError& e) {
808+
component->logger.Log(fmi2Fatal, "", e.what());
809+
return fmi2Fatal;
810+
} catch (const std::exception& e) {
811+
component->logger.Log(fmi2Error, "", e.what());
812+
return fmi2Error;
813+
}
808814
}
809815

810816
fmi2Status fmi2SetFMUstate(
811817
fmi2Component c,
812-
fmi2FMUstate)
818+
fmi2FMUstate state)
813819
{
814-
reinterpret_cast<Component*>(c)->logger.Log(
815-
fmi2Error,
816-
"cppfmu",
817-
"FMI function not supported: fmi2SetFMUstate");
818-
return fmi2Error;
820+
const auto component = reinterpret_cast<Component*>(c);
821+
try {
822+
component->slave->SetFMUState(state);
823+
return fmi2OK;
824+
} catch (const cppfmu::FatalError& e) {
825+
component->logger.Log(fmi2Fatal, "", e.what());
826+
return fmi2Fatal;
827+
} catch (const std::exception& e) {
828+
component->logger.Log(fmi2Error, "", e.what());
829+
return fmi2Error;
830+
}
819831
}
820832

821833
fmi2Status fmi2FreeFMUstate(
822834
fmi2Component c,
823-
fmi2FMUstate*)
835+
fmi2FMUstate* state)
824836
{
825-
reinterpret_cast<Component*>(c)->logger.Log(
826-
fmi2Error,
827-
"cppfmu",
828-
"FMI function not supported: fmi2FreeFMUstate");
829-
return fmi2Error;
837+
if (state == nullptr) return fmi2OK;
838+
const auto component = reinterpret_cast<Component*>(c);
839+
try {
840+
component->slave->FreeFMUState(*state);
841+
*state = nullptr;
842+
return fmi2OK;
843+
} catch (const cppfmu::FatalError& e) {
844+
component->logger.Log(fmi2Fatal, "", e.what());
845+
return fmi2Fatal;
846+
} catch (const std::exception& e) {
847+
component->logger.Log(fmi2Error, "", e.what());
848+
return fmi2Error;
849+
}
830850
}
831851

832852
fmi2Status fmi2SerializedFMUstateSize(
833853
fmi2Component c,
834-
fmi2FMUstate,
835-
size_t*)
854+
fmi2FMUstate state,
855+
size_t* size)
836856
{
837-
reinterpret_cast<Component*>(c)->logger.Log(
838-
fmi2Error,
839-
"cppfmu",
840-
"FMI function not supported: fmi2SerializedFMUstateSize");
841-
return fmi2Error;
857+
const auto component = reinterpret_cast<Component*>(c);
858+
try {
859+
*size = component->slave->SerializedFMUStateSize(state);
860+
return fmi2OK;
861+
} catch (const cppfmu::FatalError& e) {
862+
component->logger.Log(fmi2Fatal, "", e.what());
863+
return fmi2Fatal;
864+
} catch (const std::exception& e) {
865+
component->logger.Log(fmi2Error, "", e.what());
866+
return fmi2Error;
867+
}
842868
}
843869

844870
fmi2Status fmi2SerializeFMUstate(
845871
fmi2Component c,
846-
fmi2FMUstate,
847-
fmi2Byte[],
848-
size_t)
872+
fmi2FMUstate state,
873+
fmi2Byte data[],
874+
size_t size)
849875
{
850-
reinterpret_cast<Component*>(c)->logger.Log(
851-
fmi2Error,
852-
"cppfmu",
853-
"FMI function not supported: fmi2SerializeFMUstate");
854-
return fmi2Error;
876+
const auto component = reinterpret_cast<Component*>(c);
877+
try {
878+
component->slave->SerializeFMUState(state, data, size);
879+
return fmi2OK;
880+
} catch (const cppfmu::FatalError& e) {
881+
component->logger.Log(fmi2Fatal, "", e.what());
882+
return fmi2Fatal;
883+
} catch (const std::exception& e) {
884+
component->logger.Log(fmi2Error, "", e.what());
885+
return fmi2Error;
886+
}
855887
}
856888

857889
fmi2Status fmi2DeSerializeFMUstate(
858890
fmi2Component c,
859-
const fmi2Byte[],
860-
size_t,
861-
fmi2FMUstate*)
891+
const fmi2Byte data[],
892+
size_t size,
893+
fmi2FMUstate* state)
862894
{
863-
reinterpret_cast<Component*>(c)->logger.Log(
864-
fmi2Error,
865-
"cppfmu",
866-
"FMI function not supported: fmi2DeSerializeFMUstate");
867-
return fmi2Error;
895+
const auto component = reinterpret_cast<Component*>(c);
896+
try {
897+
*state = component->slave->DeserializeFMUState(data, size);
898+
return fmi2OK;
899+
} catch (const cppfmu::FatalError& e) {
900+
component->logger.Log(fmi2Fatal, "", e.what());
901+
return fmi2Fatal;
902+
} catch (const std::exception& e) {
903+
component->logger.Log(fmi2Error, "", e.what());
904+
return fmi2Error;
905+
}
868906
}
869907

870908

tests/cs_slave.cpp

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
#include <cppfmu_cs.hpp>
22

3+
#include <cstring>
34
#include <stdexcept>
45

56

67
class TestSlave : public cppfmu::SlaveInstance
78
{
89
public:
10+
explicit TestSlave(cppfmu::Memory memory)
11+
: memory_(memory)
12+
{
13+
}
14+
915
void SetReal(
1016
const cppfmu::FMIValueReference vr[],
1117
std::size_t nvr,
@@ -34,6 +40,50 @@ class TestSlave : public cppfmu::SlaveInstance
3440
}
3541
}
3642

43+
void GetFMUState(cppfmu::FMIFMUState* state) override
44+
{
45+
auto s = (*state == nullptr)
46+
? cppfmu::New<cppfmu::FMIReal>(memory_)
47+
: static_cast<cppfmu::FMIReal*>(*state);
48+
*s = value_;
49+
*state = s;
50+
}
51+
52+
void SetFMUState(cppfmu::FMIFMUState state) override
53+
{
54+
auto s = static_cast<cppfmu::FMIReal*>(state);
55+
value_ = *s;
56+
}
57+
58+
void FreeFMUState(cppfmu::FMIFMUState state) override
59+
{
60+
auto s = static_cast<cppfmu::FMIReal*>(state);
61+
cppfmu::Delete(memory_, s);
62+
}
63+
64+
std::size_t SerializedFMUStateSize(cppfmu::FMIFMUState) override
65+
{
66+
return sizeof(cppfmu::FMIReal);
67+
}
68+
69+
void SerializeFMUState(
70+
cppfmu::FMIFMUState state,
71+
cppfmu::FMIByte data[],
72+
std::size_t size) override
73+
{
74+
auto s = static_cast<cppfmu::FMIReal*>(state);
75+
std::memcpy(data, s, sizeof *s);
76+
}
77+
78+
cppfmu::FMIFMUState DeserializeFMUState(
79+
const cppfmu::FMIByte data[],
80+
std::size_t size) override
81+
{
82+
auto s = cppfmu::New<cppfmu::FMIReal>(memory_);
83+
std::memcpy(s, data, sizeof *s);
84+
return s;
85+
}
86+
3787
bool DoStep(
3888
cppfmu::FMIReal currentCommunicationPoint,
3989
cppfmu::FMIReal communicationStepSize,
@@ -44,6 +94,7 @@ class TestSlave : public cppfmu::SlaveInstance
4494
}
4595

4696
private:
97+
cppfmu::Memory memory_;
4798
cppfmu::FMIReal value_ = 0.0;
4899
};
49100

@@ -59,6 +110,6 @@ cppfmu::UniquePtr<cppfmu::SlaveInstance> CppfmuInstantiateSlave(
59110
cppfmu::Memory memory,
60111
cppfmu::Logger logger)
61112
{
62-
return cppfmu::AllocateUnique<TestSlave>(memory);
113+
return cppfmu::AllocateUnique<TestSlave>(memory, memory);
63114
}
64115

0 commit comments

Comments
 (0)