Skip to content

Commit

Permalink
Merge branch 'master' of github.com:Vico-platform/fmu4cpp
Browse files Browse the repository at this point in the history
  • Loading branch information
markaren committed Jul 28, 2024
2 parents 7b50fdd + f3f8130 commit e2bd443
Show file tree
Hide file tree
Showing 14 changed files with 156 additions and 45 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/cross-compile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ ubuntu-18.04, windows-2019 ]
os: [ ubuntu-20.04, windows-2019 ]

steps:
- uses: actions/checkout@v2
Expand Down Expand Up @@ -39,7 +39,7 @@ jobs:

deploy:
needs: build
runs-on: ubuntu-18.04
runs-on: ubuntu-20.04

steps:
- name: "Download binaries"
Expand Down
16 changes: 8 additions & 8 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,18 @@ if (MSVC)
string(REPLACE "/MDd" "/MTd" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
endif ()

if (WIN32)
set(TARGET_PLATFORM win)
elseif (APPLE)
set(TARGET_PLATFORM darwin)
if ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
set(BITNESS 64)
else ()
set(TARGET_PLATFORM linux)
set(BITNESS 32)
endif ()

if ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
set(TARGET_PLATFORM ${TARGET_PLATFORM}64)
if (WIN32)
set(TARGET_PLATFORM win${BITNESS})
elseif (APPLE)
set(TARGET_PLATFORM darwin${BITNESS})
else ()
set(TARGET_PLATFORM ${TARGET_PLATFORM}32)
set(TARGET_PLATFORM linux${BITNESS})
endif ()

add_subdirectory(export)
Expand Down
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
# FMU4cpp (early prototype)

FMU4cpp is a CMake template repository that allows you to easily create cross-platform FMUs compatible with [FMI 2.0](https://fmi-standard.org/downloads/)
for Co-simulation using C++.
FMU4cpp is a CMake template repository that allows you to easily create cross-platform FMUs
compatible with [FMI 2.0](https://fmi-standard.org/downloads/) for Co-simulation using C++.

The framework handles everything including generating the `modelDescription.xml`,
and packaging of the content into an FMU archive.
The framework generates the required `modelDescription.xml` and further packages
the necessary content into a ready-to-use FMU archive.

### How do I get started?

1. Change the value of the `modelIdentifier` variable in `CMakeLists.txt` to something more appropriate.
2. Edit the content of `src/model.cpp`.
2. Edit the content of [model.cpp](src/model.cpp).
3. Build.

An FMU named `<modelIdentifier>.fmu` is now located in your build folder.

Such easy, such wow.

#### Cross-compilation

Cross-compilation (64-bit linux/windows) occurs automatically when you push your changes to GitHub.
Simply rename the produced `model.zip` to `<modelName>.fmu`.


Such easy, such wow.


### Requirements
* C++17 compiler
* CMake >= 3.15
File renamed without changes.
File renamed without changes.
File renamed without changes.
31 changes: 25 additions & 6 deletions export/include/fmu4cpp/fmu_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "fmu_base.hpp"
#include "fmu_except.hpp"
#include "fmu_variable.hpp"
#include "logger.hpp"
#include "model_info.hpp"

namespace fmu4cpp {
Expand All @@ -35,28 +36,28 @@ namespace fmu4cpp {
}

std::optional<IntVariable> get_int_variable(const std::string &name) {
for (auto &v: integers_) {
for (const auto &v: integers_) {
if (v.name() == name) return v;
}
return std::nullopt;
}

std::optional<RealVariable> get_real_variable(const std::string &name) {
for (auto &v: reals_) {
for (const auto &v: reals_) {
if (v.name() == name) return v;
}
return std::nullopt;
}

std::optional<BoolVariable> get_bool_variable(const std::string &name) {
for (auto &v: booleans_) {
for (const auto &v: booleans_) {
if (v.name() == name) return v;
}
return std::nullopt;
}

std::optional<StringVariable> get_string_variable(const std::string &name) {
for (auto &v: strings_) {
for (const auto &v: strings_) {
if (v.name() == name) return v;
}
return std::nullopt;
Expand Down Expand Up @@ -128,14 +129,30 @@ namespace fmu4cpp {
void set_string(const unsigned int vr[], size_t nvr, const char *const value[]) {
for (unsigned i = 0; i < nvr; i++) {
unsigned int ref = vr[i];
booleans_[ref].set(value[i]);
strings_[ref].set(value[i]);
}
}

[[nodiscard]] std::string guid() const;

[[nodiscard]] std::string make_description() const;

void __set_logger(logger *logger) {
logger_ = logger;
}

void log(fmi2Status s, const std::string &message) {
if (logger_) {
logger_->log(s, message);
}
}

void debugLog(fmi2Status s, const std::string &message) {
if (logger_) {
logger_->debug(s, message);
}
}

virtual ~fmu_base() = default;

protected:
Expand All @@ -160,8 +177,10 @@ namespace fmu4cpp {
void register_variable(BoolVariable v);
void register_variable(StringVariable v);


private:
size_t numVariables{};
logger *logger_ = nullptr;
size_t numVariables_{};

std::string instanceName_;
std::string resourceLocation_;
Expand Down
47 changes: 47 additions & 0 deletions export/include/fmu4cpp/logger.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@

#ifndef FMU4CPP_TEMPLATE_LOGGER_HPP
#define FMU4CPP_TEMPLATE_LOGGER_HPP

#include <memory>

#include "fmi2/fmi2FunctionTypes.h"

namespace fmu4cpp {
class logger {

public:
logger(fmi2ComponentEnvironment c, fmi2CallbackFunctions f, std::string instanceName)
: c_(c),
fmiLogger_(f.logger),
instanceName_(std::move(instanceName)) {}

void setDebugLogging(bool flag) {
debugLogging_ = flag;
}

// Logs a message.
template<typename... Args>
void log(fmi2Status s, const std::string &message, Args &&...args) {
msgBuf_ = message;
fmiLogger_(c_, instanceName_.c_str(), s, "", msgBuf_.c_str(), std::forward<Args>(args)...);
}

// Logs a message.
template<typename... Args>
void debug(fmi2Status s, const std::string &message, Args &&...args) {
if (debugLogging_) {
log(s, message, std::forward<Args>(args)...);
}
}

private:
bool debugLogging_{false};
std::string instanceName_;
fmi2ComponentEnvironment c_;
fmi2CallbackLogger fmiLogger_;
std::string msgBuf_;
};

}// namespace fmu4cpp

#endif//FMU4CPP_TEMPLATE_LOGGER_HPP
7 changes: 4 additions & 3 deletions export/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,18 @@ configure_file(
)

set(publicHeaders
"fmi2/fmi2Functions.h"
"fmi2/fmi2FunctionTypes.h"
"fmi2/fmi2TypesPlatform.h"
"fmu4cpp/lib_info.hpp"
"fmu4cpp/logger.hpp"
"fmu4cpp/model_info.hpp"
"fmu4cpp/fmu_base.hpp"
"fmu4cpp/fmu_except.hpp"
"fmu4cpp/fmu_variable.hpp"
)

set(privateHeaders
"fmi2/fmi2Functions.h"
"fmi2/fmi2FunctionTypes.h"
"fmi2/fmi2TypesPlatform.h"
"fmu4cpp/hash.hpp"
"fmu4cpp/time.hpp"
)
Expand Down
22 changes: 16 additions & 6 deletions export/src/fmu4cpp/fmi2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,23 @@
#include <string>

#include "fmu4cpp/fmu_base.hpp"
#include "fmu4cpp/logger.hpp"

namespace {

// A struct that holds all the data for one model instance.
struct Component {

Component(std::unique_ptr<fmu4cpp::fmu_base> slave, fmi2CallbackFunctions callbackFunctions)
: lastSuccessfulTime{std::numeric_limits<double>::quiet_NaN()}, callbackFunctions(callbackFunctions), slave(std::move(slave)) {}
: lastSuccessfulTime{std::numeric_limits<double>::quiet_NaN()},
slave(std::move(slave)),
logger(this->slave.get(), callbackFunctions, this->slave->instanceName()) {
this->slave->__set_logger(&logger);
}

// Co-simulation
double lastSuccessfulTime;
fmi2CallbackFunctions callbackFunctions;
std::unique_ptr<fmu4cpp::fmu_base> slave;
fmu4cpp::logger logger;
};

}// namespace
Expand Down Expand Up @@ -48,7 +52,7 @@ fmi2Component fmi2Instantiate(fmi2String instanceName,
fmi2String fmuGUID,
fmi2String fmuResourceLocation,
const fmi2CallbackFunctions *functions,
fmi2Boolean visible,
fmi2Boolean /*visible*/,
fmi2Boolean loggingOn) {

if (fmuType != fmi2CoSimulation) {
Expand Down Expand Up @@ -77,9 +81,14 @@ fmi2Component fmi2Instantiate(fmi2String instanceName,
auto guid = slave->guid();
if (guid != fmuGUID) {
std::cerr << "[fmu4cpp] Error. Wrong guid!" << std::endl;
fmu4cpp::logger l(nullptr, *functions, instanceName);
l.log(fmi2Fatal, "", "Error. Wrong guid!");
return nullptr;
}
return new Component(std::move(slave), *functions);

auto c = new Component(std::move(slave), *functions);
c->logger.setDebugLogging(loggingOn);
return c;
}

fmi2Status fmi2SetupExperiment(fmi2Component c,
Expand Down Expand Up @@ -354,7 +363,8 @@ fmi2Status fmi2SetDebugLogging(fmi2Component c,
size_t nCategories,
const fmi2String categories[]) {
auto component = reinterpret_cast<Component *>(c);
return fmi2Error;
component->logger.setDebugLogging(loggingOn);
return fmi2OK;
}

fmi2Status fmi2SetRealInputDerivatives(fmi2Component,
Expand Down
8 changes: 4 additions & 4 deletions export/src/fmu4cpp/fmu_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,19 +221,19 @@ namespace fmu4cpp {
}

IntVariable fmu_base::integer(const std::string &name, const std::function<int()> &getter, const std::optional<std::function<void(int)>> &setter) {
return {name, static_cast<unsigned int>(integers_.size()), numVariables++, getter, setter};
return {name, static_cast<unsigned int>(integers_.size()), numVariables_++, getter, setter};
}

RealVariable fmu_base::real(const std::string &name, const std::function<double()> &getter, const std::optional<std::function<void(double)>> &setter) {
return {name, static_cast<unsigned int>(reals_.size()), numVariables++, getter, setter};
return {name, static_cast<unsigned int>(reals_.size()), numVariables_++, getter, setter};
}

BoolVariable fmu_base::boolean(const std::string &name, const std::function<bool()> &getter, const std::optional<std::function<void(bool)>> &setter) {
return {name, static_cast<unsigned int>(booleans_.size()), numVariables++, getter, setter};
return {name, static_cast<unsigned int>(booleans_.size()), numVariables_++, getter, setter};
}

StringVariable fmu_base::string(const std::string &name, const std::function<std::string()> &getter, const std::optional<std::function<void(std::string)>> &setter) {
return {name, static_cast<unsigned int>(strings_.size()), numVariables++, getter, setter};
return {name, static_cast<unsigned int>(strings_.size()), numVariables_++, getter, setter};
}

void fmu_base::register_variable(IntVariable v) {
Expand Down
33 changes: 24 additions & 9 deletions export/src/fmu4cpp/hash.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,33 @@
//https://stackoverflow.com/questions/66764096/calculating-stdhash-using-different-compilers
inline uint64_t fnv1a(std::string const &text) {

// assumes 64 bit
uint64_t constexpr fnv_prime = 1099511628211ULL;
uint64_t constexpr fnv_offset_basis = 14695981039346656037ULL;
if (sizeof(void *) == 4) {
// 32-bit environment
uint32_t constexpr fnv_prime = 16777619U;
uint32_t constexpr fnv_offset_basis = 2166136261U;

uint64_t hash = fnv_offset_basis;
uint32_t hash = fnv_offset_basis;

for (auto c: text) {
hash ^= c;
hash *= fnv_prime;
}
for (auto c: text) {
hash ^= c;
hash *= fnv_prime;
}

return hash;
} else {
// 64-bit environment
uint64_t constexpr fnv_prime = 1099511628211ULL;
uint64_t constexpr fnv_offset_basis = 14695981039346656037ULL;

uint64_t hash = fnv_offset_basis;

return hash;
for (auto c: text) {
hash ^= c;
hash *= fnv_prime;
}

return hash;
}
}

#endif//FMU4CPP_TEMPLATE_HASH_HPP
Loading

0 comments on commit e2bd443

Please sign in to comment.