Precommit (#1)

* first commit

* cleanup
This commit is contained in:
tompzf
2025-11-04 13:28:06 +01:00
committed by GitHub
parent dba45dc636
commit 6ed4b1534e
898 changed files with 256340 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
# Define project
project (sdv_dbc_util VERSION 1.0 LANGUAGES CXX)
# Add include directories
include_directories(../export)
# Define the executable
add_executable(sdv_dbc_util
main.cpp
can_dl.h
can_dl.cpp
fmu.h
fmu.cpp
cmake_generator.cpp
cmake_generator.h
codegen_base.cpp
"fmu_templates.h")
if (WIN32)
target_link_libraries(sdv_dbc_util ${CMAKE_DL_LIBS} Rpcrt4.lib)
else()
target_link_libraries(sdv_dbc_util ${CMAKE_DL_LIBS})
endif()
# Build dependencies
add_dependencies(sdv_dbc_util CompileCoreIDL)
# Appending the executable to the service list
set(SDV_Executable_List ${SDV_Executable_List} sdv_dbc_util PARENT_SCOPE)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,198 @@
#ifndef CAN_DL_H
#define CAN_DL_H
#include "../global/dbcparser/dbcparser.h"
#include <fstream>
#include "codegen_base.h"
/**
* @brief CAN data link generator class.
*/
class CCanDataLinkGen : public CCodeGeneratorBase
{
public:
/**
* @brief Constructor
* @param[in] rpathOutputDir Reference to the outpur directory.
* @param[in] rparser Reference to the DBC parser containing the definitions.
* @param[in] rssVersion Reference to a string representing a version of the dbc file (could be empty).
* @param[in] rssIfcName Reference to the string holding the interface name (could be empty).
* @param[in] nIfcIdx The interface index (valid if no name is provided).
* @param[in] rvecNodes Reference to a list of nodes this data link object is representing. An empty list will implement
* sending and receiving functions for all nodes.
*/
CCanDataLinkGen(const std::filesystem::path& rpathOutputDir, const dbc::CDbcParser& rparser, const std::string& rssVersion,
const std::string& rssIfcName, size_t nIfcIdx, const std::vector<std::string>& rvecNodes);
private:
/**
* @brief Keyword map for keyword replacement in a string.
*/
typedef std::map<std::string, std::string> CKeywordMap;
/**
* @brief Replace keywords in a string.
* @param[in] rssStr Reference to the string containing the keywords.
* @param[in] rmapKeywords Map with keywords to replace.
* @param[in] cMarker Character to identify the keyword with (placed before and after the keyword; e.g. %keyword%).
* @return Returns the string with replacements.
*/
static std::string ReplaceKeywords(const std::string& rssStr, const CKeywordMap& rmapKeywords, char cMarker = '%');
/**
* @brief validates that the string represents a float
* @param[in] rssInput Reference to the string representing a float.
* @return Returns the input string. If '.' not found it adds ".0" to the string
*/
std::string StringMustBeFloatValue(const std::string& rssInput);
/**
* @brief Composes a dbc file version information string
* @param[in] rssVersion Reference to a string representing a version of the dbc file.
* @return The code to insert.
*/
std::string CodeDBCFileVersion(const std::string& rssVersion);
/**
* @brief Provide code to determine the interface index based on the interface name (if supplied).
* @param[in] rssIfcName Reference to the string holding the interface name (could be empty).
* @return The code to insert during initialization.
*/
std::string CodeInitInterfaceIndex(const std::string& rssIfcName);
/**
* @brief Provide code for the RX message definition.
* @param[in] rsMsg Reference to the DBC message to provide the message definition for.
* @return The code to insert.
*/
std::string CodeRxMessageDefinition(const dbc::SMessageDef& rsMsg);
/**
* @brief Provide code for the TX message definition.
* @param[in] rsMsg Reference to the DBC message to provide the message definition for.
* @return The code to insert.
*/
std::string CodeTxMessageDefinition(const dbc::SMessageDef& rsMsg);
/**
* @brief Provide code for the signal declaration.
* @param[in] rsSig Reference to the DBC signal to provide a declaration for.
* @return The code to insert.
*/
std::string CodeSignalDecl(const dbc::SSignalDef& rsSig);
/**
* @brief Initialize the RX message variable.
* @param[in] rsMsg Reference to the DBC message to provide the code for.
* @return The code to insert.
*/
std::string CodeInitVarRxMessage(const dbc::SMessageDef& rsMsg);
/**
* @brief Initialize the TX message variable.
* @param[in] rsMsg Reference to the DBC message to provide the code for.
* @return The code to insert.
*/
std::string CodeInitVarTxMessage(const dbc::SMessageDef& rsMsg);
/**
* @brief Initialize the RX message structure.
* @param[in] rsMsg Reference to the DBC message to provide the code for.
* @return The code to insert.
*/
std::string CodeInitRxMessage(const dbc::SMessageDef& rsMsg);
/**
* @brief Initialize the TX message structure.
* @param[in] rsMsg Reference to the DBC message to provide the code for.
* @return The code to insert.
*/
std::string CodeInitTxMessage(const dbc::SMessageDef& rsMsg);
/**
* @brief Terminate the RX message structure.
* @param[in] rsMsg Reference to the DBC message to provide the code for.
* @return The code to insert.
*/
std::string CodeTermRxMessage(const dbc::SMessageDef& rsMsg);
/**
* @brief Terminate the TX message structure.
* @param[in] rsMsg Reference to the DBC message to provide the code for.
* @return The code to insert.
*/
std::string CodeTermTxMessage(const dbc::SMessageDef& rsMsg);
/**
* @brief Provide the RX message structure functions.
* @param[in] rsMsg Reference to the DBC message to provide the code for.
* @return The code to insert.
*/
std::string CodeRxMessageFunctions(const dbc::SMessageDef& rsMsg);
/**
* @brief Provide the TX message structure functions.
* @param[in] rsMsg Reference to the DBC message to provide the code for.
* @return The code to insert.
*/
std::string CodeTxMessageFunctions(const dbc::SMessageDef& rsMsg);
/**
* @brief Initialize the signal registration.
* @param[in] rsMsg Reference to the DBC message to provide the code for.
* @param[in] rsSig Reference to the DBC signal to provide the registration for.
* @return The code to insert.
*/
std::string CodeRegisterRxSignal(const dbc::SMessageDef& rsMsg, const dbc::SSignalDef& rsSig);
/**
* @brief Initialize the signal registration.
* @param[in] rsMsg Reference to the DBC message to provide the code for.
* @param[in] rsSig Reference to the DBC signal to provide the registration for.
* @return The code to insert.
*/
std::string CodeRegisterTxSignal(const dbc::SMessageDef& rsMsg, const dbc::SSignalDef& rsSig);
/**
* @brief Remove the signal registration.
* @param[in] rsMsg Reference to the DBC message to provide the code for.
* @param[in] rsSig Reference to the DBC signal to provide the unregistration for.
* @return The code to insert.
*/
std::string CodeUnregisterSignal(const dbc::SMessageDef& rsMsg, const dbc::SSignalDef& rsSig);
/**
* @brief Process the signal data for the specific message.
* @param[in] rsMsg Reference to the DBC message to provide the code for.
* @param[in] rsSig Reference to the DBC signal to provide the processing for.
* @return The code to insert.
*/
std::string CodeProcessRxSignal(const dbc::SMessageDef& rsMsg, const dbc::SSignalDef& rsSig);
/**
* @brief Initialize the TX trigger with the signal..
* @param[in] rsMsg Reference to the DBC message to provide the code for.
* @param[in] rsSig Reference to the DBC signal to provide the trigger initialization for.
* @return The code to insert.
*/
std::string InitTrigger(const dbc::SMessageDef& rsMsg, const dbc::SSignalDef& rsSig);
/**
* @brief Compose the message from the signal data.
* @param[in] rsMsg Reference to the DBC message to provide the code for.
* @param[in] rsSig Reference to the DBC signal to provide the composition for.
* @return The code to insert.
*/
std::string CodeComposeTxSignal(const dbc::SMessageDef& rsMsg, const dbc::SSignalDef& rsSig);
std::filesystem::path m_pathProject; ///< Project file path
std::filesystem::path m_pathHeader; ///< Header file path
std::filesystem::path m_pathCpp; ///< C++ file path
std::ofstream m_fstreamHeader; ///< The header file
std::ofstream m_fstreamCpp; ///< The C++ file
const dbc::CDbcParser& m_rparser; ///< Reference to the DBC parser.
};
#endif // !defined CAN_DL_H

View File

@@ -0,0 +1,141 @@
#include "cmake_generator.h"
#include <sstream>
#include <fstream>
#include <set>
#include <algorithm>
#include <thread>
#include <chrono>
CDbcUtilCMakeGenerator::CDbcUtilCMakeGenerator(const std::filesystem::path& rpathOutputDir, const std::string& rssComponent)
{
if (rssComponent.empty()) return; // TODO: Exception
// Create project directory
if (!rpathOutputDir.empty())
m_pathProject = rpathOutputDir;
if (!rssComponent.empty())
m_pathProject /= "can_dl";
std::filesystem::create_directories(m_pathProject);
// The source string
std::string ssSource;
// File with "CMakeLists.txt" function; read completely if existing
std::filesystem::path pathFile = m_pathProject / "CMakeLists.txt";
if (std::filesystem::exists(pathFile))
{
std::ifstream stream;
stream.open(pathFile);
if (!stream.is_open()) return; // TODO: Exception: throw CCompileException("Failed to open the CMakeLists.txt file for reading.");
// Read the complete source
std::stringstream sstream;
sstream << stream.rdbuf();
ssSource = std::move(sstream.str());
}
else // Create the file in memory
{
ssSource = R"code(# Enforce CMake version 3.20 or newer needed for path function
cmake_minimum_required (VERSION 3.20)
# Use new policy for project version settings and default warning level
cmake_policy(SET CMP0048 NEW) # requires CMake 3.14
cmake_policy(SET CMP0092 NEW) # requires CMake 3.15
# Define project
project(%component% VERSION 1.0 LANGUAGES CXX)
# Use C++17 support
set(CMAKE_CXX_STANDARD 17)
# Library symbols are hidden by default
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
# Set the SDV_FRAMEWORK_DEV_INCLUDE if not defined yet
if (NOT DEFINED SDV_FRAMEWORK_DEV_INCLUDE)
if (NOT DEFINED ENV{SDV_FRAMEWORK_DEV_INCLUDE})
message( FATAL_ERROR "The environment variable SDV_FRAMEWORK_DEV_INCLUDE needs to be pointing to the SDV V-API development include files location!")
endif()
set (SDV_FRAMEWORK_DEV_INCLUDE "$ENV{SDV_FRAMEWORK_DEV_INCLUDE}")
endif()
# Include link to export directory of SDV V-API development include files location
include_directories(${SDV_FRAMEWORK_DEV_INCLUDE})
# Set platform specific compile flags
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
add_compile_options(/W4 /WX /wd4996 /wd4100 /permissive- /Zc:rvalueCast)
else()
add_compile_options(-Werror -Wall -Wextra -Wshadow -Wpedantic -Wunreachable-code -fno-common)
endif()
# Add the dynamic library
add_library(%component% SHARED)
# Set extension to .sdv
set_target_properties(%component% PROPERTIES PREFIX "")
set_target_properties(%component% PROPERTIES SUFFIX ".sdv")
)code";
CKeywordMap mapKeywords;
mapKeywords["component"] = rssComponent;
ssSource = ReplaceKeywords(ssSource, mapKeywords);
}
// Search function for caseless finding in the string.
auto fnNCFind = [&](const std::string& rssText, size_t nPos = 0) -> size_t
{
auto it = std::search(ssSource.begin() + nPos, ssSource.end(), rssText.begin(), rssText.end(),
[](unsigned char ch1, unsigned char ch2) { return std::tolower(ch1) == std::tolower(ch2); }
);
if (it == ssSource.end()) return std::string::npos;
return std::distance(ssSource.begin(), it);
};
// Find the add_library function
size_t nPos = fnNCFind("add_library");
if (nPos == std::string::npos) return; // TODO: Exception: throw CCompileException("Missing 'add_library' keyword.");
// Search for shared keyword
nPos = fnNCFind("shared", nPos);
if (nPos == std::string::npos) return; // TODO: Exception: throw CCompileException("Missing 'shared' keyword.");
nPos += 6;
// Build set with files
size_t nStop = fnNCFind(")", nPos);
if (nStop == std::string::npos) return; // TODO: Exception: throw CCompileException("Missing ')' closing the 'add_library' statement.");
std::set<std::string> setFiles;
while (nPos < nStop)
{
// Skip whitespace
while (std::isspace(ssSource[nPos])) nPos++;
// Read file name
size_t nFileBegin = nPos;
while (nPos < nStop && !std::isspace(ssSource[nPos])) nPos++;
// Store the file
setFiles.insert(ssSource.substr(nFileBegin, nPos - nFileBegin));
}
// Insert additional files if needed
size_t nSourceSize = ssSource.size();
if (setFiles.find("datalink.h") == setFiles.end())
ssSource.insert(nStop, std::string("\n datalink.h"));
if (setFiles.find("datalink.cpp") == setFiles.end())
ssSource.insert(nStop, std::string("\n datalink.cpp"));
// Write the file again if needed
if (nSourceSize != ssSource.size())
{
std::ofstream stream;
stream.open(pathFile, std::ofstream::trunc);
if (!stream.is_open()) return; // TODO: Exception: throw CCompileException("Failed to open the CMakeLists.txt file for writing.");
// Write the complete source
stream << ssSource;
}
}
CDbcUtilCMakeGenerator::~CDbcUtilCMakeGenerator()
{}

