/** * @file model.cpp * @date 2025-09-12 15:01:57 * This file defines the data link object between CAN and the V-API devices. * This file was generated by the DBC utility from: * datalink_autoheadlight_example.dbc * DBC file version: 1.0.0.1 */ #include #include #include #include #include #include "signal_identifier.h" #include #include sdv::core::CSignal g_signalCurrent_Longitude; sdv::core::CSignal g_signalCurrent_Latitude; sdv::core::CSignal g_signalHeadLight_LowBeam; // in case the simulation timer should be used sdv::core::ITimerSimulationStep* g_pTimerSimulationStep; std::unique_ptr 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; g_signalCurrent_Longitude = dispatch.RegisterRxSignal("CAN_Input.Current_Longitude"); g_signalCurrent_Latitude = dispatch.RegisterRxSignal("CAN_Input.Current_Latitude"); g_signalHeadLight_LowBeam = dispatch.RegisterTxSignal("CAN_Output.HeadLight_LowBeam",0); if (g_signalCurrent_Longitude && g_signalCurrent_Latitude && g_signalHeadLight_LowBeam) { return sdv::core::EConfigProcessResult::successful; } return sdv::core::EConfigProcessResult::failed; } bool ResetAllSignals() { sdv::core::CDispatchService dispatch; if (g_signalCurrent_Longitude) { g_signalCurrent_Longitude.Reset(); } if (g_signalCurrent_Latitude) { g_signalCurrent_Latitude.Reset(); } if (g_signalHeadLight_LowBeam) { g_signalHeadLight_LowBeam.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 (); // // 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"); } // // // TODO: Load all configurations files // // // Get the simulation task timer service if the simulation timer should be used success &= g_appcontrol->LoadConfig("simulation_task_timer_config_file.toml") == sdv::core::EConfigProcessResult::successful; g_pTimerSimulationStep = sdv::core::GetObject("SimulationTaskTimerService"); if (!g_pTimerSimulationStep) { SDV_LOG_WARNING("Simulation timer step not available, use normal task timer "); success &= g_appcontrol->LoadConfig("task_timer_config_file.toml") == sdv::core::EConfigProcessResult::successful; } success &= g_appcontrol->LoadConfig("fmu_autoheadlight_vd_bs.toml") == sdv::core::EConfigProcessResult::successful; success &= g_appcontrol->LoadConfig("fmu_autoheadlight_cs.toml") == sdv::core::EConfigProcessResult::successful; g_appcontrol->SetRunningMode(); return success; } void OpenAPIShutdown() { ResetAllSignals(); } #ifdef __cplusplus extern "C" { #endif #include // for DBL_EPSILON #include // 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); switch (vr) { case vr_Current_Longitude: values[(*index)++] = M(Current_Longitude); break; case vr_Current_Latitude: values[(*index)++] = M(Current_Latitude); break; default: logError(comp, "Get Float64 is not allowed for value reference u.", vr); return Error; } 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); switch (vr) { case vr_HeadLight_LowBeam: values[(*index)++] = M(HeadLight_LowBeam); break; default: logError(comp, "Get Int32 is not allowed for value reference u.", vr); return Error; } 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); switch (vr) { case vr_Current_Longitude: M(Current_Longitude) = values[(*index)++]; break; case vr_Current_Latitude: M(Current_Latitude) = values[(*index)++]; break; default: logError(comp, "Set Float64 is not allowed for value reference u.", vr); return Error; } 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); switch (vr) { case vr_HeadLight_LowBeam: M(HeadLight_LowBeam) = values[(*index)++]; break; default: logError(comp, "Set Int32 is not allowed for value reference u.", vr); return Error; } return OK; } void eventUpdate(ModelInstance* comp) { if (g_pTimerSimulationStep) // in case the simulation timer was used, maybe the step size has to be adjusted { g_pTimerSimulationStep->SimulationStep(1000); } g_signalCurrent_Longitude.Write( M(Current_Longitude)); g_signalCurrent_Latitude.Write( M(Current_Latitude)); M(HeadLight_LowBeam) = g_signalHeadLight_LowBeam.Read().get(); 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