connection between 2 systems and bug fixes (#14)

This commit is contained in:
tompzf
2026-07-03 14:53:48 +02:00
committed by GitHub
parent 0fb5660d27
commit 46842200f1
284 changed files with 35200 additions and 8265 deletions

View File

@@ -119,6 +119,9 @@ else()
if (WIN32)
message("Use g++ compiler under Windows (mingw)...")
add_compile_definitions(UNICODE _UNICODE main=wmain)
# MinGW COFF object files can hit section limits for large translation units.
# Enable big object format to avoid assembler 'too many sections' failures.
add_compile_options(-Wa,-mbig-obj)
add_link_options(-municode)
else()
message("Use g++ compiler...")

View File

@@ -1,3 +1,20 @@
The 'Eclipse Open Vehicle API' project is supported by Chips JU.
<img src="funding_logos\CHIPS_logo_RGB_full_colour.png" alt="arch-module-if" height="80"/>
<img src="funding_logos\EN_Co-fundedbytheEU_RGB_POS.png" alt="arch-module-if" height="80"/>
The HAL4SDV project (Grant Agreement No. 101139789) is supported by the Chips Joint Undertaking and its members, including top-up funding by the national authorities.
<img src="funding_logos\HAL4SDV_logo_on_white.jpg" alt="arch-module-if" height="80"/>
The Shift2SDV project (Grant Agreement No. 101194245) is supported by the Chips Joint Undertaking and its members, including top-up funding by the national authorities.
<img src="funding_logos\Shift2sdv_logo_tagline_blue.svg" alt="arch-module-if" height="80"/>
---
# This is the latest news about 'Eclipse Open Vehicle API'
#
# for more information see documentation: https://eclipse.dev/openvehicle-api/

File diff suppressed because it is too large Load Diff

View File

@@ -353,7 +353,7 @@ void CConsole::StartUpdateDataThread()
m_bThreadStarted = true;
m_bRunning = true;
m_threadReadTxSignals = std::thread(&CConsole::UpdateDataThreadFunc, this);
m_threadReadTxSignals = sdv::core::secure_thread(&CConsole::UpdateDataThreadFunc, this);
}
void CConsole::StopUpdateDataThread()

View File

@@ -201,7 +201,7 @@ private:
std::string AlignString(const std::string& message, uint32_t desiredLength = 0);
mutable std::mutex m_mtxPrintToConsole; ///< Mutex to print complete message
std::thread m_threadReadTxSignals; ///< Simulation datalink thread.
sdv::core::secure_thread m_threadReadTxSignals; ///< Simulation datalink thread.
bool m_bThreadStarted = false; ///< Set when initialized.
std::atomic_bool m_bRunning = false; ///< When set, the application is running.

View File

@@ -94,7 +94,10 @@ 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 << R"toml(# Location of the SDV binaries and configuration files
[CoreLocation]
Version = 100
Framework = ")toml";
tomlFile << resources;
tomlFile << "\"\n";
tomlFile.close();

View File

@@ -43,59 +43,63 @@ file (COPY ${PROJECT_SOURCE_DIR}/door_example_receiver.asc DESTINATION ${CMAKE_B
######################################################################################################################################################################
# Execute sdv_vss_util to create IDL files for devices and basic services.
# In this example we split into into front and rear (frontdoors_proxystub.sdv and frontdoors_proxystub.sdv)
# because all interfaces combined in doors_proxystub.sdv would be to large
message("Create interface code for devices and basic services of doors example.")
execute_process(COMMAND "${SDV_VSS_UTIL}" "${PROJECT_SOURCE_DIR}/vss_doors_example.csv" "-O${PROJECT_SOURCE_DIR}/generated/" --prefixdoors --version1.0.0.1 --enable_components)
execute_process(COMMAND "${SDV_VSS_UTIL}" "${PROJECT_SOURCE_DIR}/vss_doors_front_example.csv" "-O${PROJECT_SOURCE_DIR}/generated/front/" --prefixfrontdoors --version1.0.0.1 --enable_components)
execute_process(COMMAND "${SDV_VSS_UTIL}" "${PROJECT_SOURCE_DIR}/vss_doors_rear_example.csv" "-O${PROJECT_SOURCE_DIR}/generated/rear/" --prefixreardoors --version1.0.0.1 --enable_components)
message("Compiling Interface Door01Left RX")
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/vss_files/vss_vehiclebodydooraxle_01left_vd_rx.idl" "-O${PROJECT_SOURCE_DIR}/generated/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --no_ps)
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/vss_files/vss_vehiclebodydooraxle_01left_bs_rx.idl" "-O${PROJECT_SOURCE_DIR}/generated/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --ps_lib_namedoors_proxystub)
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/front/vss_files/vss_vehiclebodydooraxle_01left_vd_rx.idl" "-O${PROJECT_SOURCE_DIR}/generated/front/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --no_ps)
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/front/vss_files/vss_vehiclebodydooraxle_01left_bs_rx.idl" "-O${PROJECT_SOURCE_DIR}/generated/front/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --ps_lib_namefrontdoors_proxystub)
message("Compiling Interface Door01Right RX")
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/vss_files/vss_vehiclebodydooraxle_01right_vd_rx.idl" "-O${PROJECT_SOURCE_DIR}/generated/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --no_ps)
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/vss_files/vss_vehiclebodydooraxle_01right_bs_rx.idl" "-O${PROJECT_SOURCE_DIR}/generated/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --ps_lib_namedoors_proxystub)
message("Compiling Interface Door02Left RX")
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/vss_files/vss_vehiclebodydooraxle_02left_vd_rx.idl" "-O${PROJECT_SOURCE_DIR}/generated/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --no_ps)
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/vss_files/vss_vehiclebodydooraxle_02left_bs_rx.idl" "-O${PROJECT_SOURCE_DIR}/generated/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --ps_lib_namedoors_proxystub)
message("Compiling Interface Door02Right RX")
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/vss_files/vss_vehiclebodydooraxle_02right_vd_rx.idl" "-O${PROJECT_SOURCE_DIR}/generated/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --no_ps)
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/vss_files/vss_vehiclebodydooraxle_02right_bs_rx.idl" "-O${PROJECT_SOURCE_DIR}/generated/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --ps_lib_namedoors_proxystub)
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/front/vss_files/vss_vehiclebodydooraxle_01right_vd_rx.idl" "-O${PROJECT_SOURCE_DIR}/generated/front/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --no_ps)
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/front/vss_files/vss_vehiclebodydooraxle_01right_bs_rx.idl" "-O${PROJECT_SOURCE_DIR}/generated/front/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --ps_lib_namefrontdoors_proxystub)
message("Compiling Interface Door01Left TX")
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/vss_files/vss_vehiclebodydooraxle_01left_vd_tx.idl" "-O${PROJECT_SOURCE_DIR}/generated/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --no_ps)
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/vss_files/vss_vehiclebodydooraxle_01left_bs_tx.idl" "-O${PROJECT_SOURCE_DIR}/generated/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --ps_lib_namedoors_proxystub)
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/front/vss_files/vss_vehiclebodydooraxle_01left_vd_tx.idl" "-O${PROJECT_SOURCE_DIR}/generated/front/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --no_ps)
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/front/vss_files/vss_vehiclebodydooraxle_01left_bs_tx.idl" "-O${PROJECT_SOURCE_DIR}/generated/front/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --ps_lib_namefrontdoors_proxystub)
message("Compiling Interface Door01Right TX")
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/vss_files/vss_vehiclebodydooraxle_01right_vd_tx.idl" "-O${PROJECT_SOURCE_DIR}/generated/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --no_ps)
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/vss_files/vss_vehiclebodydooraxle_01right_bs_tx.idl" "-O${PROJECT_SOURCE_DIR}/generated/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --ps_lib_namedoors_proxystub)
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/front/vss_files/vss_vehiclebodydooraxle_01right_vd_tx.idl" "-O${PROJECT_SOURCE_DIR}/generated/front/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --no_ps)
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/front/vss_files/vss_vehiclebodydooraxle_01right_bs_tx.idl" "-O${PROJECT_SOURCE_DIR}/generated/front/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --ps_lib_namefrontdoors_proxystub)
message("Compiling Interface Door02Left RX")
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/rear/vss_files/vss_vehiclebodydooraxle_02left_vd_rx.idl" "-O${PROJECT_SOURCE_DIR}/generated/rear/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --no_ps)
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/rear/vss_files/vss_vehiclebodydooraxle_02left_bs_rx.idl" "-O${PROJECT_SOURCE_DIR}/generated/rear/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --ps_lib_namereardoors_proxystub)
message("Compiling Interface Door02Right RX")
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/rear/vss_files/vss_vehiclebodydooraxle_02right_vd_rx.idl" "-O${PROJECT_SOURCE_DIR}/generated/rear/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --no_ps)
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/rear/vss_files/vss_vehiclebodydooraxle_02right_bs_rx.idl" "-O${PROJECT_SOURCE_DIR}/generated/rear/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --ps_lib_namereardoors_proxystub)
message("Compiling Interface Door02Left TX")
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/vss_files/vss_vehiclebodydooraxle_02left_vd_tx.idl" "-O${PROJECT_SOURCE_DIR}/generated/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --no_ps)
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/vss_files/vss_vehiclebodydooraxle_02left_bs_tx.idl" "-O${PROJECT_SOURCE_DIR}/generated/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --ps_lib_namedoors_proxystub)
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/rear/vss_files/vss_vehiclebodydooraxle_02left_vd_tx.idl" "-O${PROJECT_SOURCE_DIR}/generated/rear/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --no_ps)
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/rear/vss_files/vss_vehiclebodydooraxle_02left_bs_tx.idl" "-O${PROJECT_SOURCE_DIR}/generated/rear/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --ps_lib_namereardoors_proxystub)
message("Compiling Interface Door02Right TX")
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/vss_files/vss_vehiclebodydooraxle_02right_vd_tx.idl" "-O${PROJECT_SOURCE_DIR}/generated/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --no_ps)
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/vss_files/vss_vehiclebodydooraxle_02right_bs_tx.idl" "-O${PROJECT_SOURCE_DIR}/generated/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --ps_lib_namedoors_proxystub)
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/rear/vss_files/vss_vehiclebodydooraxle_02right_vd_tx.idl" "-O${PROJECT_SOURCE_DIR}/generated/rear/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --no_ps)
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/generated/rear/vss_files/vss_vehiclebodydooraxle_02right_bs_tx.idl" "-O${PROJECT_SOURCE_DIR}/generated/rear/vss_files/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Igenerated/vss_files/ --ps_lib_namereardoors_proxystub)
# Execute the IDL compiler for the complex service to digest interface code.
message("Compiling door_ifc.idl")
execute_process(COMMAND "${SDV_IDL_COMPILER}" "${PROJECT_SOURCE_DIR}/door_service/door_ifc.idl" "-O${PROJECT_SOURCE_DIR}/generated/door_service/" "-I${SDV_FRAMEWORK_DEV_INCLUDE}" -Iexample_service/ --ps_lib_namedoors_service_proxystub)
add_subdirectory(generated/door_service/ps)
add_subdirectory(generated/vss_files/ps)
add_subdirectory(generated/front/vss_files/ps)
add_subdirectory(generated/rear/vss_files/ps)
add_subdirectory(generated/vss_files/vd_frontdoorleft)
add_subdirectory(generated/vss_files/vd_frontdoorright)
add_subdirectory(generated/vss_files/vd_reardoorleft)
add_subdirectory(generated/vss_files/vd_reardoorright)
add_subdirectory(generated/front/vss_files/vd_frontdoorleft)
add_subdirectory(generated/front/vss_files/vd_frontdoorright)
add_subdirectory(generated/front/vss_files/bs_frontdoorleft)
add_subdirectory(generated/front/vss_files/bs_frontdoorright)
add_subdirectory(generated/vss_files/bs_frontdoorleft)
add_subdirectory(generated/vss_files/bs_frontdoorright)
add_subdirectory(generated/vss_files/bs_reardoorleft)
add_subdirectory(generated/vss_files/bs_reardoorright)
add_subdirectory(generated/rear/vss_files/vd_reardoorleft)
add_subdirectory(generated/rear/vss_files/vd_reardoorright)
add_subdirectory(generated/rear/vss_files/bs_reardoorleft)
add_subdirectory(generated/rear/vss_files/bs_reardoorright)
# Execute sdv_dbc_util to create data link code & FMU code.
message("Create data link for doors example")
@@ -167,7 +171,6 @@ else()
target_link_libraries(door_external_app Rpcrt4.lib)
endif()
######################################################################################################################################################################
# create instance 3002 of door demo example
######################################################################################################################################################################
@@ -175,23 +178,25 @@ add_custom_target(vehicle_device_doors_config
ALL
DEPENDS
can_dl_doors
doors_vd_frontdoorleft_rx
doors_vd_frontdoorright_rx
doors_vd_reardoorleft_rx
doors_vd_reardoorright_rx
COMMAND "${SDV_PACKAGER}" DIRECT_INSTALL VehicleDeviceDoors --instance3002 can_dl_doors.sdv doors_vd_frontdoorleft_rx.sdv doors_vd_frontdoorright_rx.sdv doors_vd_reardoorleft_rx.sdv doors_vd_reardoorright_rx.sdv "-I${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" --interface_config --overwrite
frontdoors_vd_frontdoorleft_rx
frontdoors_vd_frontdoorright_rx
reardoors_vd_reardoorleft_rx
reardoors_vd_reardoorright_rx
COMMAND "${SDV_PACKAGER}" DIRECT_INSTALL VehicleDeviceDoors --instance3002 can_dl_doors.sdv frontdoors_vd_frontdoorleft_rx.sdv frontdoors_vd_frontdoorright_rx.sdv reardoors_vd_reardoorleft_rx.sdv reardoors_vd_reardoorright_rx.sdv "-I${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" --interface_config --overwrite
VERBATIM
)
add_custom_target(basic_service_doors_config
ALL
DEPENDS
doors_proxystub
doors_bs_frontdoorleft_rx
doors_bs_frontdoorright_rx
doors_bs_reardoorleft_rx
doors_bs_reardoorright_rx
COMMAND "${SDV_PACKAGER}" DIRECT_INSTALL BasicServiceDoors --instance3002 doors_proxystub.sdv doors_bs_frontdoorleft_rx.sdv doors_bs_frontdoorright_rx.sdv doors_bs_reardoorleft_rx.sdv doors_bs_reardoorright_rx.sdv "-I${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" --abstract_config --overwrite
frontdoors_proxystub
reardoors_proxystub
frontdoors_bs_frontdoorleft_rx
frontdoors_bs_frontdoorright_rx
reardoors_bs_reardoorleft_rx
reardoors_bs_reardoorright_rx
COMMAND "${SDV_PACKAGER}" DIRECT_INSTALL BasicServiceDoors --instance3002 frontdoors_proxystub.sdv reardoors_proxystub.sdv frontdoors_bs_frontdoorleft_rx.sdv frontdoors_bs_frontdoorright_rx.sdv reardoors_bs_reardoorleft_rx.sdv reardoors_bs_reardoorright_rx.sdv "-I${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" --abstract_config --overwrite
VERBATIM
)

View File

@@ -2,11 +2,11 @@
Version = 100
[[Component]]
Path = "doors_vd_frontdoorleft_rx.sdv"
Path = "frontdoors_vd_frontdoorleft_rx.sdv"
Class = "Vehicle.Body.Door.Axle._01.Left_Device"
[[Component]]
Path = "doors_bs_frontdoorleft_rx.sdv"
Path = "frontdoors_bs_frontdoorleft_rx.sdv"
Class = "Vehicle.Body.Door.Axle._01.Left_Service"

View File

@@ -2,11 +2,11 @@
Version = 100
[[Component]]
Path = "doors_vd_frontdoorright_rx.sdv"
Path = "frontdoors_vd_frontdoorright_rx.sdv"
Class = "Vehicle.Body.Door.Axle._01.Right_Device"
[[Component]]
Path = "doors_bs_frontdoorright_rx.sdv"
Path = "frontdoors_bs_frontdoorright_rx.sdv"
Class = "Vehicle.Body.Door.Axle._01.Right_Service"

View File

@@ -2,11 +2,11 @@
Version = 100
[[Component]]
Path = "doors_vd_reardoorleft_rx.sdv"
Path = "reardoors_vd_reardoorleft_rx.sdv"
Class = "Vehicle.Body.Door.Axle._02.Left_Device"
[[Component]]
Path = "doors_bs_reardoorleft_rx.sdv"
Path = "reardoors_bs_reardoorleft_rx.sdv"
Class = "Vehicle.Body.Door.Axle._02.Left_Service"

View File

@@ -2,9 +2,9 @@
Version = 100
[[Component]]
Path = "doors_vd_reardoorright_rx.sdv"
Path = "reardoors_vd_reardoorright_rx.sdv"
Class = "Vehicle.Body.Door.Axle._02.Right_Device"
[[Component]]
Path = "doors_bs_reardoorright_rx.sdv"
Path = "reardoors_bs_reardoorright_rx.sdv"
Class = "Vehicle.Body.Door.Axle._02.Right_Service"

View File

@@ -128,7 +128,6 @@ void CConsole::PrintHeader(const uint32_t numberOfDoors)
PrintText(g_sTitle, title.c_str());
PrintText(g_sControlDescription, "Press 'X' to quit; Doors are toggled automatically");
}
}
bool CConsole::PrepareDataConsumers()
@@ -205,7 +204,6 @@ void CConsole::ResetSignals()
// Set the cursor position at the end
SetCursorPos(g_sCursor);
// Registrate for the vehicle device & basic service of the front left door. Front left door mzust exist, the others are optional
auto vehicleDevice =
sdv::core::GetObject("Vehicle.Body.Door.Axle._01.Left_Device").GetInterface < vss::Vehicle::Body::Door::Axle::_01 ::LeftDevice::IVSS_ReadIsOpen > ();
if (vehicleDevice)
@@ -254,7 +252,7 @@ void CConsole::StartUpdateDataThread()
m_bThreadStarted = true;
m_bRunning = true;
m_threadReadTxSignals = std::thread(&CConsole::UpdateDataThreadFunc, this);
m_threadReadTxSignals = sdv::core::secure_thread(&CConsole::UpdateDataThreadFunc, this);
}
void CConsole::StopUpdateDataThread()
@@ -299,21 +297,21 @@ bool CConsole::PrepareDataConsumersForStandAlone()
{
// Subscribe for the door and if available get TX signal. Either both exists or none of them
sdv::core::CDispatchService dispatch;
m_SignalFrontLeftDoorIsOpen = dispatch.Subscribe(doors::dsLeftDoorIsOpen01, [&](sdv::any_t value) { CallbackFrontLeftDoorIsOpen(value); });
m_SignalFrontLeftDoorIsOpen = dispatch.Subscribe(frontdoors::dsLeftDoorIsOpen01, [&](sdv::any_t value) { CallbackFrontLeftDoorIsOpen(value); });
if(m_SignalFrontLeftDoorIsOpen)
m_SignalFrontLeftDoorIsLocked = dispatch.RegisterTxSignal(doors::dsLeftLatch01, 0);
m_SignalFrontLeftDoorIsLocked = dispatch.RegisterTxSignal(frontdoors::dsLeftLatch01, 0);
m_SignalFrontRightDoorIsOpen = dispatch.Subscribe(doors::dsRightDoorIsOpen01, [&](sdv::any_t value) { CallbackFrontRightDoorIsOpen(value); });
m_SignalFrontRightDoorIsOpen = dispatch.Subscribe(frontdoors::dsRightDoorIsOpen01, [&](sdv::any_t value) { CallbackFrontRightDoorIsOpen(value); });
if(m_SignalFrontRightDoorIsOpen)
m_SignalFrontRightDoorIsLocked = dispatch.RegisterTxSignal(doors::dsRightLatch01, 0);
m_SignalFrontRightDoorIsLocked = dispatch.RegisterTxSignal(frontdoors::dsRightLatch01, 0);
m_SignalRearLeftDoorIsOpen = dispatch.Subscribe(doors::dsLeftDoorIsOpen02, [&](sdv::any_t value) {CallbackRearLeftDoorIsOpen(value); });
m_SignalRearLeftDoorIsOpen = dispatch.Subscribe(reardoors::dsLeftDoorIsOpen02, [&](sdv::any_t value) {CallbackRearLeftDoorIsOpen(value); });
if(m_SignalRearLeftDoorIsOpen)
m_SignalRearLeftDoorIsLocked = dispatch.RegisterTxSignal(doors::dsLeftLatch02, 0);
m_SignalRearLeftDoorIsLocked = dispatch.RegisterTxSignal(reardoors::dsLeftLatch02, 0);
m_SignalRearRightDoorIsOpen = dispatch.Subscribe(doors::dsRightDoorIsOpen02, [&](sdv::any_t value) { CallbackRearRightDoorIsOpen(value); });
m_SignalRearRightDoorIsOpen = dispatch.Subscribe(reardoors::dsRightDoorIsOpen02, [&](sdv::any_t value) { CallbackRearRightDoorIsOpen(value); });
if(m_SignalRearRightDoorIsOpen)
m_SignalRearRightDoorIsLocked = dispatch.RegisterTxSignal(doors::dsRightLatch02, 0);
m_SignalRearRightDoorIsLocked = dispatch.RegisterTxSignal(reardoors::dsRightLatch02, 0);
// Validate: Either both exists or none of them
if (m_SignalFrontLeftDoorIsOpen != m_SignalFrontLeftDoorIsLocked)
@@ -337,7 +335,7 @@ bool CConsole::PrepareDataConsumersForStandAlone()
return false;
}
// Registrate for the vehicle device & basic service of the front left door. Front left door mzust exist, the others are optional
// Register for the vehicle device & basic service of the front left door. Front left door must exist, the others are optional
auto vehicleDevice = sdv::core::GetObject("Vehicle.Body.Door.Axle._01.Left_Device").GetInterface<vss::Vehicle::Body::Door::Axle::_01::LeftDevice::IVSS_ReadIsOpen>();
if (!vehicleDevice)
{

View File

@@ -9,7 +9,8 @@
********************************************************************************/
#include "../door_app/include/door_application.h"
#include "../generated/vss_files/signal_identifier.h"
#include "../generated/front/vss_files/signal_identifier.h"
#include "../generated/rear/vss_files/signal_identifier.h"
#ifdef _WIN32
#include <conio.h> // Needed for _kbhit
@@ -61,23 +62,23 @@ bool CDoorControl::RegisterSignals()
{
sdv::core::CDispatchService dispatch;
m_SignalFrontLeftDoorIsOpen = dispatch.RegisterRxSignal(doors::dsLeftDoorIsOpen01);
m_SignalFrontLeftDoorIsLocked = dispatch.RegisterTxSignal(doors::dsLeftLatch01, 0);
m_SignalFrontLeftDoorIsOpen = dispatch.RegisterRxSignal(frontdoors::dsLeftDoorIsOpen01);
m_SignalFrontLeftDoorIsLocked = dispatch.RegisterTxSignal(frontdoors::dsLeftLatch01, 0);
if (m_iNumberOfDoors > 1)
{
m_SignalFrontRightDoorIsOpen = dispatch.RegisterRxSignal(doors::dsRightDoorIsOpen01);
m_SignalFrontRightDoorIsLocked = dispatch.RegisterTxSignal(doors::dsRightLatch01, 0);
m_SignalFrontRightDoorIsOpen = dispatch.RegisterRxSignal(frontdoors::dsRightDoorIsOpen01);
m_SignalFrontRightDoorIsLocked = dispatch.RegisterTxSignal(frontdoors::dsRightLatch01, 0);
if (m_iNumberOfDoors > 2)
{
m_SignalRearLeftDoorIsOpen = dispatch.RegisterRxSignal(doors::dsLeftDoorIsOpen02);
m_SignalRearLeftDoorIsLocked = dispatch.RegisterTxSignal(doors::dsLeftLatch02, 0);
m_SignalRearLeftDoorIsOpen = dispatch.RegisterRxSignal(reardoors::dsLeftDoorIsOpen02);
m_SignalRearLeftDoorIsLocked = dispatch.RegisterTxSignal(reardoors::dsLeftLatch02, 0);
if (m_iNumberOfDoors > 3)
{
m_SignalRearRightDoorIsOpen = dispatch.RegisterRxSignal(doors::dsRightDoorIsOpen02);
m_SignalRearRightDoorIsLocked = dispatch.RegisterTxSignal(doors::dsRightLatch02, 0);
m_SignalRearRightDoorIsOpen = dispatch.RegisterRxSignal(reardoors::dsRightDoorIsOpen02);
m_SignalRearRightDoorIsLocked = dispatch.RegisterTxSignal(reardoors::dsRightLatch02, 0);
}
}
}

View File

@@ -9,7 +9,8 @@
********************************************************************************/
#include "../door_app/include/door_extern_application.h"
#include "../generated/vss_files/signal_identifier.h"
#include "../generated/front/vss_files/signal_identifier.h"
#include "../generated/rear/vss_files/signal_identifier.h"
#ifdef _WIN32
#include <conio.h> // Needed for _kbhit

View File

@@ -19,15 +19,16 @@
#include <support/app_control.h>
#include <support/component_impl.h>
#include <support/timer.h>
#include "../../generated/vss_files/signal_identifier.h"
#include "../../generated/front/vss_files/signal_identifier.h"
#include "../../generated/rear/vss_files/signal_identifier.h"
#include <fcntl.h>
#include <atomic>
#include "../../generated/vss_files/vss_vehiclebodydooraxle_01left_vd_rx.h"
#include "../../generated/vss_files/vss_vehiclebodydooraxle_01left_bs_rx.h"
#include "../../generated/vss_files/vss_vehiclebodydooraxle_01right_bs_rx.h"
#include "../../generated/vss_files/vss_vehiclebodydooraxle_02left_bs_rx.h"
#include "../../generated/vss_files/vss_vehiclebodydooraxle_02right_bs_rx.h"
#include "../../generated/front/vss_files/vss_vehiclebodydooraxle_01left_vd_rx.h"
#include "../../generated/front/vss_files/vss_vehiclebodydooraxle_01left_bs_rx.h"
#include "../../generated/front/vss_files/vss_vehiclebodydooraxle_01right_bs_rx.h"
#include "../../generated/rear/vss_files/vss_vehiclebodydooraxle_02left_bs_rx.h"
#include "../../generated/rear/vss_files/vss_vehiclebodydooraxle_02right_bs_rx.h"
#ifdef __unix__
#include <termios.h> // Needed for tcgetattr and fcntl
@@ -220,7 +221,7 @@ private:
std::atomic_bool m_bRunning = false; ///< When set, the application is running.
bool m_isExternalApp = false; ///< True when we have an external application
std::thread m_threadReadTxSignals; ///< Simulation datalink thread.
sdv::core::secure_thread m_threadReadTxSignals; ///< Simulation datalink thread.
sdv::core::CSignal m_SignalFrontLeftDoorIsOpen; ///< Front Left Door signal (RX input) - open / closed
sdv::core::CSignal m_SignalFrontRightDoorIsOpen; ///< Front Right Door signal (RX input) - open / closed

View File

@@ -19,14 +19,14 @@
#include <support/timer.h>
// VSS interfaces - located in ../generated/vss_files/
#include "../generated/vss_files/vss_vehiclebodydooraxle_01left_bs_rx.h"
#include "../generated/vss_files/vss_vehiclebodydooraxle_01left_bs_tx.h"
#include "../generated/vss_files/vss_vehiclebodydooraxle_01right_bs_rx.h"
#include "../generated/vss_files/vss_vehiclebodydooraxle_01right_bs_tx.h"
#include "../generated/vss_files/vss_vehiclebodydooraxle_02left_bs_rx.h"
#include "../generated/vss_files/vss_vehiclebodydooraxle_02left_bs_tx.h"
#include "../generated/vss_files/vss_vehiclebodydooraxle_02right_bs_rx.h"
#include "../generated/vss_files/vss_vehiclebodydooraxle_02right_bs_tx.h"
#include "../generated/front/vss_files/vss_vehiclebodydooraxle_01left_bs_rx.h"
#include "../generated/front/vss_files/vss_vehiclebodydooraxle_01left_bs_tx.h"
#include "../generated/front/vss_files/vss_vehiclebodydooraxle_01right_bs_rx.h"
#include "../generated/front/vss_files/vss_vehiclebodydooraxle_01right_bs_tx.h"
#include "../generated/rear/vss_files/vss_vehiclebodydooraxle_02left_bs_rx.h"
#include "../generated/rear/vss_files/vss_vehiclebodydooraxle_02left_bs_tx.h"
#include "../generated/rear/vss_files/vss_vehiclebodydooraxle_02right_bs_rx.h"
#include "../generated/rear/vss_files/vss_vehiclebodydooraxle_02right_bs_tx.h"
#include "lock_doors_thread.h"

View File

@@ -40,7 +40,7 @@ public:
m_timeIn100MilliSeconds = timeSpan;
m_counter = 0;
m_running = true;
m_thread = std::thread(&LockDoorsThread::run, this);
m_thread = sdv::core::secure_thread(&LockDoorsThread::run, this);
}
/**
@@ -96,7 +96,7 @@ public:
std::function<void()> m_callback; ///< callback function
std::atomic<bool> m_running; ///< status if loop is running
std::thread m_thread; ///< timer thread
sdv::core::secure_thread m_thread; ///< timer thread
uint32_t m_counter; ///< loop counter
uint32_t m_timeIn100MilliSeconds; ///< time before the callback will be executed
};

View File

@@ -100,7 +100,10 @@ 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 << R"toml(# Location of the SDV binaries and configuration files
[CoreLocation]
Version = 100
Framework = ")toml";
tomlFile << resources;
tomlFile << "\"\n";
tomlFile.close();

View File

@@ -2,11 +2,11 @@
Version = 100
[[Component]]
Path = "doors_vd_frontdoorleft_rx.sdv"
Path = "frontdoors_vd_frontdoorleft_rx.sdv"
Class = "Vehicle.Body.Door.Axle._01.Left_Device"
[[Component]]
Path = "doors_bs_frontdoorleft_rx.sdv"
Path = "frontdoors_bs_frontdoorleft_rx.sdv"
Class = "Vehicle.Body.Door.Axle._01.Left_Service"

View File

@@ -2,10 +2,10 @@
Version = 100
[[Component]]
Path = "doors_vd_frontdoorright_rx.sdv"
Path = "frontdoors_vd_frontdoorright_rx.sdv"
Class = "Vehicle.Body.Door.Axle._01.Right_Device"
[[Component]]
Path = "doors_bs_frontdoorright_rx.sdv"
Path = "frontdoors_bs_frontdoorright_rx.sdv"
Class = "Vehicle.Body.Door.Axle._01.Right_Service"

View File

@@ -125,7 +125,10 @@ 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 << R"toml(# Location of the SDV binaries and configuration files
[CoreLocation]
Version = 100
Framework = ")toml";
tomlFile << resources;
tomlFile << "\"\n";
tomlFile.close();

View File

@@ -2,11 +2,11 @@
Version = 100
[[Component]]
Path = "doors_vd_frontdoorleft_rx.sdv"
Path = "frontdoors_vd_frontdoorleft_rx.sdv"
Class = "Vehicle.Body.Door.Axle._01.Left_Device"
[[Component]]
Path = "doors_bs_frontdoorleft_rx.sdv"
Path = "frontdoors_bs_frontdoorleft_rx.sdv"
Class = "Vehicle.Body.Door.Axle._01.Left_Service"

View File

@@ -2,10 +2,10 @@
Version = 100
[[Component]]
Path = "doors_vd_frontdoorright_rx.sdv"
Path = "frontdoors_vd_frontdoorright_rx.sdv"
Class = "Vehicle.Body.Door.Axle._01.Right_Device"
[[Component]]
Path = "doors_bs_frontdoorright_rx.sdv"
Path = "frontdoors_bs_frontdoorright_rx.sdv"
Class = "Vehicle.Body.Door.Axle._01.Right_Service"

View File

@@ -2,11 +2,11 @@
Version = 100
[[Component]]
Path = "doors_vd_reardoorleft_rx.sdv"
Path = "reardoors_vd_reardoorleft_rx.sdv"
Class = "Vehicle.Body.Door.Axle._02.Left_Device"
[[Component]]
Path = "doors_bs_reardoorleft_rx.sdv"
Path = "reardoors_bs_reardoorleft_rx.sdv"
Class = "Vehicle.Body.Door.Axle._02.Left_Service"

View File

@@ -2,9 +2,9 @@
Version = 100
[[Component]]
Path = "doors_vd_reardoorright_rx.sdv"
Path = "reardoors_vd_reardoorright_rx.sdv"
Class = "Vehicle.Body.Door.Axle._02.Right_Device"
[[Component]]
Path = "doors_bs_reardoorright_rx.sdv"
Path = "reardoors_bs_reardoorright_rx.sdv"
Class = "Vehicle.Body.Door.Axle._02.Right_Service"

View File

@@ -2,17 +2,9 @@
;;;;;;;
VD;FrontDoorLeft;IsOpen;leftDoorIsOpen01;Vehicle.Body.Door.Axle.01.Left;RX;boolean;CAN_Input_L1.Door01LeftIsOpen
VD;FrontDoorRight;IsOpen;rightDoorIsOpen01;Vehicle.Body.Door.Axle.01.Right;RX;boolean;CAN_Input_R1.Door01RightIsOpen
VD;RearDoorLeft;IsOpen;leftDoorIsOpen02;Vehicle.Body.Door.Axle.02.Left;RX;boolean;CAN_Input_L2.Door02LeftIsOpen
VD;RearDoorRight;IsOpen;rightDoorIsOpen02;Vehicle.Body.Door.Axle.02.Right;RX;boolean;CAN_Input_R2.Door02RightIsOpen
VD;FrontDoorLeft;Lock;leftLatch01;Vehicle.Body.Door.Axle.01.Left;TX;boolean;CAN_Output.LockDoor01Left
VD;FrontDoorRight;Lock;rightLatch01;Vehicle.Body.Door.Axle.01.Right;TX;boolean;CAN_Output.LockDoor01Right
VD;RearDoorLeft;Lock;leftLatch02;Vehicle.Body.Door.Axle.02.Left;TX;boolean;CAN_Output.LockDoor02Left
VD;RearDoorRight;Lock;rightLatch02;Vehicle.Body.Door.Axle.02.Right;TX;boolean;CAN_Output.LockDoor02Right
BS;FrontDoorLeft;IsOpenL1;leftDoorIsOpen01;Vehicle.Body.Door.Axle.01.Left;RX;boolean;Vehicle.Body.Door.Axle.01.Left
BS;FrontDoorRight;IsOpenR1;rightDoorIsOpen01;Vehicle.Body.Door.Axle.01.Right;RX;boolean;Vehicle.Body.Door.Axle.01.Right
BS;RearDoorLeft;IsOpenL2;leftDoorIsOpen02;Vehicle.Body.Door.Axle.02.Left;RX;boolean;Vehicle.Body.Door.Axle.02.Left
BS;RearDoorRight;IsOpenR2;rightDoorIsOpen02;Vehicle.Body.Door.Axle.02.Right;RX;boolean;Vehicle.Body.Door.Axle.02.Right
BS;FrontDoorLeft;Lock;leftLatch01;Vehicle.Body.Door.Axle.01.Left;TX;boolean;Vehicle.Body.Door.Axle.01.Left
BS;FrontDoorRight;Lock;rightLatch01;Vehicle.Body.Door.Axle.01.Right;TX;boolean;Vehicle.Body.Door.Axle.01.Right
BS;RearDoorLeft;Lock;leftLatch02;Vehicle.Body.Door.Axle.02.Left;TX;boolean;Vehicle.Body.Door.Axle.02.Left
BS;RearDoorRight;Lock;rightLatch02;Vehicle.Body.Door.Axle.02.Right;TX;boolean;Vehicle.Body.Door.Axle.02.Right
1 Class name Function name Signal name vss Signal direction type DBC CAN name includes CAN message name
2
3 VD FrontDoorLeft IsOpen leftDoorIsOpen01 Vehicle.Body.Door.Axle.01.Left RX boolean CAN_Input_L1.Door01LeftIsOpen
4 VD FrontDoorRight IsOpen rightDoorIsOpen01 Vehicle.Body.Door.Axle.01.Right RX boolean CAN_Input_R1.Door01RightIsOpen
VD RearDoorLeft IsOpen leftDoorIsOpen02 Vehicle.Body.Door.Axle.02.Left RX boolean CAN_Input_L2.Door02LeftIsOpen
VD RearDoorRight IsOpen rightDoorIsOpen02 Vehicle.Body.Door.Axle.02.Right RX boolean CAN_Input_R2.Door02RightIsOpen
5 VD FrontDoorLeft Lock leftLatch01 Vehicle.Body.Door.Axle.01.Left TX boolean CAN_Output.LockDoor01Left
6 VD FrontDoorRight Lock rightLatch01 Vehicle.Body.Door.Axle.01.Right TX boolean CAN_Output.LockDoor01Right
VD RearDoorLeft Lock leftLatch02 Vehicle.Body.Door.Axle.02.Left TX boolean CAN_Output.LockDoor02Left
VD RearDoorRight Lock rightLatch02 Vehicle.Body.Door.Axle.02.Right TX boolean CAN_Output.LockDoor02Right
7 BS FrontDoorLeft IsOpenL1 leftDoorIsOpen01 Vehicle.Body.Door.Axle.01.Left RX boolean Vehicle.Body.Door.Axle.01.Left
8 BS FrontDoorRight IsOpenR1 rightDoorIsOpen01 Vehicle.Body.Door.Axle.01.Right RX boolean Vehicle.Body.Door.Axle.01.Right
BS RearDoorLeft IsOpenL2 leftDoorIsOpen02 Vehicle.Body.Door.Axle.02.Left RX boolean Vehicle.Body.Door.Axle.02.Left
BS RearDoorRight IsOpenR2 rightDoorIsOpen02 Vehicle.Body.Door.Axle.02.Right RX boolean Vehicle.Body.Door.Axle.02.Right
9 BS FrontDoorLeft Lock leftLatch01 Vehicle.Body.Door.Axle.01.Left TX boolean Vehicle.Body.Door.Axle.01.Left
10 BS FrontDoorRight Lock rightLatch01 Vehicle.Body.Door.Axle.01.Right TX boolean Vehicle.Body.Door.Axle.01.Right
BS RearDoorLeft Lock leftLatch02 Vehicle.Body.Door.Axle.02.Left TX boolean Vehicle.Body.Door.Axle.02.Left
BS RearDoorRight Lock rightLatch02 Vehicle.Body.Door.Axle.02.Right TX boolean Vehicle.Body.Door.Axle.02.Right

View File

@@ -0,0 +1,10 @@
;Class name;Function name;Signal name;vss;Signal direction;type;DBC CAN name includes CAN message name
;;;;;;;
VD;RearDoorLeft;IsOpen;leftDoorIsOpen02;Vehicle.Body.Door.Axle.02.Left;RX;boolean;CAN_Input_L2.Door02LeftIsOpen
VD;RearDoorRight;IsOpen;rightDoorIsOpen02;Vehicle.Body.Door.Axle.02.Right;RX;boolean;CAN_Input_R2.Door02RightIsOpen
VD;RearDoorLeft;Lock;leftLatch02;Vehicle.Body.Door.Axle.02.Left;TX;boolean;CAN_Output.LockDoor02Left
VD;RearDoorRight;Lock;rightLatch02;Vehicle.Body.Door.Axle.02.Right;TX;boolean;CAN_Output.LockDoor02Right
BS;RearDoorLeft;IsOpenL2;leftDoorIsOpen02;Vehicle.Body.Door.Axle.02.Left;RX;boolean;Vehicle.Body.Door.Axle.02.Left
BS;RearDoorRight;IsOpenR2;rightDoorIsOpen02;Vehicle.Body.Door.Axle.02.Right;RX;boolean;Vehicle.Body.Door.Axle.02.Right
BS;RearDoorLeft;Lock;leftLatch02;Vehicle.Body.Door.Axle.02.Left;TX;boolean;Vehicle.Body.Door.Axle.02.Left
BS;RearDoorRight;Lock;rightLatch02;Vehicle.Body.Door.Axle.02.Right;TX;boolean;Vehicle.Body.Door.Axle.02.Right
1 Class name Function name Signal name vss Signal direction type DBC CAN name includes CAN message name
2
3 VD RearDoorLeft IsOpen leftDoorIsOpen02 Vehicle.Body.Door.Axle.02.Left RX boolean CAN_Input_L2.Door02LeftIsOpen
4 VD RearDoorRight IsOpen rightDoorIsOpen02 Vehicle.Body.Door.Axle.02.Right RX boolean CAN_Input_R2.Door02RightIsOpen
5 VD RearDoorLeft Lock leftLatch02 Vehicle.Body.Door.Axle.02.Left TX boolean CAN_Output.LockDoor02Left
6 VD RearDoorRight Lock rightLatch02 Vehicle.Body.Door.Axle.02.Right TX boolean CAN_Output.LockDoor02Right
7 BS RearDoorLeft IsOpenL2 leftDoorIsOpen02 Vehicle.Body.Door.Axle.02.Left RX boolean Vehicle.Body.Door.Axle.02.Left
8 BS RearDoorRight IsOpenR2 rightDoorIsOpen02 Vehicle.Body.Door.Axle.02.Right RX boolean Vehicle.Body.Door.Axle.02.Right
9 BS RearDoorLeft Lock leftLatch02 Vehicle.Body.Door.Axle.02.Left TX boolean Vehicle.Body.Door.Axle.02.Left
10 BS RearDoorRight Lock rightLatch02 Vehicle.Body.Door.Axle.02.Right TX boolean Vehicle.Body.Door.Axle.02.Right

View File

@@ -34,9 +34,11 @@ const CConsole::SConsolePos g_sComment3{ 24, 1 };
const CConsole::SConsolePos g_sSeparator5{ 26, 1 };
const CConsole::SConsolePos g_sOpenViaDevice{ 28, 1 };
const CConsole::SConsolePos g_sOpenViaService{ 29, 1 };
const CConsole::SConsolePos g_sSeparator6{ 31, 1 };
const CConsole::SConsolePos g_sControlDescription{ 33, 1 };
const CConsole::SConsolePos g_sCursor{ 34, 1 };
const CConsole::SConsolePos g_sAutoCloseTrunk{ 30, 1 };
const CConsole::SConsolePos g_sStatusTrunk{ 32, 1 };
const CConsole::SConsolePos g_sSeparator6{ 34, 1 };
const CConsole::SConsolePos g_sControlDescription{ 36, 1 };
const CConsole::SConsolePos g_sCursor{ 37, 1 };
CConsole::CConsole()
{
@@ -92,6 +94,7 @@ void CConsole::PrintHeader(uint32_t uiInstance)
{
subTtitle = "Connected to core instance ";
subTtitle.append(std::to_string(uiInstance));
subTtitle.append(" (not all interfaces available)");
}
// Print the titles
PrintText(g_sTitle, "Open Trunk example: Open trunk when vehicle is not moving");
@@ -108,7 +111,7 @@ void CConsole::PrintHeader(uint32_t uiInstance)
PrintText(g_sSeparator4, "============================================================================");
PrintText(g_sComment1, "The Open Trunk signal has a safety request.");
PrintText(g_sComment2, "Therefore the speed value is required and must be checked.");
PrintText(g_sComment3, "If the car is moving, open is blocked and trunk is closed automatically.");
PrintText(g_sComment3, "If the vehicle is moving, open is blocked and trunk is closed automatically.");
PrintText(g_sSeparator5, "============================================================================");
PrintText(g_sOpenViaDevice, "Vehicle Device Interface not available.");
PrintText(g_sOpenViaService, "Basic Service Interface not available.");
@@ -124,7 +127,7 @@ bool CConsole::PrepareDataConsumers()
if (m_SignalSpeed)
PrintValue(g_sDataLinkSpeed, "Vehicle Speed RX", m_SpeedDL, "m/s");
// Registrate for the vehicle device & basic service of the speed.
// Register for the vehicle device & basic service of the speed.
auto vehicleDevice = sdv::core::GetObject("Vehicle.Speed_Device").GetInterface<vss::Vehicle::SpeedDevice::IVSS_ReadSpeed>();
if (vehicleDevice)
{
@@ -153,6 +156,10 @@ bool CConsole::PrepareDataConsumers()
else
PrintText(g_sOpenViaDevice, "Trunk Device NOT available");
m_SignalStatusTrunk = dispatch.RegisterTxSignal(trunk::dsTrunk, 0);
if (!m_SignalStatusTrunk)
PrintText(g_sStatusTrunk, "Trunk Status not available.");
return true;
}
@@ -172,6 +179,9 @@ void CConsole::ResetSignals()
// Unregister the data link signals
if (m_SignalSpeed)
m_SignalSpeed.Reset();
if (m_SignalStatusTrunk)
m_SignalStatusTrunk.Reset();
}
void CConsole::CallbackSpeed(sdv::any_t value)
@@ -246,7 +256,13 @@ void CConsole::SetSpeed(float value)
if (bIsMoving && !m_bWasMovingBS)
{
PrintText(g_sOpenViaService, "Safety active: speed > 0, trunk close command sent.");
if (m_pTrunkService)
{
if (m_pTrunkService->SetOpen(false))
PrintText(g_sAutoCloseTrunk, "Safety feature active: Trunk closed as the vehicle started moving.");
else
PrintText(g_sOpenViaService, "Close trunk automatically failed.");
}
}
m_bWasMovingBS = bIsMoving;
}
@@ -278,9 +294,24 @@ char CConsole::GetChar()
void CConsole::RunUntilBreak()
{
bool bRunning = true;
bool bTrunkClosed = true;
while (bRunning)
{
if(m_SignalStatusTrunk)
{
auto value =m_SignalStatusTrunk.Read().get<bool>();
if (bTrunkClosed != value)
{
bTrunkClosed = value;
if (bTrunkClosed)
PrintText(g_sStatusTrunk, "Status: Trunk is open.");
else
PrintText(g_sStatusTrunk, "Status: Trunk is closed.");
}
}
// Check for a key
if (!KeyHit())
{
@@ -296,15 +327,17 @@ void CConsole::RunUntilBreak()
case 'C':
PrintText(g_sOpenViaDevice, " ");
PrintText(g_sOpenViaService, " ");
PrintText(g_sAutoCloseTrunk, " ");
break;
case 'd':
case 'D':
if (m_pTrunkDevice)
{
PrintText(g_sAutoCloseTrunk, " ");
if (m_pTrunkDevice->WriteOpen(true))
{
if (m_SpeedVD || m_SpeedBS)
PrintText(g_sOpenViaDevice, "Trunk opened directly although car was moving, not safe.");
PrintText(g_sOpenViaDevice, "Trunk opened directly although vehicle was moving, not safe.");
else
PrintText(g_sOpenViaDevice, "Trunk opened directly, not safe.");
}
@@ -316,10 +349,11 @@ void CConsole::RunUntilBreak()
case 'O':
if (m_pTrunkService)
{
PrintText(g_sAutoCloseTrunk, " ");
if (m_pTrunkService->SetOpen(true))
PrintText(g_sOpenViaService, "Trunk opened safely (auto-close if vehicle starts moving).");
else
PrintText(g_sOpenViaService, "Open trunk failed, car is moving.");
PrintText(g_sOpenViaService, "Open trunk failed, vehicle is moving.");
}
break;
case 'x':

View File

@@ -157,6 +157,7 @@ private:
mutable std::mutex m_mtxPrintToConsole; ///< Mutex to print complete message
bool m_bRunning = false; ///< When set, the application is running.
sdv::core::CSignal m_SignalStatusTrunk; ///< Status of the trunk, only available in the standalone example
sdv::core::CSignal m_SignalSpeed; ///< Speed
float m_SpeedDL = 0.0; ///< Speed Data Link
float m_SpeedVD = 0.0; ///< Speed Vehicle Device

View File

@@ -209,8 +209,7 @@ bool CConsole::PrepareDataConsumers()
m_pCounterSteeringSvc = sdv::core::GetObject("Counter Steering Example Service").GetInterface<ICounterSteeringService>();
if (!m_pCounterSteeringSvc)
{
std::cerr << "Console ERROR: Could not get complex service interface 'ICounterSteeringService'" << std::endl;
return false;
PrintText(g_sCSActive, "Attention: Complex service 'CounterSteeringService' is not available.");
}
return true;

View File

@@ -103,7 +103,7 @@ void CExampleControl::StartTestRun()
// Start the simulated datalink
m_bRunning = true;
m_threadSimulateDatalink = std::thread(&CExampleControl::SimulateDatalinkThreadFunc, this);
m_threadSimulateDatalink = sdv::core::secure_thread(&CExampleControl::SimulateDatalinkThreadFunc, this);
}
void CExampleControl::StopTestRun()

View File

@@ -172,7 +172,7 @@ private:
uint32_t m_uiInstance = 1000u; ///< Server instance to connect to.
std::filesystem::path m_pathFramework; ///< Path to the SDV V-API framework.
sdv::app::CAppControl m_appcontrol; ///< App-control of SDV V-API.
std::thread m_threadSimulateDatalink; ///< Simulation datalink thread.
sdv::core::secure_thread m_threadSimulateDatalink; ///< Simulation datalink thread.
sdv::core::CSignal m_signalSteeringWheel; ///< Steering wheel angle signal (input) - simulated datalink
sdv::core::CSignal m_signalSpeed; ///< Speed signal (input) - simulated datalink
sdv::core::CSignal m_signalRearAngle; ///< Rear angle signal (output) - simulated datalink

View File

@@ -103,7 +103,10 @@ 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 << R"toml(# Location of the SDV binaries and configuration files
[CoreLocation]
Version = 100
Framework = ")toml";
tomlFile << resources;
tomlFile << "\"\n";
tomlFile.close();

View File

@@ -103,12 +103,6 @@ module sdv
* @return The instance ID.
*/
uint32 GetInstanceID() const;
/**
* @brief Return the number of retries to establish a connection.
* @return Number of retries.
*/
uint32 GetRetries() const;
};
/**
@@ -181,5 +175,96 @@ module sdv
void RequestShutdown() raises(XAccessDenied, XInvalidState);
};
/**
* @brief Load and save the application settings.
* @remarks The interface is only available in maintenance mode.
*/
interface IAppSettingsPersist
{
/**
* @brief Load the application settings.
* @remarks When there is no settings file, this is not an error. Default settings will be assumed.
* @return Returns whether the loading was successful.
*/
boolean LoadSettings();
/**
* @brief Save the application settings file (or create when not existing yet).
* @return Returns whether the saving was successful.
*/
boolean SaveSettings();
};
/**
* @brief Application connections
* @remarks The interface is only available in maintenance mode.
*/
interface IAppConnections
{
/**
* @brief Get a sequence with listener names.
* @return Sequence with listener name strings.
*/
sequence<u8string> GetListeners() const;
/**
* @brief Get the listener configuration.
* @param[in] ssName Name of the listener.
* @return String containing the listener configuration.
*/
u8string GetListenerConfig(in u8string ssName) const;
/**
* @brief Add or update a listener configuration.
* @param[in] ssName Name of the listener configuration.
* @param[in] ssConfig The configuration string for the listener.
* @return Returns whether the listener could be added.
*/
boolean AddListenerConfig(in u8string ssName, in u8string ssConfig);
/**
* @brief Remove a listener configuration with the provided name.
* @param[in] ssName Name of the listener configuration.
* @return Returns whether the removal was successful.
*/
boolean RemoveListenerConfig(in u8string ssName);
/**
* @brief Get a sequence with connection names.
* @return Sequence with name strings.
*/
sequence<u8string> GetConnections() const;
/**
* @brief Get the connection configuration.
* @param[in] ssName Name of the connection.
* @return String containing the connection configuration.
*/
u8string GetConnectionConfig(in u8string ssName) const;
/**
* @brief Add or update a connection configuration.
* @param[in] ssName Name of the connection configuration.
* @param[in] ssConfig The configuration string for the connection.
* @param[in] ssInsertBefore Reference to the string to connection to insert the the new connection before, or empty
* when the the new connection should be placed at the end.
* @return Returns whether the connection could be added (fails when the connection already exists).
*/
boolean AddConnectionConfig(in u8string ssName, in u8string ssConfig, in u8string ssInsertBefore);
/**
* @brief Remove a connection configuration with the provided name.
* @param[in] ssName Name of the connection configuration.
* @return Returns whether the removal was successful.
*/
boolean RemoveConnectionConfig(in u8string ssName);
/**
* @brief Return the number of retries to establish a connection.
* @return Number of retries.
*/
uint32 GetConnectRetries() const;
};
}; // module app
}; // module sdv