View File

@@ -0,0 +1,30 @@
#ifndef CMAKE_GENERATOR_H
#define CMAKE_GENERATOR_H
#include <filesystem>
#include <string>
#include "codegen_base.h"
/**
* @brief CMake generator class.
*/
class CDbcUtilCMakeGenerator : public CCodeGeneratorBase
{
public:
/**
* @brief Constructor
* @param[in] rpathOutputDir Reference to the outpur directory.
* @param[in] rssComponent Current component this CMake file is for.
*/
CDbcUtilCMakeGenerator(const std::filesystem::path& rpathOutputDir, const std::string& rssComponent);
/**
* @brief Destructor
*/
virtual ~CDbcUtilCMakeGenerator();
private:
std::filesystem::path m_pathProject; ///< Project file path
};
#endif // !defined CMAKE_GENERATOR_H

View File

@@ -0,0 +1,38 @@
#include "codegen_base.h"
#include <sstream>
std::string CCodeGeneratorBase::ReplaceKeywords(const std::string& rssStr, const CKeywordMap& rmapKeywords, char cMarker /*= '%'*/)
{
std::stringstream sstream;
size_t nPos = 0;
while (nPos < rssStr.size())
{
// Find the initial separator
size_t nSeparator = rssStr.find(cMarker, nPos);
sstream << rssStr.substr(nPos, nSeparator == std::string::npos ? nSeparator : nSeparator - nPos);
nPos = nSeparator;
if (nSeparator == std::string::npos) continue;
nPos++;
// Find the next separator.
nSeparator = rssStr.find(cMarker, nPos);
if (nSeparator == std::string::npos)
{
// Internal error: missing second separator during code building.
continue;
}
// Find the keyword in the keyword map (between the separator and the position).
CKeywordMap::const_iterator itKeyword = rmapKeywords.find(rssStr.substr(nPos, nSeparator - nPos));
if (itKeyword == rmapKeywords.end())
{
// Internal error: invalid keyword during building code.
nPos = nSeparator + 1;
continue;
}
sstream << itKeyword->second;
nPos = nSeparator + 1;
}
return sstream.str();
}