View File

@@ -53,31 +53,56 @@ module sdv
};
/**
* @brief Connect to a remote system. Provided by the ConnectClient utility.
* @brief Connect to a remote system. Provided by the Connection service.
* @details This interface is exposed by the connection client service. The configuration is provided during instantiation
* of the object and is of the form:
* @code
* # Provider to use for the connection
* [Provider]
* Name = ""
*
* # Additional channel information for the client
* [IpcChannel]
* xyz = ""
* @endcode
*
* For example for shared memory:
* @code
* [Provider]
* Name = "DefaultSharedMemory"
* [IpcChannel]
* Name = "LISTENER_1234"
* @endcode
*/
interface IClientConnect
{
/**
* @brief Connect to a remote system using the connection string to contact the system.
* @remarks After a successful connection, the ConnectClient utility is not needed any more.
* @param[in] ssConnectString Optional connection string to use for connection. If not provided, the connection will
* automatically get the connection ID from the app-control service (default). The connection string for a local
* connection can be of the form:
* @code
* [Client]
* Type = "local"
* Instance = 1234 # Optional: only use when connecting to a system with a different instance ID.
* @endcode
* And the following can be used for a remote connection:
* @code
* [Client]
* Type = "remote"
* Interface = "127.0.0.1"
* Port = 2000
* @endcode
* @return Returns an interface to the repository of the remote system or a NULL pointer if not found.
* @brief Connect to a remote system.
* @return Returns whether connect was successful.
*/
IInterfaceAccess Connect(in u8string ssConnectString) raises(XAccessDenied, XNotFound, XInvalidState, XTimeout);
boolean Connect() raises(XAccessDenied, XNotFound, XInvalidState, XTimeout);
/**
* @brief Disconnect from a connected system.
* @return Returns whether disconnect was successful.
*/
boolean Disconnect() raises(XAccessDenied, XNotFound, XInvalidState, XTimeout);
/**
* @brief State of the current connection.
* @return Returns whether an active connection exists.
*/
boolean IsConnected() const;
/**
* @brief Get the remote repository that is available after connection.
* @remarks For main, isolated and external applications, the remote repository will be automatically linked to the
* local repository. Hence a requests for the repository is not needed. For all other applications, access must be
* explicitly acquired through this interface.
* @return Interface to the remote repository if a successful connection is established. The interface is valid until
* disconnect is called or the client connection service is terminated.
*/
IInterfaceAccess GetRemoteRepository();
};
/**

View File

@@ -389,6 +389,17 @@ module sdv
u8string ssInstallName; ///< Name of the installation.
};
/**
* @brief The package exceeds the maximum size.
*/
exception XPackageSizeExceeded : XSysExcept
{
/** Description */
const char _description[] = "Maximum package size exceeded.";
u8string ssFileName; ///< Name of the file which causes the exception.
};
/**
* @brief The installation doesn't contain a module.
*/

View File

@@ -56,12 +56,29 @@ module sdv
*/
template <typename TInterface>
TInterface* GetInterface()
{
try
{
return GetInterface(sdv::GetInterfaceId<TInterface>()).template get<TInterface>();
} catch (const XSysExcept&)
{
return nullptr;
}
}
#verbatim_end
};
/**
* @brief Core features.
*/
module core
{
/**
* @brief Object ID.
*/
typedef uint64 TObjectID;
};
/**
* @brief Object type enumeration.
*/
@@ -170,6 +187,17 @@ module sdv
running = 30, ///< The component should switch to running mode.
};
/**
* @brief Object information supplied to the object initialization function.
*/
struct SObjectInfo
{
core::TObjectID tObjectID; ///< Object ID (local for the running process)
SClassInfo sClassInfo; ///< Object class information
u8string ssName; ///< Object name
u8string ssConfig; ///< Object configuration TOML
};
/**
* @brief Optional interface allowing for additional control of more complex SDVObjects.
* To be implemented if the object in question calls other SDVobjects via running threads or callbacks,
@@ -179,9 +207,9 @@ module sdv
{
/**
* @brief Initialize the object.
* @param[in] ssObjectConfig Optional configuration string.
* @param[in] sObjectInfo The registration information of this object.
*/
void Initialize(in u8string ssObjectConfig);
void Initialize(in SObjectInfo sObjectInfo);
/**
* @brief Get the current state of the object.
@@ -247,50 +275,6 @@ module sdv
*/
uint32 GetCount() const;
};
/**
* @brief Attribute flags.
*/
enum EAttributeFlags : uint32
{
read_only = 0x100, ///< When set, the attribute is readonly.
};
/**
* @brief Attribute interface
*/
interface IAttributes
{
/**
* @brief Get a sequence with the available attribute names.
* @return The sequence of attribute names.
*/
sequence<u8string> GetNames() const;
/**
* @brief Get the attribute value.
* @param[in] ssAttribute Name of the attribute.
* @return The attribute value or an empty any-value if the attribute wasn't found or didn't have a value.
*/
any Get(in u8string ssAttribute) const;
/**
* @brief Set the attribute value.
* @param[in] ssAttribute Name of the attribute.
* @param[in] anyAttribute Attribute value to set.
* @return Returns 'true' when setting the attribute was successful or 'false' when the attribute was not found or the
* attribute is read-only or another error occurred.
*/
boolean Set(in u8string ssAttribute, in any anyAttribute);
/**
* @brief Get the attribute flags belonging to a certain attribute.
* @param[in] ssAttribute Name of the attribute.
* @return Returns the attribute flags (zero or more EAttributeFlags flags) or 0 when the attribute could not be found.
*/
uint32 GetFlags(in u8string ssAttribute) const;
};
}; // module sdv
#verbatim_begin

View File

@@ -13,6 +13,7 @@
#include "core.idl"
#include "process.idl"
#include "permission.idl"
/**
* @brief Software Defined Vehicle framework.
@@ -149,6 +150,7 @@ module sdv
TMarshallID tProxyID; ///< Proxy id to identify the proxy this packet is sending from or destined to.
TMarshallID tStubID; ///< Stub id to identify the stub this packet is destined to or receiving from.
uint64 uiCallIndex; ///< Call index to uniquely identify the call.
core::TPermissionID tPermissionID; ///< Permission ID used to elevate permission, or 0 for standard permission.
};
/**

View File

@@ -35,12 +35,15 @@ module sdv
///< identification must be similar to the following example:
///< @code
///< [Provider]
///< Name = "DefaultSharedMemoryChannelControl"
///< Name = "DefaultSharedMemory"
///< @endcode
};
/**
* @brief Interface for creating an IPC connection, which other participants can connect to via IChannelAccess
* @brief Interface for creating an IPC connection, which other participants can connect to via IChannelAccess.
* @attention The channel control object should allow the creation of channels with a fixed configuration (e.g. a provided
* name or a port), which is necessary for the creation of a listener. It also should allow dynamic channel creation (e.g.
* automatic name or port-number) to create additional connections between components.
*/
interface ICreateEndpoint
{

View File

@@ -0,0 +1,96 @@
/********************************************************************************
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
*
* This program and the accompanying materials are made available under the
* terms of the Apache License Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Erik Verhoeven - initial API and implementation
********************************************************************************/
#include "core.idl"
/**
* @brief Software Defined Vehicle framework.
*/
module sdv
{
/**
* @brief Core features.
*/
module core
{
/// ID corresponding to a thread specific permission request.
typedef uint64 TPermissionID;
/// ID identifying a permission transfer.
typedef uint64 TPermissionTransferID;
/**
* @brief Access type restriction. The lower the access, the more restricted.
*/
enum EAccessPermission : int32
{
not_set = -1001, ///< Permissions are not set; will be treated as restricted access.
restricted_access = -1000, ///< Restricted access (default when no other set).
remote_access = -200, ///< Access for remote execution. Access allowed to basic and complex services.
local_access = -100, ///< Access for isolated execution. Access allowed to system, basic and complex services.
full_access = 0, ///< Full access is allowed to complete system.
};
/**
* @brief Permission control interface. This interface is used for restricting permission on a thread and transferring
* permissions from one thread to another.
*/
interface IPermissionControl
{
/**
* @brief Restrict the access permission for the current thread.
* @remarks The access restriction will be assigned to the current thread and combined with previous and future
* permissions. The lowest assigned permission will determine the actual access permission for the current thread.
* @remarks The access restriction will stay in effect until it is released by the function ReleaseAccessPermission.
* @remarks A newly created thread has fully restricted access. This cannot be changed using this function. Use an
* access restriction transfer from one thread to this thread to set a higher level of access permission.
* @param[in] ePermission The permission to restrict to.
* @return The permission ID for this restriction or 0 when the access permission could not be set. Use the
* ReleaseAccessPermission to release the restriction again.
*/
TPermissionID RestrictAccessPermission(in EAccessPermission ePermission);
/**
* @brief Release a previously set access restriction for the current thread.
* @param[in] tPermissionID The ID of the access restriction previously set for the current thread.
* @return Returns whether the restriction could be released successfully.
*/
boolean ReleaseAccessPermission(in TPermissionID tPermissionID);
/**
* @brief Prepares a transfer of the access restriction from the current thread.
* @return The ID of the transfer object containing the current access permissions or 0 when the transfer preparation
* has failed.
*/
TPermissionTransferID TransferCurrentPermission();
/**
* @brief Set the access permission using a transfer object from one thread to another.
* @remarks An new thread has fully restricted access per default. Use this function to set the required access level.
* If a thread has already initialized with the proper access level, this function will set identical or lower access
* permissions for the current thread.
* @param[in] tTransferID The IS of the prepared access permission transfer.
* @return The permission ID for this restriction or 0 when the access permission could not be transferred. Use the
* ReleaseAccessPermission to release the restriction again.
*/
TPermissionID SetAccessPermission(in TPermissionTransferID tTransferID);
/**
* @brief Get the access permission level for the current thread. This will be the lowest restriction set for the
* current thread.
* @return The current access permission level.
*/
EAccessPermission GetCurrentPermission() const;
};
}; // module core
}; // module sdv

View File

@@ -25,11 +25,6 @@ module sdv
module core
{
/**
* @brief Object ID.
*/
typedef uint64 TObjectID;
/**
* @brief Interface used to access objects from other modules via the repository service
*/
@@ -229,6 +224,32 @@ module sdv
TObjectID RegisterObject(in IInterfaceAccess pObjectIfc, in u8string ssObjectName);
};
/**
* @brief The object dependency can be used to state dependencies between two objects. This influence is used during
* shutdown to determine the termination order.
*/
interface IObjectDependency
{
/**
* @brief Add a dependency for an object.
* @param ssObjectName Name of the object.
* @param ssDependsOnObject Name of the object it depends on.
*/
void AddObjectDependency(in u8string ssObjectName, in u8string ssDependsOnObject);
/**
* @brief Remove an object dependency.
* @param ssObjectName Name of the object.
* @param ssDependsOnObject Name of the object it depends on.
*/
void RemoveObjectDependency(in u8string ssObjectName, in u8string ssDependsOnObject);
};
/**
* @brief Link ID.
*/
typedef uint64 TLinkID;
/**
* @brief Connect the core repository to the local repository to allow object access by the locally running components.
* @remarks This interface is available only for isolated and external applications.
@@ -238,13 +259,15 @@ module sdv
/**
* @brief Register the core repository.
* @param[in] pCoreRepository Pointer to the proxy interface of the core repository.
* @return Returns a link ID to be used in the Unlink function. Or 0 on failure.
*/
void LinkCoreRepository(in IInterfaceAccess pCoreRepository);
TLinkID LinkCoreRepository(in IInterfaceAccess pCoreRepository);
/**
* @brief Unlink a previously linked core repository.
* @param[in] tLinkID Link ID of the repository link to remove.
*/
void UnlinkCoreRepository();
void UnlinkCoreRepository(in TLinkID tLinkID);
};
}; // module core

View File

@@ -142,10 +142,10 @@ module sdv
u8string GetComment(in ECommentType eType);
/**
* @brief Format the node automatically. This will remove the whitespace between the elements within the node. Comments
* will not be changed.
* @brief Format the node automatically, remove redundant whitespace.
* @param[in] bRemoveComments When set, the comments are removed from the node.
*/
void AutomaticFormat();
void AutomaticFormat(in boolean bRemoveComments);
/**
* @brief Is the node inline?
@@ -265,46 +265,14 @@ module sdv
/**
* @brief Convert the node to a standard node.
* @param[in] bIncludeChildren When set, applicable child nodes are made are converted to standard nodes as well (only
* tables and table-arrays can be defined as standard).
* @return Returns whether the conversion was successful. Returns 'true' when the node was already defined as standard
* node.
*/
boolean MakeStandard();
boolean MakeStandard(in boolean bIncludeChildren);
};
/**
* @brief Extend the collection node with values, arrays and tables.
*/
interface INodeCollectionInsert
{
/**
* @brief Insert a value into the collection at the location before the supplied index.
* @param[in] uiIndex The insertion location to insert the node before. Can be npos or any value larger than the
* collection count to insert the node at the end of the collection. Value nodes cannot be inserted behind external
* tables and table arrays. If the index is referencing a position behind an external table or a table array, the index
* is automatically corrected.
* @param[in] ssName Name of the node to insert. Will be ignored for an array collection. The name must adhere to the
* key names defined by the TOML specification. Defining the key multiple times is not allowed. Quotation of key names
* is done automatically; the parser decides itself whether the key is bare-key, a literal key or a quoted key.
* @param[in] anyValue The value of the node, being either an integer, floating point number, boolean value or a string.
* Conversion is automatically done to int64, double float, bool or u8string.
* @return On success the interface to the newly inserted node is returned or NULL otherwise.
*/
IInterfaceAccess InsertValue(in uint32 uiIndex, in u8string ssName, in any anyValue);
/**
* @brief Insert an array into the collection at the location before the supplied index.
* @param[in] uiIndex The insertion location to insert the node before. Can be npos or any value larger than the
* collection count to insert the node at the end of the collection. Array nodes cannot be inserted behind external
* tables and table arrays. If the index is referencing a position behind an external table or a table array, the index
* is automatically corrected.
* @param[in] ssName Name of the array node to insert. Will be ignored if the current node is also an array collection.
* The name must adhere to the key names defined by the TOML specification. Defining the key multiple times is not
* allowed. Quotation of key names is done automatically; the parser decides itself whether the key is bare-key, a
* literal key or a quoted key.
* @return On success the interface to the newly inserted node is returned or NULL otherwise.
*/
IInterfaceAccess InsertArray(in uint32 uiIndex, in u8string ssName);
/**
* @brief Insertion preference for tables and table arrays, being standard or inline.
*/
@@ -314,35 +282,74 @@ module sdv
prefer_inline = 1, ///< The node will be inserted as inline node.
};
/**
* @brief Extend the collection node with values, arrays and tables.
*/
interface INodeCollectionInsert
{
/**
* @brief Insert a value into the collection at the location before the supplied index.
* @remarks In TOML, inline nodes are located before standard nodes. Since values are presented as inline node, they
* will be inserted before any standard node (table or table array if defined as standard node).
* @param[in] ssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
* square brackets. Can be empty, causing the node to be inserted at the end.
* @param[in] ssName Name of the node to insert. This name can contain parent nodes, which are automatically created if
* not existing. With arrays, since the value in TOML doesn't have a name, the name of the value must be an empty
* string and any names provided are considered parent nodes. The name must adhere to the key names defined by the TOML
* specification. Defining the key multiple times is not allowed. Quotation of key names is done automatically; the
* parser decides itself whether the key is bare-key, a literal key or a quoted key.
* @param[in] anyValue The value of the node, being either an integer, floating point number, boolean value or a string.
* Conversion is automatically done to int64, double float, bool or u8string.
* @return On success the interface to the newly inserted node is returned or NULL otherwise.
*/
IInterfaceAccess InsertValue(in u8string ssInsertBefore, in u8string ssName, in any anyValue);
/**
* @brief Insert an array into the collection at the location before the supplied index.
* @remarks In TOML, inline nodes are located before standard nodes. Since arrays are presented as inline node, they
* will be inserted before any standard node (table or table array if defined as standard node).
* @param[in] ssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
* square brackets. Can be empty, causing the node to be inserted at the end.
* @param[in] ssName Name of the node to insert. This name can contain parent nodes, which are automatically created if
* not existing. With arrays, since the value in TOML doesn't have a name, the name of the value must be an empty
* string and any names provided are considered parent nodes. The name must adhere to the key names defined by the TOML
* specification. Defining the key multiple times is not allowed. Quotation of key names is done automatically; the
* parser decides itself whether the key is bare-key, a literal key or a quoted key.
* @return On success the interface to the newly inserted node is returned or NULL otherwise.
*/
IInterfaceAccess InsertArray(in u8string ssInsertBefore, in u8string ssName);
/**
* @brief Insert a table into the collection at the location before the supplied index.
* @param[in] uiIndex The insertion location to insert the node before. Can be npos or any value larger than the
* collection count to insert the node at the end of the collection. Table nodes cannot be inserted before value nodes
* or arrays. If the index is referencing a position before a value node or an array, the index is automatically
* corrected.
* @param[in] ssName Name of the table node to insert. Will be ignored if the parent node is an array collection.
* The name must adhere to the key names defined by the TOML specification. Defining the key multiple times is not
* allowed. Quotation of key names is done automatically; the parser decides itself whether the key is bare-key, a
* literal key or a quoted key.
* @remarks In TOML, inline nodes are located before standard nodes. Tables can be inserted as inline node, in which
* case they will be inserted before any standard node (table or table array if defined as standard node).
* @param[in] ssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
* square brackets. Can be empty, causing the node to be inserted at the end.
* @param[in] ssName Name of the node to insert. This name can contain parent nodes, which are automatically created if
* not existing. With arrays, since the value in TOML doesn't have a name, the name of the value must be an empty
* string and any names provided are considered parent nodes. The name must adhere to the key names defined by the TOML
* specification. Defining the key multiple times is not allowed. Quotation of key names is done automatically; the
* parser decides itself whether the key is bare-key, a literal key or a quoted key.
* @param[in] ePreference The preferred form of the node to be inserted.
* @return On success the interface to the newly inserted node is returned or NULL otherwise.
*/
IInterfaceAccess InsertTable(in uint32 uiIndex, in u8string ssName, in EInsertPreference ePreference);
IInterfaceAccess InsertTable(in u8string ssInsertBefore, in u8string ssName, in EInsertPreference ePreference);
/**
* @brief Insert a table array into the collection at the location before the supplied index.
* @param[in] uiIndex The insertion location to insert the node before. Can be npos or any value larger than the
* collection count to insert the node at the end of the collection. Table array nodes cannot be inserted before value
* nodes or arrays. If the index is referencing a position before a value node or an array, the index is automatically
* corrected.
* @param[in] ssName Name of the array node to insert. Will be ignored if the parent node is also an array collection.
* The name must adhere to the key names defined by the TOML specification. Defining the key multiple times is not
* allowed. Quotation of key names is done automatically; the parser decides itself whether the key is bare-key, a
* literal key or a quoted key.
* @remarks In TOML, inline nodes are located before standard nodes. Table arrays can be inserted as inline node, in
* which case they will be inserted before any standard node (table or table array if defined as standard node).
* @param[in] ssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
* square brackets. Can be empty, causing the node to be inserted at the end.
* @param[in] ssName Name of the node to insert. This name can contain parent nodes, which are automatically created if
* not existing. With arrays, since the value in TOML doesn't have a name, the name of the value must be an empty
* string and any names provided are considered parent nodes. The name must adhere to the key names defined by the TOML
* specification. Defining the key multiple times is not allowed. Quotation of key names is done automatically; the
* parser decides itself whether the key is bare-key, a literal key or a quoted key.
* @param[in] ePreference The preferred form of the node to be inserted.
* @return On success the interface to the newly inserted node is returned or NULL otherwise.
*/
IInterfaceAccess InsertTableArray(in uint32 uiIndex, in u8string ssName, in EInsertPreference ePreference);
IInterfaceAccess InsertTableArray(in u8string ssInsertBefore, in u8string ssName, in EInsertPreference ePreference);
/**
* @brief The result of the TOML string to insert.
@@ -358,17 +365,15 @@ module sdv
* @brief Insert a TOML string as a child of the current collection node. If the collection is a table, the TOML string
* should contain values and inline/external/array-table nodes with names. If the collection is an array, the TOML
* string should contain and inline table nodes without names.
* @attention Even though the TOML might be defining the node(s) in standard form, if the parent node is an inline node,
* the node will be inserted as inline node.
* @param[in] uiIndex The insertion location to insert the node before. Can be npos or any value larger than the
* collection count to insert the node at the end of the collection. Table array nodes cannot be inserted before value
* nodes or arrays. If the index is referencing a position before a value node or an array, the index is automatically
* corrected.
* @remarks In TOML, inline nodes are located before standard nodes. Dependable on the nodes defined in the TOML they
* might be transferred to inline or they might be inserted at a different location.
* @param[in] ssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
* square brackets. Can be empty, causing the node to be inserted at the end.
* @param[in] ssTOML The TOML string to insert. This string can hold one or more nodes that should be inserted.
* @param[in] bRollbackOnFailure If only part of the nodes could be inserted, no node will be inserted.
* @return The result of the insertion.
*/
EInsertResult InsertTOML(in uint32 uiIndex, in u8string ssTOML, in boolean bRollbackOnFailure);
EInsertResult InsertTOML(in u8string ssInsertBefore, in u8string ssTOML, in boolean bRollbackOnFailure);
};
/**

View File

@@ -24,6 +24,9 @@
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 26495)
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
namespace sdv
@@ -1738,6 +1741,8 @@ namespace sdv
#ifdef _MSC_VER
#pragma warning(pop)
#else
#pragma GCC diagnostic pop
#endif
#endif // !defined SDV_ANY_INL

View File

@@ -65,6 +65,7 @@ namespace sdv
bool Startup(const std::string& rssConfig)
{
IAppControl* pAppControl = core::GetCore() ? core::GetCore<IAppControl>() : nullptr;
if (!pAppControl) return false;
if (m_eState != EAppOperationState::not_started) return false;
try
@@ -78,45 +79,6 @@ namespace sdv
{
m_eContext = pAppContext->GetContextType();
m_uiInstanceID = pAppContext->GetInstanceID();
m_uiRetries = pAppContext->GetRetries();
}
// Automatically connect to the server
if (m_eContext == EAppContext::external)
{
// Try to connect
m_ptrServerRepository = sdv::com::ConnectToLocalServerRepository(m_uiInstanceID, m_uiRetries);
if (!m_ptrServerRepository)
{
if (!ConsoleIsSilent())
std::cerr << "ERROR: Failed to connect to the server repository." << std::endl;
Shutdown();
return false;
}
// Get access to the module control service
sdv::core::IObjectAccess* pObjectAccess = m_ptrServerRepository.GetInterface<sdv::core::IObjectAccess>();
const sdv::core::IRepositoryControl* pRepoControl = nullptr;
if (pObjectAccess)
pRepoControl = sdv::TInterfaceAccessPtr(pObjectAccess->GetObject("RepositoryService")).
GetInterface<sdv::core::IRepositoryControl>();
if (!pRepoControl)
{
if (!ConsoleIsSilent())
std::cerr << "ERROR: Failed to access the server repository." << std::endl;
return false;
}
// Link the local repository to the server repository.
sdv::core::ILinkCoreRepository* pLinkCoreRepo =
sdv::core::GetObject<sdv::core::ILinkCoreRepository>("RepositoryService");
if (!pLinkCoreRepo)
{
if (!ConsoleIsSilent())
std::cerr << "ERROR: Cannot link local and server repositories." << std::endl;
return false;
}
pLinkCoreRepo->LinkCoreRepository(m_ptrServerRepository);
}
return bRet;
@@ -154,23 +116,6 @@ namespace sdv
*/
void Shutdown()
{
// Disconnect local and remote repositories.
if (m_ptrServerRepository)
{
// Link the local repository to the server repository.
sdv::core::ILinkCoreRepository* pLinkCoreRepo =
sdv::core::GetObject<sdv::core::ILinkCoreRepository>("RepositoryService");
if (!pLinkCoreRepo)
{
if (!ConsoleIsSilent())
std::cerr << "ERROR: Cannot unlink local and server repositories." << std::endl;
} else
pLinkCoreRepo->UnlinkCoreRepository();
}
// Disconnect from the server (if connected at all).
m_ptrServerRepository.Clear();
// Shutdown.
IAppControl* pAppControl = core::GetCore() ? core::GetCore<IAppControl>() : nullptr;
try
@@ -194,28 +139,86 @@ namespace sdv
return m_eState == EAppOperationState::running;
}
/**
* @brief Get the absolute path to the currently run executable
* @return Absolute std::filesystem::path to the currently run executable
*/
static std::filesystem::path GetAppDirectory()
{
static std::filesystem::path pathExeDir;
if (!pathExeDir.empty())
return pathExeDir;
#ifdef _WIN32
// Windows specific
std::wstring ssPath(32768, '\0');
GetModuleFileNameW(NULL, ssPath.data(), static_cast<DWORD>(ssPath.size() - 1));
#elif defined __linux__
// Linux specific
std::string ssPath(PATH_MAX + 1, '\0');
const ssize_t nCount = readlink("/proc/self/exe", ssPath.data(), PATH_MAX);
if (nCount < 0 || nCount >= PATH_MAX)
return pathExeDir; // some error
ssPath.at(nCount) = '\0';
#else
#error OS is not supported!
#endif
pathExeDir = std::filesystem::path{ssPath.c_str()}.parent_path() / ""; // To finish the folder path with (back)slash
return pathExeDir;
}
/**
* @brief Get the filename of the currently run executable
* @return The filename to the currently run executable
*/
static std::filesystem::path GetAppFilename()
{
static std::filesystem::path pathExeFilename;
if (!pathExeFilename.empty())
return pathExeFilename;
#ifdef _WIN32
// Windows specific
std::wstring ssPath(32768, '\0');
GetModuleFileNameW(NULL, ssPath.data(), static_cast<DWORD>(ssPath.size() - 1));
#elif defined __linux__
// Linux specific
std::string ssPath(PATH_MAX + 1, '\0');
const ssize_t nCount = readlink("/proc/self/exe", ssPath.data(), PATH_MAX);
if (nCount < 0 || nCount >= PATH_MAX)
return pathExeFilename; // some error
ssPath.at(nCount) = '\0';
#else
#error OS is not supported!
#endif
pathExeFilename = std::filesystem::path{ssPath.c_str()}.filename();
return pathExeFilename;
}
/**
* @brief Get the SDV_FRAMEWORK_RUNTIME environment variable for this application.
* @return Path directing to the SDV V-API Framework directory if available or an empty path if not.
* @remarks If the environment variable is empty or if the variable contains a relative path, the path will be enhanced
* with the application path.
* @return Absolute path directing to the SDV Vehicle API Framework directory.
*/
static std::filesystem::path GetFrameworkRuntimeDirectory()
{
std::filesystem::path path;
#ifdef _WIN32
const wchar_t* szFrameworkDir = _wgetenv(L"SDV_FRAMEWORK_RUNTIME");
if (!szFrameworkDir) return {};
return szFrameworkDir;
if (szFrameworkDir) path = szFrameworkDir;
#elif defined __unix__
const char* szFrameworkDir = getenv("SDV_FRAMEWORK_RUNTIME");
if (!szFrameworkDir) return {};
return szFrameworkDir;
if (szFrameworkDir) path = szFrameworkDir;
#else
#error The OS is not supported!
#endif
if (path.empty() || path.is_relative()) path = GetAppDirectory() / path;
return path.lexically_normal();
}
/**
* @brief Set or overwrite the SDV_FRAMEWORK_RUNTIME environment variable for this application.
* @param[in] rpathDir Reference of the path directing to the SDV V-API Framework directory.
* @param[in] rpathDir Reference of the path directing to the SDV Vehicle API Framework directory.
*/
static void SetFrameworkRuntimeDirectory(const std::filesystem::path& rpathDir)
{
@@ -232,26 +235,30 @@ namespace sdv
/**
* @brief Get the SDV_COMPONENT_INSTALL environment variable for this application.
* @return Path directing to the SDV V-API component installation directory if available or an empty path if not.
* @remarks If the environment variable is empty, the runtime directory is taken. If the variable contains a relative
* path, the path will be enhanced with the application path.
* @return Absolute path directing to the SDV Vehicle API component installation directory.
*/
static std::filesystem::path GetComponentInstallDirectory()
{
std::filesystem::path path;
#ifdef _WIN32
const wchar_t* szComponentDir = _wgetenv(L"SDV_COMPONENT_INSTALL");
if (!szComponentDir) return {};
return szComponentDir;
if (szComponentDir) path = szComponentDir;
#elif defined __unix__
const char* szComponentDir = getenv("SDV_COMPONENT_INSTALL");
if (!szComponentDir) return {};
return szComponentDir;
if (szComponentDir) path = szComponentDir;
#else
#error The OS is not supported!
#endif
if (path.empty()) return GetFrameworkRuntimeDirectory();
if (path.is_relative()) path = GetAppDirectory() / path;
return path.lexically_normal();
}
/**
* @brief Set or overwrite the SDV_COMPONENT_INSTALL environment variable for this application.
* @param[in] rpathDir Reference of the path directing to the SDV V-API component installation directory.
* @param[in] rpathDir Reference of the path directing to the SDV Vehicle API component installation directory.
*/
static void SetComponentInstallDirectory(const std::filesystem::path& rpathDir)
{
@@ -527,8 +534,7 @@ namespace sdv
EAppOperationState m_eState = EAppOperationState::not_started; ///< Application state.
EAppContext m_eContext = EAppContext::no_context; ///< Application context.
uint32_t m_uiInstanceID = 0u; ///< Core instance.
uint32_t m_uiRetries = 0u; ///< Number of retries to establish a connection.
sdv::TObjectPtr m_ptrServerRepository; ///< Server repository interface.
uint32_t m_uiConnectRetries = 0u; ///< Number of retries to establish a connection.
};
} // namespace app
} // namespace sdv

View File

@@ -20,6 +20,8 @@
#include <vector>
#include <string>
#include <sstream>
#include <atomic>
#include <memory>
#include "../interfaces/core_types.h"
#include "../interfaces/core.h"
@@ -683,9 +685,9 @@ namespace sdv
/**
* @brief Initialize the object. Overload of IObjectControl::Initialize.
* @param[in] ssObjectConfig Optional configuration string.
* @param[in] sObjectInfo The registration information of this object.
*/
virtual void Initialize(/*in*/ const u8string& ssObjectConfig) override
virtual void Initialize(/*in*/ const SObjectInfo& sObjectInfo) override
{
// Not started before or ended completely?
if (GetObjectState() != EObjectState::initialization_pending && GetObjectState() != EObjectState::destruction_pending)
@@ -700,19 +702,19 @@ namespace sdv
// Initialize the parameter map.
InitParamMap();
// Copy the configuration
m_ssObjectConfig = ssObjectConfig;
// Copy the object information
m_sSelf = sObjectInfo;
// Prepare initialization
OnPreInitialize();
// Parse the object configuration if there is any.
if (!ssObjectConfig.empty())
if (!m_sSelf.ssConfig.empty())
{
try
{
// Parse the config TOML.
toml::CTOMLParser parser(ssObjectConfig);
toml::CTOMLParser parser(m_sSelf.ssConfig);
if (!parser.IsValid())
{
m_eObjectState = EObjectState::config_error;
@@ -781,6 +783,15 @@ namespace sdv
return m_eObjectState;
}
/**
* @brief Get information about ourself.
* @return The object information about ourself.
*/
const SObjectInfo& Self() const
{
return m_sSelf;
}
/**
* @brief Set the component operation mode. Overload of IObjectControl::SetOperationMode.
* @param[in] eMode The operation mode, the component should run in.
@@ -831,15 +842,11 @@ namespace sdv
}
/**
* @brief Get the object configuration for persistence.
* @brief Build the object configuration from the parameter map and the stored initial configuration.
* @return The object configuration as TOML string.
*/
virtual u8string GetObjectConfig() const override
virtual u8string BuildObjectConfig() const
{
// During the initialization, return the stored object configuration.
if (m_eObjectState == EObjectState::initializing || m_eObjectState == EObjectState::initialization_pending)
return m_ssObjectConfig;
// Split path function (splits the group from the parameter names)
auto fnSplitPath = [](const u8string& rssPath) -> std::pair<u8string, u8string>
{
@@ -849,13 +856,10 @@ namespace sdv
return std::make_pair(rssPath.substr(0, nPos), rssPath.substr(nPos + 1));
};
// Create a new configuration string from the parameters.
auto seqParameters = GetParamPaths();
if (seqParameters.empty()) return {};
// Iterate through the list of parameter names and create the TOML entries for it.
auto seqParameters = GetParamPaths();
u8string ssGroup;
toml::CTOMLParser parser("");
toml::CTOMLParser parser(m_sSelf.ssConfig);
toml::CNodeCollection table(parser);
for (auto ssParamPath : seqParameters)
{
@@ -863,7 +867,7 @@ namespace sdv
auto ptrParam = FindParamObject(ssParamPath);
// Read only and temporary parameters are not stored
if ((!ptrParam->Locked() && ptrParam->ReadOnly()) || !ptrParam->Temporary())
if ((!ptrParam->Locked() && ptrParam->ReadOnly()) || ptrParam->Temporary())
continue;
// Get the value
@@ -877,6 +881,8 @@ namespace sdv
// Need to add a group?
if (prParam.first != ssGroup)
{
table = parser.GetDirect(prParam.first);
if (!table)
table = parser.AddTable(prParam.first);
ssGroup = prParam.first;
}
@@ -888,6 +894,20 @@ namespace sdv
return parser.GetTOML();
}
/**
* @brief Get the object configuration for persistence. Overload of IObjectControl::GetObjectConfig.
* @return The object configuration as TOML string.
*/
virtual u8string GetObjectConfig() const override
{
// During the initialization, return the stored object configuration.
if (m_eObjectState == EObjectState::initializing || m_eObjectState == EObjectState::initialization_pending)
return m_sSelf.ssConfig;
return BuildObjectConfig();
}
/**
* @brief Shutdown called before the object is destroyed. Overload of IObjectControl::Shutdown.
* @attention Implement calls to other SDV objects here as this is no longer considered safe during the destructor of the
@@ -992,6 +1012,12 @@ namespace sdv
*/
virtual void OnShutdown() {}
/**
* @brief Last function called before destruction. The object integrity is still in tact. It can be assumed that all
* dependencies to the object have been released.
*/
virtual void OnDestroy() {}
/**
* @brief Interface map
*/
@@ -1002,7 +1028,8 @@ namespace sdv
private:
std::atomic<EObjectState> m_eObjectState = EObjectState::initialization_pending; ///< Object state
std::string m_ssObjectConfig; ///< Copy of the configuration TOML.
CLifetimeCookie m_lifetime = CreateLifetimeCookie(); ///< Manage module lifetime.
SObjectInfo m_sSelf; ///< Information about ourself.
};
/**
@@ -1022,6 +1049,206 @@ namespace sdv
END_SDV_INTERFACE_MAP()
};
/**
* @brief Lifetime control implementation class.
*/
class CLifetimeControlImpl : public virtual IInterfaceAccess, public IObjectLifetime, protected IObjectDestroy
{
public:
/**
* @brief Default constructor
*/
CLifetimeControlImpl()
{}
/**
* @brief Deleted copy constructor.
* @param[in] rClass Reference to the class to copy from.
*/
CLifetimeControlImpl(const CLifetimeControlImpl& rClass) = delete;
/**
* @brief Deleted move constructor.
* @param[in] rClass Reference to the class to copy from.
*/
CLifetimeControlImpl(CLifetimeControlImpl&& rClass) = delete;
/**
* @brief Destructor.
*/
virtual ~CLifetimeControlImpl()
{}
// Interface map (IObjectDestroy is not exposed)
BEGIN_SDV_INTERFACE_MAP()
SDV_INTERFACE_ENTRY(IObjectLifetime)
END_SDV_INTERFACE_MAP()
/**
* @brief Deleted copy assignment constructor.
* @param[in] rClass Reference to the class to copy from.
* @return Reference to this class.
*/
CLifetimeControlImpl& operator=(const CLifetimeControlImpl& rClass) = delete;
/**
* @brief Deleted move assignment constructor.
* @param[in] rClass Reference to the class to copy from.
* @return Reference to this class.
*/
CLifetimeControlImpl& operator=(CLifetimeControlImpl&& rClass) = delete;
/**
* @brief Increment the lifetime. Needs to be balanced by a call to Decrement. Overload of IObjectLifetime::Increment.
*/
virtual void Increment() override
{
m_uiLifetimeCnt++;
}
/**
* @brief Decrement the lifetime. If the lifetime reaches zero, the object will be destroyed (through the exposed
* IObjectDestroy interface). Overload of IObjectLifetime::Decrement.
* @return Returns 'true' if the object was destroyed, false if not.
*/
virtual bool Decrement() override
{
if (m_uiLifetimeCnt && !(--m_uiLifetimeCnt))
{
DestroyObject();
return true;
}
return false;
}
/**
* @brief Get the current lifetime count. Overload of IObjectLifetime::GetCount.
* @remarks The GetCount function returns a momentary value, which can be changed at any moment.
* @return Returns the current counter value.
*/
virtual uint32_t GetCount() const override
{
return m_uiLifetimeCnt;
}
protected:
/**
* @brief Destroy the object. Default implementation deletes 'this'. Overload of IObjectDestroy::DestroyObject.
* @attention After a call of this function, all exposed interfaces render invalid and should not be used any more.
*/
virtual void DestroyObject() override
{
delete this;
}
private:
CLifetimeCookie m_lifetime = CreateLifetimeCookie(); ///< Module lifetime
std::atomic_uint32_t m_uiLifetimeCnt = 1; ///< Lifetime reference counter
};
/**
* @brief Lifetime control implementation class based on shared pointer.
* @tparam TClass The type of class deriving CSharedLifetimeControlImpl class.
*/
template <class TClass>
class CSharedLifetimeControlImpl : public std::enable_shared_from_this<TClass>, public CLifetimeControlImpl
{
public:
/**
* @brief Default constructor
*/
CSharedLifetimeControlImpl()
{}
/**
* @brief Deleted copy constructor.
* @param[in] rClass Reference to the class to copy from.
*/
CSharedLifetimeControlImpl(const CSharedLifetimeControlImpl& rClass) = delete;
/**
* @brief Deleted move constructor.
* @param[in] rClass Reference to the class to copy from.
*/
CSharedLifetimeControlImpl(CSharedLifetimeControlImpl&& rClass) = delete;
/**
* @brief Destructor.
*/
virtual ~CSharedLifetimeControlImpl()
{
}
// Interface map (IObjectDestroy is not exposed)
BEGIN_SDV_INTERFACE_MAP()
SDV_INTERFACE_ENTRY(IObjectLifetime)
END_SDV_INTERFACE_MAP()
/**
* @brief Deleted copy assignment constructor.
* @param[in] rClass Reference to the class to copy from.
* @return Reference to this class.
*/
CSharedLifetimeControlImpl& operator=(const CSharedLifetimeControlImpl& rClass) = delete;
/**
* @brief Deleted move assignment constructor.
* @param[in] rClass Reference to the class to copy from.
* @return Reference to this class.
*/
CSharedLifetimeControlImpl& operator=(CSharedLifetimeControlImpl&& rClass) = delete;
/**
* @brief Increment the lifetime. Needs to be balanced by a call to Decrement. Overload of IObjectLifetime::Increment.
*/
virtual void Increment() override
{
if (!m_uiLifetimeCnt++)
m_ptrLocking = std::enable_shared_from_this<TClass>::shared_from_this();
}
/**
* @brief Decrement the lifetime. If the lifetime reaches zero, the object will be destroyed (through the exposed
* IObjectDestroy interface). Overload of IObjectLifetime::Decrement.
* @return Returns 'true' if the object was destroyed, false if not.
*/
virtual bool Decrement() override
{
if (m_uiLifetimeCnt && !(--m_uiLifetimeCnt))
{
DestroyObject();
return true;
}
return false;
}
/**
* @brief Get the current lifetime count. Overload of IObjectLifetime::GetCount.
* @remarks The GetCount function returns a momentary value, which can be changed at any moment.
* @return Returns the current counter value.
*/
virtual uint32_t GetCount() const override
{
return m_uiLifetimeCnt;
}
protected:
/**
* @brief Destroy the object. Default implementation deletes 'this'. Overload of IObjectDestroy::DestroyObject.
* @attention After a call of this function, all exposed interfaces render invalid and should not be used any more.
*/
virtual void DestroyObject() override
{
// Reset the locking; this might delete the class if no other references are present.
m_ptrLocking.reset();
}
private:
std::shared_ptr<TClass> m_ptrLocking; ///< Holder of the instance of the class during lifetime.
CLifetimeCookie m_lifetime = CreateLifetimeCookie(); ///< Module lifetime
std::atomic_uint32_t m_uiLifetimeCnt = 0; ///< Lifetime reference counter
};
/////////////////////////////////////////
// Object control class implementation //
/////////////////////////////////////////
@@ -1114,6 +1341,7 @@ namespace sdv
auto objectPtr = std::move(*iter);
m_vecActiveObjects.erase(iter);
lockObjects.unlock();
objectPtr->OnDestroy();
objectPtr = nullptr;
if (m_uiActiveObjectCount) --m_uiActiveObjectCount;
return;

View File

@@ -388,8 +388,14 @@ namespace sdv
*/
template <typename TIfc>
TIfc* GetInterface() const
{
try
{
return m_pInterface ? m_pInterface.load()->GetInterface(GetInterfaceId<TIfc>()).template get<TIfc>() : nullptr;
} catch (const XSysExcept&)
{
return nullptr;
}
}
private:

View File

@@ -18,10 +18,17 @@
#include "../interfaces/log.h"
#include "../interfaces/repository.h"
#include "../interfaces/com.h"
#include "../interfaces/app.h"
#include "../interfaces/param.h"
#include "../interfaces/permission.h"
#include "interface_ptr.h"
#include <thread>
#include <utility>
#include <functional>
#include <sstream>
#include <utility>
#include <string>
#include <stdexcept>
#ifdef __GNUC__
// Needed for getpid()
#include <unistd.h>
@@ -49,9 +56,11 @@ namespace sdv
*/
inline TInterfaceAccessPtr GetObject(const std::string& rssObjectName)
{
if (!GetCore()) return nullptr;
if (!GetCore())
return nullptr;
IObjectAccess* pRepository = GetCore<IObjectAccess>();
if (!pRepository) return nullptr;
if (!pRepository)
return nullptr;
return pRepository->GetObject(rssObjectName);
}
@@ -63,9 +72,11 @@ namespace sdv
*/
inline TInterfaceAccessPtr GetObject(TObjectID tObjectID)
{
if (!GetCore()) return nullptr;
if (!GetCore())
return nullptr;
IObjectAccess* pRepository = GetCore<IObjectAccess>();
if (!pRepository) return nullptr;
if (!pRepository)
return nullptr;
return pRepository->GetObjectByID(tObjectID);
}
#else
@@ -123,11 +134,13 @@ namespace sdv
{
ILogger* pLogger = GetCore() ? GetCore<ILogger>() : nullptr;
#ifdef _WIN32
if (pLogger) pLogger->Log(eSeverity, rssSrcFile, uiSrcLine, _getpid(), "", rssMessage);
if (pLogger)
pLogger->Log(eSeverity, rssSrcFile, uiSrcLine, _getpid(), "", rssMessage);
#elif defined __unix__
if (pLogger) pLogger->Log(eSeverity, rssSrcFile, uiSrcLine, getpid(), "", rssMessage);
if (pLogger)
pLogger->Log(eSeverity, rssSrcFile, uiSrcLine, getpid(), "", rssMessage);
#else
#error The OS is currently not supported!
#error The OS is currently not supported!
#endif
}
@@ -176,15 +189,15 @@ namespace sdv
* @param[in] uiSrcLine Line of the file from which the message is logged. Specified by C++ standard.
* @param[in] ...args identifier specified by C++ standard that uses the ellipsis notation in the parameters.
*/
template <typename ...Args>
inline void CSDVLogImpl(ELogSeverity eSeverity, const char* szSrcFile, uint32_t uiSrcLine, Args&& ...args)
template <typename... Args>
inline void CSDVLogImpl(ELogSeverity eSeverity, const char* szSrcFile, uint32_t uiSrcLine, Args&&... args)
{
std::ostringstream stream;
(stream << ... << std::forward<Args>(args));
Log(eSeverity, szSrcFile ? szSrcFile : "", uiSrcLine, stream.str().c_str());
}
}
} // namespace internal
/**
* @brief Create a utility
@@ -199,8 +212,529 @@ namespace sdv
if (!pUtilityCreate) return nullptr;
return pUtilityCreate->CreateUtility(rssUtilityName, rssUtilityConfig);
}
} // namespace core
/**
* @brief Get a parameter from the object smart pointer.
* @param[in] pParameters Pointer to the parameter map interface of an object.
* @param[in] rssParamName Name of the parameter (incl. groups preceding the name and separated with a dot).
* @param[in] bNoExcept When set, do not trigger an std::runtime exception when the object or the parameter could not be
* found.
* @return Returns the value of the parameter or an empty any_t when the object or the parameter could not be found and
* bNoExcept was set.
*/
inline any_t GetParameter(const IParameters* pParameters, const std::string& rssParamName, bool bNoExcept = true)
{
if (!pParameters)
{
if (bNoExcept) return {};
throw std::runtime_error("The object doesn't expose IParameters interface.");
}
any_t any = pParameters->GetParam(rssParamName);
if (any.empty())
{
if (bNoExcept) return {};
throw std::runtime_error("The parameter could not be found.");
}
return any;
}
/**
* @brief Get a parameter from the parameter interface.
* @param[in] rptrObject Reference to object smart pointer to the the parameter of.
* @param[in] rssParamName Name of the parameter (incl. groups preceding the name and separated with a dot).
* @param[in] bNoExcept When set, do not trigger an std::runtime exception when the object or the parameter could not be
* found.
* @return Returns the value of the parameter or an empty any_t when the object or the parameter could not be found and
* bNoExcept was set.
*/
inline any_t GetParameter(const TInterfaceAccessPtr& rptrObject, const std::string& rssParamName, bool bNoExcept = true)
{
const IParameters* pParameters = rptrObject.GetInterface<IParameters>();
if (!pParameters)
{
if (bNoExcept) return {};
throw std::runtime_error("The object doesn't expose IParameters interface.");
}
return GetParameter(pParameters, rssParamName, bNoExcept);
}
/**
* @brief Get a parameter from the object with the supplied name.
* @param[in] rssObjectName Reference to the string containing the name of the object or service.
* @param[in] rssParamName Name of the parameter (incl. groups preceding the name and separated with a dot).
* @param[in] bNoExcept When set, do not trigger an std::runtime exception when the object or the parameter could not be
* found.
* @return Returns the value of the parameter or an empty any_t when the object or the parameter could not be found and
* bNoExcept was set.
*/
inline any_t GetParameter(const std::string& rssObjectName, const std::string& rssParamName, bool bNoExcept = true)
{
TInterfaceAccessPtr ptrObject = GetObject(rssObjectName);
if (!ptrObject)
{
if (bNoExcept) return {};
throw std::runtime_error("An object with the name '" + rssObjectName + "' could not be found.");
}
return GetParameter(ptrObject, rssParamName, bNoExcept);
}
/**
* @brief Get a parameter from the object with the supplied name. Resolve enums and bitmask objects in the returned
* parameter string.
* @param[in] rssObjectName Reference to the string containing the name of the object or service.
* @param[in] rssParamName Name of the parameter (incl. groups preceding the name and separated with a dot).
* @param[in] bNoExcept When set, do not trigger an std::runtime exception when the object or the parameter could not be
* found.
* @return Returns the value of the parameter as a text string or an empty string when the object or the parameter could
* not be found and bNoExcept was set.
*/
inline std::string GetParameterExpand(const std::string& rssObjectName, const std::string& rssParamName, bool bNoExcept = true)
{
TInterfaceAccessPtr ptrObject = GetObject(rssObjectName);
if (!ptrObject)
{
if (bNoExcept) return {};
throw std::runtime_error("An object with the name '" + rssObjectName + "' could not be found.");
}
const IParameters* pParameters = ptrObject.GetInterface<IParameters>();
if (!pParameters)
{
if (bNoExcept) return {};
throw std::runtime_error("The object doesn't expose IParameters interface.");
}
any_t any = pParameters->GetParam(rssParamName);
if (any.empty())
{
if (bNoExcept) return {};
throw std::runtime_error("The parameter could not be found.");
}
SParamInfo sParamInfo = pParameters->GetParamInfo(rssParamName);
if (sParamInfo.get_switch() == EParamType::enum_param)
{
for (const SLabelInfo::SLabel& rsLabel : sParamInfo.uExtInfo.sEnumInfo.seqLabels)
{
if (rsLabel.anyValue == any)
return rsLabel.ssLabel;
}
}
if (sParamInfo.get_switch() == EParamType::bitmask_param)
{
uint64_t uiValue = static_cast<uint64_t>(any);
std::stringstream sstreamValue;
for (const SLabelInfo::SLabel& rsLabel : sParamInfo.uExtInfo.sBitmaskInfo.seqLabels)
{
uint64_t uiValueLabel = static_cast<uint64_t>(rsLabel.anyValue);
if (uiValue & uiValueLabel)
{
if (sstreamValue.rdbuf()->in_avail()) // Has characters
sstreamValue << "|";
sstreamValue << rsLabel.ssLabel;
uiValue = uiValue & ~uiValueLabel;
}
}
if (uiValue) // Not all bits have labels
{
if (sstreamValue.rdbuf()->in_avail()) // Has characters
sstreamValue << "|";
sstreamValue << uiValue;
}
return sstreamValue.str();
}
return any;
}
/// Internal namespace
namespace internal
{
/**
* @brief Trim whitespace at the begin and end of the text.
* @param[in] rssText Reference to the text to trim whitespace for.
* @return The trimmed text.
*/
inline std::string TrimWhitespace(const std::string& rssText)
{
size_t nFirst = rssText.find_first_not_of(" \t\r\n");
if (nFirst == std::string::npos) return "";
size_t nLast = rssText.find_last_not_of(" \t\r\n");
return rssText.substr(nFirst, (nLast - nFirst + 1));
}
/**
* @brief Helper function to safely check if a string contains a valid, unescaped $(...) sequence.
* @param[in] rssText The text to check.
* @return Returns whether the text represents a valid variable.
*/
inline bool ContainsValidVariable(const std::string& rssText)
{
size_t nLength = rssText.length();
size_t nIndex = 0;
while (nIndex < nLength)
{
if (rssText[nIndex] == '\\')
{
// Skip the escape and the escaped character
nIndex += 2;
}
else if (rssText[nIndex] == '$')
{
// Check if it forms the start of a token sequence '$( '
if (nIndex + 1 < nLength && rssText[nIndex + 1] == '(')
{
size_t nClose = rssText.find(')', nIndex + 2);
if (nClose != std::string::npos)
{
// Found a valid structural candidate
return true;
}
}
nIndex++;
}
else
{
nIndex++;
}
}
return false;
}
} // namespace internal
/**
* @brief Resolves embedded object parameter variables formatted as $(object:param) within a text string.
* @param[in] rssText The source text containing potential variables and backslash escapes.
* @param[in] bRecursive If true, continues resolving until no more unescaped variables remain.
* @param[in] bNoExcept If true, returns an empty string for errors; if false, throws std::runtime_error.
* @return The fully resolved text string.
*/
inline std::string ResolveText(const std::string& rssText, bool bRecursive = true, bool bNoExcept = true)
{
std::string ssCurrentText = rssText;
bool bMayHaveMoreVariables = true;
while (bMayHaveMoreVariables)
{
bMayHaveMoreVariables = false;
std::string ssResult = "";
ssResult.reserve(ssCurrentText.length()); // Pre-allocate memory for performance
size_t nLength = ssCurrentText.length();
size_t nIndex = 0;
while (nIndex < nLength)
{
char cCurrent = ssCurrentText[nIndex];
// Handle backslash escape sequences
if (cCurrent == '\\')
{
// Check if the next character is a '$'
if (nIndex + 1 < nLength && ssCurrentText[nIndex + 1] == '$')
{
ssResult.push_back('$'); // Strip the escape character, keep the literal '$'
nIndex += 2;
}
else
{
ssResult.push_back('\\'); // Preserve other backslashes for paths
nIndex++;
}
}
// Identify potential variables
else if (cCurrent == '$')
{
// extension 2: Only throw an error or treat as a variable if it is
// explicitly part of a dynamic sequence tracking towards a '$(...)' match.
if (nIndex + 1 >= nLength || ssCurrentText[nIndex + 1] != '(')
{
// It is a loose literal '$' (like currency). Keep it and do not throw.
ssResult.push_back('$');
nIndex++;
continue;
}
size_t nVarStart = nIndex + 2; // Position right after "$("
size_t nVarEnd = ssCurrentText.find(')', nVarStart);
// Validate that a matching closing parenthesis exists
if (nVarEnd == std::string::npos)
{
if (!bNoExcept)
throw std::runtime_error(
"Format error: Missing closing parenthesis ')' for variable starting at index "
+ std::to_string(nIndex));
return "";
}
// Extract the inner payload block
std::string sVariableContent = ssCurrentText.substr(nVarStart, nVarEnd - nVarStart);
size_t nColonPos = sVariableContent.find(':');
// Validate that the delimiter ':' separates object and parameter names
if (nColonPos == std::string::npos)
{
if (!bNoExcept)
throw std::runtime_error("Format error: Variable content '" + sVariableContent
+ "' lacks an 'object:param' colon separator");
return "";
}
// Extract and clean whitespace before/after tokens, preserving inner spaces
std::string sObjName = internal::TrimWhitespace(sVariableContent.substr(0, nColonPos));
std::string sParamName = internal::TrimWhitespace(sVariableContent.substr(nColonPos + 1));
// Request the parameter.
std::string ssValue = GetParameterExpand(sObjName, sParamName, bNoExcept);
// Add the parameter to the string
ssResult.append(ssValue);
nIndex = nVarEnd + 1; // Move parsing index past the ')'
}
else
{
ssResult.push_back(cCurrent);
nIndex++;
}
}
ssCurrentText = ssResult;
// Exit immediately if recursive resolution was disabled
if (!bRecursive) break;
// extension 2: Intelligently analyze if a recursive processing loop is required
if (internal::ContainsValidVariable(ssCurrentText))
bMayHaveMoreVariables = true;
}
return ssCurrentText;
}
/**
* @brief Get the current access permission.
* @return The current access permission.
*/
inline EAccessPermission GetCurrentAccessPermission()
{
IPermissionControl* pPermissionControl = GetCore<IPermissionControl>();
if (!pPermissionControl)
return EAccessPermission::not_set;
return pPermissionControl->GetCurrentPermission();
}
/**
* @brief Get the current transmission from this thread and prepare a transfer to another thread.
* @return Transfer ID identifying the permission of this thread.
*/
inline TPermissionTransferID TransferCurrentPermission()
{
IPermissionControl* pPermissionControl = GetCore<IPermissionControl>();
if (!pPermissionControl) return 0u;
return pPermissionControl->TransferCurrentPermission();
}
/**
* @brief Class managing the lifetime of an access permission.
*/
class CAccessPermission
{
// Friend functions
friend CAccessPermission RestrictAccessPermission(EAccessPermission);
friend CAccessPermission SetAccessPermission(TPermissionTransferID);
public:
/**
* @brief Default constructor
*/
CAccessPermission() = default;
private:
/**
* @brief Constructor
* @param[in] tPermissionID The access permission to manage.
*/
CAccessPermission(TPermissionID tPermissionID) : m_tPermissionID(tPermissionID)
{}
public:
/**
* @brief Copy constructor is deleted.
* @param[in] rPermission Reference to the permission to copy from.
*/
CAccessPermission(const CAccessPermission& rPermission) = delete;
/**
* @brief Move constructor.
* @param[in] rPermission Reference to the permission to move from.
*/
CAccessPermission(CAccessPermission&& rPermission) : m_tPermissionID(rPermission.m_tPermissionID)
{
rPermission.m_tPermissionID = 0u;
}
/**
* @brief Destructor
*/
~CAccessPermission()
{
Release();
}
/**
* @brief Copy assignment operator is deleted.
* @param[in] rPermission Reference to the permission to copy from.
* @return Reference to this class.
*/
CAccessPermission& operator=(const CAccessPermission& rPermission) = delete;
/**
* @brief Move assignment operator.
* @param[in] rPermission Reference to the permission to move from.
* @return Reference to this class.
*/
CAccessPermission& operator=(CAccessPermission&& rPermission)
{
m_tPermissionID = rPermission.m_tPermissionID;
rPermission.m_tPermissionID = 0u;
return *this;
}
/**
* @brief Boolean operator.
* @return Returns whether a valid permission ID is assigned to this class.
*/
operator bool() const
{
return m_tPermissionID ? true : false;
}
/**
* @brief Does the access permission class contain a valid permission ID.
* @return Returns whether a valid permission ID is assigned to this class.
*/
bool IsValid() const
{
return m_tPermissionID ? true : false;
}
/**
* @brief Release the permission.
*/
void Release()
{
if (!m_tPermissionID) return;
IPermissionControl* pPermissionControl = GetCore<IPermissionControl>();
if (!pPermissionControl) return;
pPermissionControl->ReleaseAccessPermission(m_tPermissionID);
m_tPermissionID = 0u;
}
private:
TPermissionID m_tPermissionID = 0u; ///< Permission ID to be managed by this class.
};
/**
* @brief Restrict the current access permission.
* @param[in] ePermission The permission the access should be restricted to.
* @return The access permission connected to this restriction. The lifetime of the access permission is managed by the
* returned class.
*/
inline CAccessPermission RestrictAccessPermission(EAccessPermission ePermission)
{
IPermissionControl* pPermissionControl = GetCore<IPermissionControl>();
if (!pPermissionControl) return {};
return pPermissionControl->RestrictAccessPermission(ePermission);
}
/**
* @brief Set the access permission from a transfer ID that defined the access permission of a different thread.
* @param[in] tTransferID The ID of the transferred access permission.
* @return The access permission for the current thread. The lifetime of the access permission is managed by the returned
* class.
*/
inline CAccessPermission SetAccessPermission(TPermissionTransferID tTransferID)
{
IPermissionControl* pPermissionControl = GetCore<IPermissionControl>();
if (!pPermissionControl) return {};
return pPermissionControl->SetAccessPermission(tTransferID);
}
/**
* @brief Secure thread implementation based on std::thread transferring the permissions from the creation thread to the
* execution thread.
*/
class secure_thread : public std::thread
{
public:
/**
* @brief Default constructor
*/
secure_thread() = default;
/**
* @brief Copy constructor is deleted.
* @param[in] rthread Reference to the thread object.
*/
secure_thread(const secure_thread& rthread) = delete;
/**
* @brief Move constructor.
* @param[in] rthread Reference to the thread object.
*/
secure_thread(secure_thread&& rthread) : std::thread(static_cast<std::thread&&>(rthread))
{}
/**
* @brief Assignment constructor for thread execution.
* @tparam F The function to execute.
* @tparam Args The argument types of the function to execute.
* @param[in] f Reference to the function.
* @param[in] args Reference to zero or more arguments.
*/
template <class F, class... Args>
explicit secure_thread(F&& f, Args&&... args)
{
static_cast<std::thread&>(*this) = std::thread(
[](TPermissionTransferID tTransferID, auto&& function, auto&&... arguments)
{
CAccessPermission permission = SetAccessPermission(tTransferID);
std::invoke(std::forward<decltype(function)>(function), std::forward<decltype(arguments)>(arguments)...);
}, TransferCurrentPermission(), std::forward<F>(f), std::forward<Args>(args)...);
}
/**
* @brief Move assignment operator.
* @param[in] rthread Reference to the thread object.
* @return Reference to this object.
*/
secure_thread& operator=(secure_thread&& rthread)
{
static_cast<std::thread&>(*this) = static_cast<std::thread&&>(rthread);
return *this;
}
};
} // namespace core
}// namespace sdv
/**
* @{
* @brief Comparison operators
* @param[in] e1 First permission
* @param[in] e2 Second permission
* @return Result of the comparison
*/
inline bool operator<(sdv::core::EAccessPermission e1, sdv::core::EAccessPermission e2) { return static_cast<int32_t>(e1) < static_cast<int32_t>(e2); }
inline bool operator<=(sdv::core::EAccessPermission e1, sdv::core::EAccessPermission e2) { return static_cast<int32_t>(e1) <= static_cast<int32_t>(e2); }
inline bool operator>(sdv::core::EAccessPermission e1, sdv::core::EAccessPermission e2) { return static_cast<int32_t>(e1) > static_cast<int32_t>(e2); }
inline bool operator>=(sdv::core::EAccessPermission e1, sdv::core::EAccessPermission e2) { return static_cast<int32_t>(e1) >= static_cast<int32_t>(e2); }
/**
* @}
*/
namespace sdv
{
namespace app
{
/**
@@ -208,11 +742,11 @@ namespace sdv
* @param[in] rssAttribute Name of the attribute.
* @return The attribute value or an empty any-value if the attribute wasn't found or didn't have a value.
*/
inline any_t GetAppAttribute(const std::string& rssAttribute)
inline any_t GetAppSettingsAttribute(const std::string& rssAttribute)
{
const IAttributes* ptrAppAttributes = core::GetObject<IAttributes>("AppControlService");
if (!ptrAppAttributes) return {};
return ptrAppAttributes->Get(rssAttribute);
const IParameters* pParameters = core::GetObject<IParameters>("AppSettingsService");
if (!pParameters) return {};
return pParameters->GetParam(rssAttribute);
}
/**
@@ -221,7 +755,7 @@ namespace sdv
*/
inline bool ConsoleIsSilent()
{
return GetAppAttribute("console.info_level") == "silent";
return GetAppSettingsAttribute("Console.Reporting") == "Silent";
}
/**
@@ -230,7 +764,7 @@ namespace sdv
*/
inline bool ConsoleIsVerbose()
{
return GetAppAttribute("console.info_level") == "verbose";
return GetAppSettingsAttribute("Console.Reporting") == "Verbose";
}
/**
@@ -239,7 +773,7 @@ namespace sdv
*/
inline uint32_t GetAppInstanceID()
{
return GetAppAttribute("app.instance_id");
return GetAppSettingsAttribute("Application.Instance");
}
} // namespace app
@@ -247,64 +781,81 @@ namespace sdv
{
/**
* @brief Create a repository connection to a local server.
* @param[in] uiInstanceID Optionally the instance ID of the target system to connect to or 0 (default) to connect to the
* instance identified by app-control.
* @param[in] nRetries Number of retries to connect (optional, default 30, minimum 3).
* @return Returns a smart pointer to the repository proxy. Disconnection takes place when IObjectDestroy::DestroyObject is
* called.
*/
inline TObjectPtr ConnectToLocalServerRepository(uint32_t uiInstanceID = 0, size_t nRetries = 30)
inline TObjectPtr ConnectToLocalServerRepository(size_t nRetries = 30)
{
com::IClientConnect* pClientConnect = core::GetObject<com::IClientConnect>("ConnectionService");
if (!pClientConnect)
// This function works with main, external and maintenance applications.
const app::IAppContext* pAppContext = core::GetCore<app::IAppContext>();
if (!pAppContext) return {};
switch (pAppContext->GetContextType())
{
if (!app::ConsoleIsSilent())
std::cerr << "ERROR: Could not access the connection service." << std::endl;
case app::EAppContext::main:
case app::EAppContext::external:
case app::EAppContext::maintenance:
break;
default:
return {};
}
const sdv::app::IAppConnections* pConnections = core::GetObject<sdv::app::IAppConnections>("AppSettingsService");
if (!pConnections) return {};
std::string ssConnectionConfig = pConnections->GetConnectionConfig("Default");
if (ssConnectionConfig.empty()) return {};
sdv::core::IRepositoryControl* pRepository = core::GetObject<sdv::core::IRepositoryControl>("RepositoryService");
if (!pRepository) return {};
auto tConnectSvcID = pRepository->CreateObject("ClientConnectService", "ClientDefault", ssConnectionConfig);
if (!tConnectSvcID) return {};
sdv::TInterfaceAccessPtr ptrConnectSvc = core::GetObject(tConnectSvcID);
sdv::com::IClientConnect* pClientConnect = ptrConnectSvc.GetInterface<sdv::com::IClientConnect>();
if (!pClientConnect)
{
pRepository->DestroyObject("ClientDefault");
return {};
}
// Connect the client to the server and return the server repository interface.
std::string ssConnectString = R"code([Client]
Type = "Local"
)code";
if (uiInstanceID)
ssConnectString += "Instance = " + std::to_string(uiInstanceID) + R"code(
)code";
try
{
// Try to connect (30 times with 1 second in between).
size_t nCnt = 0;
sdv::TObjectPtr ptrRepository;
while (!ptrRepository && nCnt < nRetries)
sdv::TObjectPtr ptrRemoteRepo;
while (!ptrRemoteRepo && nCnt < std::max(nRetries, static_cast<size_t>(3u)))
{
nCnt++;
ptrRepository = pClientConnect->Connect(ssConnectString);
if (!ptrRepository)
if (pClientConnect->IsConnected() || pClientConnect->Connect())
{
ptrRemoteRepo = pClientConnect->GetRemoteRepository();
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
// Return the result
return ptrRepository;
return ptrRemoteRepo;
}
catch (const XAccessDenied& /*rExcept*/)
{
if (!app::ConsoleIsSilent())
std::cout << "Access denied trying to connect to a local repository with server instance ID#" <<
(uiInstanceID?uiInstanceID : app::GetAppInstanceID()) << "." << std::endl;
app::GetAppInstanceID() << "." << std::endl;
return {};
}
catch (const XNotFound& /*rExcept*/)
{
if (!app::ConsoleIsSilent())
std::cout << "Local repository with server instance ID#" <<
(uiInstanceID?uiInstanceID : app::GetAppInstanceID()) << " not found." << std::endl;
app::GetAppInstanceID() << " not found." << std::endl;
return {};
}
catch (const XInvalidState& rExcept)
{
if (!app::ConsoleIsSilent())
std::cout << "The local repository with server instance ID#" <<
(uiInstanceID?uiInstanceID : app::GetAppInstanceID()) << " is in an invalid state: " << rExcept.what() <<
app::GetAppInstanceID() << " is in an invalid state: " << rExcept.what() <<
std::endl;
return {};
}
@@ -312,12 +863,11 @@ Type = "Local"
{
if (!app::ConsoleIsSilent())
std::cout << "Timeout occurred trying to connect to a local repository with server instance ID#" <<
(uiInstanceID?uiInstanceID : app::GetAppInstanceID()) << "." << std::endl;
app::GetAppInstanceID() << "." << std::endl;
return {};
}
}
} // namespace core
} // namespace com
} // namespace sdv
#endif // !defined LOCAL_SERVICE_ACCESS_H