View File

@@ -0,0 +1,71 @@
#ifndef CODEGEN_BASE_H
#define CODEGEN_BASE_H
#include <map>
#include <string>
#include <sstream>
#include <cmath>
/**
* @brief Code generator base class.
*/
class CCodeGeneratorBase
{
protected:
/**
* @brief Keyword map for keyword replacement in a string.
*/
typedef std::map<std::string, std::string> CKeywordMap;
/**
* @brief Replace keywords in a string.
* @param[in] rssStr Reference to the string containing the keywords.
* @param[in] rmapKeywords Map with keywords to replace.
* @param[in] cMarker Character to identify the keyword with (placed before and after the keyword; e.g. %keyword%).
* @return Returns the string with replacements.
*/
static std::string ReplaceKeywords(const std::string& rssStr, const CKeywordMap& rmapKeywords, char cMarker = '%');
/**
* @brief Generator specific string generator. The std::to_string doesn't handle floating points very well.
* @tparam T Type of the variable to stringetize.
* @param[in] rtVar Reference to the variable.
* @return The generated string object.
*/
template <typename T>
static std::string to_string(const T& rtVar)
{
std::ostringstream sstream;
sstream << rtVar;
return sstream.str();
}
/**
* @brief Overloading for double.
* @param[in] rdVar Reference to the double variable.
* @return The generated string object.
*/
static std::string to_string(const double& rdVar)
{
std::ostringstream sstream;
sstream << rdVar;
if (std::round(rdVar) == rdVar) sstream << ".0";
return sstream.str();
}
/**
* @brief Overloading for float.
* @param[in] rfVar Reference to the float variable.
* @return The generated string object.
*/
static std::string to_string(const float& rfVar)
{
std::ostringstream sstream;
sstream << rfVar;
if (std::round(rfVar) == rfVar) sstream << ".0";
sstream << "f";
return sstream.str();
}
};
#endif // !defined CODEGEN_BASE_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,398 @@
#ifndef SOFTCAR_FMU_H
#define SOFTCAR_FMU_H
#ifdef WIN32
#include <Rpc.h>
#endif
#include "../global/dbcparser/dbcparser.h"
#include <fstream>
#include "codegen_base.h"
/**
* @brief Signal definition structure
*/
struct signalDefinition
{
std::string message_name; ///< Message name
std::string name; ///< Signal name
std::string attributes; ///< Attributes
uint32_t index = 0; ///< Index
bool isInput = false; ///< Is input signal
bool isDouble = false; ///< for FMU we distinguish only between integer and double (float)
uint32_t uiSize = 0; ///< everything > 8 we declare as isDouble
dbc::SSignalDef::EValueType signalType = dbc::SSignalDef::EValueType::signed_integer; ///< Signal type
};
/**
* @brief CAN data link generator class.
*/
class CSoftcarFMUGen : public CCodeGeneratorBase
{
public:
/**
* @brief Constructor
* @param[in] rpathOutputDir Reference to the outpur directory.
* @param[in] rparser Reference to the DBC parser containing the definitions.
* @param[in] ssModelIdentifier Reference to the modelIdentifier of the FMU.
* @param[in] rsVersion Reference to a string representing a version of the dbc file (could be empty).
* @param[in] rvecNodes Reference to a list of nodes this data link object is representing. An empty list will implement
* sending and receiving functions for all nodes.
*/
CSoftcarFMUGen(const std::filesystem::path& rpathOutputDir, const dbc::CDbcParser& rparser, const std::string& ssModelIdentifier, const std::string& rsVersion, const std::vector<std::string>& rvecNodes);
private:
/**
* @brief Keyword map for keyword replacement in a string.
*/
typedef std::map<std::string, std::string> CKeywordMap;
/**
* @brief Add keywords to the map.
* @param[in] rsModelIdentifier Reference to the modelIdentifier of the FMU.
* @param[in] rsVersion Reference to a string representing a version of the dbc file (could be empty).
* @param[in] rvecNodes Reference to a list of nodes this data link object is representing. An empty list will implement
* @param[in] rmapKeywords Map with keywords to replace.
* @return Returns the string with replacements.
*/
void UpdateKeywordMap(const std::string& rsModelIdentifier, const std::string& rsVersion,
const std::vector<std::string>& rvecNodes, CKeywordMap& rmapKeywords) const;
/**
* @brief Create files in the resources folder.
* @param[in] rRootPath parent folder
* @return Returns the string with replacements.
*/
void CreateResourcesFiles(const std::filesystem::path& rRootPath) const;
/**
* @brief Create files in the source folder.
* @param[in] rRootPath parent folder
* @return Returns the string with replacements.
*/
void CreateSourceFiles(const std::filesystem::path& rRootPath) const;
/**
* @brief Create files in the include folder.
* @param[in] rRootPath parent folder
* @return Returns the string with replacements.
*/
void CreateIncludeFiles(const std::filesystem::path& rRootPath) const;
/**
* @brief Create files in the include folder.
* @param[in] rRootPath parent folder
* @param[in] rsModelIdentifier Reference to the modelIdentifier of the FMU.
* @param[in] rmapKeywords Map with keywords to replace.
* @return Returns the string with replacements.
*/
void CreateFMUFiles(const std::filesystem::path& rRootPath, const std::string& rsModelIdentifier, CKeywordMap& rmapKeywords) const;
/**
* @brief Cleanup the directory except of the root cmake file
* @param[in] rpathRootDirectory root folder.
* @return Returns true if folder exists or could be created, otherwise false.
*/
bool CleanUpDirectory(const std::filesystem::path& rpathRootDirectory) const;
/**
* @brief Create subfolder if not exists
* @param[in] rpathRootDirectory root folder.
* @param[in] rpathSubDirectory sub folder.
* @return Returns true if folder exists or could be created, otherwise false.
*/
bool CreateDirectories(const std::filesystem::path& rpathRootDirectory, const std::filesystem::path& rpathSubDirectory) const;
/**
* @brief Create content of the signal_identifier file
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
* @return The code to insert.
*/
std::string Code_AllSignalsIdentifierList(const std::vector<signalDefinition>& rvecSignalDefinitions) const;
/**
* @brief Create single signal line of the signal_identifier file
* @param[in] rSignal Reference to the signal definition.
* @return The code to insert.
*/
std::string Code_SignalIdentifierList(const signalDefinition& rSignal) const;
/**
* @brief Replace keywords in a string.
* @param[in] rsStr Reference to the string containing the keywords.
* @param[in] rmapKeywords Map with keywords to replace.
* @param[in] cMarker Character to identify the keyword with (placed before and after the keyword; e.g. %keyword%).
* @return Returns the string with replacements.
*/
static std::string ReplaceKeywords(const std::string& rsStr, const CKeywordMap& rmapKeywords, char cMarker = '%');
/**
* @brief Composes the fmi build description xml
* @param[in] rsModelIdentifier Reference to model identifier.*
* @return The code to insert.
*/
std::string CodeBuildDescriptionXML(const std::string& rsModelIdentifier) const;
/**
* @brief Composes a dbc file version information string
* @param[in] rsVersion Reference to a string representing a version of the dbc file.
* @return The code to insert.
*/
std::string CodeDBCFileVersion(const std::string& rsVersion) const;
/**
* @brief returns a basic model identifier if not available
* @param[in] rsModelIdentifier Reference to a string representing a version of the dbc file.
* @return The code to insert.
*/
std::string CodeModelIdentifier(const std::string& rsModelIdentifier) const;
/**
* @brief Get List of variables for the fmi xml file.
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
* @return The code to insert.
*/
std::string CodeFMIFile_VariableList(const std::vector<signalDefinition>& rvecSignalDefinitions) const;
/**
* @brief Get List of variables for the fmi xml file.
* @param[in] rSignal Reference to the signal definition.
* @return The code to insert.
*/
std::string CodeFMIFile_SignalVariableList(const signalDefinition& rSignal) const;
/**
* @brief Get List of variables for the value reference in the config.h file.
* @param[in] rsMsg Reference to the DBC message to provide the code for.
* @param[in] rIndex Reference to the index of the variable starting with 0.
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
* @return The code to insert.
*/
std::string CodeConfigH_Rx_ValueReference(const dbc::SMessageDef& rsMsg, uint32_t& rIndex,
std::vector<signalDefinition>& rvecSignalDefinitions) const;
/**
* @brief Get List of variables for the value reference in the config.h file.
* @param[in] rsMsg Reference to the DBC message to provide the code for.
* @param[in] rIndex Reference to the index of the variable starting with 0.
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
* @return The code to insert.
*/
std::string CodeConfigH_Tx_ValueReference(const dbc::SMessageDef& rsMsg, uint32_t& rIndex,
std::vector<signalDefinition>& rvecSignalDefinitions) const;
/**
* @brief Get List of variables for the value reference in the config.h file.
* @param[in] rsSig Reference to the DBC signal to provide the information for.
* @param[in] index Reference to the index of the variable starting with 0.
* @param[in] rsMessageName Reference to the message name.
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
* @return The code to insert.
*/
std::string CodeConfigH_Rx_SignalForValueReference(const dbc::SSignalDef& rsSig, const uint32_t index,
const std::string& rsMessageName, std::vector<signalDefinition>& rvecSignalDefinitions) const;
/**
* @brief Get List of variables for the value reference in the config.h file.
* @param[in] rsSig Reference to the DBC signal to provide the information for.
* @param[in] index Reference to the index of the variable starting with 0.
* @param[in] rsMessageName Reference to the message name.
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
* @return The code to insert.
*/
std::string CodeConfigH_Tx_SignalForValueReference(const dbc::SSignalDef& rsSig, const uint32_t index,
const std::string& rsMessageName, std::vector<signalDefinition>& rvecSignalDefinitions) const;
/**
* @brief Get List of variables for the model data in the config.h file.
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
* @return The code to insert.
*/
std::string CodeConfigH_ModelDataList(const std::vector<signalDefinition>& rvecSignalDefinitions) const;
/**
* @brief Get List of variables for the model data in the config.h file.
* @param[in] rSignal Reference to the signal definition.
* @return The code to insert.
*/
std::string CodeConfigH_SignalForModelData(const signalDefinition& rSignal) const;
/**
* @brief Get List of variables for the mapping trigger file.
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
* @return The code to insert.
*/
std::string CodeVariableList(const std::vector<signalDefinition>& rvecSignalDefinitions) const;
/**
* @brief Get List of variables for the mapping trigger file.
* @param[in] rSignal Reference to the signal definition.
* @return The code to insert.
*/
std::string CodeVariableName(const signalDefinition& rSignal) const;
/**
* @brief Get List of global signals definitions for the model.cpp file.
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
* @return The code to insert.
*/
std::string CodeModelCPP_GlobalDefinitionList(const std::vector<signalDefinition>& rvecSignalDefinitions) const;
/**
* @brief Get global signal definitions for the model.cpp file.
* @param[in] rSignal Reference to the signal definition.
* @return The code to insert.
*/
std::string CodeModelCPP_GlobalSignalDefinition(const signalDefinition& rSignal) const;
/**
* @brief Get List of registering the global signals for the model.cpp file.
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
* @return The code to insert.
*/
std::string CodeModelCPP_GlobalRegisterList(const std::vector<signalDefinition>& rvecSignalDefinitions) const;
/**
* @brief Check list of registered global signals for the model.cpp file.
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
* @return The code to insert.
*/
std::string CodeModelCPP_GlobalRegisterCheckList(const std::vector<signalDefinition>& rvecSignalDefinitions) const;
/**
* @brief Get registering the a global signal for the model.cpp file.
* @param[in] rSignal Reference to the signal definition.
* @return The code to insert.
*/
std::string CodeModelCPP_GlobalRegisterSignal(const signalDefinition& rSignal) const;
/**
* @brief Get check of a global signal for the model.cpp file.
* @param[in] rSignal Reference to the signal definition.
* @param[in] first should be true for the first call, otherwise false.
* @return The code to insert.
*/
std::string CodeModelCPP_GlobalRegisterSignalCheck(const signalDefinition& rSignal, bool first) const;
/**
* @brief Get List of resetting the global signals for the model.cpp file.
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
* @return The code to insert.
*/
std::string CodeModelCPP_GlobalResetList(const std::vector<signalDefinition>& rvecSignalDefinitions) const;
/**
* @brief Get resetting the a global signal for the model.cpp file.
* @param[in] rSignal Reference to the signal definition.
* @return The code to insert.
*/
std::string CodeModelCPP_GlobalResetSignal(const signalDefinition& rSignal) const;
/**
* @brief Get List of signals for the update event for the model.cpp file.
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
* @return The code to insert.
*/
std::string CodeModelCPP_EventUpdateList(const std::vector<signalDefinition>& rvecSignalDefinitions) const;
/**
* @brief Get Signal for writing int the update event method for the model.cpp file.
* @param[in] rSignal Reference to the signal definition.
* @return The code to insert.
*/
std::string CodeModelCPP_EventUpdateSignalDefinitionWrite(const signalDefinition& rSignal) const;
/**
* @brief Get Signal for reading the update event method for the model.cpp file.
* @param[in] rSignal Reference to the signal definition.
* @return The code to insert.
*/
std::string CodeModelCPP_EventUpdateSignalDefinitionRead(const signalDefinition& rSignal) const;
/**
* @brief Get List of signals for the GetFloat64 method for the model.cpp file.
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
* @return The code to insert.
*/
std::string CodeModelCPP_GetFloat64(const std::vector<signalDefinition>& rvecSignalDefinitions) const;
/**
* @brief Get List of signals for the GetInt32 method for the model.cpp file.
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
* @return The code to insert.
*/
std::string CodeModelCPP_GetInt32(const std::vector<signalDefinition>& rvecSignalDefinitions) const;
/**
* @brief Get List of signals for the SetFloat64 method for the model.cpp file.
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
* @return The code to insert.
*/
std::string CodeModelCPP_SetFloat64(const std::vector<signalDefinition>& rvecSignalDefinitions) const;
/**
* @brief Get List of signals for the SetInt32 method for the model.cpp file.
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
* @return The code to insert.
*/
std::string CodeModelCPP_SetInt32(const std::vector<signalDefinition>& rvecSignalDefinitions) const;
/**
* @brief Get Signal for GetFloat64 method for the model.cpp file.
* @param[in] rSignal Reference to the signal definition.
* @return The code to insert.
*/
std::string CodeModelCPP_GetFloat64SignalDefinition(const signalDefinition& rSignal) const;
/**
* @brief Get Signal for GetInt32 method for the model.cpp file.
* @param[in] rSignal Reference to the signal definition.
* @return The code to insert.
*/
std::string CodeModelCPP_GetInt32SignalDefinition(const signalDefinition& rSignal) const;
/**
* @brief Get Signal for SetFloat64 method for the model.cpp file.
* @param[in] rSignal Reference to the signal definition.
* @return The code to insert.
*/
std::string CodeModelCPP_SetFloat64SignalDefinition(const signalDefinition& rSignal) const;
/**
* @brief Get Signal for SetInt32 method for the model.cpp file.
* @param[in] rSignal Reference to the signal definition.
* @return The code to insert.
*/
std::string CodeModelCPP_SetInt32SignalDefinition(const signalDefinition& rSignal) const;
/**
* @brief Get comment for the OpenAPILoad function for the model.cpp file.
* @return The code to insert.
*/
std::string CodeModelCPP_OpenAPILoadFunction() const;
/**
* @brief Get default value of a tx signal. Used as start value un the build description.
* @param[in] rSignal Reference to the signal definition.
* @return The code to insert.
*/
std::string CodeGetDefaultValueOfTxSignal(const dbc::SSignalDef& rSignal) const;
/**
* @brief Get minimum and maximum of a signal
* @param[in] rSignal Reference to the signal definition.
* @param[in] isDouble Reference to bool variable. Signal is either integer or double.
* @return The code to insert.
*/
std::string GetAttributes(const dbc::SSignalDef& rSignal, const bool& isDouble) const;
/**
* @brief returns guid string
* @return The guid.
*/
std::string newUUID() const;
const dbc::CDbcParser& m_rparser; ///< Reference to the DBC parser.
};
#endif // !defined SOFTCAR_FMU_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,550 @@
/**
* @brief Build description template. File 'buildDescription.xml'. Code chunks are inserted at the keywords surrounded by %%.
*/
const char szBuildDescriptionTemplate[] = R"code(<!--
@file %buiddescription_path%
@date %date%
This file is the fmi Build Description xml.
This file was generated by the DBC utility from:
%dbc_sources%
%dbc_version%
-->
%buildDescription_xml%
)code";
/**
* @brief CMake build project template. File 'CMakeLists.txt'. Code chunks are inserted at the keywords surrounded by %%.
*/
const char szMappingCMakeFileListsTemplate[] = R"code(
# @file %cmakefilelists_path%
# This file is cmake project file.
# This file was generated by the DBC utility from:
# %dbc_sources%
# %dbc_version%
# Based on CMakeLists.txt from https://github.com/modelica/Reference-FMUs
# only FMI 2.0, only CoSimulation
# without fumsim
# Only valid for Windows
if ( WIN32 )
# Enforce CMake version 3.20 or newer needed for path function
cmake_minimum_required (VERSION 3.20)
# Use new policy for project version settings and default warning level
cmake_policy(SET CMP0048 NEW) # requires CMake 3.14
cmake_policy(SET CMP0092 NEW) # requires CMake 3.15
project (%model_Identifier%Project)
# Use C++17 support
set(CMAKE_CXX_STANDARD 17)
# Library symbols are hidden by default
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
# Set the SDV_FRAMEWORK_DEV_INCLUDE if not defined yet
if (NOT DEFINED SDV_FRAMEWORK_DEV_INCLUDE)
if (NOT DEFINED ENV{SDV_FRAMEWORK_DEV_INCLUDE})
message( FATAL_ERROR "The environment variable SDV_FRAMEWORK_DEV_INCLUDE needs to be pointing to the SDV V-API development include files location!")
endif()
set (SDV_FRAMEWORK_DEV_INCLUDE "$ENV{SDV_FRAMEWORK_DEV_INCLUDE}")
endif()
# Include link to export directory of SDV V-API development include files location
include_directories(${SDV_FRAMEWORK_DEV_INCLUDE})
set(VAPI_CORE_SDV_BINARY_DIR ${CMAKE_BINARY_DIR}/bin)
set(MODEL_NAME %model_Identifier%)
set(TARGET_NAME ${MODEL_NAME})
set(FMU_FULL_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/fmus/${MODEL_NAME}.fmu")
FUNCTION(cat IN_FILE OUT_FILE)
file(READ ${IN_FILE} CONTENTS)
file(APPEND ${OUT_FILE} "${CONTENTS}")
ENDFUNCTION()
set(FMI_VERSION 2 CACHE STRING "FMI Version")
set_property(CACHE FMI_VERSION PROPERTY STRINGS 2)
set(FMI_TYPE CS CACHE STRING "FMI Version")
set_property(CACHE FMI_TYPE PROPERTY STRINGS CS)
set(FMI_TYPE "")
set (FMI_PLATFORM win32)
if ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
set (FMI_PLATFORM win64)
endif ()
SET(HEADERS
${MODEL_NAME}/config.h
include/cosimulation.h
include/model.h
)
SET(HEADERS
${HEADERS}
include/fmi2Functions.h
include/fmi2FunctionTypes.h
include/fmi2TypesPlatform.h
)
SET(SOURCES
${MODEL_NAME}/model.cpp
src/fmi${FMI_VERSION}Functions.c
src/cosimulation.c
)
add_library(${TARGET_NAME} SHARED
${HEADERS}
${SOURCES}
${MODEL_NAME}/FMI${FMI_VERSION}${FMI_TYPE}.xml
${MODEL_NAME}/buildDescription.xml
)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/fmus)
set(FMU_BUILD_DIR temp/${MODEL_NAME})
target_compile_definitions(${TARGET_NAME} PRIVATE
FMI_VERSION=${FMI_VERSION}
DISABLE_PREFIX
)
#[[
if (MSVC)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libstdc++ -static-libgcc")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libstdc++ -static-libgcc")
endif()
]]
target_compile_definitions(${TARGET_NAME} PRIVATE FMI_COSIMULATION)
target_include_directories(${TARGET_NAME} PRIVATE include ${MODEL_NAME})
target_link_libraries(${TARGET_NAME} Winmm Ws2_32 Rpcrt4.lib)
set_target_properties(${TARGET_NAME} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}"
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}"
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}"
LIBRARY_OUTPUT_DIRECTORY "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}"
LIBRARY_OUTPUT_DIRECTORY_DEBUG "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}"
LIBRARY_OUTPUT_DIRECTORY_RELEASE "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}"
ARCHIVE_OUTPUT_DIRECTORY "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}"
ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}"
ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}"
)
set_target_properties(${TARGET_NAME} PROPERTIES PREFIX "")
set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${MODEL_NAME})
# modelDescription.xml
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/${MODEL_NAME}/FMI${FMI_VERSION}${FMI_TYPE}.xml
"${FMU_BUILD_DIR}/modelDescription.xml"
)
set(ARCHIVE_FILES "modelDescription.xml" "binaries")
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${MODEL_NAME}/resources")
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory
"${CMAKE_CURRENT_SOURCE_DIR}/${MODEL_NAME}/resources"
"${FMU_BUILD_DIR}/resources/"
)
set(ARCHIVE_FILES ${ARCHIVE_FILES} "resources")
endif()
# When windows robocopy command (using cmd.exe) is used to copy files its important to set the dependencies
# to assure that the copy command is finished before the next custom action to avoid copy/file access failures
# Copy sdv binaries of this FMU
set(DEST_DIR "${FMU_BUILD_DIR}/resources")
set(SOURCE_DIR_EXAMPLES_BIN "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
add_custom_target(copy_function_sdv_files_${TARGET_NAME} DEPENDS ${TARGET_NAME})
add_custom_command(TARGET copy_function_sdv_files_${TARGET_NAME}
COMMAND cmd /C "robocopy \"${SOURCE_DIR_EXAMPLES_BIN}\" \"${DEST_DIR}\" *.pdb *.sdv /NP /R:3 /W:5 || exit /b 0"
COMMENT "Copying contents from ${SOURCE_DIR_EXAMPLES_BIN} to ${DEST_DIR}, include only *.pdb *.sdv files"
)
add_dependencies(copy_function_sdv_files_${TARGET_NAME} ${TARGET_NAME})
# Copy framework sdv binaries
set(SOURCE_DIR_CORE_BIN "${SDV_FRAMEWORK_RUNTIME}")
add_custom_target(copy_framework_sdv_files_${TARGET_NAME} DEPENDS copy_function_sdv_files_${TARGET_NAME})
add_custom_command(TARGET copy_framework_sdv_files_${TARGET_NAME}
COMMAND cmd /C "robocopy \"${SOURCE_DIR_CORE_BIN}\" \"${DEST_DIR}\" *.pdb *.sdv /NP /R:3 /W:5 || exit /b 0"
COMMENT "Copying contents from ${SOURCE_DIR_CORE_BIN} to ${DEST_DIR}, include only *.pdb *.sdv files"
)
add_dependencies(copy_framework_sdv_files_${TARGET_NAME} copy_function_sdv_files_${TARGET_NAME})
# FMU content created, all files copied
# to zip the files create a new target 'create_zip' which is build after all files have been copied
add_custom_target(create_zip_${TARGET_NAME} ALL DEPENDS copy_framework_sdv_files_${TARGET_NAME} )
add_custom_command(TARGET create_zip_${TARGET_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E tar "cfv" ${FMU_FULL_FILE_NAME} --format=zip ${ARCHIVE_FILES}
WORKING_DIRECTORY ${FMU_BUILD_DIR}
COMMENT "Creating ZIP ${FMU_FULL_FILE_NAME}"
)
add_dependencies(create_zip_${TARGET_NAME} copy_framework_sdv_files_${TARGET_NAME})
#TODO
#add_dependencies(${TARGET_NAME} <add_cmake_target_this_depends_on>)
endif ()
)code";
/**
*@brief Config Header template. File 'config.h'. Code chunks are inserted at the keywords surrounded by %%.
*/
const char szConfigHTemplate[] = R"code(/**
* @file %configH_path%
* @date %date%
* This file defines the data link object between CAN and the V-API devices.
* This file was generated by the DBC utility from:
* %dbc_sources%
* %dbc_version%
*/
#ifndef %safeguardconfig%
#define %safeguardconfig%
#include <stdint.h>
// define class name and unique id
#define MODEL_IDENTIFIER %model_Identifier%
#define INSTANTIATION_TOKEN "%model_guid%"
#define FMI_VERSION 2
#define CO_SIMULATION
// define model size
#define NX 0
#define NZ 0
#define GET_INT32
#define SET_INT32
#define GET_FLAOT64
#define SET_FLOAT64
#define EVENT_UPDATE
#define CLEAN_UP
#define FIXED_SOLVER_STEP 0.04
#define DEFAULT_STOP_TIME 10
typedef enum {
%value_reference%
} ValueReference;
typedef struct {
%model_data%
} ModelData;
#endif // !defined %safeguardconfig%
)code";
/**
*@brief FMI2 xml template. File 'FMI2.XML'. Code chunks are inserted at the keywords surrounded by %%.
*/
const char szFMI2XMLTemplate[] = R"code(<?xml version="1.0" encoding="UTF-8"?>
<fmiModelDescription
fmiVersion = "2.0"
modelName = "%model_Identifier%"
guid = "%model_guid%"
description = "TargetLink FMU for %model_Identifier%"
generationTool = "TargetLink was generated by the DBC utility: %dbc_sources%"
generationDateAndTime = "%date%"
variableNamingConvention = "structured"
numberOfEventIndicators = "0">
<CoSimulation
modelIdentifier = "%model_Identifier%"
canHandleVariableCommunicationStepSize = "false"
canGetAndSetFMUstate = "false"
canSerializeFMUstate = "false"
providesDirectionalDerivative = "false"
canBeInstantiatedOnlyOncePerProcess = "true"
canInterpolateInputs = "false"
canRunAsynchronuously = "false">
<SourceFiles>
<File name="all.c"/>
</SourceFiles>
</CoSimulation>
<DefaultExperiment startTime="0" stepSize="0.01"/>
<ModelVariables>
%model_variables%
</ModelVariables>
<ModelStructure>
<Outputs>
<Unknown index="%unknown_index%"/>
</Outputs>
</ModelStructure>
</fmiModelDescription>
)code";
/**
*@brief Model cpp template. File 'model.cpp'. Code chunks are inserted at the keywords surrounded by %%.
*/
const char szModelCPPTemplate[] = R"code(/**
* @file %modelcpp_path%
* @date %date%
* This file defines the data link object between CAN and the V-API devices.
* This file was generated by the DBC utility from:
* %dbc_sources%
* %dbc_version%
*/
#include <memory>
#include <vector>
#include <iostream>
#include <fstream>
#include <support/timer.h>
#include "signal_identifier.h"
#include <support/signal_support.h>
#include <support/app_control.h>
%global_signals%
// in case the simulation timer should be used
sdv::core::ITimerSimulationStep* g_pTimerSimulationStep;
std::unique_ptr<sdv::app::CAppControl> g_appcontrol;
bool InitializeAppControl(const std::string& resource, const std::string& configFileName)
{
auto bResult = g_appcontrol->AddModuleSearchDir( resource );
bResult &= g_appcontrol->Startup("");
g_appcontrol->SetConfigMode();
bResult &= g_appcontrol->AddConfigSearchDir( resource );
if (!configFileName.empty())
{
bResult &= g_appcontrol->LoadConfig(configFileName.c_str()) == sdv::core::EConfigProcessResult::successful;
}
return bResult;
}
sdv::core::EConfigProcessResult RegisterAllSignals()
{
std::string msg = "register all signals: ";
sdv::core::CDispatchService dispatch;
%global_signals_register%
%global_signals_register_check%
return sdv::core::EConfigProcessResult::failed;
}
bool ResetAllSignals()
{
sdv::core::CDispatchService dispatch;
%global_signals_reset%
SDV_LOG_INFO("Reset signals");
return true;
}
bool CreateCoreServiceTomlFile(const std::string& resources)
{
std::ofstream tomlFile("sdv_core_reloc.toml");
if (tomlFile.is_open())
{
tomlFile << "# Location of the SDV binaries and configuration files\ndirectory = \"";
tomlFile << resources;
tomlFile << "\"\n";
tomlFile.close();
return true;
}
return false;
}
bool OpenAPILoad(const std::string& resources)
{
bool success = CreateCoreServiceTomlFile(resources);
g_appcontrol = std::make_unique<sdv::app::CAppControl> ();
//
// TODO: Dispatch service must be loaded first, adjust the correct toml file
//
success &= InitializeAppControl(resources, "data_dispatch_config_file.toml");
if (!success)
{
std::cout << "Error: InitializeAppControl() failed" << std::endl;
SDV_LOG_ERROR("Failed InitializeAppControl");
return false;
}
success &= RegisterAllSignals() == sdv::core::EConfigProcessResult::successful;
if (!success)
{
SDV_LOG_ERROR("Signals could not be registered");
}
%vapi_load_config_files%
g_appcontrol->SetRunningMode();
return success;
}
void OpenAPIShutdown()
{
ResetAllSignals();
}
#ifdef __cplusplus
extern "C" {
#endif
#include <float.h> // for DBL_EPSILON
#include <math.h> // for fabs()
#include "config.h"
#include "model.h"
Status cleanup(ModelInstance*)
{
SDV_LOG_INFO("Shutting down...");
OpenAPIShutdown();
return OK;
}
bool setStartValues(ModelInstance* comp)
{
std::string path(comp->resourceLocation);
std::string resourcePath = path.substr(8);
std::replace(resourcePath.begin(), resourcePath.end(), '\\', '/');
if (!OpenAPILoad(resourcePath))
{
std::cout << "Error: OpenAPILoad() failed." << std::endl;
comp->terminateSimulation = true;
return false;
}
// TODO: move this to initialize()?
comp->nextEventTime = 0;
comp->nextEventTimeDefined = true;
return true;
}
Status calculateValues(ModelInstance* comp)
{
UNUSED(comp);
// nothing to do
return OK;
}
Status getFloat64(ModelInstance* comp, [[maybe_unused]] ValueReference vr, [[maybe_unused]] double values[], [[maybe_unused]] size_t nValues, [[maybe_unused]] size_t* index)
{
ASSERT_NVALUES(1);
%getFloat64%
return OK;
}
Status getInt32(ModelInstance* comp, [[maybe_unused]] ValueReference vr, [[maybe_unused]] int32_t values[], [[maybe_unused]] size_t nValues, [[maybe_unused]] size_t* index)
{
ASSERT_NVALUES(1);
%getInt32%
return OK;
}
Status setFloat64(ModelInstance* comp, [[maybe_unused]] ValueReference vr, [[maybe_unused]] const double values[], [[maybe_unused]] size_t nValues, [[maybe_unused]] size_t* index)
{
ASSERT_NVALUES(1);
%setFloat64%
return OK;
}
Status setInt32(ModelInstance* comp, [[maybe_unused]] ValueReference vr, [[maybe_unused]] const int32_t values[], [[maybe_unused]] size_t nValues, [[maybe_unused]] size_t* index)
{
ASSERT_NVALUES(1);
%setInt32%
return OK;
}
void eventUpdate(ModelInstance* comp)
{
%event_update%
double epsilon = (1.0 + fabs(comp->time)) * DBL_EPSILON;
if (comp->nextEventTimeDefined && comp->time + epsilon >= comp->nextEventTime) {
comp->nextEventTime += FIXED_SOLVER_STEP;
}
comp->valuesOfContinuousStatesChanged = false;
comp->nominalsOfContinuousStatesChanged = false;
comp->terminateSimulation = false;
comp->nextEventTimeDefined = true;
}
#ifdef __cplusplus
} // end of extern "C"
#endif
)code";
/**
*@brief Signal name mapping template. Signal names contain the can names of the signal which must match the names of the vehicle devices.
* File 'signal_identifier.h'. Code chunks are inserted at the keywords surrounded by %%.
*/
const char szMappingSignalIdentifierTemplate[] = R"code(/**
@file %signalidentifierfile_path%
@date %date%
This file is the signal identifier header.
This file was generated by the DBC utility from:
%dbc_sources%
%dbc_version%
*/
#ifndef %safeguardsignalidentifier%
#define %safeguardsignalidentifier%
namespace %object_prefix%
{
// Data Dispatch Service signal names to dbc variable names C-type RX/TX vss name space
%signals%
} // %object_prefix%
#endif // %safeguardsignalidentifier%
)code";
/**
*@brief Data dispatch service config template. File 'data_dispatch_config_file.toml'. Code chunks are inserted at the keywords surrounded by %%.
*/
const char szDataDispatchServiceTomlFile[] = R"code([Configuration]
Version = 100
[[Component]]
Path = "data_dispatch_service.sdv"
Class = "DataDispatchService"
)code";
/**
*@brief Simulation task timer service config template. File 'simulation_task_timer_config_file.toml'. Code chunks are inserted at the keywords surrounded by %%.
*/
const char szSimulationTaskTimerServiceTomlFile[] = R"code([Configuration]
Version = 100
[[Component]]
Path = "simulation_task_timer.sdv"
Class = "SimulationTaskTimerService"
)code";
/**
*@brief Task timer service config template. File 'task_timer_config_file.toml'. Code chunks are inserted at the keywords surrounded by %%.
*/
const char szTaskTimerhServiceTomlFile[] = R"code([Configuration]
Version = 100
[[Component]]
Path = "task_timer.sdv"
Class = "TaskTimerService"
)code";