View File

@@ -435,12 +435,14 @@ namespace sdv
* @tparam TInfoConstruct The type of the variables that are provided to the constructor function of the parameter
* information.
* @param[in] rtVar Reference to the parameter variable.
* @param[in] bReadOnly When set, the parameter is read-only (even when writable) and will not be initialized.
* @param[in] bLockable When set, the parameter is lockable. Only use with writable parameters.
* @param[in] bAutoDirty When set, the parameter dirty flag is detected automatically. Only use with writable parameters.
* @param[in] bAutoDirty When set, the parameter dirty flag is detected automatically. Only use with writable
* parameters.
* @param[in] tConstruct The construct function arguments.
*/
template <typename... TInfoConstruct>
CParamValue(TVar& rtVar, bool bLockable, bool bAutoDirty, TInfoConstruct... tConstruct);
CParamValue(TVar& rtVar, bool bReadOnly, bool bLockable, bool bAutoDirty, TInfoConstruct... tConstruct);
/**
* @brief Set a value. Overload of CParamGuardian::Set.
@@ -1107,8 +1109,9 @@ namespace sdv
} \
else \
{ \
std::shared_ptr<sdv::CSdvParamInfo> ptrParamInfo = pObject->RegisterParameter(pObject->var, bLockable, true, name_string, \
default_val, unit_string, ssGroup, description_string, uiFlags); \
std::shared_ptr<sdv::CSdvParamInfo> ptrParamInfo = pObject->RegisterParameter(pObject->var, \
uiFlags & static_cast<uint32_t>(::sdv::EParamFlags::read_only), bLockable, true, name_string, default_val, \
unit_string, ssGroup, description_string, uiFlags); \
if (ptrParamInfo) vecParamInfo.push_back(std::move(ptrParamInfo)); \
}
@@ -1144,8 +1147,9 @@ namespace sdv
} \
else \
{ \
std::shared_ptr<sdv::CSdvParamInfo> ptrParamInfo = pObject->RegisterParameter(pObject->var, bLockable, true, \
name_string, default_val, anyLower, prLowLimit.second != sdv::internal::ELimitType::up_to_limit, anyUpper, \
std::shared_ptr<sdv::CSdvParamInfo> ptrParamInfo = pObject->RegisterParameter(pObject->var, \
uiFlags & static_cast<uint32_t>(::sdv::EParamFlags::read_only), bLockable, true, name_string, default_val, \
anyLower, prLowLimit.second != sdv::internal::ELimitType::up_to_limit, anyUpper, \
prHighLimit.second != sdv::internal::ELimitType::up_to_limit, unit_string, ssGroup, description_string, \
uiFlags); \
if (ptrParamInfo)vecParamInfo.push_back(std::move(ptrParamInfo)); \
@@ -1181,8 +1185,9 @@ namespace sdv
} \
else \
{ \
std::shared_ptr<sdv::CSdvParamInfo> ptrParamInfo = pObject->RegisterParameter(pObject->var, bLockable, true, name_string, \
default_val, pattern_string, unit_string, ssGroup, description_string, uiFlags); \
std::shared_ptr<sdv::CSdvParamInfo> ptrParamInfo = pObject->RegisterParameter(pObject->var, \
uiFlags & static_cast<uint32_t>(::sdv::EParamFlags::read_only), bLockable, true, name_string, default_val, \
pattern_string, unit_string, ssGroup, description_string, uiFlags); \
if (ptrParamInfo) vecParamInfo.push_back(std::move(ptrParamInfo)); \
}
@@ -1213,8 +1218,9 @@ namespace sdv
} \
else \
{ \
std::shared_ptr<sdv::CSdvParamInfo> ptrParamInfo = pObject->RegisterParameter(pObject->var, bLockable, true, name_string, \
default_val, sdv::internal::GetLabelMapHelper().GetLabelMap<TEnum>(), ssGroup, description_string, uiFlags); \
std::shared_ptr<sdv::CSdvParamInfo> ptrParamInfo = pObject->RegisterParameter(pObject->var, \
uiFlags & static_cast<uint32_t>(::sdv::EParamFlags::read_only), bLockable, true, name_string, default_val, \
sdv::internal::GetLabelMapHelper().GetLabelMap<TEnum>(), ssGroup, description_string, uiFlags); \
if (ptrParamInfo) vecParamInfo.push_back(std::move(ptrParamInfo)); \
}
@@ -1238,11 +1244,12 @@ namespace sdv
std::vector<std::shared_ptr<sdv::CSdvParamInfo>> vecParamInfoMember; \
if constexpr (bStatic) \
{ \
vecParamInfoMember = sdv::internal::SMemberMap<decltype(member)>::BuildStatic(); \
vecParamInfoMember = sdv::internal::SMemberMap<std::decay_t<decltype(member)>>::BuildStatic(); \
} \
else \
{ \
auto ptrMemberMap = std::make_shared<sdv::internal::SMemberMap<decltype(member)>>(pObject->member, pObject); \
auto ptrMemberMap = \
std::make_shared<sdv::internal::SMemberMap<std::decay_t<decltype(member)>>>(pObject->member, pObject); \
if (ptrMemberMap) \
{ \
ptrMemberMap->BuildMap(); \
@@ -1388,13 +1395,15 @@ namespace sdv
* @tparam TVar Type of the variable.
* @tparam TConstruct The arguments for the parameter info construct function.
* @param[in] rtVar Reference to the parameter.
* @param[in] bReadOnly When set, the parameter is read only and will not be initialized.
* @param[in] bLockable When set, the parameter is lockable. Only use with writable parameters.
* @param[in] bAutoDirty When set, the parameter dirty flag is detected automatically. Only use with writable parameters.
* @param[in] tConstruct The construct function arguments.
* @return Smart pointer to the parameter information structure.
*/
template <typename TVar, typename... TConstruct>
std::shared_ptr<CSdvParamInfo> RegisterParameter(TVar& rtVar, bool bLockable, bool bAutoDirty, TConstruct... tConstruct);
std::shared_ptr<CSdvParamInfo> RegisterParameter(TVar& rtVar, bool bReadOnly, bool bLockable, bool bAutoDirty,
TConstruct... tConstruct);
/**
* @brief Register a member parameter map into this parameter map.

View File

@@ -412,13 +412,14 @@ namespace sdv
template <typename TVar>
template <typename... TInfoConstruct>
inline CParamValue<TVar>::CParamValue(TVar& rtVar, bool bLockable, bool bAutoDirty, TInfoConstruct... tConstruct) :
inline CParamValue<TVar>::CParamValue(TVar& rtVar, bool bReadOnly, bool bLockable, bool bAutoDirty,
TInfoConstruct... tConstruct) :
CParamGuardian(bLockable, bAutoDirty, rtVar, tConstruct...), m_rtVar(rtVar)
{
// Assign the default value
if constexpr (!CSdvParamInfo::TypeIsReadOnly<TVar>())
{
m_rtVar = DefaultVal().get<TVar>();
if (!bReadOnly) m_rtVar = DefaultVal().get<TVar>();
UpdateDirty(DefaultVal());
ResetDirty();
}
@@ -678,10 +679,10 @@ namespace sdv
}
template <typename TVar, typename... TConstruct>
inline std::shared_ptr<CSdvParamInfo> CSdvParamMap::RegisterParameter(TVar& rtVar, bool bLockable, bool bAutoDirty,
TConstruct... tConstruct)
inline std::shared_ptr<CSdvParamInfo> CSdvParamMap::RegisterParameter(TVar& rtVar, bool bReadOnly, bool bLockable,
bool bAutoDirty, TConstruct... tConstruct)
{
auto ptrParam = std::make_shared<internal::CParamValue<TVar>>(rtVar, bLockable, bAutoDirty, tConstruct...);
auto ptrParam = std::make_shared<internal::CParamValue<TVar>>(rtVar, bReadOnly, bLockable, bAutoDirty, tConstruct...);
m_vecParamMapRegistration.push_back(SParamRegistration(ptrParam));
return ptrParam;
}

View File

@@ -32,6 +32,7 @@
#include <functional>
#include <chrono>
#include <queue>
#include <list>
namespace serdes
{
@@ -378,7 +379,25 @@ namespace sdv
inline CRawDataBypass& GetRawDataBypass()
{
#if defined __GNUC__ && defined _WIN32
// https://dev.azure.com/SW4ZF/AZP-431_DivDI_Vehicle_API/_workitems/edit/610009
// In MINGW GCC implementation of thread_local, there is an issue with complex classes being used after the destruction.
// This is caused by an architectural bug (https://github.com/msys2/MINGW-packages/issues/2519) causing the emutls (GCC
// Emulated TLS) managing the memory allocation to be executed before the __cxa_thread_exit, the thread cleanup callback
// of Windows. The solution is to use trivial data only (pointer, reference, integers, etc.). A workaround is
// implemented to use a reference of the permission list and map instead of an instance to the list and map.
static auto fnCreateBypass = []() -> CRawDataBypass&
{
static std::mutex mtx;
static std::list<CRawDataBypass> lstRawDataBypasses;
std::unique_lock<std::mutex> lock(mtx);
lstRawDataBypasses.resize(lstRawDataBypasses.size() + 1);
return lstRawDataBypasses.back();
};
thread_local static CRawDataBypass& bypass = fnCreateBypass();
#else
thread_local static CRawDataBypass bypass;
#endif
return bypass;
}

View File

@@ -25,6 +25,7 @@
#include <cctype>
#include <stdlib.h>
#include <functional>
#include <sstream>
#ifdef _WIN32
// Resolve conflict
@@ -59,6 +60,8 @@
#error OS is not supported!
#endif
#include "simple_toml.h"
namespace sdv
{
/**
@@ -148,6 +151,35 @@ namespace sdv{
{
/**
* @brief The SDV core loader
* @details The SDV core loader class searches for the core library and does the first startup. The core library uses
* the following environment variables to identify its location:
* - SDV_FRAMEWORK_RUNTIME directs to the Vehicle API core location.
* - SDV_COMPONENT_INSTALL directs to the location of the component installations.
* - SDV_FRAMEWORK_DEV_TOOLS directs to the location of the development tools used during the build process of SDV
* components.
* - SDV_FRAMEWORK_DEV_INCLUDE directs to the header file location to allow building components for use with the
* Vehicle API framework.
*
* The SDV core loader supports different core stacks to coexist. For this there is a location procedure for the core
* systems:
* 1. Check for a "sdv_core_reloc.toml" file that contain one or more paths to the core system. The paths defined in the
* file override the global environment variables for this application and all child applications.
* 2. Check for the environment variables. If the SDV_FRAMEWORK_RUNTIM variable is set, it is used to extract all other
* variables as well, if not set.
* 3. If no variable is set, use the location of the EXE as core location. This might work in some situations if the
* path variable has been set properly.
*
* If none of the above strategies work, the core cannot be loaded.
*
* The "sdv_core_reloc.toml" file has the following format:
* @code
* [CoreLocation]
* Version = 100 # Version; currently supported 100 for version 1.0
* Runtime = "<core runtime directory>"
* Install = "<component install directory>" # Typically identical to runtime directory
* DevTools = "<development tools directory>" # Typically identical to runtime directory
* Include = "<include directory>" # Typically in the include subdirectory
* @endcode
*/
class CSDVCoreLoader
{
@@ -189,77 +221,50 @@ namespace sdv{
{
if (m_bInit) return; // Prevent trying to load again.
m_bInit = true;
bool bRelocFileError = false;
std::string ssRelocFileInfo = "";
std::string ssEnvironmentInfo = "";
// Check for the executable directory
std::filesystem::path pathCoreLib;
if (std::filesystem::exists(GetExecDirectory() / "core_services.sdv"))
pathCoreLib = GetExecDirectory() / "core_services.sdv";
// Step 1: check for the "sdv_core_reloc.toml"
ProcessRelocationFile();
if (pathCoreLib.empty())
{
if (std::filesystem::exists(GetExecDirectory() / "sdv_core_reloc.toml"))
{
// Check for the library in the relocation directory
auto relocFolder = GetRelocationPath();
if (!relocFolder.empty())
{
auto coreLibFolder = std::filesystem::path(relocFolder) / "core_services.sdv";
if (coreLibFolder.is_relative())
coreLibFolder = (GetExecDirectory() / coreLibFolder).lexically_normal();
if (std::filesystem::exists(coreLibFolder))
pathCoreLib = coreLibFolder;
}
if (pathCoreLib.empty())
{
bRelocFileError = true; // we found the file but not the core library, we must run into an error
ssRelocFileInfo = "Error: Invalid \"sdv_core_reloc.toml\" file found (but no core library), it contains: " + relocFolder;
}
}
}
if (pathCoreLib.empty())
{
// Step 2: check for environment variables (either set globally or overwritten by the sdv_core_reloc.toml).
#ifdef _WIN32
std::wstring ssPathCoreTemp(32768, '\0');
GetEnvironmentVariable(L"SDV_FRAMEWORK_RUNTIME", ssPathCoreTemp.data(), static_cast<DWORD>(ssPathCoreTemp.size()));
GetEnvironmentVariable(
L"SDV_FRAMEWORK_RUNTIME", ssPathCoreTemp.data(), static_cast<DWORD>(ssPathCoreTemp.size()));
ssPathCoreTemp.resize(wcsnlen(ssPathCoreTemp.c_str(), ssPathCoreTemp.size()));
if (!ssPathCoreTemp.empty())
{
pathCoreLib = std::filesystem::path(ssPathCoreTemp) / "core_services.sdv";
m_pathCoreLib = std::filesystem::path(ssPathCoreTemp) / "core_services.sdv";
#else
std::string ssPathCoreTemp = std::getenv("SDV_FRAMEWORK_RUNTIME") ? std::getenv("SDV_FRAMEWORK_RUNTIME") : "";
if (!ssPathCoreTemp.empty())
{
pathCoreLib = std::filesystem::path(ssPathCoreTemp) / "core_services.sdv";
m_pathCoreLib = std::filesystem::path(ssPathCoreTemp) / "core_services.sdv";
#endif
if (pathCoreLib.is_relative())
pathCoreLib = (GetExecDirectory() / pathCoreLib).lexically_normal();
if (m_pathCoreLib.is_relative())
m_pathCoreLib = (GetExecDirectory() / m_pathCoreLib).lexically_normal();
if (!pathCoreLib.empty())
ssEnvironmentInfo = "System environment path: " + pathCoreLib.generic_string();
}
}
// Depend on system path to find the library
if (pathCoreLib.empty())
pathCoreLib = "core_services.sdv";
// Open the library only if there is no or a valid 'sdv_core_reloc.toml' file
if (!bRelocFileError)
// Step 3: check for the executable directory or otherwise check globally
if (m_pathCoreLib.empty())
{
if (std::filesystem::exists(GetExecDirectory() / "core_services.sdv"))
m_pathCoreLib = GetExecDirectory() / "core_services.sdv";
else
m_pathCoreLib = "core_services.sdv";
}
ssEnvironmentInfo = "System environment path: " + m_pathCoreLib.generic_string();
#ifdef _WIN32
SetErrorMode(SEM_FAILCRITICALERRORS);
m_tModule = reinterpret_cast<core::TModuleID>(LoadLibraryW(pathCoreLib.native().c_str()));
m_tModule = reinterpret_cast<core::TModuleID>(LoadLibraryW(m_pathCoreLib.native().c_str()));
#elif defined __unix__
m_tModule = reinterpret_cast<core::TModuleID>(dlopen(pathCoreLib.native().c_str(), RTLD_LAZY));
m_tModule = reinterpret_cast<core::TModuleID>(dlopen(m_pathCoreLib.native().c_str(), RTLD_LAZY));
#else
#error OS is not supported!
#endif
}
if (!m_tModule)
{
@@ -275,16 +280,12 @@ namespace sdv{
#else
#error OS is not supported!
#endif
if (ssRelocFileInfo.empty() && ssEnvironmentInfo.empty())
std::cerr << "No environment variable set and no realocation file found." << std::endl;
if (!ssRelocFileInfo.empty())
std::cerr << ssRelocFileInfo << std::endl;
if (!ssEnvironmentInfo.empty())
std::cerr << ssEnvironmentInfo << std::endl;
std::cerr << "Could not load \"core_services.sdv\" library";
if (!ssError.empty()) std::cerr << ": " << ssError;
std::cerr << std::endl;
m_ssErrMsg = "Could not load \"core_services.sdv\" library";
if (!ssError.empty())
m_ssErrMsg += ": " + ssError;
std::cerr << m_ssErrMsg << std::endl;
return;
}
@@ -301,7 +302,8 @@ namespace sdv{
#endif
if (!fnSDVCore)
{
std::cerr << "The library \"core_services.sdv\" doesn't expose the SDVCore function." << std::endl;
m_ssErrMsg = "The library \"core_services.sdv\" doesn't expose the SDVCore function.";
std::cerr << m_ssErrMsg << std::endl;
return;
}
@@ -311,7 +313,8 @@ namespace sdv{
m_pCore = fnSDVCore();
if (!m_pCore)
{
std::cerr << "The library \"core_services.sdv\" doesn't provide a valid interface." << std::endl;
m_ssErrMsg = "The library \"core_services.sdv\" doesn't provide a valid interface.";
std::cerr << m_ssErrMsg << std::endl;
return;
}
}
@@ -321,7 +324,6 @@ namespace sdv{
*/
operator TInterfaceAccessPtr() const { return m_pCore; }
private:
/**
* @brief Get the directory of the executable.
* @return Path to the directory.
@@ -346,86 +348,170 @@ namespace sdv{
}
/**
* @brief Get the folder path in the file 'sdv_core_reloc.toml'.
* @return Path content, empty string if not found.
* @brief Get the path to the core library.
* @return Returns a reference to the path to the core library.
*/
static std::string GetRelocationPath()
const std::filesystem::path& GetCoreLibPath() const
{
if (std::filesystem::exists(GetExecDirectory() / "sdv_core_reloc.toml"))
return m_pathCoreLib;
}
/**
* @brief Has loaded successfully?
* @return Returns whether loading was successful.
*/
bool HasLoaded() const
{
return m_bInit && m_tModule && m_pCore;
}
/**
* @brief Get the error message if loading was unsuccessful.
* @return Returns the a reference to the string containing the error message or an empty string if not available.
*/
const std::string& GetErrorMsg() const
{
return m_ssErrMsg;
}
private:
/**
* @brief Check for the 'sdv_core_reloc.toml' file containing the information about core relocation.
* @details Set the environment variables following the information from the core relocation file.
*/
static void ProcessRelocationFile()
{
if (!std::filesystem::exists(GetExecDirectory() / "sdv_core_reloc.toml")) return;
std::ifstream fstream(GetExecDirectory() / "sdv_core_reloc.toml");
std::string ssLine;
while (std::getline(fstream, ssLine))
{
size_t nPos = 0;
auto fnSkipWhitespace = [&]() { while (std::isspace(ssLine[nPos])) nPos++; };
fnSkipWhitespace();
if (ssLine[nPos] == '#') continue; // Rest of the line is comments
if (ssLine.substr(nPos, 9) != "directory") continue; // not the keq of interest: skip line
nPos += 9;
fnSkipWhitespace();
if (ssLine[nPos] != '=')
{
std::cout << "Error in \"sdv_core_reloc.toml\": expecting assignment character '=' following"
" keyword 'directory'." << std::endl;
break;
}
nPos++;
fnSkipWhitespace();
if (ssLine[nPos] != '\"')
{
std::cout << "Error in \"sdv_core_reloc.toml\": expecting double quote character '\"' indicating"
" a string begin'." << std::endl;
break;
}
nPos++;
size_t nStart = nPos;
while (nPos < ssLine.length() && ssLine[nPos] != '\"')
{
// Check for escape character
if (ssLine[nPos] == '\\') nPos++;
if (!fstream.is_open()) return;
// Skip character
nPos++;
}
if (nPos >= ssLine.length() || ssLine[nPos] != '\"')
std::stringstream sstreamContent;
sstreamContent << fstream.rdbuf();
fstream.close();
try
{
std::cout << "Error in \"sdv_core_reloc.toml\": expecting double quote character '\"' indicating"
" a string end'." << std::endl;
break;
}
std::string ssDirectory = ssLine.substr(nStart, nPos - nStart);
while (ssDirectory.empty())
sdv::toml::simple_parser::CParser parser(sstreamContent.str());
if (parser.Root().GetDirect("CoreLocation.Version").GetValue<uint32_t>() != SDVFrameworkInterfaceVersion)
{
std::cout << "Error in \"sdv_core_reloc.toml\": expecting a valid value following the assignment"
" of the 'directory' key." << std::endl;
break;
std::cerr << "Invalid version in sdv_core_reloc.toml" << std::endl;
return; // Version not supported
}
return ssDirectory;
const auto& sRuntimeNode = parser.Root().GetDirect("CoreLocation.Runtime");
if (sRuntimeNode)
{
// Note: since the system might load multiple executables and the path is relative to this executable,
// but maybe not to another executable, create an absolute path before assigning the environment
// variable.
std::filesystem::path pathRuntime = sRuntimeNode.GetValue<std::string>();
if (pathRuntime.is_relative())
pathRuntime = (GetExecDirectory() / pathRuntime).lexically_normal();
#ifdef _WIN32
// NOTE: In windows there are two environment variables which need to be updated.
std::ignore = SetEnvironmentVariable(L"SDV_FRAMEWORK_RUNTIME", pathRuntime.native().c_str());
std::ignore = _wputenv((std::wstring(L"SDV_FRAMEWORK_RUNTIME=") + pathRuntime.native()).c_str());
#elif defined __unix__
std::ignore = setenv("SDV_FRAMEWORK_RUNTIME", pathRuntime.generic_u8string().c_str(), 1);
#else
#error The OS is not supported!
#endif
}
const auto& sInstallNode = parser.Root().GetDirect("CoreLocation.Install");
if (sInstallNode)
{
// Note: since the system might load multiple executables and the path is relative to this executable,
// but maybe not to another executable, create an absolute path before assigning the environment
// variable.
std::filesystem::path pathInstall = sInstallNode.GetValue<std::string>();
if (pathInstall.is_relative())
pathInstall = (GetExecDirectory() / pathInstall).lexically_normal();
#ifdef _WIN32
// NOTE: In windows there are two environment variables which need to be updated.
std::ignore = SetEnvironmentVariable(L"SDV_COMPONENT_INSTALL", pathInstall.native().c_str());
std::ignore = _wputenv((std::wstring(L"SDV_COMPONENT_INSTALL=") + pathInstall.native()).c_str());
#elif defined __unix__
std::ignore = setenv("SDV_COMPONENT_INSTALL", pathInstall.generic_u8string().c_str(), 1);
#else
#error The OS is not supported!
#endif
}
const auto& sDevToolsNode = parser.Root().GetDirect("CoreLocation.DevTools");
if (sDevToolsNode)
{
// Note: since the system might load multiple executables and the path is relative to this executable,
// but maybe not to another executable, create an absolute path before assigning the environment
// variable.
std::filesystem::path pathDevTools = sDevToolsNode.GetValue<std::string>();
if (pathDevTools.is_relative())
pathDevTools = (GetExecDirectory() / pathDevTools).lexically_normal();
#ifdef _WIN32
// NOTE: In windows there are two environment variables which need to be updated.
std::ignore = SetEnvironmentVariable(L"SDV_FRAMEWORK_DEV_TOOLS", pathDevTools.native().c_str());
std::ignore = _wputenv((std::wstring(L"SDV_FRAMEWORK_DEV_TOOLS=") + pathDevTools.native()).c_str());
#elif defined __unix__
std::ignore = setenv("SDV_FRAMEWORK_DEV_TOOLS", pathDevTools.generic_u8string().c_str(), 1);
#else
#error The OS is not supported!
#endif
}
const auto& sIncludeNode = parser.Root().GetDirect("CoreLocation.Include");
if (sIncludeNode)
{
// Note: since the system might load multiple executables and the path is relative to this executable,
// but maybe not to another executable, create an absolute path before assigning the environment
// variable.
std::filesystem::path pathInclude = sIncludeNode.GetValue<std::string>();
if (pathInclude.is_relative())
pathInclude = (GetExecDirectory() / pathInclude).lexically_normal();
#ifdef _WIN32
// NOTE: In windows there are two environment variables which need to be updated.
std::ignore = SetEnvironmentVariable(L"SDV_FRAMEWORK_DEV_INCLUDE", pathInclude.native().c_str());
std::ignore = _wputenv((std::wstring(L"SDV_FRAMEWORK_DEV_INCLUDE=") + pathInclude.native()).c_str());
#elif defined __unix__
std::ignore = setenv("SDV_FRAMEWORK_DEV_INCLUDE", pathInclude.generic_u8string().c_str(), 1);
#else
#error The OS is not supported!
#endif
}
}
return "";
catch (const std::exception&)
{}
}
bool m_bInit = false; ///< Is the loader initialized?
core::TModuleID m_tModule = 0; ///< Module ID
IInterfaceAccess* m_pCore = nullptr; ///< Pointer to the core services.
std::filesystem::path m_pathCoreLib; ///< Path to the core library.
std::string m_ssErrMsg; ///< Error message for failed loading.
};
} // namespace internal
#ifndef NO_SDV_CORE_FUNC
/**
* @brief Access to the core.
* @return Smart pointer to the core services interface.
* @brief Access to the core loader.
* @return Reference to the one core loader instance.
*/
inline TInterfaceAccessPtr GetCore()
inline internal::CSDVCoreLoader& GetCoreLoader()
{
static internal::CSDVCoreLoader core;
core.Load();
return core;
}
/**
* @brief Access to the core interfaces.
* @return Smart pointer to the core services interfaces.
*/
inline TInterfaceAccessPtr GetCore()
{
return GetCoreLoader();
}
/**
* @brief Access to specific interface of the core.
* @tparam TInterface Type of interface to return.

View File

@@ -548,8 +548,8 @@ namespace sdv
CDispatchService& m_rDispatch; ///< Reference to the dispatch service.
std::function<void(any_t)> m_funcSignalReceive; ///< Receive signal data - callback function.
IInterfaceAccess* m_pSubscription = nullptr; ///< Cookie received by adding an receive subscription.
std::unique_ptr<CValueAssignmentHelper> m_ptrValue; ///< Value to update instead of a callback function.
IInterfaceAccess* m_pSubscription = nullptr; ///< Cookie received by adding a subscription.
std::unique_ptr<CValueAssignmentHelper> m_ptrValue; ///< Value to update instead of callback func.
};
/**

1010
export/support/simple_toml.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -11,12 +11,14 @@
* Erik Verhoeven - initial API and implementation
********************************************************************************/
#ifndef SDV_CONFIG_H
#define SDV_CONFIG_H
#ifndef SDV_TOML_H
#define SDV_TOML_H
#include <charconv>
#include "../interfaces/toml.h"
#include "interface_ptr.h"
#include "local_service_access.h"
#include "interface_ptr.h"
namespace sdv::toml
{
@@ -82,6 +84,18 @@ namespace sdv::toml
*/
ENodeType GetType() const;
/**
* @brief Get the index of this node within the parent collection.
* @return The index of the node within the parent collection node or npos when no parent is available.
*/
uint32_t GetIndex() const;
/**
* @brief Is the node defined as inline node?
* @return The inline flag.
*/
bool IsInline() const;
/**
* @brief Return any associated comment text for this node.
* @return The node comment or an empty string when there is not comment for this node.
@@ -132,6 +146,12 @@ namespace sdv::toml
*/
virtual void Clear();
/**
* @brief Format the node automatically, remove redundant whitespace.
* @param[in] bRemoveComments When set, the comments are removed from the node.
*/
void AutomaticFormat(bool bRemoveComments);
/**
* @brief Get the TOML string from this node including all children.
* @return The TOML string.
@@ -228,23 +248,29 @@ namespace sdv::toml
*/
CNode GetDirect(const sdv::u8string& rssNode) const;
/**
* @brief Return the node name for a node in the collection. If the collection is an array, provides the index between
* square brackets.
* @param[in] nIndex Index to return the node name for.
* @return Name of the node or an empty string if the index is larger than the amount of nodes in the collection.
*/
std::string GetNodeNameByIndex(size_t nIndex) const;
/**
* @brief Insert a value node before the provided position.
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
* standard nodes.
* @param[in] nIndex The index before which to insert the node. Can be larger than the count value as well as
* sdv::toml::npos when adding the node at the end.
* @remarks In TOML, inline nodes are located before standard nodes. Since values are presented as inline node, they
* will be inserted before any standard node (table or table array if defined as standard node).
* @param[in] rssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
* square brackets. Can be empty, causing the node to be inserted at the end.
* @param[in] rssName Reference to the name of the new value node. If this collection is an array, the name is ignored.
* Otherwise the name must be unique within this collection.
* @param[in] ranyValue The value to assign to the node. The value also determines the type of value node.
* @return Returns the node when successfully inserted or an empty node when not.
*/
CNode InsertValue(size_t nIndex, const std::string& rssName, const sdv::any_t& ranyValue);
CNode InsertValue(const std::string& rssInsertBefore, const std::string& rssName, const sdv::any_t& ranyValue);
/**
* @brief Add a value node to the collection.
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
* standard nodes.
* @param[in] rssName Reference to the name of the new array collection node. If this collection is an array, the name is
* ignored. Otherwise the name must be unique within this collection.
* @param[in] ranyValue The value to assign to the node. The value also determines the type of value node.
@@ -254,20 +280,18 @@ namespace sdv::toml
/**
* @brief Insert an array collection before the provided position.
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
* standard nodes.
* @param[in] nIndex The index before which to insert the node. Can be larger than the count value as well as
* sdv::toml::npos when adding the node at the end.
* @remarks In TOML, inline nodes are located before standard nodes. Since arrays are presented as inline node, they
* will be inserted before any standard node (table or table array if defined as standard node).
* @param[in] rssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
* square brackets. Can be empty, causing the node to be inserted at the end.
* @param[in] rssName Reference to the name of the new value node. If this collection is an array, the name is ignored.
* Otherwise the name must be unique within this collection.
* @return Returns the collection node when successfully inserted or an empty node when not.
*/
CNodeCollection InsertArray(size_t nIndex, const std::string& rssName);
CNodeCollection InsertArray(const std::string& rssInsertBefore, const std::string& rssName);
/**
* @brief Add an array collection to this collection.
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
* standard nodes.
* @param[in] rssName Reference to the name of the new array collection node. If this collection is an array, the name is
* ignored. Otherwise the name must be unique within this collection.
* @return Returns the collection node when successfully added or an empty node when not.
@@ -276,22 +300,20 @@ namespace sdv::toml
/**
* @brief Insert a table collection before the provided position.
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
* standard nodes.
* @param[in] nIndex The index before which to insert the node. Can be larger than the count value as well as
* sdv::toml::npos when adding the node at the end.
* @remarks In TOML, inline nodes are located before standard nodes. Tables can be inserted as inline node, in which
* case they will be inserted before any standard node (table or table array if defined as standard node).
* @param[in] rssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
* square brackets. Can be empty, causing the node to be inserted at the end.
* @param[in] rssName Reference to the name of the new table collection node. If this collection is an array, the name is
* ignored. Otherwise the name must be unique within this collection.
* @param[in] bFavorInline When set, the node will be added as inline collection node. When not, the node will be inserted
* as inline collection if the this collection is also inline, as standard when not.
* @return Returns the collection node when successfully inserted or an empty node when not.
*/
CNodeCollection InsertTable(size_t nIndex, const std::string& rssName, bool bFavorInline = false);
CNodeCollection InsertTable(const std::string& rssInsertBefore, const std::string& rssName, bool bFavorInline = false);
/**
* @brief Add a table collection to this collection.
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
* standard nodes.
* @param[in] rssName Reference to the name of the new table collection node. If this collection is an array, the name is
* ignored. Otherwise the name must be unique within this collection.
* @param[in] bFavorInline When set, the node will be added as inline collection node. When not, the node will be inserted
@@ -302,12 +324,12 @@ namespace sdv::toml
/**
* @brief Insert a table array collection before the provided position.
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
* standard nodes.
* @remarks A table array is an array with table inside. Inserting a table array node can also be done by creating an array,
* if not existing already, and adding a table to the array.
* @param[in] nIndex The index before which to insert the node. Can be larger than the count value as well as
* sdv::toml::npos when adding the node at the end.
* @remarks In TOML, inline nodes are located before standard nodes. Table arrays can be inserted as inline node, in
* which case they will be inserted before any standard node (table or table array if defined as standard node).
* @param[in] rssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
* square brackets. Can be empty, causing the node to be inserted at the end.
* @param[in] rssName Reference to the name of the new table array node. If this collection is an array, the name is
* ignored. Otherwise the name must be unique within this collection.
* @param[in] bFavorInline When set, the node will be added as inline collection node. When not, the node will be inserted
@@ -315,12 +337,10 @@ namespace sdv::toml
* @return Returns the collection node when successfully inserted or an empty node when not. The collection node represents
* a table collection.
*/
CNodeCollection InsertTableArray(size_t nIndex, const std::string& rssName, bool bFavorInline = false);
CNodeCollection InsertTableArray(const std::string& rssInsertBefore, const std::string& rssName, bool bFavorInline = false);
/**
* @brief Add a table array collection to this collection.
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
* standard nodes.
* @remarks A table array is an array with table inside. Inserting a table array node can also be done by creating an array,
* if not existing already, and adding a table to the array.
* @param[in] rssName Reference to the name of the new table array node. If this collection is an array, the name is
@@ -335,10 +355,10 @@ namespace sdv::toml
/**
* @brief Insert a TOML string to the collection. All nodes specified in the TOML will be added in the collection except
* when the nodes already exist. Comment and whitespace are preserved when possible.
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
* standard nodes.
* @param[in] nIndex The index before which to insert the node. Can be larger than the count value as well as
* sdv::toml::npos when adding the node at the end.
* @remarks In TOML, inline nodes are located before standard nodes. Dependable on the nodes defined in the TOML they
* might be transferred to inline or they might be inserted at a different location.
* @param[in] rssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
* square brackets. Can be empty, causing the node to be inserted at the end.
* @param[in] rssTOML Reference to the TOML string containing the nodes. The TOML string can be empty, which is not an
* error. If required the TOML nodes are converted to inline nodes.
* @param[in] bAllowPartial When set, duplicate nodes (already present in this collection) will be ignored and do not
@@ -346,7 +366,7 @@ namespace sdv::toml
* @return Returns 1 if the complete TOMl could be inserted, 0 if no TOML could be inserted or -1 when the TOML could be
* partially inserted.
*/
int InsertTOML(size_t nIndex, const std::string& rssTOML, bool bAllowPartial = false);
int InsertTOML(const std::string& rssInsertBefore, const std::string& rssTOML, bool bAllowPartial = false);
/**
* @brief Add a TOML string to this collection. All nodes specified in the TOML will be added in the collection except
@@ -372,16 +392,11 @@ namespace sdv::toml
class CTOMLParser : public CNodeCollection
{
public:
/**
* @brief Default constructor.
*/
CTOMLParser() = default;
/**
* @brief Constructor providing automatic processing.
* @param[in] rssConfig Reference to the configuration.
*/
CTOMLParser(const std::string& rssConfig);
CTOMLParser(const std::string& rssConfig = "");
/**
* @brief Process a configuration. This will clear any previous configuration.
@@ -414,6 +429,52 @@ namespace sdv::toml
ITOMLParser* m_pParser = nullptr; ///< Pointer to the parser interface.
};
/**
* @brief Compare flags
*/
enum class ECompareFlags : uint32_t
{
compare_ignore_whitespace = 1, ///< Compare, but ignore whitespace
compare_ignore_comments = 2, ///< Compare, but ignore comments
compare_ignore_inline = 8, ///< Compare, but ignore inline or explicit
compare_ignore_all = 255, ///< Compare with all ignore flags
};
/**
* @brief Compare result
*/
enum class ECompareResult : int32_t
{
compare_identical = 0, ///< The comparison resulted into identical TOML strings
compare_different = 1, ///< The comparison resulted into different TOML strings
compare_error = -1 ///< The comparison could not be done due to a failure
};
/// Internal namespace
namespace internal
{
/**
* @brief Compare the content of the node with the content of another node.
* @attention This function changes the nodes dependable on the provided flags.
* @param[in] rnode1 First node interface to compare with the second node.
* @param[in] rnode2 Second node interface to compare with the first node.
* @param[in] uiCompareFlags Zero or more flags from ECompareFlags.
* @return The comparison result.
*/
ECompareResult CompareNodes(CNode& rnode1, CNode& rnode2,
uint32_t uiCompareFlags = static_cast<uint32_t>(ECompareFlags::compare_ignore_all));
} // namespace internal;
/**
* @brief Compare the content of TOML string with the content of another TOML string.
* @param[in] rssToml1 Reference to the first TOML string to compare with the second TOML string.
* @param[in] rssToml2 Reference to the second TOML string to compare with the first TOML string.
* @param[in] uiCompareFlags Zero or more flags from ECompareFlags.
* @return The comparison result.
*/
ECompareResult Compare(const std::string& rssToml1, const std::string& rssToml2,
uint32_t uiCompareFlags = static_cast<uint32_t>(ECompareFlags::compare_ignore_all));
inline CNode::CNode(const TInterfaceAccessPtr& rptrNode)
{
m_pNodeInfo = rptrNode.GetInterface<INodeInfo>();
@@ -461,6 +522,16 @@ namespace sdv::toml
return m_pNodeInfo ? m_pNodeInfo->GetType() : ENodeType::node_invalid;
}
inline uint32_t CNode::GetIndex() const
{
return m_pNodeInfo ? m_pNodeInfo->GetIndex() : npos;
}
inline bool CNode::IsInline() const
{
return m_pNodeInfo ? m_pNodeInfo->IsInline() : true;
}
inline std::string CNode::GetComment() const
{
if (!m_pNodeInfo) return {};
@@ -527,7 +598,9 @@ namespace sdv::toml
{
INodeUpdate* pNodeUpdate = m_ptrNode.GetInterface<INodeUpdate>();
if (!pNodeUpdate) return false;
return pNodeUpdate->DeleteNode();
bool bRet = pNodeUpdate->DeleteNode();
Clear(); // Not valid any more.
return bRet;
}
inline void CNode::Clear()
@@ -536,6 +609,11 @@ namespace sdv::toml
m_pNodeInfo = nullptr;
}
inline void CNode::AutomaticFormat(bool bRemoveComments)
{
if (m_pNodeInfo) m_pNodeInfo->AutomaticFormat(bRemoveComments);
}
inline sdv::u8string CNode::GetTOML() const
{
return m_pNodeInfo ? m_pNodeInfo->GetTOML() : sdv::u8string();
@@ -605,76 +683,86 @@ namespace sdv::toml
return m_pCollection ? CNode(m_pCollection->GetNodeDirect(rssNode)) : CNode();
}
inline CNode CNodeCollection::InsertValue(size_t nIndex, const std::string& rssName, const sdv::any_t& ranyValue)
inline std::string CNodeCollection::GetNodeNameByIndex(size_t nIndex) const
{
if (!m_pCollection) return {};
if (nIndex >= m_pCollection->GetCount()) return {};
if (GetType() == ENodeType::node_array) return "[" + std::to_string(nIndex) + "]";
TInterfaceAccessPtr ptrNode = m_pCollection->GetNode(static_cast<uint32_t>(nIndex));
const auto* pAccess = ptrNode.GetInterface<INodeInfo>();
if (!pAccess) return {};
return pAccess->GetName();
}
inline CNode CNodeCollection::InsertValue(const std::string& rssInsertBefore, const std::string& rssName,
const sdv::any_t& ranyValue)
{
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
if (!pInsert) return {};
return CNode(pInsert->InsertValue(static_cast<uint32_t>(nIndex), rssName, ranyValue));
return CNode(pInsert->InsertValue(rssInsertBefore, rssName, ranyValue));
}
inline CNode CNodeCollection::AddValue(const std::string& rssName, const sdv::any_t& ranyValue)
{
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
if (!pInsert) return {};
return CNode(pInsert->InsertValue(npos, rssName, ranyValue));
return CNode(pInsert->InsertValue("", rssName, ranyValue));
}
inline CNodeCollection CNodeCollection::InsertArray(size_t nIndex, const std::string& rssName)
inline CNodeCollection CNodeCollection::InsertArray(const std::string& rssInsertBefore, const std::string& rssName)
{
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
if (!pInsert) return {};
return CNodeCollection(pInsert->InsertArray(static_cast<uint32_t>(nIndex), rssName));
return CNodeCollection(pInsert->InsertArray(rssInsertBefore, rssName));
}
inline CNodeCollection CNodeCollection::AddArray(const std::string& rssName)
{
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
if (!pInsert) return {};
return CNodeCollection(pInsert->InsertArray(npos, rssName));
return CNodeCollection(pInsert->InsertArray("", rssName));
}
inline CNodeCollection CNodeCollection::InsertTable(size_t nIndex, const std::string& rssName, bool bFavorInline /*= false*/)
inline CNodeCollection CNodeCollection::InsertTable(const std::string& rssInsertBefore, const std::string& rssName,
bool bFavorInline /*= false*/)
{
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
if (!pInsert) return {};
return CNodeCollection(pInsert->InsertTable(static_cast<uint32_t>(nIndex), rssName,
bFavorInline ? INodeCollectionInsert::EInsertPreference::prefer_inline :
INodeCollectionInsert::EInsertPreference::prefer_standard));
return CNodeCollection(pInsert->InsertTable(rssInsertBefore, rssName, bFavorInline ? EInsertPreference::prefer_inline :
EInsertPreference::prefer_standard));
}
inline CNodeCollection CNodeCollection::AddTable(const std::string& rssName, bool bFavorInline /*= false*/)
{
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
if (!pInsert) return {};
return CNodeCollection(pInsert->InsertTable(npos, rssName,
bFavorInline ? INodeCollectionInsert::EInsertPreference::prefer_inline :
INodeCollectionInsert::EInsertPreference::prefer_standard));
return CNodeCollection(pInsert->InsertTable("", rssName, bFavorInline ? EInsertPreference::prefer_inline :
EInsertPreference::prefer_standard));
}
inline CNodeCollection CNodeCollection::InsertTableArray(size_t nIndex, const std::string& rssName,
inline CNodeCollection CNodeCollection::InsertTableArray(const std::string& rssInsertBefore, const std::string& rssName,
bool bFavorInline /*= false*/)
{
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
if (!pInsert) return {};
return CNodeCollection(pInsert->InsertTableArray(static_cast<uint32_t>(nIndex), rssName,
bFavorInline ? INodeCollectionInsert::EInsertPreference::prefer_inline :
INodeCollectionInsert::EInsertPreference::prefer_standard));
return CNodeCollection(pInsert->InsertTableArray(rssInsertBefore, rssName, bFavorInline ? EInsertPreference::prefer_inline :
EInsertPreference::prefer_standard));
}
inline CNodeCollection CNodeCollection::AddTableArray(const std::string& rssName, bool bFavorInline /*= false*/)
{
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
if (!pInsert) return {};
return CNodeCollection(pInsert->InsertTableArray(npos, rssName,
bFavorInline ? INodeCollectionInsert::EInsertPreference::prefer_inline :
INodeCollectionInsert::EInsertPreference::prefer_standard));
return CNodeCollection(pInsert->InsertTableArray("", rssName, bFavorInline ? EInsertPreference::prefer_inline :
EInsertPreference::prefer_standard));
}
inline int CNodeCollection::InsertTOML(size_t nIndex, const std::string& rssTOML, bool bAllowPartial /*= false*/)
inline int CNodeCollection::InsertTOML(const std::string& rssInsertBefore, const std::string& rssTOML,
bool bAllowPartial /*= false*/)
{
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
if (!pInsert) return 0;
INodeCollectionInsert::EInsertResult eRet = pInsert->InsertTOML(static_cast<uint32_t>(nIndex), rssTOML, !bAllowPartial);
INodeCollectionInsert::EInsertResult eRet = pInsert->InsertTOML(rssInsertBefore, rssTOML, !bAllowPartial);
switch (eRet)
{
case INodeCollectionInsert::EInsertResult::insert_success:
@@ -691,7 +779,7 @@ namespace sdv::toml
{
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
if (!pInsert) return 0;
INodeCollectionInsert::EInsertResult eRet = pInsert->InsertTOML(npos, rssTOML, !bAllowPartial);
INodeCollectionInsert::EInsertResult eRet = pInsert->InsertTOML("", rssTOML, !bAllowPartial);
switch (eRet)
{
case INodeCollectionInsert::EInsertResult::insert_success:
@@ -746,6 +834,59 @@ namespace sdv::toml
m_ptrParserUtil.Clear();
}
namespace internal
{
inline ECompareResult CompareNodes(CNode& rnode1, CNode& rnode2,
uint32_t uiCompareFlags /*= static_cast<uint32_t>(ECompareFlags::compare_ignore_all)*/)
{
if (!rnode1 || !rnode2) return ECompareResult::compare_error;
// Format the nodes when ignore whitespace and/or comments
bool bIgnoreComments = uiCompareFlags & static_cast<uint32_t>(ECompareFlags::compare_ignore_comments);
bool bIgnoreWhitespace = bIgnoreComments ||
(uiCompareFlags & static_cast<uint32_t>(ECompareFlags::compare_ignore_whitespace));
if (bIgnoreWhitespace)
{
INodeInfo* pNodeInfo1 = rnode1.GetInterface().GetInterface<INodeInfo>();
if (!pNodeInfo1) return ECompareResult::compare_error;
pNodeInfo1->AutomaticFormat(bIgnoreComments);
INodeInfo* pNodeInfo2 = rnode2.GetInterface().GetInterface<INodeInfo>();
if (!pNodeInfo2) return ECompareResult::compare_error;
pNodeInfo2->AutomaticFormat(bIgnoreComments);
}
// Convert to standard if ignoring inline
INodeCollectionConvert* pConvert1 = rnode1.GetInterface().GetInterface<INodeCollectionConvert>();
INodeCollectionConvert* pConvert2 = rnode2.GetInterface().GetInterface<INodeCollectionConvert>();
if (pConvert1 && pConvert2 && uiCompareFlags & static_cast<uint32_t>(ECompareFlags::compare_ignore_inline))
{
// Making inline nodes as standard, might only change the upper node.
// Making standard nodes inline, will have all child nodes be made inline as well, because inline nodes can only
// have inline nodes.
pConvert1->MakeInline();
pConvert2->MakeInline();
}
// Generate the TOMLs and compare
return rnode1.GetTOML() == rnode2.GetTOML() ? ECompareResult::compare_identical : ECompareResult::compare_different;
}
} // namespace internal
inline ECompareResult Compare(const std::string& rssToml1, const std::string& rssToml2,
uint32_t uiCompareFlags /*= static_cast<uint32_t>(ECompareFlags::compare_ignore_all)*/)
{
try
{
CTOMLParser parser1(rssToml1);
CTOMLParser parser2(rssToml2);
return internal::CompareNodes(parser1, parser2, uiCompareFlags);
}
catch (const sdv::toml::XTOMLParseException&)
{
return ECompareResult::compare_error;
}
}
}
#endif // !defined SDV_CONFIG_H
#endif // !defined SDV_TOML_H

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

View File

@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 509.93 258.96">
<defs>
<style>
.cls-1 {
fill: #0023f4;
stroke-width: 0px;
}
</style>
</defs>
<g>
<path class="cls-1" d="M16.52,243.21v2.73h-7.34v3.36h6.91v2.75h-6.91v3.79h7.8l-.33,2.73H5.94v-15.36h10.58Z"/>
<path class="cls-1" d="M23.45,243.21l6.39,10.07v-10.07h3.15v15.36h-2.89l-6.41-9.98v9.98h-3.15v-15.36h2.91Z"/>
<path class="cls-1" d="M50.52,250.16v6.5c-.8.73-1.75,1.3-2.85,1.7-1.1.4-2.24.6-3.41.6-1.23,0-2.31-.19-3.23-.58-.92-.39-1.68-.93-2.29-1.64-.61-.7-1.06-1.55-1.37-2.55-.3-1-.46-2.1-.46-3.3s.17-2.37.5-3.36.81-1.84,1.42-2.54c.62-.7,1.37-1.24,2.25-1.61s1.87-.56,2.96-.56c1,0,1.86.12,2.57.37.72.24,1.33.58,1.83,1.01.5.43.9.93,1.2,1.51.3.57.51,1.19.64,1.85l-3.22.41c-.09-.39-.19-.73-.32-1.02s-.3-.54-.53-.75-.52-.37-.87-.47-.78-.16-1.3-.16c-1.26,0-2.2.47-2.82,1.4s-.93,2.25-.93,3.94.32,3.02.95,3.95c.63.92,1.65,1.39,3.07,1.39.68,0,1.27-.07,1.77-.21.5-.14.98-.35,1.44-.63v-2.56h-2.96v-2.67h5.95Z"/>
<path class="cls-1" d="M57.69,243.21v15.36h-3.24v-15.36h3.24Z"/>
<path class="cls-1" d="M65.04,243.21l6.39,10.07v-10.07h3.15v15.36h-2.89l-6.41-9.98v9.98h-3.15v-15.36h2.91Z"/>
<path class="cls-1" d="M89.59,243.21v2.73h-7.34v3.36h6.91v2.75h-6.91v3.79h7.8l-.33,2.73h-10.71v-15.36h10.58Z"/>
<path class="cls-1" d="M104.19,243.21v2.73h-7.34v3.36h6.91v2.75h-6.91v3.79h7.8l-.33,2.73h-10.71v-15.36h10.58Z"/>
<path class="cls-1" d="M113.7,243.21c1.22,0,2.22.14,3.01.42.79.28,1.41.65,1.86,1.1s.76.95.93,1.51c.17.55.26,1.09.26,1.62,0,.99-.18,1.82-.54,2.5s-.97,1.24-1.83,1.7l3.15,6.52h-3.5l-2.61-5.77h-3.04v5.77h-3.19v-15.36h5.5ZM115.18,249.98c.33-.11.6-.26.79-.45s.33-.43.4-.7.11-.57.11-.9c0-.27-.04-.54-.13-.79s-.24-.47-.45-.67c-.21-.19-.5-.34-.87-.45s-.84-.16-1.4-.16h-2.24v4.28h2.52c.51,0,.93-.05,1.26-.16Z"/>
<path class="cls-1" d="M126.89,243.21v15.36h-3.24v-15.36h3.24Z"/>
<path class="cls-1" d="M134.23,243.21l6.39,10.07v-10.07h3.15v15.36h-2.89l-6.41-9.98v9.98h-3.15v-15.36h2.91Z"/>
<path class="cls-1" d="M161.31,250.16v6.5c-.8.73-1.75,1.3-2.85,1.7-1.1.4-2.24.6-3.41.6-1.23,0-2.31-.19-3.23-.58-.92-.39-1.68-.93-2.29-1.64-.61-.7-1.06-1.55-1.37-2.55-.3-1-.46-2.1-.46-3.3s.17-2.37.5-3.36.81-1.84,1.42-2.54c.62-.7,1.37-1.24,2.25-1.61s1.87-.56,2.96-.56c1,0,1.86.12,2.57.37.72.24,1.33.58,1.83,1.01.5.43.9.93,1.2,1.51.3.57.51,1.19.64,1.85l-3.22.41c-.09-.39-.19-.73-.32-1.02s-.3-.54-.53-.75-.52-.37-.87-.47-.78-.16-1.3-.16c-1.26,0-2.2.47-2.82,1.4s-.93,2.25-.93,3.94.32,3.02.95,3.95c.63.92,1.65,1.39,3.07,1.39.68,0,1.27-.07,1.77-.21.5-.14.98-.35,1.44-.63v-2.56h-2.96v-2.67h5.95Z"/>
<path class="cls-1" d="M169.95,245.99v-2.78h12.6v2.78h-4.67v12.59h-3.26v-12.59h-4.67Z"/>
<path class="cls-1" d="M189.07,243.21v5.94h6.15v-5.94h3.24v15.36h-3.24v-6.45h-6.15v6.45h-3.24v-15.36h3.24Z"/>
<path class="cls-1" d="M213.47,243.21v2.73h-7.34v3.36h6.91v2.75h-6.91v3.79h7.8l-.33,2.73h-10.71v-15.36h10.58Z"/>
<path class="cls-1" d="M225.16,243.21l3.76,10.86,3.87-10.86h3.48l-5.82,15.36h-3.06l-5.82-15.36h3.61Z"/>
<path class="cls-1" d="M249.91,243.21v2.73h-7.34v3.36h6.91v2.75h-6.91v3.79h7.8l-.33,2.73h-10.71v-15.36h10.58Z"/>
<path class="cls-1" d="M257.16,243.21v5.94h6.15v-5.94h3.24v15.36h-3.24v-6.45h-6.15v6.45h-3.24v-15.36h3.24Z"/>
<path class="cls-1" d="M274.22,243.21v15.36h-3.24v-15.36h3.24Z"/>
<path class="cls-1" d="M291.33,255.53c-.31.7-.74,1.3-1.28,1.81-.54.51-1.21.91-2,1.19s-1.71.43-2.75.43c-1.17,0-2.21-.19-3.1-.58-.89-.39-1.64-.93-2.24-1.64-.6-.7-1.05-1.55-1.36-2.55-.3-1-.46-2.1-.46-3.3s.17-2.37.5-3.36c.33-.99.81-1.84,1.43-2.54.62-.7,1.38-1.24,2.26-1.61s1.88-.56,3-.56c.99,0,1.84.12,2.57.37.73.24,1.35.59,1.85,1.05s.9,1.01,1.21,1.66.53,1.37.67,2.17l-3.22.41c-.16-.9-.47-1.61-.92-2.13s-1.18-.77-2.16-.77c-1.25,0-2.19.46-2.84,1.39s-.97,2.23-.97,3.93.34,3.02,1.03,3.94,1.61,1.38,2.77,1.38c1,0,1.73-.25,2.21-.76.47-.51.76-1.24.88-2.18h3.48c-.07.82-.26,1.57-.58,2.27Z"/>
<path class="cls-1" d="M298.64,243.21v12.61h7.34l-.35,2.75h-10.23v-15.36h3.24Z"/>
<path class="cls-1" d="M319.93,243.21v2.73h-7.34v3.36h6.91v2.75h-6.91v3.79h7.8l-.33,2.73h-10.71v-15.36h10.58Z"/>
<path class="cls-1" d="M333.62,258.4c-.91-.37-1.69-.91-2.32-1.61-.64-.7-1.13-1.55-1.47-2.54-.34-.99-.51-2.11-.51-3.36s.17-2.37.51-3.36.83-1.84,1.48-2.54c.64-.7,1.42-1.24,2.34-1.61s1.94-.56,3.09-.56,2.19.19,3.11.56,1.68.91,2.31,1.61c.63.7,1.11,1.55,1.44,2.54s.5,2.11.5,3.36-.16,2.37-.49,3.36c-.33.99-.8,1.84-1.43,2.54-.63.7-1.4,1.24-2.31,1.61s-1.96.56-3.13.56-2.19-.19-3.11-.56ZM339.74,254.83c.67-.92,1-2.23,1-3.94s-.33-3-1-3.93-1.68-1.39-3.04-1.39-2.38.46-3.04,1.39-1,2.23-1,3.93.33,3.02,1,3.94,1.68,1.38,3.04,1.38,2.38-.46,3.04-1.38Z"/>
<path class="cls-1" d="M358.21,243.21v2.75h-6.95v3.61h6.54v2.75h-6.54v6.24h-3.24v-15.36h10.19Z"/>
<path class="cls-1" d="M366.68,245.99v-2.78h12.6v2.78h-4.67v12.59h-3.26v-12.59h-4.67Z"/>
<path class="cls-1" d="M385.8,243.21v5.94h6.15v-5.94h3.24v15.36h-3.24v-6.45h-6.15v6.45h-3.24v-15.36h3.24Z"/>
<path class="cls-1" d="M410.2,243.21v2.73h-7.34v3.36h6.91v2.75h-6.91v3.79h7.8l-.33,2.73h-10.71v-15.36h10.58Z"/>
<path class="cls-1" d="M430.28,243.21v2.75h-6.95v3.61h6.54v2.75h-6.54v6.24h-3.24v-15.36h10.19Z"/>
<path class="cls-1" d="M436.97,243.21v9.14c0,1.31.23,2.27.7,2.9s1.24.95,2.32.95,1.86-.32,2.31-.95.68-1.6.68-2.9v-9.14h3.24v9.14c0,1.16-.14,2.16-.43,2.99s-.7,1.52-1.24,2.05c-.54.54-1.19.93-1.97,1.18s-1.65.38-2.62.38-1.87-.13-2.64-.39-1.43-.66-1.97-1.19-.94-1.23-1.22-2.08c-.28-.85-.41-1.85-.41-3.01v-9.08h3.24Z"/>
<path class="cls-1" d="M449.2,245.99v-2.78h12.6v2.78h-4.67v12.59h-3.26v-12.59h-4.67Z"/>
<path class="cls-1" d="M468.01,243.21v9.14c0,1.31.23,2.27.7,2.9s1.24.95,2.32.95,1.86-.32,2.31-.95.68-1.6.68-2.9v-9.14h3.24v9.14c0,1.16-.14,2.16-.43,2.99s-.7,1.52-1.24,2.05c-.54.54-1.19.93-1.97,1.18s-1.65.38-2.62.38-1.87-.13-2.64-.39-1.43-.66-1.97-1.19-.94-1.23-1.22-2.08c-.28-.85-.41-1.85-.41-3.01v-9.08h3.24Z"/>
<path class="cls-1" d="M486.89,243.21c1.22,0,2.22.14,3.01.42.79.28,1.41.65,1.86,1.1s.76.95.93,1.51c.17.55.26,1.09.26,1.62,0,.99-.18,1.82-.54,2.5s-.97,1.24-1.83,1.7l3.15,6.52h-3.5l-2.61-5.77h-3.04v5.77h-3.19v-15.36h5.5ZM488.37,249.98c.33-.11.6-.26.79-.45s.33-.43.4-.7.11-.57.11-.9c0-.27-.04-.54-.13-.79s-.24-.47-.45-.67c-.21-.19-.5-.34-.87-.45s-.84-.16-1.4-.16h-2.24v4.28h2.52c.51,0,.93-.05,1.26-.16Z"/>
<path class="cls-1" d="M507.43,243.21v2.73h-7.34v3.36h6.91v2.75h-6.91v3.79h7.8l-.33,2.73h-10.71v-15.36h10.58Z"/>
</g>
<g>
<path class="cls-1" d="M18.99,50.96c2.16,1.71,5.35,2.57,9.56,2.57,2.02,0,3.72-.21,5.1-.64s2.51-1,3.37-1.71,1.48-1.56,1.86-2.53c.37-.97.56-2.03.56-3.17,0-1.6-.61-3.1-1.82-4.5-1.21-1.4-3.43-2.41-6.66-3.04l-8.04-1.46c-3.17-.57-5.97-1.31-8.39-2.23-2.42-.91-4.45-2.1-6.1-3.55s-2.9-3.24-3.76-5.35c-.87-2.11-1.3-4.62-1.3-7.54s.59-5.48,1.77-7.71c1.18-2.23,2.83-4.08,4.93-5.57,2.1-1.49,4.63-2.61,7.57-3.38,2.94-.77,6.17-1.16,9.69-1.16,4.5,0,8.25.51,11.25,1.54s5.42,2.38,7.27,4.07,3.21,3.64,4.11,5.87c.89,2.23,1.48,4.54,1.77,6.94l-12.2,1.54c-.63-3.37-1.86-5.79-3.68-7.28-1.82-1.48-4.57-2.23-8.26-2.23-2.19,0-3.99.19-5.41.56-1.41.37-2.55.86-3.42,1.46s-1.47,1.3-1.82,2.1c-.35.8-.52,1.63-.52,2.48,0,2.28.65,4,1.95,5.14,1.3,1.14,3.5,2.03,6.62,2.66l8.48,1.63c6.69,1.31,11.59,3.44,14.71,6.38,3.11,2.94,4.67,7.18,4.67,12.72,0,2.68-.5,5.15-1.51,7.41-1.01,2.25-2.51,4.22-4.5,5.91s-4.48,3-7.48,3.94c-3,.94-6.52,1.41-10.55,1.41-8.42,0-14.86-1.78-19.33-5.35-4.47-3.57-6.88-8.95-7.22-16.14h13.06c.29,3.77,1.51,6.51,3.68,8.22Z"/>
<path class="cls-1" d="M78.12,1.54v22.1c1.79-2.4,3.86-4.17,6.23-5.31,2.36-1.14,4.84-1.71,7.44-1.71,5.13,0,8.94,1.33,11.42,3.98,2.48,2.66,3.72,6.84,3.72,12.55v29.55h-12.11v-27.92c0-3.14-.61-5.28-1.82-6.42-1.21-1.14-2.83-1.71-4.84-1.71-1.56,0-2.9.23-4.02.69-1.12.46-2.18,1.11-3.16,1.97-.81.8-1.48,1.76-2.03,2.87s-.82,2.33-.82,3.64v26.89h-12.11V1.54h12.11Z"/>
<path class="cls-1" d="M134.6,1.54v10.79h-12.46V1.54h12.46ZM134.43,17.99v44.71h-12.11V17.99h12.11Z"/>
<path class="cls-1" d="M146.11,27.32v-9.34h7.09v-1.46c0-2.74.4-5.11,1.21-7.11.81-2,1.92-3.63,3.33-4.88,1.41-1.26,3.07-2.18,4.97-2.78s3.98-.9,6.23-.9c1.44,0,2.96.09,4.54.26,1.59.17,3.21.51,4.89,1.03l-1.64,8.74c-1.85-.46-3.6-.69-5.28-.69-1.56,0-2.97.44-4.24,1.33-1.27.89-1.9,2.47-1.9,4.75v1.71h10.47v9.34h-10.47v35.37h-12.11V27.32h-7.09Z"/>
<path class="cls-1" d="M185.03,27.32v-9.34h7.09V6.08h12.11v11.91h10.38v9.34h-10.38v20.64c0,2.34.49,3.93,1.47,4.75.98.83,2.25,1.24,3.81,1.24.81,0,1.63-.04,2.47-.13.84-.09,1.66-.24,2.47-.47l1.73,8.82c-1.67.51-3.3.87-4.89,1.07-1.59.2-3.1.3-4.54.3-4.96,0-8.64-1.17-11.03-3.51-2.39-2.34-3.59-6.28-3.59-11.82v-20.9h-7.09Z"/>
<path class="cls-1" d="M233.3,47.49c2.42-1.97,4.87-4.04,7.35-6.21,2.42-2.11,4.54-4.03,6.36-5.74,1.82-1.71,3.33-3.37,4.54-4.97,1.21-1.6,2.12-3.18,2.72-4.75.61-1.57.91-3.3.91-5.18,0-2.46-.71-4.47-2.12-6.04-1.41-1.57-3.33-2.36-5.75-2.36-2.88,0-5.15.64-6.79,1.93-1.64,1.29-2.87,3.73-3.68,7.32l-11.76-1.37c.52-2.46,1.27-4.78,2.25-6.98.98-2.2,2.32-4.14,4.02-5.82,1.7-1.68,3.85-3.01,6.44-3.98,2.6-.97,5.8-1.46,9.6-1.46,6.69,0,11.76,1.63,15.22,4.88,3.46,3.25,5.19,7.68,5.19,13.28,0,2.4-.3,4.61-.91,6.64-.61,2.03-1.51,4.01-2.72,5.95s-2.75,3.9-4.63,5.87-4.11,4.1-6.7,6.38c-1.38,1.14-2.78,2.28-4.2,3.43-1.41,1.14-2.93,2.46-4.54,3.94h24.57l-1.3,10.45h-41.43v-8.99c2.48-2.17,4.93-4.24,7.35-6.21Z"/>
</g>
<path class="cls-1" d="M29.38,103.53v60.85c-16.23,0-29.38-13.16-29.38-29.38v-2.09c0-16.23,13.16-29.38,29.38-29.38ZM127.44,164.38c16.12,0,29.18,13.06,29.18,29.17v7.96c0,16.1-13.06,29.17-29.17,29.17H2.81v-24.15h100.5c13.26,0,24.02,10.69,24.14,23.92v-66.08h0ZM127.45,164.38H29.38c0-13.33,10.81-24.15,24.15-24.15h49.77c13.34,0,24.15,10.81,24.15,24.15ZM154.94,103.53H29.39c0-13.33,10.81-24.15,24.14-24.15h101.41v24.15Z"/>
<path class="cls-1" d="M343.48,137.25v36.19c0,15.51-12.57,28.07-28.06,28.07h-1.03c-.05,16.07-13.18,29.17-29.26,29.17h-100.45V79.38h100.93c15.84,0,28.7,12.86,28.72,28.7,16.1,0,29.15,13.07,29.15,29.17ZM314.31,108.1l-100.45-.03v93.44l100.45-.1v-93.31Z"/>
<path class="cls-1" d="M509.93,79.18l-16.65,97.91c-2.73,16.08-17.56,29.12-32.63,29.17-.18,1-.51,2.09-.79,3.05-3.43,11.89-14.51,21.09-26.04,21.09h-4.24c-11.53,0-22.61-9.2-26.03-21.09-.29-1-.53-2.02-.7-3.05-15.1,0-29.98-13.07-32.72-29.17l-16.65-97.91h27.76l21.61,127.07,57.73-.09,21.59-126.98h27.76Z"/>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -451,7 +451,7 @@ namespace dbc
if (!bNoDefaultDef)
{
// Parse the standard attribute definitions
CDbcSource source(std::string(R"code(
CDbcSource source(std::string(R"dbc(
BA_DEF_ BO_ "VFrameFormat" ENUM "StandardCAN","ExtendedCAN","StandardFD","ExtendedFD";
BA_DEF_ BO_ "GenMsgSendType" ENUM "cyclic","triggered","cyclicIfActive","cyclicAndTriggered","cyclicIfActiveAndTriggered","none";
BA_DEF_ BO_ "GenMsgCycleTime" INT 0 10000;
@@ -472,7 +472,7 @@ BA_DEF_DEF_ "GenSigDelayTime" 0;
BA_DEF_DEF_ "GenSigCycleTime" 0;
BA_DEF_DEF_ "GenSigStartDelayTime" 0;
BA_DEF_DEF_ "GenSigStartValue" 0;
)code"));
)dbc"));
Parse(source);
}
}

View File

@@ -11,8 +11,8 @@
* Erik Verhoeven - initial API and implementation
********************************************************************************/
#ifndef THREAD_POOL_H
#define THREAD_POOL_H
#ifndef SCHEDULER_H
#define SCHEDULER_H
#include <thread>
#include <mutex>
@@ -27,33 +27,38 @@
#include "../flags.h"
/**
* @brief Job scheduler that uses a dynamic threadpool to schedule the task.
* @brief Schedule flags to influence the scheduling.
*/
enum class EScheduleFlags
{
normal = 0x0, ///< If thread level threshold has been reached, queue the call at the end of the queue.
priority = 0x1, ///< If thread level threshold has been reached, insert the call at the begin of the queue.
no_queue = 0x2, ///< If thread level threshold has been reached, fail the schedule call.
};
/**
* @brief Task scheduler that uses a dynamic threadpool to schedule the task.
* @tparam TThread Type of thread class to use for scheduling; must be derived from std::thread.
* @tparam nMinIdle The amount of idle threads that should stay present if there is nothing to process at the moment.
* @tparam nMaxBusy The maximum amount of threads that is used for processing.
*/
template <class TThread = std::thread, size_t nMinIdle = 4, size_t nMaxBusy = 32>
class CTaskScheduler
{
public:
// The thread class must be derived from std::thread.
static_assert(std::is_base_of_v<std::thread, TThread>);
/**
* @brief Constructor
* @param[in] nMinIdle The amount of idle threads that should stay present if there is nothing to process at the moment.
* @param[in] nMaxBusy The maximum amount of threads that is used for processing.
*/
CTaskScheduler(size_t nMinIdle = 4, size_t nMaxBusy = 32);
CTaskScheduler();
/**
* @brief Destructor
*/
~CTaskScheduler();
/**
* @brief Schedule flags to influence the scheduling.
*/
enum class EScheduleFlags
{
normal = 0x0, ///< If thread level threshold has been reached, queue the call at the end of the queue.
priority = 0x1, ///< If thread level threshold has been reached, insert the call at the begin of the queue.
no_queue = 0x2, ///< If thread level threshold has been reached, fail the schedule call.
};
/**
* @brief Schedule the asynchronous execution of the task.
* @details If an idle thread is available, the thread will execute the task. If no thread is available and the maximum thread
@@ -125,7 +130,7 @@ private:
*/
void ThreadFunc();
std::thread m_thread; ///< The thread that executes the tasks.
TThread m_thread; ///< The thread that executes the tasks.
std::atomic_bool m_bShutdown = false; ///< Set when the thread should terminate.
std::atomic_bool m_bStarted = false; ///< Set when the thread has started.
std::function<void()> m_fnTask; ///< The task to execute (will be updated with new tasks before execution).
@@ -143,15 +148,18 @@ private:
* @param[in] itThread The thread to use for the execution.
* @param[in] fnTask The task to execute.
*/
void Execute(std::list<std::shared_ptr<CThread>>::iterator itThread, std::function<void()> fnTask);
void Execute(typename std::list<std::shared_ptr<CThread>>::iterator itThread, std::function<void()> fnTask);
size_t m_nMinIdle = 4; ///< The minimal required amount of idle threads
size_t m_nMaxBusy = 32; ///< The maximum allowed amount of busy threads
size_t m_nMaxThreads = 0; ///< The maximum amount threads at the same time.
mutable std::mutex m_mtxQueueAccess; ///< Sync access to queue, list and double-ended-queue.
std::queue<std::list<std::shared_ptr<CThread>>::iterator> m_queueIdleThreads; ///< Idle thread queue.
std::list<std::shared_ptr<CThread>> m_lstThreads; ///< List with all threads.
std::queue<typename std::list<std::shared_ptr<CThread>>::iterator> m_queueIdleThreads; ///< Idle thread queue.
std::list<typename std::shared_ptr<CThread>> m_lstThreads; ///< List with all threads.
std::deque<std::function<void()>> m_dequeTasks; ///< Double ended task queue.
};
#endif // !defined THREAD_POOL_H
// Include the implementation
#include "scheduler.inl"
#endif // !defined SCHEDULER_H

View File

@@ -11,10 +11,17 @@
* Erik Verhoeven - initial API and implementation
********************************************************************************/
#ifndef SCHEDULER_H
#include "scheduler.h"
#endif
#ifndef SCHEDULER_INL
#define SCHEDULER_INL
#include <cassert>
CTaskScheduler::CTaskScheduler(size_t nMinIdle /*= 4*/, size_t nMaxBusy /*= 32*/) :
template <class TThread, size_t nMinIdle, size_t nMaxBusy>
inline CTaskScheduler<TThread, nMinIdle, nMaxBusy>::CTaskScheduler() :
m_nMinIdle(nMinIdle), m_nMaxBusy(nMaxBusy)
{
// Check min/max values
@@ -30,17 +37,20 @@ CTaskScheduler::CTaskScheduler(size_t nMinIdle /*= 4*/, size_t nMaxBusy /*= 32*/
m_nMaxThreads = m_lstThreads.size();
}
CTaskScheduler::~CTaskScheduler()
template <class TThread, size_t nMinIdle, size_t nMaxBusy>
inline CTaskScheduler<TThread, nMinIdle, nMaxBusy>::~CTaskScheduler()
{
WaitForExecution();
}
bool CTaskScheduler::Schedule(std::function<void()> fnTask, hlpr::flags<EScheduleFlags> flags /*= 0*/)
template <class TThread, size_t nMinIdle, size_t nMaxBusy>
inline bool CTaskScheduler<TThread, nMinIdle, nMaxBusy>::Schedule(std::function<void()> fnTask,
hlpr::flags<EScheduleFlags> flags /*= 0*/)
{
std::unique_lock<std::mutex> lock(m_mtxQueueAccess);
// Get a thread - either from the idle queue or new.
std::list<std::shared_ptr<CThread>>::iterator itThread = m_lstThreads.end();
typename std::list<std::shared_ptr<CThread>>::iterator itThread = m_lstThreads.end();
if (m_queueIdleThreads.empty())
{
// No thread is available. Allowed to make one?
@@ -77,7 +87,8 @@ bool CTaskScheduler::Schedule(std::function<void()> fnTask, hlpr::flags<ESchedul
return true;
}
void CTaskScheduler::WaitForExecution()
template <class TThread, size_t nMinIdle, size_t nMaxBusy>
inline void CTaskScheduler<TThread, nMinIdle, nMaxBusy>::WaitForExecution()
{
std::unique_lock<std::mutex> lock(m_mtxQueueAccess);
@@ -111,31 +122,37 @@ void CTaskScheduler::WaitForExecution()
m_nMinIdle = nMinIdleTemp;
}
size_t CTaskScheduler::GetThreadCount() const
template <class TThread, size_t nMinIdle, size_t nMaxBusy>
inline size_t CTaskScheduler<TThread, nMinIdle, nMaxBusy>::GetThreadCount() const
{
std::unique_lock<std::mutex> lock(m_mtxQueueAccess);
return m_lstThreads.size();
}
size_t CTaskScheduler::GetMaxThreadCount() const
template <class TThread, size_t nMinIdle, size_t nMaxBusy>
inline size_t CTaskScheduler<TThread, nMinIdle, nMaxBusy>::GetMaxThreadCount() const
{
std::unique_lock<std::mutex> lock(m_mtxQueueAccess);
return m_nMaxThreads;
}
size_t CTaskScheduler::GetBusyThreadCount() const
template <class TThread, size_t nMinIdle, size_t nMaxBusy>
inline size_t CTaskScheduler<TThread, nMinIdle, nMaxBusy>::GetBusyThreadCount() const
{
std::unique_lock<std::mutex> lock(m_mtxQueueAccess);
return m_lstThreads.size() - m_queueIdleThreads.size();
}
size_t CTaskScheduler::GetIdleThreadCount() const
template <class TThread, size_t nMinIdle, size_t nMaxBusy>
inline size_t CTaskScheduler<TThread, nMinIdle, nMaxBusy>::GetIdleThreadCount() const
{
std::unique_lock<std::mutex> lock(m_mtxQueueAccess);
return m_queueIdleThreads.size();
}
void CTaskScheduler::Execute(std::list<std::shared_ptr<CThread>>::iterator itThread, std::function<void()> fnTask)
template <class TThread, size_t nMinIdle, size_t nMaxBusy>
inline void CTaskScheduler<TThread, nMinIdle, nMaxBusy>::Execute(typename std::list<std::shared_ptr<CThread>>::iterator itThread,
std::function<void()> fnTask)
{
std::shared_ptr<CThread>& rptrThread = *itThread;
@@ -176,16 +193,18 @@ void CTaskScheduler::Execute(std::list<std::shared_ptr<CThread>>::iterator itThr
});
}
CTaskScheduler::CThread::CThread()
template <class TThread, size_t nMinIdle, size_t nMaxBusy>
inline CTaskScheduler<TThread, nMinIdle, nMaxBusy>::CThread::CThread()
{
// Wait for the start
std::unique_lock<std::mutex> lockStart(m_mtxSyncStart);
m_thread = std::thread(&CThread::ThreadFunc, this);
m_thread = TThread(&CThread::ThreadFunc, this);
while (!m_bStarted)
m_cvStarted.wait_for(lockStart, std::chrono::milliseconds(10));
}
CTaskScheduler::CThread::~CThread()
template <class TThread, size_t nMinIdle, size_t nMaxBusy>
inline CTaskScheduler<TThread, nMinIdle, nMaxBusy>::CThread::~CThread()
{
// Lock to prevent execution still to take place. Then shutdown.
std::unique_lock<std::mutex> lock(m_mtxSyncExecute);
@@ -196,7 +215,8 @@ CTaskScheduler::CThread::~CThread()
m_thread.join();
}
void CTaskScheduler::CThread::Execute(std::function<void()> fnTask)
template <class TThread, size_t nMinIdle, size_t nMaxBusy>
inline void CTaskScheduler<TThread, nMinIdle, nMaxBusy>::CThread::Execute(std::function<void()> fnTask)
{
// Assign the task and notify for execution.
std::unique_lock<std::mutex> lock(m_mtxSyncExecute);
@@ -205,7 +225,8 @@ void CTaskScheduler::CThread::Execute(std::function<void()> fnTask)
lock.unlock();
}
void CTaskScheduler::CThread::ThreadFunc()
template <class TThread, size_t nMinIdle, size_t nMaxBusy>
inline void CTaskScheduler<TThread, nMinIdle, nMaxBusy>::CThread::ThreadFunc()
{
// Thread has started (needed, since the condition variable doesn't keep its state).
m_bStarted = true;
@@ -232,3 +253,5 @@ void CTaskScheduler::CThread::ThreadFunc()
m_fnTask = {};
}
}
#endif // !defined SCHEDULER_INL

View File

@@ -20,6 +20,8 @@
#include <sstream>
#include <map>
#include <atomic>
#include <memory>
#include <thread>
/**
* @brief trace fifo open flags

114
global/unique_id.h Normal file
View File

@@ -0,0 +1,114 @@
/********************************************************************************
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
*
* This program and the accompanying materials are made available under the
* terms of the Apache License Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Erik Verhoeven - initial API and implementation
********************************************************************************/
#ifndef UNIQUE_ID_H
#define UNIQUE_ID_H
#include <set>
#include <cstdlib>
#include <cstdint>
#include <ctime>
/**
* @brief Create a unique ID using the random number generator.
* @tparam TType Type of the variable that represents the ID.
* @tparam nDepth The depth of the ID generation in bits.
*/
template <typename TType = uint64_t, size_t nDepth = sizeof(TType) * 8>
class CUniqueID
{
public:
static_assert(nDepth <= sizeof(TType) * 8);
static_assert(nDepth > 0);
/**
* @brief Constructor
*/
CUniqueID()
{
std::srand(static_cast<unsigned int>(std::time(nullptr)));
}
/**
* @brief Generate a unique ID.
* @return The optional result with the ID if successful or 0 when not successful.
*/
TType Generate()
{
// Create a number with the supplied bit amount.
auto fnCreate = [](size_t nMaxDepth)
{
TType tNumber{};
// Create a new number
size_t nBitsFilled = 0;
while (nBitsFilled < nMaxDepth)
{
size_t nBitsToShiftIn = std::min(nMaxDepth - nBitsFilled, m_nRandMaxBits);
tNumber = (tNumber << nBitsToShiftIn) | static_cast<TType>(static_cast<size_t>(std::rand()) & ((1u << nBitsToShiftIn) - 1));
nBitsFilled += nBitsToShiftIn;
}
return tNumber;
};
// Treat a depth of 48 bits and more separately
if constexpr (nDepth >= 48)
{
// Combination of the time in seconds (22 bits only - can hold 48 days).
return (static_cast<TType>(std::time(nullptr)) << (nDepth - 22)) | fnCreate(nDepth - 22);
}
else
{
// Maximum iterations is 10000 for less than 24 bits and otherwise unlimited (value 0)
size_t nMaxIterations = nDepth < 24 ? 10000u : 0u;
// Generate
size_t nCnt = 0;
while (!nMaxIterations || (++nCnt < nMaxIterations))
{
TType tID = fnCreate(nDepth);
// Check whether not 0 and not generated already
if (tID && (m_setUsedNumbers.find(tID) == m_setUsedNumbers.end()))
{
m_setUsedNumbers.insert(tID);
return tID;
}
}
// No ID found
return TType{};
}
}
private:
/**
* @brief Recursive constexpr function to find the number of bits needed to hold the number.
* @param uiNumber The number to check for.
* @return The amount of bits needed to hold the number.
*/
static constexpr size_t GetBitWidth(uint64_t uiNumber)
{
return (!uiNumber) ? 0u : 1u + GetBitWidth(uiNumber >> 1);
}
/// The bits needed to hold the random number
static constexpr size_t m_nRandMaxBits = GetBitWidth(static_cast<uint64_t>(RAND_MAX));
// Static assertion to verify at compile-time
static_assert(m_nRandMaxBits > 0, "RAND_MAX bits must be greater than 0");
std::set<TType> m_setUsedNumbers; ///< Numbers generated previously already (numbers < 48 bits only).
};
#endif // !defined UNIQUE_ID_H

View File

@@ -60,12 +60,22 @@ MAKE_ERROR_MSG(-134, CONFIG_SERVICE_ACCESS_ERROR, "Configuration service is not
MAKE_ERROR_MSG(-135, COMMUNICATION_CONTROL_SERVICE_ACCESS_ERROR, "Communication control service is not accessible.", "The communication control service service could not be accessed.")
MAKE_ERROR_MSG(-136, APP_CONTROL_SERVICE_ACCESS_ERROR, "Application control service is not accessible.", "The application control service could not be accessed.")
MAKE_ERROR_MSG(-170, CANNOT_FIND_OBJECT, "The object cannot be found.", "A search for an object with supplied name was not successful.")
MAKE_ERROR_MSG(-180, CANNOT_LOAD_SETTINGS, "The system settings cannot be loaded.", "For a specific instance, the system settings cannot be loaded.")
MAKE_ERROR_MSG(-180, CANNOT_SAVE_SETTINGS, "The system settings cannot be saved.", "For a specific instance, the system settings cannot be saved.")
MAKE_ERROR_MSG(-181, PROCESS_LISTENER_CONFIG_ERROR, "The listener configuration contains errors.", "The listener configuration contains errors and cannot be processed.")
MAKE_ERROR_MSG(-182, PROCESS_CONNECTION_CONFIG_ERROR, "The connection configuration contains errors.", "The connection configuration contains errors and cannot be processed.")
MAKE_ERROR_MSG(-183, ADD_LISTENER_ERROR, "Failed to add a listener to the system settings.", "The listener configuration could not be added to the system settings. This might be caused by a duplicate listener configuration.")
MAKE_ERROR_MSG(-184, REMOVE_LISTENER_ERROR, "Failed to remove a listener from the system settings.", "The listener configuration could not be removed from the system settings. This might be caused by a missing listener configuration.")
MAKE_ERROR_MSG(-185, SHOW_LISTENER_ERROR, "Failed to request the listener configuration from the system settings.", "The listener configuration could not be requested. This might be caused by a missing listener configuration.")
MAKE_ERROR_MSG(-186, ADD_CONNECTION_ERROR, "Failed to add a connection to the system settings.", "The connection configuration could not be added to the system settings. This might be caused by a duplicate connection configuration.")
MAKE_ERROR_MSG(-187, REMOVE_CONNECTION_ERROR, "Failed to remove a connection from the system settings.", "The connection configuration could not be removed from the system settings. This might be caused by a missing connection configuration.")
MAKE_ERROR_MSG(-188, SHOW_CONNECTION_ERROR, "Failed to request the connection configuration from the system settings.", "The connection configuration could not be requested. This might be caused by a missing connection configuration.")
////////// LOCAL APP CONTROL ERROR CODES ////////////
MAKE_ERROR_MSG(-204, APP_CONTROL_STARTUP_ERROR, "Cannot start application control.", "Application control start was initiated, but returned an error.")
MAKE_ERROR_MSG(-205, APP_CONTROL_START_LOOP_FAIELD, "Starting the running loop failed.", "Failed to enter the processing loop for a server application.")
MAKE_ERROR_MSG(-205, APP_CONTROL_START_LOOP_FAILED, "Starting the running loop failed.", "Failed to enter the processing loop for a server application.")
MAKE_ERROR_MSG(-206, APP_CONTROL_DUPLICATE_INSTANCE, "Another process with specified instance is already running.", "Another core process initiated the application control with the same instance. Only one core process per instance is allowed.")
MAKE_ERROR_MSG(-210, APP_CONTROL_INVALID_ISOLATION_CONFIG, "An invalid isolation configuration was supplied.", "The application control configuration section contains an invalid isolation configuration.")
MAKE_ERROR_MSG(-218, SETTING_FILE_VERSION_INVALID, "Settings file has an invalid version.", "Settings file contains an invalid/incompatible version number.")

View File

@@ -25,7 +25,7 @@ add_executable(sdv_control
"startup_shutdown.h"
"startup_shutdown.cpp"
"context.h"
"print_table.h" "start_stop_service.cpp" "start_stop_service.h" "installation.h" "installation.cpp")
"print_table.h" "start_stop_service.cpp" "start_stop_service.h" "installation.h" "installation.cpp" "connection_config.h" "connection_config.cpp")
target_link_libraries(sdv_control ${CMAKE_DL_LIBS})

View File

@@ -0,0 +1,471 @@
/********************************************************************************
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
*
* This program and the accompanying materials are made available under the
* terms of the Apache License Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Erik Verhoeven - initial API and implementation
********************************************************************************/
#include "connection_config.h"
#include "../../global/cmdlnparser/cmdlnparser.h"
#include <support/toml.h>
#include <interfaces/app.h>
#include "../error_msg.h"
#include <charconv>
void ListenerHelp(const SContext& rsContext)
{
// First argument should be "LISTENER"
if (rsContext.seqCmdLine.size() < 1)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: missing listener command..." << std::endl;
return;
}
if (iequals(rsContext.seqCmdLine[0], "LISTENER"))
{
CCommandLine::PrintHelpText(std::cout,
"Usage: sdv_control LISTENER ADD <name> <provider> <parameters...> [options...]\n"
" sdv_control LISTENER REMOVE <name> [options...]\n"
" sdv_control LISTENER SHOW <name> [options...]\n\n"
"Configure the system to add (or update) or remove a listener. The command doesn't check for valid parameters. A "
"server restart is required for the new listener settings to take effect.\n\n"
"A list of actively configured listeners can be requested by executing \"sdv_control LIST LISTENERS\"\n\n"
"Note: if not explicitly added, a default listener will added to the list for the communication between isolated "
"applications and the core system.\n\n");
return;
}
if (!rsContext.bSilent)
std::cerr << "ERROR: invalid listener command..." << std::endl;
}
void ConnectionHelp(const SContext& rsContext)
{
// First argument should be "CONNECTION"
if (rsContext.seqCmdLine.size() < 1)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: missing connection command..." << std::endl;
return;
}
if (iequals(rsContext.seqCmdLine[0], "CONNECTION"))
{
CCommandLine::PrintHelpText(std::cout,
"Usage: sdv_control CONNECTION ADD <name> <provider> <parameters...> [options...]\n"
" sdv_control CONNECTION REMOVE <name> [options...]\n"
" sdv_control CONNECTION SHOW <name> [options...]\n\n"
"Configure the system to add (or update) or remove a connection. The command doesn't check for valid parameters. A "
"server restart is required for the new connection settings to take effect.\n\n"
"A list of actively configured connections can be requested by executing \"sdv_control LIST CONNECTIONS\"\n\n"
"Note: if not explicitly added, a default connetion will be added to the list for the communication between external "
"applications and the core system.\n\n"
"Options:\n"
" --insert_before<string> With ADD, Insert the connection before an existing connection with the supplied name.\n\n");
return;
}
if (!rsContext.bSilent)
std::cerr << "ERROR: invalid connection command..." << std::endl;
}
int ConfigureListener(const SContext& rsContext)
{
// First argument should be "CONNECTION"
if (rsContext.seqCmdLine.size() < 2)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Missing listener command... " << std::endl;
return CMDLN_ARG_ERR;
}
if (!iequals(rsContext.seqCmdLine[0], "LISTENER"))
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Invalid command: " << rsContext.seqCmdLine[0] << std::endl;
return CMDLN_ARG_ERR;
}
// Which list command is requested
enum class ECommand { unknown, add, remove, show } eCommand = ECommand::unknown;
if (iequals(rsContext.seqCmdLine[1], "ADD")) eCommand = ECommand::add;
else if (iequals(rsContext.seqCmdLine[1], "REMOVE")) eCommand = ECommand::remove;
else if (iequals(rsContext.seqCmdLine[1], "SHOW")) eCommand = ECommand::show;
else
{
if (!rsContext.bSilent)
{
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Invalid listener command." << std::endl;
ListenerHelp(rsContext);
}
return CMDLN_ARG_ERR;
}
if (rsContext.seqCmdLine.size() < 3)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Missing listener name... " << std::endl;
return CMDLN_ARG_ERR;
}
// Get the name
std::string ssListener = rsContext.seqCmdLine[2];
switch (eCommand)
{
case ECommand::remove:
return RemoveListener(ssListener, rsContext);
case ECommand::show:
return ShowListenerConfig(ssListener, rsContext);
case ECommand::add:
default:
break;
}
// For add, check for provider and parameters
if (rsContext.seqCmdLine.size() < 4)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Missing listener provider... " << std::endl;
return CMDLN_ARG_ERR;
}
std::string ssProvider = rsContext.seqCmdLine[3];
sdv::toml::CTOMLParser parser;
parser.AddValue("Provider.Name", ssProvider);
// Check for parameters
// Parameters have the format "param=value". It is possible that parameters have additional sub-tables. Then the format is:
// "table.param=value".
sdv::toml::CNodeCollection ipc_channel_table = parser.AddTable("IpcChannel");
for (size_t nIndex = 4; nIndex < rsContext.seqCmdLine.size(); nIndex++)
{
std::string ssRawParam = rsContext.seqCmdLine[nIndex];
// Search for the equal sign
size_t nEqualPos = ssRawParam.find_first_of('=');
std::string ssParamName = ssRawParam.substr(0, nEqualPos);
while (!ssParamName.empty() && std::isspace(ssParamName.back()))
ssParamName.pop_back();
if (ssParamName.empty() || nEqualPos == std::string::npos)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Invalid listener parameter: " << ssRawParam << std::endl;
return CMDLN_ARG_ERR;
}
sdv::any_t anyValue;
size_t nValuePos = nEqualPos + 1;
while (nValuePos < ssRawParam.size() && std::isspace(ssRawParam[nValuePos]))
nValuePos++;
if (nValuePos < ssRawParam.size())
{
std::string ssValue = ssRawParam.substr(nValuePos);
if (!ssValue.empty() && ssValue.find_first_not_of("-0123456789") == std::string::npos)
{
int64_t iValue = 0;
if (std::from_chars(ssValue.data(), ssValue.data() + ssValue.size(), iValue).ec == std::errc())
anyValue = iValue;
else
anyValue = ssValue;
}
else
anyValue = ssValue;
}
ipc_channel_table.AddValue(ssParamName, anyValue);
}
return AddListener(ssListener, parser.GetTOML(), rsContext);
}
int AddListener(const std::string& rssListener, const std::string& rssConfig, const SContext& rsContext)
{
// Load the settings.
auto ptrAppService = sdv::core::GetObject("AppSettingsService");
sdv::app::IAppSettingsPersist* pAppSettingsPersist = ptrAppService.GetInterface<sdv::app::IAppSettingsPersist>();
sdv::app::IAppConnections* pAppConnections = ptrAppService.GetInterface<sdv::app::IAppConnections>();
if (!pAppSettingsPersist || !pAppConnections || !pAppSettingsPersist->LoadSettings())
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CANNOT_LOAD_SETTINGS_MSG << std::endl;
return CANNOT_LOAD_SETTINGS;
}
// Add the listener
if (!pAppConnections->AddListenerConfig(rssListener, rssConfig))
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << ADD_LISTENER_ERROR_MSG << std::endl;
return ADD_LISTENER_ERROR;
}
// Save the settings.
if (!pAppSettingsPersist->SaveSettings())
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CANNOT_SAVE_SETTINGS_MSG << std::endl;
return CANNOT_SAVE_SETTINGS;
}
return NO_ERROR;
}
int RemoveListener(const std::string& rssListener, const SContext& rsContext)
{
// Load the settings.
auto ptrAppService = sdv::core::GetObject("AppSettingsService");
sdv::app::IAppSettingsPersist* pAppSettingsPersist = ptrAppService.GetInterface<sdv::app::IAppSettingsPersist>();
sdv::app::IAppConnections* pAppConnections = ptrAppService.GetInterface<sdv::app::IAppConnections>();
if (!pAppSettingsPersist || !pAppConnections || !pAppSettingsPersist->LoadSettings())
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CANNOT_LOAD_SETTINGS_MSG << std::endl;
return CANNOT_LOAD_SETTINGS;
}
// Remove the listener
if (!pAppConnections->RemoveListenerConfig(rssListener))
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << REMOVE_LISTENER_ERROR_MSG << std::endl;
return REMOVE_LISTENER_ERROR;
}
// Save the settings.
if (!pAppSettingsPersist->SaveSettings())
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CANNOT_SAVE_SETTINGS_MSG << std::endl;
return CANNOT_SAVE_SETTINGS;
}
return NO_ERROR;
}
int ShowListenerConfig(const std::string& rssListener, const SContext& rsContext)
{
// Load the settings.
auto ptrAppService = sdv::core::GetObject("AppSettingsService");
sdv::app::IAppSettingsPersist* pAppSettingsPersist = ptrAppService.GetInterface<sdv::app::IAppSettingsPersist>();
sdv::app::IAppConnections* pAppConnections = ptrAppService.GetInterface<sdv::app::IAppConnections>();
if (!pAppSettingsPersist || !pAppConnections || !pAppSettingsPersist->LoadSettings())
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CANNOT_LOAD_SETTINGS_MSG << std::endl;
return CANNOT_LOAD_SETTINGS;
}
// Remove the listener
std::string ssConfig = pAppConnections->GetListenerConfig(rssListener);
if (ssConfig.empty())
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << SHOW_LISTENER_ERROR_MSG << std::endl;
return SHOW_LISTENER_ERROR;
}
std::cout << ssConfig << std::endl;
return NO_ERROR;
}
int ConfigureConnection(const SContext& rsContext)
{
// First argument should be "CONNECTION"
if (rsContext.seqCmdLine.size() < 2)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Missing connection command... " << std::endl;
return CMDLN_ARG_ERR;
}
if (!iequals(rsContext.seqCmdLine[0], "CONNECTION"))
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Invalid command: " << rsContext.seqCmdLine[0] << std::endl;
return CMDLN_ARG_ERR;
}
// Which list command is requested
enum class ECommand { unknown, add, remove, show } eCommand = ECommand::unknown;
if (iequals(rsContext.seqCmdLine[1], "ADD")) eCommand = ECommand::add;
else if (iequals(rsContext.seqCmdLine[1], "REMOVE")) eCommand = ECommand::remove;
else if (iequals(rsContext.seqCmdLine[1], "SHOW")) eCommand = ECommand::show;
else
{
if (!rsContext.bSilent)
{
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Invalid connection command." << std::endl;
ConnectionHelp(rsContext);
}
return CMDLN_ARG_ERR;
}
if (rsContext.seqCmdLine.size() < 3)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Missing connection name... " << std::endl;
return CMDLN_ARG_ERR;
}
// Get the name
std::string ssConnection = rsContext.seqCmdLine[2];
switch (eCommand)
{
case ECommand::remove:
return RemoveConnection(ssConnection, rsContext);
case ECommand::show:
return ShowConnectionConfig(ssConnection, rsContext);
case ECommand::add:
default:
break;
}
// For add, check for provider and parameters
if (rsContext.seqCmdLine.size() < 4)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Missing connection provider... " << std::endl;
return CMDLN_ARG_ERR;
}
std::string ssProvider = rsContext.seqCmdLine[3];
sdv::toml::CTOMLParser parser;
parser.AddValue("Provider.Name", ssProvider);
// Check for parameters
// Parameters have the format "param=value". It is possible that parameters have additional sub-tables. Then the format is:
// "table.param=value".
sdv::toml::CNodeCollection ipc_channel_table = parser.AddTable("IpcChannel");
for (size_t nIndex = 4; nIndex < rsContext.seqCmdLine.size(); nIndex++)
{
std::string ssRawParam = rsContext.seqCmdLine[nIndex];
// Search for the equal sign
size_t nEqualPos = ssRawParam.find_first_of('=');
std::string ssParamName = ssRawParam.substr(0, nEqualPos);
while (!ssParamName.empty() && std::isspace(ssParamName.back()))
ssParamName.pop_back();
if (ssParamName.empty() || nEqualPos == std::string::npos)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Invalid listener parameter: " << ssRawParam << std::endl;
return CMDLN_ARG_ERR;
}
sdv::any_t anyValue;
size_t nValuePos = nEqualPos + 1;
while (nValuePos < ssRawParam.size() && std::isspace(ssRawParam[nValuePos]))
nValuePos++;
if (nValuePos < ssRawParam.size())
{
std::string ssValue = ssRawParam.substr(nValuePos);
if (!ssValue.empty() && ssValue.find_first_not_of("-0123456789") == std::string::npos)
{
int64_t iValue = 0;
if (std::from_chars(ssValue.data(), ssValue.data() + ssValue.size(), iValue).ec == std::errc())
anyValue = iValue;
else
anyValue = ssValue;
}
else
anyValue = ssValue;
}
ipc_channel_table.AddValue(ssParamName, anyValue);
}
return AddConnection(ssConnection, parser.GetTOML(), rsContext);
}
int AddConnection(const std::string& rssConnection, const std::string& rssConfig, const SContext& rsContext)
{
// Load the settings.
auto ptrAppService = sdv::core::GetObject("AppSettingsService");
sdv::app::IAppSettingsPersist* pAppSettingsPersist = ptrAppService.GetInterface<sdv::app::IAppSettingsPersist>();
sdv::app::IAppConnections* pAppConnections = ptrAppService.GetInterface<sdv::app::IAppConnections>();
if (!pAppSettingsPersist || !pAppConnections || !pAppSettingsPersist->LoadSettings())
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CANNOT_LOAD_SETTINGS_MSG << std::endl;
return CANNOT_LOAD_SETTINGS;
}
// Add the connection
if (!pAppConnections->AddConnectionConfig(rssConnection, rssConfig, rsContext.ssInsertBeforeConnection))
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << ADD_CONNECTION_ERROR_MSG << std::endl;
return ADD_CONNECTION_ERROR;
}
// Save the settings.
if (!pAppSettingsPersist->SaveSettings())
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CANNOT_SAVE_SETTINGS_MSG << std::endl;
return CANNOT_SAVE_SETTINGS;
}
return NO_ERROR;
}
int RemoveConnection(const std::string& rssConnection, const SContext& rsContext)
{
// Load the settings.
auto ptrAppService = sdv::core::GetObject("AppSettingsService");
sdv::app::IAppSettingsPersist* pAppSettingsPersist = ptrAppService.GetInterface<sdv::app::IAppSettingsPersist>();
sdv::app::IAppConnections* pAppConnections = ptrAppService.GetInterface<sdv::app::IAppConnections>();
if (!pAppSettingsPersist || !pAppConnections || !pAppSettingsPersist->LoadSettings())
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CANNOT_LOAD_SETTINGS_MSG << std::endl;
return CANNOT_LOAD_SETTINGS;
}
// Remove the connection
if (!pAppConnections->RemoveConnectionConfig(rssConnection))
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << REMOVE_CONNECTION_ERROR_MSG << std::endl;
return REMOVE_CONNECTION_ERROR;
}
// Save the settings.
if (!pAppSettingsPersist->SaveSettings())
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CANNOT_SAVE_SETTINGS_MSG << std::endl;
return CANNOT_SAVE_SETTINGS;
}
return NO_ERROR;
}
int ShowConnectionConfig(const std::string& rssConnection, const SContext& rsContext)
{
// Load the settings.
auto ptrAppService = sdv::core::GetObject("AppSettingsService");
sdv::app::IAppSettingsPersist* pAppSettingsPersist = ptrAppService.GetInterface<sdv::app::IAppSettingsPersist>();
sdv::app::IAppConnections* pAppConnections = ptrAppService.GetInterface<sdv::app::IAppConnections>();
if (!pAppSettingsPersist || !pAppConnections || !pAppSettingsPersist->LoadSettings())
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CANNOT_LOAD_SETTINGS_MSG << std::endl;
return CANNOT_LOAD_SETTINGS;
}
// Remove the connection
std::string ssConfig = pAppConnections->GetConnectionConfig(rssConnection);
if (ssConfig.empty())
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << SHOW_CONNECTION_ERROR_MSG << std::endl;
return SHOW_CONNECTION_ERROR;
}
std::cout << ssConfig << std::endl;
return NO_ERROR;
}