View File

@@ -0,0 +1,103 @@
#include "../../global/process_watchdog.h"
#include <interfaces/core.h>
#include <interfaces/mem.h>
#include "../../global/cmdlnparser/cmdlnparser.cpp"
#include "../../global/dbcparser/dbcparser.cpp"
#include "../../global/localmemmgr.h"
#include <iostream>
#include "can_dl.h"
#include "fmu.h"
#include "cmake_generator.h"
#include "../error_msg.h"
#if defined(_WIN32) && defined(_UNICODE)
extern "C" int wmain(int iArgc, const wchar_t* rgszArgv[])
#else
extern "C" int main(int iArgc, const char* rgszArgv[])
#endif
{
// Workaround for GCC to make certain that POSIX thread library is loaded before the components are loaded.
// REASON: If the first call to a thread is done in a dynamic library, the application is already classified as single
// threaded and a termination is initiated.
// See: https://stackoverflow.com/questions/51209268/using-stdthread-in-a-library-loaded-with-dlopen-leads-to-a-sigsev
// NOTE EVE 27.05.2025: This task has been taken over by the process watchdog.
CProcessWatchdog watchdog;
// Suppress the warning supplied by ccpcheck about an unsused variable. The memory manager registers itself into the system and
// needs to stay in scope.
// cppcheck-suppress unusedVariable
CLocalMemMgr memmgr;
CCommandLine cmdln(static_cast<uint32_t>(CCommandLine::EParseFlags::no_assignment_character));
bool bHelp = false;
bool bError = false;
bool bSilent = false;
bool bVerbose = false;
size_t nIfcIndex = 0;
std::string ssIfcName;
std::string ssVersion;
std::string ssModelIdentifier;
std::string ssDataLinkLibName = "can_dl";
std::vector<std::filesystem::path> vecFileNames;
std::vector<std::string> vecNodes;
std::filesystem::path pathOutputDir;
try
{
auto& rArgHelpDef = cmdln.DefineOption("?", bHelp, "Show help");
rArgHelpDef.AddSubOptionName("help");
auto& rArgSilentDef = cmdln.DefineOption("s", bSilent, "Do not show any information on STDOUT. Not compatible with 'verbose'.");
rArgSilentDef.AddSubOptionName("silent");
auto& rArgVerboseDef = cmdln.DefineOption("v", bVerbose, "Provide verbose information. Not compatible with 'silent'.");
rArgVerboseDef.AddSubOptionName("verbose");
cmdln.DefineSubOption("version", ssVersion, "Optional: version information of the dbc file.");
cmdln.DefineSubOption("module", ssModelIdentifier, "Optional: module identifier for the fmu. Default 'BasicModelIdentifier'");
cmdln.DefineSubOption("dl_lib_name", ssDataLinkLibName, "Data link library target name in the generated cmake file (default=\"can_dl\")..");
cmdln.DefineOption("O", pathOutputDir, "Set output directory");
cmdln.DefineSubOption("ifc_idx", nIfcIndex, "Interface index this DBC file is aiming for.");
cmdln.DefineSubOption("ifc_name", ssIfcName, "Name of the interface this DBC file is aiming for.");
cmdln.DefineSubOption("nodes", vecNodes, "List of nodes that will be implemented.");
cmdln.DefineDefaultArgument(vecFileNames, "One or more DBC files");
cmdln.Parse(static_cast<size_t>(iArgc), rgszArgv);
} catch (const SArgumentParseException& rsExcept)
{
std::cout << "ERROR: " << rsExcept.what() << std::endl;
bHelp = true;
bError = true;
}
if (!bSilent)
{
std::cout << "DBC utility" << std::endl;
std::cout << "Copyright (C): 2022-2025 ZF Friedrichshafen AG" << std::endl;
std::cout << "Author: Erik Verhoeven" << std::endl;
}
if (bHelp)
{
if (!bSilent)
cmdln.PrintHelp(std::cout);
return bError ? CMDLN_ARG_ERR : NO_ERROR;
}
dbc::CDbcParser parser;
for (const std::filesystem::path& rpath : vecFileNames)
{
try
{
if (bVerbose)
std::cout << "Processing: " << rpath.generic_u8string() << std::endl;
dbc::CDbcSource src(rpath);
parser.Parse(src);
CSoftcarFMUGen fmu(pathOutputDir, parser, ssModelIdentifier, ssVersion, vecNodes);
CCanDataLinkGen dl(pathOutputDir, parser, ssVersion, ssIfcName, nIfcIndex, vecNodes);
CDbcUtilCMakeGenerator cmakegen(pathOutputDir, ssDataLinkLibName);
}
catch (dbc::SDbcParserException& rsException)
{
if (!bSilent)
std::cout << "ERROR " << LOAD_DBC_FILE_ERROR_MSG << " Reason: " << rsException.what() << std::endl;
return LOAD_DBC_FILE_ERROR;
}
}
return NO_ERROR;
}