View File

@@ -0,0 +1,98 @@
/********************************************************************************
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
*
* This program and the accompanying materials are made available under the
* terms of the Apache License Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Erik Verhoeven - initial API and implementation
********************************************************************************/
#ifndef CONNECTION_CONFIG_H
#define CONNECTION_CONFIG_H
#include "context.h"
#include <support/sequence.h>
#include <support/string.h>
/**
* @brief Help for configuring listeners.
* @param[in] rsContext Reference to the context.
*/
void ListenerHelp(const SContext& rsContext);
/**
* @brief Help for configuring connections.
* @param[in] rsContext Reference to the context.
*/
void ConnectionHelp(const SContext& rsContext);
/**
* @brief Configure the listener.
* @param[in] rsContext Reference to the context.
* @return The application exit code. 0 is no error.
*/
int ConfigureListener(const SContext& rsContext);
/**
* @brief Add a listener to the system settings.
* @param[in] rssListener Reference to the string containing the listener configuration name.
* @param[in] rssConfig Reference to the string containing the listener configuration.
* @param[in] rsContext Reference to the context.
* @return The application exit code. 0 is no error.
*/
int AddListener(const std::string& rssListener, const std::string& rssConfig, const SContext& rsContext);
/**
* @brief Remove a listener from the system settings.
* @param[in] rssListener Reference to the string containing the listener configuration name.
* @param[in] rsContext Reference to the context.
* @return The application exit code. 0 is no error.
*/
int RemoveListener(const std::string& rssListener, const SContext& rsContext);
/**
* @brief Show a listener configuration.
* @param[in] rssListener Reference to the string containing the listener configuration name.
* @param[in] rsContext Reference to the context.
* @return The application exit code. 0 is no error.
*/
int ShowListenerConfig(const std::string& rssListener, const SContext& rsContext);
/**
* @brief Configure the connection.
* @param[in] rsContext Reference to the context.
* @return The application exit code. 0 is no error.
*/
int ConfigureConnection(const SContext& rsContext);
/**
* @brief Add a connection to the system settings.
* @param[in] rssConnection Reference to the string containing the connection configuration name.
* @param[in] rssConfig Reference to the string containing the connection configuration.
* @param[in] rsContext Reference to the context.
* @return The application exit code. 0 is no error.
*/
int AddConnection(const std::string& rssConnection, const std::string& rssConfig, const SContext& rsContext);
/**
* @brief Remove a connection from the system settings.
* @param[in] rssConnection Reference to the string containing the connection configuration name.
* @param[in] rsContext Reference to the context.
* @return The application exit code. 0 is no error.
*/
int RemoveConnection(const std::string& rssConnection, const SContext& rsContext);
/**
* @brief Show a connection configuration.
* @param[in] rssConnection Reference to the string containing the connection configuration name.
* @param[in] rsContext Reference to the context.
* @return The application exit code. 0 is no error.
*/
int ShowConnectionConfig(const std::string& rssConnection, const SContext& rsContext);
#endif // !defined CONNECTION_CONFIG_H

View File

@@ -33,6 +33,7 @@ struct SContext
bool bListShort = false; ///< Print only a shortened list with one column.
sdv::sequence<sdv::u8string> seqCmdLine; ///< The commands provided on the command line.
std::filesystem::path pathInstallDir; ///< Optional installation directory.
std::string ssInsertBeforeConnection; ///< Insert before the provided connection
};
#include <cctype> // std::tolower

View File

@@ -88,7 +88,7 @@ int Install(const SContext& rsContext)
ssName = rsContext.seqCmdLine[1];
// Try to connect
sdv::TObjectPtr ptrRepository = sdv::com::ConnectToLocalServerRepository(rsContext.uiInstanceID);
sdv::TObjectPtr ptrRepository = sdv::com::ConnectToLocalServerRepository();
if (!ptrRepository)
{
if (!rsContext.bSilent)

View File

@@ -14,8 +14,10 @@
#include "list_elements.h"
#include "print_table.h"
#include <interfaces/config.h>
#include <interfaces/app.h>
#include <support/sdv_core.h>
#include <support/local_service_access.h>
#include <support/toml.h>
#include "../../global/cmdlnparser/cmdlnparser.h"
#include "../../global/exec_dir_helper.h"
#include "../../global/flags.h"
@@ -38,13 +40,14 @@ void ListHelp(const SContext& rsContext)
}
// Which list command help is requested
enum class EListCommand { unknown, modules, classes, components, installations, connections } eListCommand = EListCommand::unknown;
enum class EListCommand { unknown, modules, classes, components, installations, listeners, connections } eListCommand = EListCommand::unknown;
if (rsContext.seqCmdLine.size() >= 2)
{
if (iequals(rsContext.seqCmdLine[1], "MODULES")) eListCommand = EListCommand::modules;
else if (iequals(rsContext.seqCmdLine[1], "CLASSES")) eListCommand = EListCommand::classes;
else if (iequals(rsContext.seqCmdLine[1], "COMPONENTS")) eListCommand = EListCommand::components;
else if (iequals(rsContext.seqCmdLine[1], "INSTALLATIONS")) eListCommand = EListCommand::installations;
else if (iequals(rsContext.seqCmdLine[1], "LISTENERS")) eListCommand = EListCommand::listeners;
else if (iequals(rsContext.seqCmdLine[1], "CONNECTIONS")) eListCommand = EListCommand::connections;
}
@@ -65,20 +68,24 @@ void ListHelp(const SContext& rsContext)
case EListCommand::installations:
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control LIST INSTALLATIONS [options...]\n\nShow a list of all installations.\n");
break;
case EListCommand::listeners:
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control LIST LISTENERS [options...]\n\nShow a list of all configured listeners.\n");
break;
case EListCommand::connections:
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control LIST CONNECTIONS [options...]\n\nShow a list of all connected applications.\n");
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control LIST CONNECTIONS [options...]\n\nShow a list of all configured connections.\n");
break;
default:
CCommandLine::PrintHelpText(std::cout, R"code(Usage: sdv_control LIST <list_command> [options...]
CCommandLine::PrintHelpText(std::cout, R"text(Usage: sdv_control LIST <list_command> [options...]
Supported listing commands:
LIST MODULES Show a list of loaded server modules.
LIST CLASSES Show a list of available component classes.
LIST COMPONENTS Show a list of instantiated server components
LIST INSTALLATIONS Show a list of installations.
LIST LISTENERS Show a list of current listeners.
LIST CONNECTIONS Show a list of current connections.
)code");
)text");
break;
}
std::cout << "Options:\n";
@@ -103,34 +110,40 @@ int ListElements(const SContext& rsContext, std::ostream& rstream /*= std::cout*
return CMDLN_ARG_ERR;
}
// Which list command help is requested
enum class EListCommand { unknown, modules, classes, components, installations, connections } eListCommand = EListCommand::unknown;
// Which list command is requested
enum class EListCommand { unknown, modules, classes, components, installations, listeners, connections } eListCommand = EListCommand::unknown;
if (rsContext.seqCmdLine.size() >= 2)
{
if (iequals(rsContext.seqCmdLine[1], "MODULES")) eListCommand = EListCommand::modules;
else if (iequals(rsContext.seqCmdLine[1], "CLASSES")) eListCommand = EListCommand::classes;
else if (iequals(rsContext.seqCmdLine[1], "COMPONENTS")) eListCommand = EListCommand::components;
else if (iequals(rsContext.seqCmdLine[1], "INSTALLATIONS")) eListCommand = EListCommand::installations;
else if (iequals(rsContext.seqCmdLine[1], "LISTENERS")) eListCommand = EListCommand::listeners;
else if (iequals(rsContext.seqCmdLine[1], "CONNECTIONS")) eListCommand = EListCommand::connections;
}
else
{
if (!rsContext.bSilent)
{
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Missing listing command.." << std::endl << std::endl;
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Missing listing command." << std::endl;
ListHelp(rsContext);
}
return CMDLN_ARG_ERR;
}
// Try to connect
sdv::TObjectPtr ptrRepository = sdv::com::ConnectToLocalServerRepository(rsContext.uiInstanceID);
// Try to connect (except when listing the listeners and connections... they can be read from the settings).
sdv::TObjectPtr ptrRepository;
if (eListCommand != EListCommand::listeners && eListCommand != EListCommand::connections)
{
ptrRepository = sdv::com::ConnectToLocalServerRepository();
if (!ptrRepository)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CONNECT_SDV_SERVER_ERROR_MSG << " Instance #" << rsContext.uiInstanceID << "." << std::endl;
std::cerr << "ERROR: " << CONNECT_SDV_SERVER_ERROR_MSG << " Instance #" << rsContext.uiInstanceID << "."
<< std::endl;
return CONNECT_SDV_SERVER_ERROR;
}
}
int iRet = -100;
switch (eListCommand)
@@ -147,12 +160,16 @@ int ListElements(const SContext& rsContext, std::ostream& rstream /*= std::cout*
case EListCommand::installations:
iRet = ListInstallations(rsContext, ptrRepository, rstream);
break;
case EListCommand::listeners:
iRet = ListListeners(rsContext, rstream);
break;
case EListCommand::connections:
iRet = ListConnections(rsContext, ptrRepository, rstream);
iRet = ListConnections(rsContext, rstream);
break;
default:
break;
}
rstream << std::endl;
return iRet;
}
@@ -388,8 +405,107 @@ int ListInstallations(const SContext& rsContext, const sdv::TObjectPtr& rptrRepo
return NO_ERROR;
}
int ListConnections(const SContext& /*rsContext*/, const sdv::TObjectPtr& /*rptrRepository*/, std::ostream& /*rstream = std::cout */ )
std::string BuildParameters(const sdv::toml::CNodeCollection& rtable, const std::string& ssPrefix = std::string())
{
std::cout << "ERROR: " << NOT_IMPLEMENTED_MSG << " :-(" << std::endl;
return NOT_IMPLEMENTED;
std::string ssParams;
for (uint32_t uiIndex = 0; uiIndex < rtable.GetCount(); uiIndex++)
{
sdv::toml::CNode node = rtable.Get(uiIndex);
if (!node) continue;
std::string ssNodeText;
if (node.GetType() == sdv::toml::ENodeType::node_table)
{
sdv::toml::CNodeCollection tableChild(node);
if (!tableChild) continue;
ssNodeText = BuildParameters(tableChild, static_cast<std::string>(tableChild.GetName()) + ".");
}
else if (node.GetType() == sdv::toml::ENodeType::node_array)
{
// TODO...
}
else
ssNodeText = ssPrefix + node.GetName() + "=" + node.GetValueAsString();
// Add the text
if (!ssParams.empty())
ssParams += ", ";
ssParams += ssNodeText;
}
return ssParams;
}
int ListListeners(const SContext& rsContext, std::ostream& rstream /*= std::cout */ )
{
std::vector<std::array<std::string, 3>> vecListenerList;
vecListenerList.push_back({"Listener", "Provider", "Parameters"});
// Request the settings.
auto ptrAppService = sdv::core::GetObject("AppSettingsService");
sdv::app::IAppSettingsPersist* pAppSettingsPersist = ptrAppService.GetInterface<sdv::app::IAppSettingsPersist>();
sdv::app::IAppConnections* pAppConnections = ptrAppService.GetInterface<sdv::app::IAppConnections>();
if (!pAppSettingsPersist || !pAppConnections)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CANNOT_LOAD_SETTINGS_MSG << std::endl;
return CANNOT_LOAD_SETTINGS;
}
auto seqListeners = pAppConnections->GetListeners();
for (const sdv::u8string& rssListener : seqListeners)
{
std::string ssListener = rssListener;
auto ssConfig = pAppConnections->GetListenerConfig(rssListener);
sdv::toml::CTOMLParser parser(ssConfig);
if (!parser)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << PROCESS_LISTENER_CONFIG_ERROR_MSG << std::endl;
return PROCESS_LISTENER_CONFIG_ERROR;
}
std::string ssProvider = parser.GetDirect("Provider.Name").GetValueAsString();
std::string ssParams = BuildParameters(parser.GetDirect("IpcChannel"));
vecListenerList.push_back({ssListener, ssProvider, ssParams});
}
PrintTable(vecListenerList, rstream, rsContext.bListNoHdr);
if (vecListenerList.size() < 2)
rstream << " No listeners configured!" << std::endl;
return NO_ERROR;
}
int ListConnections(const SContext& rsContext, std::ostream& rstream /*= std::cout */ )
{
std::vector<std::array<std::string, 3>> vecConnectionList;
vecConnectionList.push_back({"Connection", "Provider", "Parameters"});
// Request the settings.
auto ptrAppService = sdv::core::GetObject("AppSettingsService");
sdv::app::IAppSettingsPersist* pAppSettingsPersist = ptrAppService.GetInterface<sdv::app::IAppSettingsPersist>();
sdv::app::IAppConnections* pAppConnections = ptrAppService.GetInterface<sdv::app::IAppConnections>();
if (!pAppSettingsPersist || !pAppConnections || !pAppSettingsPersist->LoadSettings())
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CANNOT_LOAD_SETTINGS_MSG << std::endl;
return CANNOT_LOAD_SETTINGS;
}
auto seqConnections = pAppConnections->GetConnections();
for (const sdv::u8string& rssConnection : seqConnections)
{
std::string ssConnection = rssConnection;
auto ssConfig = pAppConnections->GetConnectionConfig(rssConnection);
sdv::toml::CTOMLParser parser(ssConfig);
if (!parser)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << PROCESS_CONNECTION_CONFIG_ERROR_MSG << std::endl;
return PROCESS_CONNECTION_CONFIG_ERROR;
}
std::string ssProvider = parser.GetDirect("Provider.Name").GetValueAsString();
std::string ssParams = BuildParameters(parser.GetDirect("IpcChannel"));
vecConnectionList.push_back({ssConnection, ssProvider, ssParams});
}
PrintTable(vecConnectionList, rstream, rsContext.bListNoHdr);
if (vecConnectionList.size() < 2)
rstream << " No connections configured!" << std::endl;
return NO_ERROR;
}

View File

@@ -71,12 +71,19 @@ int ListComponents(const SContext& rsContext, const sdv::TObjectPtr& rptrReposit
int ListInstallations(const SContext& rsContext, const sdv::TObjectPtr& rptrRepository, std::ostream& rstream);
/**
* @brief List the current connections.
* @brief List the current configured listeners.
* @param[in] rsContext Reference to the context.
* @param[in] rptrRepository Reference to the saerver repository.
* @param[in] rstream The output stream to use for printing (table only).
* @return The application exit code. 0 is no error.
*/
int ListConnections(const SContext& rsContext, const sdv::TObjectPtr& rptrRepository, std::ostream& rstream);
int ListListeners(const SContext& rsContext, std::ostream& rstream);
/**
* @brief List the current connections.
* @param[in] rsContext Reference to the context.
* @param[in] rstream The output stream to use for printing (table only).
* @return The application exit code. 0 is no error.
*/
int ListConnections(const SContext& rsContext, std::ostream& rstream);
#endif // !defined LIST_ELEMENTS_H

View File

@@ -27,6 +27,7 @@
#include "list_elements.h"
#include "start_stop_service.h"
#include "installation.h"
#include "connection_config.h"
#include "../error_msg.h"
/**
@@ -53,12 +54,6 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
// NOTE EVE 27.05.2025: This task has been taken over by the process watchdog.
CProcessWatchdog watchdog;
// If not set, set the runtime location to the EXE directory.
if (sdv::app::CAppControl::GetFrameworkRuntimeDirectory().empty())
sdv::app::CAppControl::SetFrameworkRuntimeDirectory(GetExecDirectory());
if (sdv::app::CAppControl::GetComponentInstallDirectory().empty())
sdv::app::CAppControl::SetComponentInstallDirectory(GetExecDirectory());
CCommandLine cmdln(static_cast<uint32_t>(CCommandLine::EParseFlags::no_assignment_character));
SContext sContext;
bool bError = false;
@@ -67,24 +62,40 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
std::string ssArgError;
try
{
auto& rArgHelpDef = cmdln.DefineOption("?", bHelp, "Show help. Use <COMMAND> --help for specific help on the command.");
// Argument groups 1 - 10:
// STARTUP
// SHUTDOWN
// LIST
// INSTALL
// UPDATE
// UNINSTALL
// START
// STOP
// LISTENER
// CONNECTION
auto& rArgHelpDef =
cmdln.DefineOption("?", bHelp, "Show help. Use <COMMAND> --help for specific help on the command.");
rArgHelpDef.AddSubOptionName("help");
auto& rArgSilentDef = cmdln.DefineOption("s", sContext.bSilent, "Do not show any information on std::cout. Not compatible with 'verbose'.");
auto& rArgSilentDef = cmdln.DefineOption("s", sContext.bSilent, "Do not show any information on std::cout. Not compatible "
"with 'verbose'.");
rArgSilentDef.AddSubOptionName("silent");
auto& rArgVerboseDef = cmdln.DefineOption("v", sContext.bVerbose, "Provide verbose information. Not compatible with 'silent'.");
auto& rArgVerboseDef = cmdln.DefineOption("v", sContext.bVerbose, "Provide verbose information. Not compatible with "
"'silent'.");
rArgVerboseDef.AddSubOptionName("verbose");
cmdln.DefineSubOption("version", bVersion, "Show version information.");
cmdln.DefineSubOption("instance", sContext.uiInstanceID, "The instance ID of the SDV instance (default ID is 1000).");
cmdln.DefineSubOption("server_silent", sContext.bServerSilent, "Only used with STARTUP command: Server is started using "
"silent option. Not compatible with 'server_verbose'.");
"silent option. Not compatible with 'server_verbose'.", true, 1);
cmdln.DefineSubOption("server_verbose", sContext.bServerVerbose, "Only used with STARTUP command: Server is started using "
"verbose option. Not compatible with 'server_silent'.");
"verbose option. Not compatible with 'server_silent'.", true, 1);
cmdln.DefineSubOption("install_dir", sContext.pathInstallDir, "Only used with STARTUP command: Installation directory "
"(absolute or relative to the sdv_core executable).");
"(absolute or relative to the sdv_core executable).", true, 1);
cmdln.DefineSubOption("no_header", sContext.bListNoHdr, "Only used with LIST command: Do not print a header for the "
"listing table.");
"listing table.", true, 3);
cmdln.DefineSubOption("short", sContext.bListShort, "Only used with LIST command: Print only the most essential "
"information as one column.");
"information as one column.", true, 3);
cmdln.DefineSubOption(
"insert_before", sContext.ssInsertBeforeConnection, "Name of the connection to insert before.", true, 10);
cmdln.DefineDefaultArgument(sContext.seqCmdLine, "COMMAND");
cmdln.Parse(static_cast<size_t>(iArgc), rgszArgv);
@@ -98,7 +109,7 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
if (!sContext.bSilent)
{
std::cout << "SDV Server Control Utility" << std::endl;
std::cout << "Copyright (C): 2022-2025 ZF Friedrichshafen AG" << std::endl;
std::cout << "Copyright (C): 2022-2026 ZF Friedrichshafen AG" << std::endl;
std::cout << "Author: Erik Verhoeven" << std::endl << std::endl;
}
@@ -113,7 +124,7 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
bError = true;
}
enum class ECommand { unknown, startup, shutdown, list, install, update, uninstall, start, stop } eCommand = ECommand::unknown;
enum class ECommand { unknown, startup, shutdown, list, install, update, uninstall, start, stop, listener, connection } eCommand = ECommand::unknown;
if (!sContext.seqCmdLine.empty())
{
if (iequals(sContext.seqCmdLine[0], "STARTUP")) eCommand = ECommand::startup;
@@ -124,6 +135,8 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
else if (iequals(sContext.seqCmdLine[0], "UNINSTALL")) eCommand = ECommand::uninstall;
else if (iequals(sContext.seqCmdLine[0], "START")) eCommand = ECommand::start;
else if (iequals(sContext.seqCmdLine[0], "STOP")) eCommand = ECommand::stop;
else if (iequals(sContext.seqCmdLine[0], "LISTENER")) eCommand = ECommand::listener;
else if (iequals(sContext.seqCmdLine[0], "CONNECTION")) eCommand = ECommand::connection;
else
{
if (!sContext.bSilent)
@@ -157,17 +170,25 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
case ECommand::uninstall:
InstallationHelp(sContext);
break;
case ECommand::listener:
ListenerHelp(sContext);
break;
case ECommand::connection:
ConnectionHelp(sContext);
break;
default:
cmdln.PrintHelp(std::cout, R"code(Supported commands:
cmdln.PrintHelp(std::cout, R"text(Supported commands:
STARTUP Start the core application server
SHUTDOWN Stop the core application server
LIST List module/classes/component/installation/connection information.
LIST List information about modules/classes/components/installations/listeners/connections.
INSTALL Install a new application or service.
UPDATE Update an existing installation.
UNINSTALL Uninstall an installed application or service.
START Start a service (complex services only).
STOP Stop a service (complex services only).
)code");
START Start a service (complex services and vehicle functions only).
STOP Stop a service (complex services and vehicle functions only).
LISTENER Add or remove a communication listener configuration.
CONNECTION Add or remove a connection configuration.
)text");
break;
}
}
@@ -185,11 +206,11 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
if (sContext.bVerbose)
std::cout << "Starting local application control.." << std::endl;
sdv::app::CAppControl appcontrol;
std::string ssAppConfig = std::string(R"code(
std::string ssAppConfig = std::string(R"toml(
[Application]
Mode = "Maintenance"
Instance = )code") + std::to_string(sContext.uiInstanceID) + R"code(
)code";
Instance = )toml") + std::to_string(sContext.uiInstanceID) + R"toml(
)toml";
if (!appcontrol.Startup(ssAppConfig))
{
if (!sContext.bSilent)
@@ -224,6 +245,12 @@ Instance = )code") + std::to_string(sContext.uiInstanceID) + R"code(
case ECommand::uninstall:
iRet = Uninstall(sContext);
break;
case ECommand::listener:
iRet = ConfigureListener(sContext);
break;
case ECommand::connection:
iRet = ConfigureConnection(sContext);
break;
default:
std::cout << "Command missing :-(" << std::endl;
break;

View File

@@ -35,8 +35,8 @@ void StartStopServiceHelp(const SContext& rsContext)
" sdv_control START <class> <name> [options...]\n\n"
"Start a complex service with the supplied object name as is defined in the configuration (first usage) or the "
"supplied class name and with object name assignment and add to the configuration (second usage).\n"
"Only complex services can be started. If the service depends on not running other services, these are started as "
"well.\n\n");
"Only vehicle functions and complex services can be started. If the service depends on not running other services, "
"these are started as well.\n\n");
return;
}
if (iequals(rsContext.seqCmdLine[0], "STOP"))
@@ -47,15 +47,14 @@ void StartStopServiceHelp(const SContext& rsContext)
" sdv_control STOP <module> [options...]\n\n"
"Stop the complex service(s) with the supplied object name (first usage), with supplied object ID (second usage), with "
"supplied class name (third usage) or contained in the module with the supplied module name (fourth usage).\n"
"Only complex services can be stopped. Dependent services are stopped as well. If one of object to be stopped is not a "
"complex service, the command fails.\n\n");
"Only vehicle functions and complex services can be stopped. Dependent services are stopped as well. If one of object "
"to be stopped is not a vehicle function or a complex service, the command fails.\n\n");
return;
}
if (!rsContext.bSilent)
std::cerr << "ERROR: invalid start/stop command..." << std::endl;
}
int StartService(const SContext& rsContext)
{
// First argument should be "START"
@@ -88,7 +87,7 @@ int StartService(const SContext& rsContext)
ssName = rsContext.seqCmdLine[1];
// Try to connect
sdv::TObjectPtr ptrRepository = sdv::com::ConnectToLocalServerRepository(rsContext.uiInstanceID);
sdv::TObjectPtr ptrRepository = sdv::com::ConnectToLocalServerRepository();
if (!ptrRepository)
{
if (!rsContext.bSilent)
@@ -154,7 +153,7 @@ int StopService(const SContext& rsContext)
ssName = rsContext.seqCmdLine[1];
// Try to connect
sdv::TObjectPtr ptrRepository = sdv::com::ConnectToLocalServerRepository(rsContext.uiInstanceID);
sdv::TObjectPtr ptrRepository = sdv::com::ConnectToLocalServerRepository();
if (!ptrRepository)
{
if (!rsContext.bSilent)

View File

@@ -78,7 +78,7 @@ void StartupShutdownHelp(const SContext& rsContext)
"Options:\n"
" --server_silent Server is started using silent option. Not compatible with 'server_verbose'.\n"
" --server_verbose Server is started using verbose option. Not compatible with 'server_silent'.\n"
" --install_dir Installation directory (absolute or relative to the sdv_core executable).\n\n");
" --install_dir<path> Installation directory (absolute or relative to the sdv_core executable).\n\n");
return;
}
if (iequals(rsContext.seqCmdLine[0], "SHUTDOWN"))
@@ -156,7 +156,7 @@ int StartupSDVServer(const SContext& rsContext)
}
// Try to connect
auto ptrRepository = sdv::com::ConnectToLocalServerRepository(rsContext.uiInstanceID);
auto ptrRepository = sdv::com::ConnectToLocalServerRepository();
if (!ptrRepository)
{
if (!rsContext.bSilent)
@@ -183,7 +183,7 @@ int ShutdownSDVServer(const SContext& rsContext)
std::cout << "Connecting to the SDV #" << rsContext.uiInstanceID << " server..." << std::endl;
// Try to connect
auto ptrRepository = sdv::com::ConnectToLocalServerRepository(rsContext.uiInstanceID);
auto ptrRepository = sdv::com::ConnectToLocalServerRepository();
if (!ptrRepository)
{
if (!rsContext.bSilent)

View File

@@ -18,6 +18,40 @@
#include <support/app_control.h>
#include "../error_msg.h"
#ifdef _WIN32
/**
* @brief Console application control handler (CTRL+C, close, shutdown, etc.).
* @param[in] dwCtrlType The control type triggered by the system.
* @return Returns TRUE when the signal was handled.
*/
static BOOL WINAPI ControlHandler(DWORD dwCtrlType)
{
switch (dwCtrlType)
{
case CTRL_C_EVENT:
case CTRL_BREAK_EVENT:
case CTRL_CLOSE_EVENT:
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
return TRUE;
break;
default:
return FALSE;
}
}
#elif defined __unix__
#include <signal.h>
/**
* @brief Signal handler to catch signal events.
* @param[in] iSigNum The signal type that was triggered.
*/
static void SignalHandler(int /*iSigNum*/)
{
// Do nothing...
}
#endif
/**
* @brief Main function of the executable.
* @param[in] iArgc Amount of arguments provided.
@@ -46,12 +80,6 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
if (thread.joinable())
thread.join();
// If not set, set the runtime location to the EXE directory.
if (sdv::app::CAppControl::GetFrameworkRuntimeDirectory().empty())
sdv::app::CAppControl::SetFrameworkRuntimeDirectory(GetExecDirectory());
if (sdv::app::CAppControl::GetComponentInstallDirectory().empty())
sdv::app::CAppControl::SetComponentInstallDirectory(GetExecDirectory());
CCommandLine cmdln(static_cast<uint32_t>(CCommandLine::EParseFlags::no_assignment_character));
bool bHelp = false;
bool bError = false;
@@ -91,7 +119,7 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
if (!bSilent && !bNoBanner)
{
std::cout << "SDV core application" << std::endl;
std::cout << "Copyright (C): 2022-2025 ZF Friedrichshafen AG" << std::endl;
std::cout << "Copyright (C): 2022-2026 ZF Friedrichshafen AG" << std::endl;
std::cout << "Author: Erik Verhoeven" << std::endl << std::endl;
}
@@ -185,14 +213,40 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
return APP_CONTROL_STARTUP_ERROR;
}
#ifdef _WIN32
// Register the console control handler
if (!SetConsoleCtrlHandler(&ControlHandler, TRUE))
{
if (!bSilent)
std::cerr << "ERROR: " << APP_CONTROL_START_LOOP_FAILED_MSG << " - failed registering control handler." << std::endl;
return APP_CONTROL_START_LOOP_FAILED;
}
#elif defined __unix__
// Install our signal handler
struct sigaction sSigAction
{};
sSigAction.sa_handler = SignalHandler;
sSigAction.sa_flags = SA_RESTART;
if (sigaction(SIGINT, &sSigAction, NULL) == -1)
{
if (!bSilent)
std::cerr << "ERROR: " << APP_CONTROL_START_LOOP_FAILED_MSG << " - failed registering control handler." << std::endl;
return APP_CONTROL_START_LOOP_FAILED;
}
#endif
// Start the running loop
if (!appcontrol.RunLoop())
{
if (!bSilent)
std::cerr << "ERROR: " << APP_CONTROL_DUPLICATE_INSTANCE_MSG << std::endl;
return APP_CONTROL_DUPLICATE_INSTANCE;
std::cerr << "ERROR: " << APP_CONTROL_START_LOOP_FAILED_MSG << std::endl;
return APP_CONTROL_START_LOOP_FAILED;
}
#ifdef _WIN32
SetConsoleCtrlHandler(&ControlHandler, FALSE);
#endif
if (bVerbose)
{
std::cout << "Shutdown request received..." << std::endl;

View File

@@ -372,7 +372,10 @@ 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 << R"toml(# Location of the SDV binaries and configuration files
[CoreLocation]
Version = 100
Framework = ")toml";
tomlFile << resources;
tomlFile << "\"\n";
tomlFile.close();

View File

@@ -82,7 +82,7 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
if (!bSilent)
{
std::cout << "DBC utility" << std::endl;
std::cout << "Copyright (C): 2022-2025 ZF Friedrichshafen AG" << std::endl;
std::cout << "Copyright (C): 2022-2026 ZF Friedrichshafen AG" << std::endl;
std::cout << "Author: Erik Verhoeven" << std::endl;
}
if (bHelp)

View File

@@ -174,6 +174,9 @@ std::string CProxyGenerator::GetFuncImpl(const SFuncInfo& rsFunc, CKeywordMap& r
else
sstreamExceptions << R"code(sdv::XUnknownException exception;
exception.unknown_id = except_id;
// Cpp-Check 2.7 warns about the uninitialized variable _id. This variable is allocated as inline static const and is
// assigned a value. Suppress the warning.
// cppcheck-suppress uninitvar
throw exception;)code";
for (const std::string& rssException : rvecExceptions)
{
@@ -181,6 +184,9 @@ std::string CProxyGenerator::GetFuncImpl(const SFuncInfo& rsFunc, CKeywordMap& r
{
)code" << rssException << R"code( exception;
desOutput >> exception;
// Cpp-Check 2.7 warns about the uninitialized variable _id. This variable is allocated as inline static const and is
// assigned a value. Suppress the warning.
// cppcheck-suppress uninitvar
throw exception;
}
)code";
@@ -190,6 +196,9 @@ std::string CProxyGenerator::GetFuncImpl(const SFuncInfo& rsFunc, CKeywordMap& r
{
sdv::XUnknownException exception;
exception.unknown_id = except_id;
// Cpp-Check 2.7 warns about the uninitialized variable _id. This variable is allocated as inline static const and is
// assigned a value. Suppress the warning.
// cppcheck-suppress uninitvar
throw exception;
}
})code";

View File

@@ -41,7 +41,7 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
CProcessWatchdog watchdog;
std::cout << "SDV IDL Compiler" << std::endl;
std::cout << "Copyright (C): 2022-2025 ZF Friedrichshafen AG" << std::endl;
std::cout << "Copyright (C): 2022-2026 ZF Friedrichshafen AG" << std::endl;
std::cout << "Author: Erik Verhoeven" << std::endl;
// Create a list of UTF-8 arguments

View File

@@ -28,6 +28,7 @@
#include "token.h"
#include <fstream>
#include <filesystem>
#include <clocale>
#include <locale>
#include <codecvt>
#include <cuchar>
@@ -71,7 +72,7 @@ const std::string& CSource::GetCodeRef() const
void CSource::ReadFile(const std::filesystem::path& rpath)
{
// Set the locale to work with UTF8
std::setlocale(LC_ALL, "en_US.utf8");
::setlocale(LC_ALL, "en_US.utf8");
if (rpath.empty())
throw CCompileException("File name missing");

View File

@@ -22,6 +22,40 @@
#include <support/local_service_access.h>
#include "../error_msg.h"
#ifdef _WIN32
/**
* @brief Console application control handler (CTRL+C, close, shutdown, etc.).
* @param[in] dwCtrlType The control type triggered by the system.
* @return Returns TRUE when the signal was handled.
*/
static BOOL WINAPI ControlHandler(DWORD dwCtrlType)
{
switch (dwCtrlType)
{
case CTRL_C_EVENT:
case CTRL_BREAK_EVENT:
case CTRL_CLOSE_EVENT:
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
return TRUE;
break;
default:
return FALSE;
}
}
#elif defined __unix__
#include <signal.h>
/**
* @brief Signal handler to catch signal events.
* @param[in] iSigNum The signal type that was triggered.
*/
static void SignalHandler(int /*iSigNum*/)
{
// Do nothing...
}
#endif
/**
* @brief Connect event callback wrapper. Calls shutdown request on disconnect or error.
*/
@@ -93,12 +127,6 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
if (thread.joinable())
thread.join();
// If not set, set the runtime location to the EXE directory.
if (sdv::app::CAppControl::GetFrameworkRuntimeDirectory().empty())
sdv::app::CAppControl::SetFrameworkRuntimeDirectory(GetExecDirectory());
if (sdv::app::CAppControl::GetComponentInstallDirectory().empty())
sdv::app::CAppControl::SetComponentInstallDirectory(GetExecDirectory());
CCommandLine cmdln(static_cast<uint32_t>(CCommandLine::EParseFlags::no_assignment_character));
bool bHelp = false;
bool bError = false;
@@ -126,23 +154,29 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
{
ssArgError = rsExcept.what();
bHelp = true;
bError = true;
}
if (!bSilent)
{
std::cout << "SDV isolation application" << std::endl;
std::cout << "Copyright (C): 2022-2025 ZF Friedrichshafen AG" << std::endl;
std::cout << "Copyright (C): 2022-2026 ZF Friedrichshafen AG" << std::endl;
std::cout << "Author: Erik Verhoeven" << std::endl << std::endl;
}
if (!ssArgError.empty() && !bSilent)
if (!ssArgError.empty() && !bSilent && !bHelp && !bVersion)
std::cerr << "ERROR: " << ssArgError << std::endl;
if (ssConfigBase64.empty())
if (bVersion || bVerbose)
{
ssArgError = "Missing app configuration.";
bHelp = true;
std::cout << "Version: " << (SDVFrameworkBuildVersion / 100) << "." << (SDVFrameworkBuildVersion % 100) << " build "
<< SDVFrameworkSubbuildVersion << " interface " << SDVFrameworkInterfaceVersion << std::endl;
}
if (!bHelp && ssConfigBase64.empty())
{
if (!bSilent && !bVersion)
std::cout << "Missing app configuration.";
bError = true;
}
if (bHelp)
@@ -153,17 +187,14 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
std::cout << std::endl;
cmdln.PrintHelp(std::cout, "The isolation application is used to isolate components from the core process. The "
"isolation aims to improve the overall stability of the system.\n");
return bError ? CMDLN_ARG_ERR : NO_ERROR;
}
return (bError && !bVersion && !bHelp) ? CMDLN_ARG_ERR : NO_ERROR;
}
if (bError) return CMDLN_ARG_ERR;
if (bError) return (bError && !bVersion && !bHelp) ? CMDLN_ARG_ERR : NO_ERROR;
// Check for encoded configuration
std::string ssIsoAppConfig = Base64DecodePlainText(ssConfigBase64);
if (bVersion || bVerbose)
std::cout << "Version: " << (SDVFrameworkBuildVersion / 100) << "." << (SDVFrameworkBuildVersion % 100) << " build " <<
SDVFrameworkSubbuildVersion << " interface " << SDVFrameworkInterfaceVersion << std::endl;
if (!bSilent)
std::cout << "Instance ID: " << uiInstanceID << std::endl;
@@ -267,7 +298,7 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
std::cerr << "ERROR: " << LINK_REPO_SERVICE_ERROR_MSG << std::endl;
return LINK_REPO_SERVICE_ERROR;
}
pLinkCoreRepo->LinkCoreRepository(pCoreRepo);
sdv::core::TLinkID tRepoLink = pLinkCoreRepo->LinkCoreRepository(pCoreRepo);
// Create the one object... is this a service or a utility?
std::string ssClassName = parser.GetDirect("Isolation.Class").GetValue();
@@ -332,6 +363,28 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
// The lifetime of the object is now taken over by the core or if failed, the object will be destroyed.
ptrObject.Clear();
#ifdef _WIN32
// Register the console control handler
if (!SetConsoleCtrlHandler(&ControlHandler, TRUE))
{
if (!bSilent)
std::cerr << "ERROR: " << APP_CONTROL_START_LOOP_FAILED_MSG << " - failed registering control handler." << std::endl;
return APP_CONTROL_START_LOOP_FAILED;
}
#elif defined __unix__
// Install our signal handler
struct sigaction sSigAction
{};
sSigAction.sa_handler = SignalHandler;
sSigAction.sa_flags = SA_RESTART;
if (sigaction(SIGINT, &sSigAction, NULL) == -1)
{
if (!bSilent)
std::cerr << "ERROR: " << APP_CONTROL_START_LOOP_FAILED_MSG << " - failed registering control handler." << std::endl;
return APP_CONTROL_START_LOOP_FAILED;
}
#endif
// Deactivate the configuration mode.
appcontrol.SetRunningMode();
@@ -339,10 +392,14 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
if (!appcontrol.RunLoop())
{
if (!bSilent)
std::cerr << "ERROR: " << APP_CONTROL_START_LOOP_FAIELD_MSG << std::endl;
return APP_CONTROL_START_LOOP_FAIELD;
std::cerr << "ERROR: " << APP_CONTROL_START_LOOP_FAILED_MSG << std::endl;
return APP_CONTROL_START_LOOP_FAILED;
}
#ifdef _WIN32
SetConsoleCtrlHandler(&ControlHandler, FALSE);
#endif
// TODO EVE
if (appcontrol.IsConfiguring())
std::cout << "Iso app configuring... " << __LINE__ << std::endl;
@@ -358,7 +415,7 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
// Shutdwown
pConnect->UnregisterStateEventCallback(uiCookie);
parser.Clear();
pLinkCoreRepo->UnlinkCoreRepository();
pLinkCoreRepo->UnlinkCoreRepository(tRepoLink);
appcontrol.Shutdown();
if (!bSilent)

View File

@@ -32,12 +32,6 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
// NOTE EVE 27.05.2025: This task has been taken over by the process watchdog.
CProcessWatchdog watchdog;
// If not set, set the runtime location to the EXE directory.
if (sdv::app::CAppControl::GetFrameworkRuntimeDirectory().empty())
sdv::app::CAppControl::SetFrameworkRuntimeDirectory(GetExecDirectory());
if (sdv::app::CAppControl::GetComponentInstallDirectory().empty())
sdv::app::CAppControl::SetComponentInstallDirectory(GetExecDirectory());
CCommandLine cmdln(static_cast<uint32_t>(CCommandLine::EParseFlags::no_assignment_character));
bool bHelp = false;
bool bError = false;
@@ -67,7 +61,7 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
if (!bSilent)
{
std::cout << "SDV Local Instance Shutdown Utility" << std::endl;
std::cout << "Copyright (C): 2022-2025 ZF Friedrichshafen AG" << std::endl;
std::cout << "Copyright (C): 2022-2026 ZF Friedrichshafen AG" << std::endl;
std::cout << "Author: Erik Verhoeven" << std::endl << std::endl;
}

View File

@@ -24,4 +24,5 @@
#include "../../sdv_services/core/toml_parser/character_reader_utf_8.cpp"
#include "../../sdv_services/core/toml_parser/miscellaneous.cpp"
#include "../../sdv_services/core/toml_parser/code_snippet.cpp"
#include "../../sdv_services/core/toml_parser/parser_node_indexer.cpp"

View File

@@ -12,9 +12,8 @@
********************************************************************************/
#include "environment.h"
#include <string_view>
#include "../../global/exec_dir_helper.h"
#include "../../global/cmdlnparser/cmdlnparser.cpp"
CSdvPackagerEnvironment::CSdvPackagerEnvironment() :
@@ -862,13 +861,16 @@ bool CSdvPackagerEnvironment::ProcessCommandLine(const std::vector<std::string>&
{
#ifdef _WIN32
const wchar_t* szInstallDir = _wgetenv(L"SDV_COMPONENT_INSTALL");
if (!szInstallDir) szInstallDir = _wgetenv(L"SDV_FRAMEWORK_RUNTIME");
if (szInstallDir) m_pathTargetLocation = szInstallDir;
#elif defined __unix__
const char* szInstallDir = getenv("SDV_COMPONENT_INSTALL");
if (!szInstallDir) szInstallDir = getenv("SDV_FRAMEWORK_RUNTIME");
if (szInstallDir) m_pathTargetLocation = std::filesystem::u8path(szInstallDir);
#else
#error OS not supported!
#endif
if (m_pathTargetLocation.empty()) m_pathTargetLocation = GetExecDirectory();
}
// Is the directory existing? If not, create the directory

View File

@@ -41,12 +41,6 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
// NOTE EVE 27.05.2025: This task has been taken over by the process watchdog.
CProcessWatchdog watchdog;
// If not set, set the runtime location to the EXE directory.
if (sdv::app::CAppControl::GetFrameworkRuntimeDirectory().empty())
sdv::app::CAppControl::SetFrameworkRuntimeDirectory(GetExecDirectory());
if (sdv::app::CAppControl::GetComponentInstallDirectory().empty())
sdv::app::CAppControl::SetComponentInstallDirectory(GetExecDirectory());
// Process the command line.
CSdvPackagerEnvironment environment(iArgc, rgszArgv);
@@ -54,7 +48,7 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
if (!environment.Silent())
{
std::cout << "SDV Component Installation Package Utility" << std::endl;
std::cout << "Copyright (C): 2022-2025 ZF Friedrichshafen AG" << std::endl;
std::cout << "Copyright (C): 2022-2026 ZF Friedrichshafen AG" << std::endl;
std::cout << "Author: Erik Verhoeven" << std::endl << std::endl;
}
@@ -114,7 +108,7 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
}
// If running as server, load the settings file
if (!environment.Local() && !GetAppSettings().LoadSettingsFile())
if (!environment.Local() && !GetAppSettings().LoadSettings())
{
std::cerr << "ERROR: Failed to load the application settings file; cannot continue!" << std::endl;
return -1;

View File

@@ -450,7 +450,7 @@ bool CPackager::Configure()
m_ssArgError = CMDLN_MISSING_TARGET_MSG;
return false;
}
if (!GetAppSettings().SaveSettingsFile())
if (!GetAppSettings().SaveSettings())
{
SDV_LOG_ERROR("Failed to save application settings. Cannot configure components!");
return false;
@@ -743,7 +743,7 @@ bool CPackager::ConfigureFromManifest(const CInstallManifest& rmanifest)
auto pathConfig = GetAppSettings().GetConfigPath(CAppSettings::EConfigType::user_config);
WriteConfig(vecClasses, pathConfig, vecComponentsToAdd, true, vecAddedToConfig);
}
if (!GetAppSettings().SaveSettingsFile())
if (!GetAppSettings().SaveSettings())
{
SDV_LOG_ERROR("Failed to save application settings. Cannot configure components!");
return false;
@@ -806,11 +806,11 @@ void CPackager::WriteConfig(const std::vector<sdv::SClassInfo>& rvecAllClasses,
break;
case sdv::EObjectType::complex_service:
case sdv::EObjectType::vehicle_function:
case sdv::EObjectType::utility:
eIncompatible = bUserConfig ? ECompatibility::compatible : ECompatibility::incompatible;
break;
case sdv::EObjectType::proxy:
case sdv::EObjectType::stub:
case sdv::EObjectType::utility:
eIncompatible = ECompatibility::silent_incompatible;
break;
default:

View File

@@ -65,7 +65,7 @@ static BOOL WINAPI ControlHandler(DWORD dwCtrlType)
}
#elif defined __unix__
/**
* @brief Signal handler to catch signal eevents.
* @brief Signal handler to catch signal events.
* @param[in] iSigNum The signal type that was triggered.
*/
static void SignalHandler(int iSigNum)
@@ -97,12 +97,6 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
if (thread.joinable())
thread.join();
// If not set, set the runtime location to the EXE directory.
if (sdv::app::CAppControl::GetFrameworkRuntimeDirectory().empty())
sdv::app::CAppControl::SetFrameworkRuntimeDirectory(GetExecDirectory());
if (sdv::app::CAppControl::GetComponentInstallDirectory().empty())
sdv::app::CAppControl::SetComponentInstallDirectory(GetExecDirectory());
CCommandLine cmdln(static_cast<uint32_t>(CCommandLine::EParseFlags::no_assignment_character));
bool bHelp = false;
bool bVersion = false;
@@ -123,7 +117,7 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
}
std::cout << "SDV Server Log Monitor Utility" << std::endl;
std::cout << "Copyright (C): 2022-2025 ZF Friedrichshafen AG" << std::endl;
std::cout << "Copyright (C): 2022-2026 ZF Friedrichshafen AG" << std::endl;
std::cout << "Author: Erik Verhoeven" << std::endl << std::endl;
if (bVersion)

View File

@@ -109,7 +109,7 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
if (!bSilent)
{
std::cout << "abtract device / basic services utility" << std::endl;
std::cout << "Copyright (C): 2022-2025 ZF Friedrichshafen AG" << std::endl;
std::cout << "Copyright (C): 2022-2026 ZF Friedrichshafen AG" << std::endl;
std::cout << "Author: Thomas Pfleiderer" << std::endl;
}

View File

@@ -170,6 +170,14 @@ add_custom_command(
COMMAND sdv_idl_compiler ${INTERFACE_DIR}/repository.idl -O${INTERFACE_DIR}
VERBATIM
)
add_custom_command(
OUTPUT ${INTERFACE_DIR}/permission.h
DEPENDS sdv_idl_compiler
MAIN_DEPENDENCY ${INTERFACE_DIR}/permission.idl
COMMENT "Compiling permission.idl"
COMMAND sdv_idl_compiler ${INTERFACE_DIR}/permission.idl -O${INTERFACE_DIR} --no_ps
VERBATIM
)
add_custom_command(
OUTPUT ${INTERFACE_DIR}/timer.h
DEPENDS sdv_idl_compiler
@@ -198,6 +206,7 @@ add_custom_target(CompileCoreIDL
${INTERFACE_DIR}/process.h
${INTERFACE_DIR}/param.h
${INTERFACE_DIR}/repository.h
${INTERFACE_DIR}/permission.h
${INTERFACE_DIR}/timer.h
)
@@ -212,10 +221,14 @@ add_subdirectory(task_timer)
add_subdirectory(ipc_com)
add_subdirectory(ipc_connect)
add_subdirectory(ipc_shared_mem)
add_subdirectory(uds_unix_sockets)
add_subdirectory(uds_unix_tunnel)
add_subdirectory(uds_win_sockets)
add_subdirectory(uds_win_tunnel)
if(UNIX)
add_subdirectory(uds_unix_sockets)
add_subdirectory(uds_unix_tunnel)
endif()
if(WIN32)
add_subdirectory(uds_win_sockets)
add_subdirectory(uds_win_tunnel)
endif()
add_subdirectory(process_control)
add_subdirectory(hardware_ident)
add_subdirectory(manifest_util)

View File

@@ -118,7 +118,7 @@ private:
*/
void PlaybackFunc(const asc::SCanMessage& rsMsg);
std::thread m_threadReceive; ///< Receive thread.
sdv::core::secure_thread m_threadReceive; ///< Receive thread.
mutable std::mutex m_mtxReceivers; ///< Protect the receiver set.
std::set<sdv::can::IReceive*> m_setReceivers; ///< Set with receiver interfaces.
mutable std::mutex m_mtxInterfaces; ///< Protect the nodes set.

View File

@@ -64,7 +64,7 @@ bool CCANSockets::OnInitialize()
}
LogConfigurations();
m_threadReceive = std::thread(&CCANSockets::ReceiveThreadFunc, this);
m_threadReceive = sdv::core::secure_thread(&CCANSockets::ReceiveThreadFunc, this);
return true;
}

View File

@@ -146,7 +146,7 @@ private:
std::string name; ///< interface name, can be empty in case of an invalid socket element
};
std::thread m_threadReceive; ///< Receive thread.
sdv::core::secure_thread m_threadReceive; ///< Receive thread.
mutable std::mutex m_mtxReceivers; ///< Protect the receiver set.
std::set<sdv::can::IReceive*> m_setReceivers; ///< Set with receiver interfaces.
mutable std::mutex m_mtxSockets; ///< Protect the socket list.

View File

@@ -49,13 +49,14 @@ add_library(core_services SHARED
"toml_parser_util.h"
"installation_manifest.h"
"installation_manifest.cpp"
"../../global/tracefifo/trace_fifo.cpp"
"local_shutdown_request.h"
"iso_monitor.h"
"iso_monitor.cpp"
"installation_composer.h"
"installation_composer.cpp"
"toml_parser/lexer_toml_token.h" "toml_parser/lexer_toml_token.cpp" "toml_parser/miscellaneous.h" "toml_parser/miscellaneous.cpp" "toml_parser/code_snippet.h" "toml_parser/code_snippet.cpp" "app_settings.h" "app_settings.cpp" "app_config_file.h" "app_config_file.cpp")
"toml_parser/lexer_toml_token.h" "toml_parser/lexer_toml_token.cpp" "toml_parser/miscellaneous.h" "toml_parser/miscellaneous.cpp" "toml_parser/code_snippet.h" "toml_parser/code_snippet.cpp" "app_settings.h" "app_settings.cpp" "app_config_file.h" "app_config_file.cpp" "toml_parser/parser_node_indexer.h" "toml_parser/parser_node_indexer.cpp" "permission_control.h" "permission_control.cpp")
# Compiler settiings
add_compile_definitions(SDV_NO_EXPORT_DEFINITION)

View File

@@ -33,61 +33,6 @@ CAppConfig& GetAppConfig()
return app_config;
}
// GetCoreDirectory might have been redirected for unit tests.
#ifndef GetCoreDirectory
std::filesystem::path GetCoreDirectory()
{
static std::filesystem::path pathCoreDir;
if (!pathCoreDir.empty())
return pathCoreDir;
#ifdef _WIN32
// Windows specific
std::wstring ssPath(32768, '\0');
MEMORY_BASIC_INFORMATION sMemInfo{};
if (!VirtualQuery(&pathCoreDir, &sMemInfo, sizeof(sMemInfo)))
return pathCoreDir;
DWORD dwLength = GetModuleFileNameW(reinterpret_cast<HINSTANCE>(sMemInfo.AllocationBase), ssPath.data(), 32767);
ssPath.resize(dwLength);
pathCoreDir = std::filesystem::path(ssPath);
return pathCoreDir.remove_filename();
#elif __linux__
// Read the maps file. It contains all loaded SOs.
std::ifstream fstream("/proc/self/maps");
std::stringstream sstreamMap;
sstreamMap << fstream.rdbuf();
std::string ssMap = sstreamMap.str();
if (ssMap.empty())
return pathCoreDir; // Some error
// Find the "core_services.sdv"
size_t nPos = ssMap.find("core_services.sdv");
if (nPos == std::string::npos)
return pathCoreDir;
size_t nEnd = nPos;
// Find the start... runbackwards until the beginning of the line and remember the earliest occurance of a slash
size_t nBegin = 0;
while (nPos && ssMap[nPos] != '\n')
{
if (ssMap[nPos] == '/')
nBegin = nPos;
nPos--;
}
if (!nBegin)
nBegin = nPos;
// Return the path
pathCoreDir = ssMap.substr(nBegin, nEnd - nBegin);
return pathCoreDir;
#else
#error The OS is not supported!
#endif
}
#endif // !defined GetCoreDirectory
bool CAppConfig::LoadInstallationManifests()
{
// Check for allowance
@@ -96,13 +41,14 @@ bool CAppConfig::LoadInstallationManifests()
{
case sdv::app::EAppContext::main:
case sdv::app::EAppContext::isolated:
case sdv::app::EAppContext::external:
case sdv::app::EAppContext::maintenance:
bServerApp = true;
default:
break;
}
std::filesystem::path pathCore = GetCoreDirectory();
std::filesystem::path pathCore = GetAppSettings().GetFrameworkDir();
std::filesystem::path pathExe = GetExecDirectory();
std::filesystem::path pathInstall = GetAppSettings().GetInstallDir();
@@ -155,8 +101,8 @@ void CAppConfig::UnloadInstallatonManifests()
bool CAppConfig::LoadAppConfigs()
{
// Isolated applications do not load configurations
if (GetAppSettings().IsIsolatedApplication()) return false;
// Isolated and external applications do not load configurations
if (GetAppSettings().IsIsolatedApplication() || GetAppSettings().IsExternalApplication()) return false;
// When running as server application, load the system configurations
if (GetAppSettings().IsMainApplication() || GetAppSettings().IsMaintenanceApplication())
@@ -243,6 +189,7 @@ sdv::core::EConfigProcessResult CAppConfig::ProcessConfig(/*in*/ const sdv::u8st
{
case sdv::app::EAppContext::main:
case sdv::app::EAppContext::isolated:
case sdv::app::EAppContext::external:
case sdv::app::EAppContext::maintenance:
return sdv::core::EConfigProcessResult::failed;
default:
@@ -275,7 +222,7 @@ sdv::core::EConfigProcessResult CAppConfig::ProcessConfig(/*in*/ const sdv::u8st
//size_t nLoadable = 0;
//size_t nNotLoadable = 0;
//if (!GetAppSettings().IsMainApplication() && !GetAppSettings().IsIsolatedApplication() &&
// !GetAppSettings().IsMaintenanceApplication())
// !GetAppSettings().IsExternalApplication() && !GetAppSettings().IsMaintenanceApplication())
//{
// // Load all modules in the component section
// auto ptrComponents = parser.Root().Direct("Component");
@@ -394,7 +341,7 @@ sdv::core::EConfigProcessResult CAppConfig::ProcessConfig(/*in*/ const sdv::u8st
// // loaded; get the module ID.
// sdv::core::TObjectID tObjectID = 0;
// if (!GetAppSettings().IsMainApplication() && !GetAppSettings().IsIsolatedApplication() &&
// !GetAppSettings().IsMaintenanceApplication())
// !GetAppSettings().IsExternalApplication() && !GetAppSettings().IsMaintenanceApplication())
// {
// auto itModule = mapModules.find(pathModule);
// if (itModule == mapModules.end()) continue; // Module was not loaded before...
@@ -880,6 +827,7 @@ std::filesystem::path CAppConfig::FindInstalledModule(const std::filesystem::pat
{
case sdv::app::EAppContext::main:
case sdv::app::EAppContext::isolated:
case sdv::app::EAppContext::external:
case sdv::app::EAppContext::maintenance:
bServerApp = true;
default:
@@ -914,6 +862,7 @@ std::string CAppConfig::FindInstalledModuleManifest(const std::filesystem::path&
{
case sdv::app::EAppContext::main:
case sdv::app::EAppContext::isolated:
case sdv::app::EAppContext::external:
case sdv::app::EAppContext::maintenance:
bServerApp = true;
default:
@@ -948,6 +897,7 @@ std::optional<sdv::SClassInfo> CAppConfig::FindInstalledComponent(const std::str
{
case sdv::app::EAppContext::main:
case sdv::app::EAppContext::isolated:
case sdv::app::EAppContext::external:
case sdv::app::EAppContext::maintenance:
bServerApp = true;
default:
@@ -980,6 +930,7 @@ bool CAppConfig::RemoveFromConfig(const CInstallManifest& /*rManifest*/)
//{
//case sdv::app::EAppContext::main:
//case sdv::app::EAppContext::isolated:
//case sdv::app::EAppContext::external:
//case sdv::app::EAppContext::maintenance:
// bServerApp = true;
//default:
@@ -1043,7 +994,7 @@ void CAppConfig::AddCurrentPath()
if (!m_lstSearchPaths.empty()) return;
// Add the core directory
std::filesystem::path pathCoreDir = GetCoreDirectory().lexically_normal();
std::filesystem::path pathCoreDir = GetAppSettings().GetFrameworkDir().lexically_normal();
m_lstSearchPaths.push_back(pathCoreDir / "config/");
// Add the exe dir

View File

@@ -39,12 +39,6 @@
// The installation might need companion files to be installed in various relative sub-directories.
// @endcond
/**
* @brief Get the location of the core_services.sdv.
* @return Path to the directory containing the loaded core directory.
*/
std::filesystem::path GetCoreDirectory();
/**
* @brief Application configuration service
* @details In the configuration system objects, devices, basic services, complex services and apps are defined and will be started

View File

@@ -346,9 +346,9 @@ Version = )toml" + std::to_string(SDVFrameworkInterfaceVersion) + R"toml(
// Modules leftover in the vector are added to the list
auto vecModuleListCopy = m_vecModuleList;
sdv::toml::CNodeCollection nodeModules = nodeConfig.GetDirect("Module");
for (size_t nIndex = nodeModules.GetCount() - 1; nIndex < nodeModules.GetCount(); --nIndex)
for (int64_t iIndex = static_cast<int64_t>(nodeModules.GetCount() - 1); iIndex >= 0; --iIndex)
{
sdv::toml::CNodeCollection tableModule = nodeModules.Get(nIndex);
sdv::toml::CNodeCollection tableModule = nodeModules.Get(static_cast<size_t>(iIndex));
std::filesystem::path pathModule = tableModule.GetDirect("Path").GetValue().get<std::string>();
auto itModule = std::find_if(vecModuleListCopy.begin(), vecModuleListCopy.end(),
[&](const SModule& rsModule) { return pathModule == rsModule.pathModule; });
@@ -374,9 +374,9 @@ Version = )toml" + std::to_string(SDVFrameworkInterfaceVersion) + R"toml(
// Classes leftover in the vector are added to the list
auto vecClassListCopy = m_vecClassList;
sdv::toml::CNodeCollection arrayClasses = nodeConfig.GetDirect("Class");
for (size_t nIndex = arrayClasses.GetCount() -1; nIndex < arrayClasses.GetCount(); --nIndex)
for (int64_t iIndex = static_cast<int64_t>(arrayClasses.GetCount() - 1); iIndex >= 0; --iIndex)
{
sdv::toml::CNodeCollection tableClass = arrayClasses.Get(nIndex);
sdv::toml::CNodeCollection tableClass = arrayClasses.Get(static_cast<size_t>(iIndex));
std::filesystem::path pathModule;
if (!bServerApp)
pathModule = tableClass.GetDirect("Path").GetValue().get<std::string>();
@@ -419,8 +419,7 @@ Version = )toml" + std::to_string(SDVFrameworkInterfaceVersion) + R"toml(
if (ssExistingTOML != itClass->ssDefaultConfig)
{
if (tableParams) tableParams.Delete();
if (!itClass->ssDefaultConfig.empty())
tableClass.InsertTOML(sdv::toml::npos, itClass->ssDefaultConfig);
if (!itClass->ssDefaultConfig.empty()) tableClass.InsertTOML("", itClass->ssDefaultConfig);
rbChanged = true;
}
@@ -433,8 +432,7 @@ Version = )toml" + std::to_string(SDVFrameworkInterfaceVersion) + R"toml(
tableClass.AddValue("Class", rsClass.ssName);
if (!bServerApp)
tableClass.AddValue("Path", std::filesystem::u8path(static_cast<std::string>(rsClass.ssModulePath)));
if (!rsClass.ssDefaultConfig.empty())
tableClass.InsertTOML(sdv::toml::npos, rsClass.ssDefaultConfig);
if (!rsClass.ssDefaultConfig.empty()) tableClass.InsertTOML("", rsClass.ssDefaultConfig);
rbChanged = true;
}
@@ -444,9 +442,9 @@ Version = )toml" + std::to_string(SDVFrameworkInterfaceVersion) + R"toml(
// Components leftover in the vector are added to the list
auto vecComponentListCopy = m_vecComponentList;
sdv::toml::CNodeCollection nodeComponents = nodeConfig.GetDirect("Component");
for (size_t nIndex = nodeComponents.GetCount() - 1; nIndex < nodeComponents.GetCount(); --nIndex)
for (int64_t iIndex = static_cast<int64_t>(nodeComponents.GetCount() - 1); iIndex >= 0; --iIndex)
{
sdv::toml::CNodeCollection tableComponent = nodeComponents.Get(nIndex);
sdv::toml::CNodeCollection tableComponent = nodeComponents.Get(static_cast<size_t>(iIndex));
std::filesystem::path pathModule;
if (!bServerApp)
pathModule = tableComponent.GetDirect("Path").GetValue().get<std::string>();
@@ -518,8 +516,8 @@ Version = )toml" + std::to_string(SDVFrameworkInterfaceVersion) + R"toml(
else if (!tableParams)
{
// Simply add the parameters
tableParams = tableComponent.InsertTable(sdv::toml::npos, "Parameters");
tableParams.InsertTOML(sdv::toml::npos, itComponent->ssParameterTOML);
tableParams = tableComponent.InsertTable("", "Parameters");
tableParams.InsertTOML("", itComponent->ssParameterTOML);
rbChanged = true;
}
}
@@ -536,8 +534,8 @@ Version = )toml" + std::to_string(SDVFrameworkInterfaceVersion) + R"toml(
tableComponent.AddValue("Name", rsComponent.ssInstanceName);
if (!rsComponent.ssParameterTOML.empty())
{
sdv::toml::CNodeCollection tableParams = tableComponent.InsertTable(sdv::toml::npos, "Parameters");
tableParams.InsertTOML(sdv::toml::npos, rsComponent.ssParameterTOML);
sdv::toml::CNodeCollection tableParams = tableComponent.InsertTable("", "Parameters");
tableParams.InsertTOML("", rsComponent.ssParameterTOML);
}
rbChanged = true;
}
@@ -628,12 +626,12 @@ bool CAppConfigFile::InsertComponent(size_t nIndex, const std::filesystem::path&
// Need to add a group?
if (prKey.first != ssGroup)
{
group = root.InsertTable(sdv::toml::npos, prKey.first);
group = root.InsertTable("", prKey.first);
ssGroup = prKey.first;
}
// Add the parameter
group.InsertValue(sdv::toml::npos, prKey.second, prParameter.second);
group.InsertValue("", prKey.second, prParameter.second);
}
ssParameterTOML = parser.GenerateTOML();
}

View File

@@ -266,6 +266,9 @@ public:
*/
void RemoveModule(const std::filesystem::path& rpathModule);
/**
* @brief Merge result enum.
*/
enum class EMergeResult
{
successful,

View File

@@ -15,7 +15,6 @@
#include "module_control.h"
#include "repository.h"
#include "../../global/base64.h"
#include "../../global/tracefifo/trace_fifo.cpp"
#include "toml_parser/parser_toml.h"
#include "local_shutdown_request.h"
#include "app_settings.h"
@@ -49,6 +48,9 @@ bool CAppControl::Startup(/*in*/ const sdv::u8string& ssConfig, /*in*/ IInterfac
{
m_pEvent = pEventHandler ? pEventHandler->GetInterface<sdv::app::IAppEvent>() : nullptr;
// Allow this thread full access
m_optpermission = GetPermissionControl().CreatePermissionObject(sdv::core::EAccessPermission::full_access);
// Intercept the logging...
std::stringstream sstreamCOUT, sstreamCLOG, sstreamCERR;
std::streambuf* pstreambufCOUT = std::cout.rdbuf(sstreamCOUT.rdbuf());
@@ -86,7 +88,7 @@ bool CAppControl::Startup(/*in*/ const sdv::u8string& ssConfig, /*in*/ IInterfac
}
// Open the stream buffer and attach the streams if the application control is initialized as main app.
if (GetAppSettings().IsMainApplication())
if (!GetAppSettings().RedirectMonitorToConsole() && GetAppSettings().IsMainApplication())
{
m_fifoTraceStreamBuffer.SetInstanceID(GetAppSettings().GetInstanceID());
m_fifoTraceStreamBuffer.Open(1000);
@@ -99,7 +101,7 @@ bool CAppControl::Startup(/*in*/ const sdv::u8string& ssConfig, /*in*/ IInterfac
std::cerr << sstreamCERR.str();
// Check for a correctly opened stream buffer
if (GetAppSettings().IsMainApplication() && !m_fifoTraceStreamBuffer.IsOpened())
if (!GetAppSettings().RedirectMonitorToConsole() && GetAppSettings().IsMainApplication() && !m_fifoTraceStreamBuffer.IsOpened())
{
if (!GetAppSettings().IsConsoleSilent())
std::cerr << "ERROR: Log streaming could not be initialized; cannot continue!" << std::endl;
@@ -142,7 +144,7 @@ bool CAppControl::Startup(/*in*/ const sdv::u8string& ssConfig, /*in*/ IInterfac
};
auto fnCreateObject = [&ssErrorString](const sdv::u8string& rssClass, const sdv::u8string& rssObject, const sdv::u8string& rssConfig) -> bool
{
bool bLocalRet = GetRepository().CreateObject2(rssClass, rssObject, rssConfig);
bool bLocalRet = GetRepository().CreateObject(rssClass, rssObject, rssConfig);
if (!bLocalRet)
{
ssErrorString = std::string("Failed to instantiate a new object from class '") + rssClass + "'";
@@ -179,7 +181,7 @@ bool CAppControl::Startup(/*in*/ const sdv::u8string& ssConfig, /*in*/ IInterfac
sdv::IInterfaceAccess* pLoggerObj = GetRepository().GetObject(GetAppSettings().GetLoggerClass());
if (!pLoggerObj)
{
GetRepository().DestroyObject2(GetAppSettings().GetLoggerClass());
GetRepository().DestroyObject(GetAppSettings().GetLoggerClass());
if (!GetAppSettings().IsConsoleSilent())
std::cerr << "ERROR: Failed to start the logger. Cannot continue!" << std::endl;
Shutdown(true);
@@ -247,7 +249,7 @@ bool CAppControl::Startup(/*in*/ const sdv::u8string& ssConfig, /*in*/ IInterfac
}
// Load the application settings.
if (!GetAppSettings().LoadSettingsFile())
if (!GetAppSettings().LoadSettings())
{
if (!GetAppSettings().IsConsoleSilent())
std::cerr << "ERROR: Failed to load application settings file. Cannot continue!" << std::endl;
@@ -275,32 +277,88 @@ bool CAppControl::Startup(/*in*/ const sdv::u8string& ssConfig, /*in*/ IInterfac
bRet = fnLoadModule("hardware_ident.sdv") ? true : false;
if (bRet) bRet = fnCreateObject("HardwareIdentificationService", "", "");
// Load shared memory channel
if (bRet) bRet = fnLoadModule("ipc_shared_mem.sdv") ? true : false;
if (bRet) bRet = fnCreateObject("DefaultSharedMemoryChannelControl", "", "");
// Load default communication provider
if (bRet) bRet = fnCreateObject(GetAppSettings().GetDefaultComProvider(), "", "");
// Load IPC service
if (bRet) bRet = fnLoadModule("ipc_com.sdv") ? true : false;
if (bRet) bRet = fnCreateObject("CommunicationControl", "", "");
// Load IPC service and create listener local connections
if (bRet) bRet = fnLoadModule("ipc_listener.sdv") ? true : false;
if (bRet) bRet = fnCreateObject("ConnectionListenerService", "", R"code([Listener]
Type = "Local"
)code");
// Load IPC service
if (bRet) bRet = fnLoadModule("ipc_connect.sdv") ? true : false;
if (bRet) bRet = fnCreateObject("ConnectionService", "", "");
// Load proxy/stub for core interfaces
if (bRet) bRet = fnLoadModule("core_ps.sdv") ? true : false;
// // Start the listener
// if (bRet) bRet = fnLoadModule("ipc_listener.sdv") ? true : false;
// if (bRet) bRet = GetRepository().CreateObject("ConnectionListenerService", "ConnectionListenerService", R"code([Listener]
//Type="local"
//Instance=)code" + std::to_string(GetInstanceID()));
// Load the connection services
if (bRet) bRet = fnLoadModule("ipc_listener.sdv") ? true : false;
if (bRet) bRet = fnLoadModule("ipc_connect.sdv") ? true : false;
// For the main application start the configured listeners.
if (bRet)
{
auto seqListeners = GetAppSettings().GetListeners();
for (const auto& rssListener : seqListeners)
{
if (!bRet) break;
auto ssListenerConfig = GetAppSettings().GetListenerConfig(rssListener);
bRet = fnCreateObject("ListenerConnectService", "Listener_" + rssListener, ssListenerConfig);
}
}
// For the main application connect the configured connections (except default connection).
if (bRet)
{
auto seqConnections = GetAppSettings().GetConnections();
for (const auto& rssConnection : seqConnections)
{
if (!bRet) break;
if (rssConnection == "Default") continue;
if (!GetAppSettings().IsConsoleSilent())
std::cout << "INFO: Trying to connect to " << rssConnection << "..." << std::endl;
auto ssConnectionConfig = GetAppSettings().GetConnectionConfig(rssConnection);
std::string ssObjectName = "Client_" + rssConnection;
bRet = fnCreateObject("ClientConnectService", ssObjectName, ssConnectionConfig);
// Try connect (for at least nTries) and when successful bind repositories
sdv::TInterfaceAccessPtr ptrClient = GetRepository().GetObject(ssObjectName);
sdv::com::IClientConnect* pClientConnect = ptrClient.GetInterface<sdv::com::IClientConnect>();
if (pClientConnect)
{
for (uint32_t uiCnt = 0; uiCnt < GetAppSettings().GetConnectRetries(); uiCnt++)
{
// Try to connect. If not working, wait for 300 ms
if (pClientConnect->Connect()) break;
std::this_thread::sleep_for(std::chrono::milliseconds(300));
}
if (pClientConnect->IsConnected())
{
// Register the core repo as repo access
sdv::core::TLinkID tLinkID = GetRepository().LinkCoreRepository(pClientConnect->GetRemoteRepository());
if (!GetAppSettings().IsConsoleSilent())
std::cout << "INFO: Connection established... " << std::endl;
// Store the connection object.
m_vecConnections.push_back(std::make_pair(ssObjectName, tLinkID));
}
else
{
ssErrorString = "Not connected...";
if (!GetAppSettings().IsConsoleSilent())
std::cout << "ERROR: Failed to connect to " << ssConnectionConfig << std::endl;
bRet = false;
}
}
else
{
ssErrorString = "No client connect interface...";
if (!GetAppSettings().IsConsoleSilent())
std::cerr << "ERROR: Cannot create connection object for " << rssConnection << std::endl;
bRet = false;
}
}
}
if (!bRet)
{
@@ -314,24 +372,68 @@ Type = "Local"
}
else if (bRet && bLoadRPCClient)
{
// Interpret the connect string...
// Load hardware identification
bRet = fnLoadModule("hardware_ident.sdv") ? true : false;
if (bRet) bRet = fnCreateObject("HardwareIdentificationService", "", "");
// Load shared memory channel
if (bRet) bRet = fnLoadModule("ipc_shared_mem.sdv") ? true : false;
if (bRet) bRet = fnCreateObject("DefaultSharedMemoryChannelControl", "", "");
// Load default communication provider
if (bRet) bRet = fnCreateObject(GetAppSettings().GetDefaultComProvider(), "", "");
// Load IPC service
if (bRet) bRet = fnLoadModule("ipc_com.sdv") ? true : false;
if (bRet) bRet = fnCreateObject("CommunicationControl", "", "");
// Load IPC service
if (bRet) bRet = fnLoadModule("ipc_connect.sdv") ? true : false;
if (bRet) bRet = fnCreateObject("ConnectionService", "", "");
// Connect to the core system when running as external aplication. Use the default connection for this.
if (bRet && GetAppSettings().GetContextType() == sdv::app::EAppContext::external)
{
// Load the connection services
bRet = fnLoadModule("ipc_connect.sdv") ? true : false;
if (!GetAppSettings().IsConsoleSilent())
std::cout << "INFO: Trying to connect to the core system..." << std::endl;
// And the one connection
auto ssConnectionConfig = GetAppSettings().GetConnectionConfig("Default");
if (bRet && !ssConnectionConfig.empty())
bRet = fnCreateObject("ClientConnectService", "Client_Default", ssConnectionConfig);
// Try connect (for at least nTries) and when successful bind repositories
sdv::TInterfaceAccessPtr ptrClient = GetRepository().GetObject("Client_Default");
sdv::com::IClientConnect* pClientConnect = ptrClient.GetInterface<sdv::com::IClientConnect>();
if (pClientConnect)
{
for (uint32_t uiCnt = 0; uiCnt < GetAppSettings().GetConnectRetries(); uiCnt++)
{
// Try to connect. If not working, wait for 300 ms
if (pClientConnect->Connect()) break;
std::this_thread::sleep_for(std::chrono::milliseconds(300));
}
if (pClientConnect->IsConnected())
{
// Register the core repo as repo access
sdv::core::TLinkID tLinkID = GetRepository().LinkCoreRepository(pClientConnect->GetRemoteRepository());
if (!GetAppSettings().IsConsoleSilent())
std::cout << "INFO: Connection established... " << std::endl;
// Store the connection object.
m_vecConnections.push_back(std::make_pair("Default", tLinkID));
}
else
{
if (!GetAppSettings().IsConsoleSilent())
std::cout << "ERROR: Failed to connect to the core system" << std::endl;
bRet = false;
}
}
else
{
if (!GetAppSettings().IsConsoleSilent())
std::cerr << "ERROR: Cannot create connection object for connecting to the core system." << std::endl;
bRet = false;
}
}
// Load proxy/stub for core interfaces
if (bRet) bRet = fnLoadModule("core_ps.sdv") ? true : false;
@@ -428,6 +530,7 @@ void CAppControl::RunLoop()
{
case sdv::app::EAppContext::main:
case sdv::app::EAppContext::isolated:
case sdv::app::EAppContext::external:
bLocal = false;
break;
case sdv::app::EAppContext::maintenance:
@@ -490,8 +593,22 @@ void CAppControl::Shutdown(/*in*/ bool bForce)
// Disable automatic configuration saving.
m_bAutoSaveConfig = false;
// Update the application settings file
GetAppSettings().SaveSettingsFile();
// TODO EVE: This is likely not wanted
//// Update the application settings file
//GetAppSettings().SaveSettings();
// Disconnect all automatic connections.
for (const auto& rprConnectObject : m_vecConnections)
{
// If there is a registered link ID, unlink the ID.
if (rprConnectObject.second)
GetRepository().UnlinkCoreRepository(rprConnectObject.second);
sdv::TInterfaceAccessPtr ptrClient = GetRepository().GetObject(rprConnectObject.first);
sdv::com::IClientConnect* pClientConnect = ptrClient.GetInterface<sdv::com::IClientConnect>();
if (pClientConnect) pClientConnect->Disconnect();
}
m_vecConnections.clear();
// Destroy all objects... this should also remove any registered services, except the custom logger.
GetRepository().DestroyAllObjects(std::vector<std::string>({GetAppSettings().GetLoggerClass()}), bForce);
@@ -537,7 +654,7 @@ void CAppControl::Shutdown(/*in*/ bool bForce)
}
// End trace streaming
if (GetAppSettings().IsMainApplication())
if (!GetAppSettings().RedirectMonitorToConsole() && GetAppSettings().IsMainApplication())
{
std::cout << "**********************************************" << std::endl;
@@ -551,6 +668,7 @@ void CAppControl::Shutdown(/*in*/ bool bForce)
m_bAutoSaveConfig = false;
m_bEnableAutoSave = false;
GetAppSettings().Reset();
m_optpermission.reset();
}
void CAppControl::RequestShutdown()

View File

@@ -18,6 +18,8 @@
#include <support/component_impl.h>
#include <support/interface_ptr.h>
#include "../../global/tracefifo/trace_fifo.h"
#include "permission_control.h"
#include <optional>
/**
* @brief Application control class.
@@ -151,6 +153,9 @@ private:
CTraceFifoStdBuffer m_fifoTraceStreamBuffer; ///< Trace stream buffer to redirect std::log, std::out and
///< std::err when running as service.
bool m_bAutoSaveConfig = false; ///< System setting for automatic saving of the user configuration.
std::vector<std::pair<std::string, sdv::core::TLinkID>> m_vecConnections; ///< Connection objects that were successfully
///< connected.
std::optional<CAccessPermission> m_optpermission; ///< Main access permission for the core.
};
/**

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More