diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml index 26b2926..44a18e9 100644 --- a/.github/workflows/cmake-multi-platform.yml +++ b/.github/workflows/cmake-multi-platform.yml @@ -30,12 +30,15 @@ jobs: - os: windows-latest c_compiler: cl cpp_compiler: cl + test_executable: \test\Release\DsVeosCoSimTest.exe - os: ubuntu-latest c_compiler: gcc cpp_compiler: g++ + test_executable: /test/DsVeosCoSimTest - os: ubuntu-latest c_compiler: clang cpp_compiler: clang++ + test_executable: /test/DsVeosCoSimTest exclude: - os: windows-latest c_compiler: gcc @@ -65,6 +68,7 @@ jobs: -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} + -DDSVEOSCOSIM_BUILD_TESTS=ON -S ${{ github.workspace }} - name: Build @@ -75,4 +79,4 @@ jobs: working-directory: ${{ steps.strings.outputs.build-output-dir }} # Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail - run: ctest --build-config ${{ matrix.build_type }} + run: ${{ steps.strings.outputs.build-output-dir }}${{ matrix.test_executable }} diff --git a/.gitignore b/.gitignore index 7687b01..92161ff 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ obj/ tmplin/ tmpwin/ .mono/ + +debug.log diff --git a/.vscode/settings.json b/.vscode/settings.json index 3ded918..4b43b19 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -18,5 +18,101 @@ "swappable", "vecu", "vpus" - ] + ], + "files.associations": { + "algorithm": "cpp", + "any": "cpp", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "bitset": "cpp", + "cctype": "cpp", + "cfenv": "cpp", + "charconv": "cpp", + "chrono": "cpp", + "cinttypes": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "codecvt": "cpp", + "compare": "cpp", + "complex": "cpp", + "concepts": "cpp", + "condition_variable": "cpp", + "coroutine": "cpp", + "csignal": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "deque": "cpp", + "exception": "cpp", + "expected": "cpp", + "filesystem": "cpp", + "format": "cpp", + "forward_list": "cpp", + "fstream": "cpp", + "functional": "cpp", + "future": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "ios": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "iterator": "cpp", + "limits": "cpp", + "list": "cpp", + "locale": "cpp", + "map": "cpp", + "memory": "cpp", + "mutex": "cpp", + "new": "cpp", + "numeric": "cpp", + "optional": "cpp", + "ostream": "cpp", + "queue": "cpp", + "random": "cpp", + "ranges": "cpp", + "ratio": "cpp", + "regex": "cpp", + "set": "cpp", + "source_location": "cpp", + "span": "cpp", + "sstream": "cpp", + "stack": "cpp", + "stdexcept": "cpp", + "stop_token": "cpp", + "streambuf": "cpp", + "string": "cpp", + "system_error": "cpp", + "thread": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "typeindex": "cpp", + "typeinfo": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "utility": "cpp", + "variant": "cpp", + "vector": "cpp", + "xfacet": "cpp", + "xhash": "cpp", + "xiosbase": "cpp", + "xlocale": "cpp", + "xlocbuf": "cpp", + "xlocinfo": "cpp", + "xlocmes": "cpp", + "xlocmon": "cpp", + "xlocnum": "cpp", + "xloctime": "cpp", + "xmemory": "cpp", + "xstring": "cpp", + "xtr1common": "cpp", + "xtree": "cpp", + "xutility": "cpp" + } } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 656de95..eb560b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ option(BUILD_SHARED_LIBS "Compile dSPACE VEOS CoSim as a shared library" OFF) option(DSVEOSCOSIM_BUILD_TESTS "Create tests for dSPACE VEOS CoSim" OFF) option(DSVEOSCOSIM_BUILD_BENCHMARKS "Create benchmarks for dSPACE VEOS CoSim" OFF) -set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED TRUE) set(DSVEOSCOSIM_TYPE STATIC) @@ -27,12 +27,12 @@ if(DSVEOSCOSIM_BUILD_TESTS) add_subdirectory(test) add_subdirectory(utilities/TestClient) add_subdirectory(utilities/TestServer) + add_subdirectory(utilities/PerformanceTestClient) + add_subdirectory(utilities/PerformanceTestServer) endif() if(DSVEOSCOSIM_BUILD_BENCHMARKS) add_subdirectory(benchmark) - add_subdirectory(utilities/PerformanceTestClient) - add_subdirectory(utilities/PerformanceTestServer) endif() install(EXPORT DsVeosCoSimTargets diff --git a/benchmark/BenchmarkBusBuffer.cpp b/benchmark/BenchmarkBusBuffer.cpp index ac28f55..3a308b1 100644 --- a/benchmark/BenchmarkBusBuffer.cpp +++ b/benchmark/BenchmarkBusBuffer.cpp @@ -59,12 +59,12 @@ void RunTest(benchmark::State& state, bool stopThread{}; Event endEvent; - std::jthread thread(ReceiveMessages, - count, - std::ref(receiverBusBuffer), - std::ref(receiverChannel), - std::ref(stopThread), - std::ref(endEvent)); + std::thread thread(ReceiveMessages, + count, + std::ref(receiverBusBuffer), + std::ref(receiverChannel), + std::ref(stopThread), + std::ref(endEvent)); TMessage sendMessage{}; FillWithRandom(sendMessage, controller.id); @@ -91,6 +91,8 @@ void RunTest(benchmark::State& state, MUST_BE_TRUE(transmitterBusBuffer.Serialize(senderChannel.GetWriter())); MUST_BE_TRUE(senderChannel.GetWriter().EndWrite()); + + thread.join(); } template diff --git a/benchmark/BenchmarkIoBuffer.cpp b/benchmark/BenchmarkIoBuffer.cpp index 7eb3f59..71e2aca 100644 --- a/benchmark/BenchmarkIoBuffer.cpp +++ b/benchmark/BenchmarkIoBuffer.cpp @@ -51,12 +51,12 @@ void RunTest(benchmark::State& state, bool stopThread{}; Event endEvent; - std::jthread thread(Receive, - std::ref(signal), - std::ref(readerIoBuffer), - std::ref(receiverChannel), - std::ref(stopThread), - std::ref(endEvent)); + std::thread thread(Receive, + std::ref(signal), + std::ref(readerIoBuffer), + std::ref(receiverChannel), + std::ref(stopThread), + std::ref(endEvent)); for (auto _ : state) { writeValue[0]++; @@ -75,6 +75,8 @@ void RunTest(benchmark::State& state, MUST_BE_TRUE(writerIoBuffer.Serialize(senderChannel.GetWriter())); MUST_BE_TRUE(senderChannel.GetWriter().EndWrite()); + + thread.join(); } void TcpIo(benchmark::State& state) { diff --git a/benchmark/Communication/BenchmarkChannel.cpp b/benchmark/Communication/BenchmarkChannel.cpp index 2fe4f51..16c8ae6 100644 --- a/benchmark/Communication/BenchmarkChannel.cpp +++ b/benchmark/Communication/BenchmarkChannel.cpp @@ -34,7 +34,7 @@ void RunTest(benchmark::State& state, Channel& channel1, Channel& channel2) { size_t size = state.range(0); bool stopThread{}; - std::jthread thread(CounterPart, std::ref(channel1), std::ref(stopThread), size); + std::thread thread(CounterPart, std::ref(channel1), std::ref(stopThread), size); std::vector buffer; buffer.resize(size); @@ -48,6 +48,8 @@ void RunTest(benchmark::State& state, Channel& channel1, Channel& channel2) { stopThread = true; MUST_BE_TRUE(channel2.GetWriter().Write(buffer.data(), buffer.size())); MUST_BE_TRUE(channel2.GetWriter().EndWrite()); + + thread.join(); } void TcpChannelRoundtrip(benchmark::State& state) { diff --git a/benchmark/OsAbstraction/BenchmarkNamedEvent.cpp b/benchmark/OsAbstraction/BenchmarkNamedEvent.cpp index f392f1d..d57e044 100644 --- a/benchmark/OsAbstraction/BenchmarkNamedEvent.cpp +++ b/benchmark/OsAbstraction/BenchmarkNamedEvent.cpp @@ -54,7 +54,7 @@ void EventRoundtrip(benchmark::State& state) { NamedEvent event2 = NamedEvent::CreateOrOpen(eventName2); stopThread = false; - std::jthread thread(WaitAndSet, eventName1, eventName2); + std::thread thread(WaitAndSet, eventName1, eventName2); for (auto _ : state) { event1.Set(); @@ -63,6 +63,8 @@ void EventRoundtrip(benchmark::State& state) { stopThread = true; event1.Set(); + + thread.join(); } } // namespace diff --git a/benchmark/OsAbstraction/BenchmarkSocket.cpp b/benchmark/OsAbstraction/BenchmarkSocket.cpp index 2958800..14f2423 100644 --- a/benchmark/OsAbstraction/BenchmarkSocket.cpp +++ b/benchmark/OsAbstraction/BenchmarkSocket.cpp @@ -32,7 +32,7 @@ void RunTest(benchmark::State& state, Socket& socket1, Socket& socket2) { buffer.resize(size); bool stopThread{}; - std::jthread thread(CounterPart, std::ref(socket1), std::ref(stopThread), size); + std::thread thread(CounterPart, std::ref(socket1), std::ref(stopThread), size); for (auto _ : state) { MUST_BE_TRUE(SendComplete(socket2, buffer.data(), buffer.size())); @@ -41,6 +41,8 @@ void RunTest(benchmark::State& state, Socket& socket1, Socket& socket2) { stopThread = true; MUST_BE_TRUE(SendComplete(socket2, buffer.data(), buffer.size())); + + thread.join(); } void SocketTcpRoundtrip(benchmark::State& state) { diff --git a/build.cmd b/build.cmd index f1cc103..6a1ce77 100644 --- a/build.cmd +++ b/build.cmd @@ -36,7 +36,7 @@ echo Building %config% %platformToUse% ... set buildDir=%currentDir%\tmpwin\%config%\%platformToUse% if not exist "%buildDir%" mkdir "%buildDir%" || exit /b 1 cd "%buildDir%" -cmake ..\..\.. -GNinja -DCMAKE_BUILD_TYPE=%config% -DDSVEOSCOSIM_BUILD_TESTS=ON -DDSVEOSCOSIM_BUILD_BENCHMARKS=ON || exit /b 1 +cmake ..\..\.. -GNinja -DCMAKE_BUILD_TYPE=%config% -DDSVEOSCOSIM_BUILD_TESTS=ON || exit /b 1 cmake --build . --config %config% || exit /b 1 echo Building %config% %platformToUse% finished successfully. diff --git a/build.sh b/build.sh index b381c64..0c4d697 100755 --- a/build.sh +++ b/build.sh @@ -13,7 +13,7 @@ echo Building $config ... mkdir -p "$currentDir/tmplin/$config" || exit 1 cd "$currentDir/tmplin/$config" -cmake ../.. -GNinja -DCMAKE_BUILD_TYPE=$config -DDSVEOSCOSIM_BUILD_TESTS=ON -DDSVEOSCOSIM_BUILD_BENCHMARKS=ON || exit 1 +cmake ../.. -GNinja -DCMAKE_BUILD_TYPE=$config -DDSVEOSCOSIM_BUILD_TESTS=ON || exit 1 cmake --build . || exit 1 echo Building $config finished successfully. diff --git a/include/DsVeosCoSim/DsVeosCoSim.h b/include/DsVeosCoSim/DsVeosCoSim.h index 0682511..c08f163 100644 --- a/include/DsVeosCoSim/DsVeosCoSim.h +++ b/include/DsVeosCoSim/DsVeosCoSim.h @@ -1134,8 +1134,48 @@ DSVEOSCOSIM_DECL DsVeosCoSim_Result DsVeosCoSim_ReceiveLinMessage(DsVeosCoSim_Ha DSVEOSCOSIM_DECL DsVeosCoSim_Result DsVeosCoSim_TransmitLinMessage(DsVeosCoSim_Handle handle, const DsVeosCoSim_LinMessage* message); +DSVEOSCOSIM_DECL DsVeosCoSim_Result DsVeosCoSim_StartSimulation(DsVeosCoSim_Handle handle); +DSVEOSCOSIM_DECL DsVeosCoSim_Result DsVeosCoSim_StopSimulation(DsVeosCoSim_Handle handle); +DSVEOSCOSIM_DECL DsVeosCoSim_Result DsVeosCoSim_PauseSimulation(DsVeosCoSim_Handle handle); +DSVEOSCOSIM_DECL DsVeosCoSim_Result DsVeosCoSim_ContinueSimulation(DsVeosCoSim_Handle handle); +DSVEOSCOSIM_DECL DsVeosCoSim_Result DsVeosCoSim_TerminateSimulation(DsVeosCoSim_Handle handle, + DsVeosCoSim_TerminateReason terminateReason); + #ifdef __cplusplus +extern DSVEOSCOSIM_API std::string DsVeosCoSim_SimulationTimeToString(DsVeosCoSim_SimulationTime simulationTime); +extern DSVEOSCOSIM_API std::string DsVeosCoSim_ResultToString(DsVeosCoSim_Result result); +extern DSVEOSCOSIM_API std::string DsVeosCoSim_CommandToString(DsVeosCoSim_Command command); +extern DSVEOSCOSIM_API std::string DsVeosCoSim_SeverityToString(DsVeosCoSim_Severity severity); +extern DSVEOSCOSIM_API std::string DsVeosCoSim_TerminateReasonToString(DsVeosCoSim_TerminateReason terminateReason); +extern DSVEOSCOSIM_API std::string DsVeosCoSim_ConnectionStateToString(DsVeosCoSim_ConnectionState connectionState); +extern DSVEOSCOSIM_API std::string DsVeosCoSim_DataTypeToString(DsVeosCoSim_DataType dataType); +extern DSVEOSCOSIM_API std::string DsVeosCoSim_SizeKindToString(DsVeosCoSim_SizeKind sizeKind); +extern DSVEOSCOSIM_API std::string DsVeosCoSim_IoSignalToString(const DsVeosCoSim_IoSignal& ioSignal); +extern DSVEOSCOSIM_API std::string DsVeosCoSim_CanControllerToString(const DsVeosCoSim_CanController& controller); +extern DSVEOSCOSIM_API std::string DsVeosCoSim_EthControllerToString(const DsVeosCoSim_EthController& controller); +extern DSVEOSCOSIM_API std::string DsVeosCoSim_LinControllerToString(const DsVeosCoSim_LinController& controller); +extern DSVEOSCOSIM_API std::string DsVeosCoSim_ValueToString(DsVeosCoSim_DataType dataType, + uint32_t length, + const void* value); +extern DSVEOSCOSIM_API std::string DsVeosCoSim_DataToString(const uint8_t* data, size_t dataLength, char separator = 0); +extern DSVEOSCOSIM_API std::string DsVeosCoSim_IoDataToString(DsVeosCoSim_SimulationTime simulationTime, + const DsVeosCoSim_IoSignal& ioSignal, + uint32_t length, + const void* value); +extern DSVEOSCOSIM_API std::string DsVeosCoSim_CanMessageToString(DsVeosCoSim_SimulationTime simulationTime, + const DsVeosCoSim_CanController& controller, + const DsVeosCoSim_CanMessage& message); +extern DSVEOSCOSIM_API std::string DsVeosCoSim_EthMessageToString(DsVeosCoSim_SimulationTime simulationTime, + const DsVeosCoSim_EthController& controller, + const DsVeosCoSim_EthMessage& message); +extern DSVEOSCOSIM_API std::string DsVeosCoSim_LinMessageToString(DsVeosCoSim_SimulationTime simulationTime, + const DsVeosCoSim_LinController& controller, + const DsVeosCoSim_LinMessage& message); +extern DSVEOSCOSIM_API std::string DsVeosCoSim_LinControllerTypeToString( + DsVeosCoSim_LinControllerType linControllerType); extern DSVEOSCOSIM_API std::string DsVeosCoSim_CanMessageFlagsToString(DsVeosCoSim_CanMessageFlags flags); extern DSVEOSCOSIM_API std::string DsVeosCoSim_EthMessageFlagsToString(DsVeosCoSim_EthMessageFlags flags); extern DSVEOSCOSIM_API std::string DsVeosCoSim_LinMessageFlagsToString(DsVeosCoSim_LinMessageFlags flags); + +extern DSVEOSCOSIM_API size_t DsVeosCoSim_GetDataTypeSize(DsVeosCoSim_DataType dataType); #endif diff --git a/shared/BackgroundService.cpp b/shared/BackgroundService.cpp deleted file mode 100644 index ecc5d3e..0000000 --- a/shared/BackgroundService.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright dSPACE GmbH. All rights reserved. - -#include "BackgroundService.h" - -#include - -using namespace DsVeosCoSim; - -BackgroundService::BackgroundService(CoSimServer& coSimServer) : _coSimServer(coSimServer) { - _thread = std::thread([this] { - while (!_stopEvent.Wait(1)) { - try { - _coSimServer.BackgroundService(); - } catch (const std::exception& e) { - LogError(e.what()); - } - } - }); -} - -BackgroundService::~BackgroundService() noexcept { - _stopEvent.Set(); - if (std::this_thread::get_id() == _thread.get_id()) { - _thread.detach(); - } else { - _thread.join(); - } -} diff --git a/shared/BackgroundService.h b/shared/BackgroundService.h deleted file mode 100644 index 8018d32..0000000 --- a/shared/BackgroundService.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright dSPACE GmbH. All rights reserved. - -#pragma once - -#include - -#include "CoSimServer.h" -#include "Event.h" - -class BackgroundService final { -public: - explicit BackgroundService(DsVeosCoSim::CoSimServer& coSimServer); - ~BackgroundService() noexcept; - - BackgroundService(const BackgroundService&) = delete; - BackgroundService& operator=(const BackgroundService&) = delete; - - BackgroundService(BackgroundService&&) = delete; - BackgroundService& operator=(BackgroundService&&) = delete; - -private: - DsVeosCoSim::CoSimServer& _coSimServer; - DsVeosCoSim::Event _stopEvent; - std::thread _thread; -}; diff --git a/shared/CMakeLists.txt b/shared/CMakeLists.txt index cb2556a..b16b745 100644 --- a/shared/CMakeLists.txt +++ b/shared/CMakeLists.txt @@ -8,8 +8,6 @@ add_library( target_sources( shared PRIVATE - BackgroundService.cpp - ClientServerTestHelper.cpp Generator.cpp Helper.cpp LogHelper.cpp diff --git a/shared/ClientServerTestHelper.cpp b/shared/ClientServerTestHelper.cpp deleted file mode 100644 index 6f1b13b..0000000 --- a/shared/ClientServerTestHelper.cpp +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright dSPACE GmbH. All rights reserved. - -#include "ClientServerTestHelper.h" - -#include -#include - -#include "BusBuffer.h" -#include "CoSimHelper.h" -#include "Generator.h" - -using namespace DsVeosCoSim; - -namespace { - -bool g_sendIoData; -bool g_sendCanMessages; -bool g_sendEthMessages; -bool g_sendLinMessages; - -void PrintStatus(bool value, std::string_view what) { - LogInfo(fmt::format("{} sending {}.", value ? "Enabled" : "Disabled", what)); -} - -} // namespace - -void SwitchSendingIoSignals() { - g_sendIoData = !g_sendIoData; - PrintStatus(g_sendIoData, "IO data"); -} - -void SwitchSendingCanMessages() { - g_sendCanMessages = !g_sendCanMessages; - PrintStatus(g_sendCanMessages, "CAN messages"); -} - -void SwitchSendingEthMessages() { - g_sendEthMessages = !g_sendEthMessages; - PrintStatus(g_sendEthMessages, "ETH messages"); -} - -void SwitchSendingLinMessages() { - g_sendLinMessages = !g_sendLinMessages; - PrintStatus(g_sendLinMessages, "LIN messages"); -} - -[[nodiscard]] bool IsSendingIoSignalsEnabled() { - return g_sendIoData; -} - -[[nodiscard]] bool IsSendingCanMessagesEnabled() { - return g_sendCanMessages; -} - -[[nodiscard]] bool IsSendingEthMessagesEnabled() { - return g_sendEthMessages; -} - -[[nodiscard]] bool IsSendingLinMessagesEnabled() { - return g_sendLinMessages; -} - -[[nodiscard]] bool SendSomeData(DsVeosCoSim_SimulationTime simulationTime, const RunTimeInfo& runTimeInfo) { - static int64_t lastHalfSecond = -1; - static int64_t counter = 0; - const int64_t currentHalfSecond = simulationTime / 500000000; - if (currentHalfSecond == lastHalfSecond) { - return true; - } - - lastHalfSecond = currentHalfSecond; - counter++; - - if (IsSendingIoSignalsEnabled() && ((counter % 4) == 0)) { - for (const IoSignal& signal : runTimeInfo.outgoingSignals) { - std::vector data = GenerateIoData(signal); - runTimeInfo.write(signal.id, signal.length, data.data()); - } - } - - if (IsSendingCanMessagesEnabled() && ((counter % 4) == 1)) { - for (const CanController& controller : runTimeInfo.canControllers) { - CanMessage message{}; - FillWithRandom(message, controller.id); - CheckResult(runTimeInfo.transmitCan(message)); - } - } - - if (IsSendingEthMessagesEnabled() && ((counter % 4) == 2)) { - for (const EthController& controller : runTimeInfo.ethControllers) { - EthMessage message{}; - FillWithRandom(message, controller.id); - CheckResult(runTimeInfo.transmitEth(message)); - } - } - - if (IsSendingLinMessagesEnabled() && ((counter % 4) == 3)) { - for (const LinController& controller : runTimeInfo.linControllers) { - LinMessage message{}; - FillWithRandom(message, controller.id); - CheckResult(runTimeInfo.transmitLin(message)); - } - } - - return true; -} diff --git a/shared/ClientServerTestHelper.h b/shared/ClientServerTestHelper.h deleted file mode 100644 index e769156..0000000 --- a/shared/ClientServerTestHelper.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright dSPACE GmbH. All rights reserved. - -#pragma once - -#include -#include - -#include "CoSimTypes.h" - -struct RunTimeInfo { - std::vector canControllers; - std::vector ethControllers; - std::vector linControllers; - std::vector incomingSignals; - std::vector outgoingSignals; - std::function write; - std::function transmitCan; - std::function transmitEth; - std::function transmitLin; -}; - -void SwitchSendingIoSignals(); -void SwitchSendingCanMessages(); -void SwitchSendingEthMessages(); -void SwitchSendingLinMessages(); - -[[nodiscard]] bool IsSendingIoSignalsEnabled(); -[[nodiscard]] bool IsSendingCanMessagesEnabled(); -[[nodiscard]] bool IsSendingEthMessagesEnabled(); -[[nodiscard]] bool IsSendingLinMessagesEnabled(); - -[[nodiscard]] bool SendSomeData(DsVeosCoSim_SimulationTime simulationTime, const RunTimeInfo& runTimeInfo); \ No newline at end of file diff --git a/shared/Generator.h b/shared/Generator.h index c386c29..61e7128 100644 --- a/shared/Generator.h +++ b/shared/Generator.h @@ -25,9 +25,6 @@ template [[nodiscard]] int64_t GenerateI64(); [[nodiscard]] std::string GenerateString(std::string_view prefix); -[[nodiscard]] DsVeosCoSim_DataType GenerateDataType(); -[[nodiscard]] DsVeosCoSim_SizeKind GenerateSizeKind(); - [[nodiscard]] DsVeosCoSim::IoSignal CreateSignal(); [[nodiscard]] DsVeosCoSim::IoSignal CreateSignal(DsVeosCoSim_DataType dataType); [[nodiscard]] DsVeosCoSim::IoSignal CreateSignal(DsVeosCoSim_DataType dataType, DsVeosCoSim_SizeKind sizeKind); diff --git a/shared/Helper.cpp b/shared/Helper.cpp index 179b07c..2efb49c 100644 --- a/shared/Helper.cpp +++ b/shared/Helper.cpp @@ -58,26 +58,6 @@ namespace { return true; } -[[nodiscard]] int32_t GetChar() { -#ifdef _WIN32 - return _getch(); -#else - termios oldt{}; - tcgetattr(STDIN_FILENO, &oldt); - - termios newt = oldt; - newt.c_lflag &= ~(ICANON | ECHO); - - tcsetattr(STDIN_FILENO, TCSANOW, &newt); - - int32_t character = getchar(); - - tcsetattr(STDIN_FILENO, TCSANOW, &oldt); - - return character; -#endif -} - [[nodiscard]] Socket ConnectSocket(std::string_view ipAddress, uint16_t remotePort) { std::optional connectedSocket = Socket::TryConnect(ipAddress, remotePort, 0, DefaultTimeout); if (connectedSocket) { diff --git a/shared/Helper.h b/shared/Helper.h index 7975745..97b0f80 100644 --- a/shared/Helper.h +++ b/shared/Helper.h @@ -16,10 +16,6 @@ constexpr uint32_t Infinite = UINT32_MAX; // NOLINT -#ifndef CTRL -#define CTRL(c) ((c) & 037) -#endif - #define MUST_BE_TRUE(actual) \ do { \ if (!(actual)) { \ @@ -27,8 +23,6 @@ constexpr uint32_t Infinite = UINT32_MAX; // NOLINT } \ } while (0) -[[nodiscard]] int32_t GetChar(); - constexpr uint32_t DefaultTimeout = 1000; // NOLINT [[nodiscard]] bool StartUp(); diff --git a/shared/LogHelper.cpp b/shared/LogHelper.cpp index 12295a8..cb22756 100644 --- a/shared/LogHelper.cpp +++ b/shared/LogHelper.cpp @@ -3,7 +3,6 @@ #include "LogHelper.h" #include -#include #include #include "CoSimHelper.h" @@ -19,57 +18,9 @@ namespace { std::string g_lastMessage; fmt::text_style red = fg(fmt::color::red); -fmt::text_style cyan = fg(fmt::color::cyan); -fmt::text_style green = fg(fmt::color::lime); fmt::text_style yellow = fg(fmt::color::yellow); fmt::text_style white = fg(fmt::color::white); fmt::text_style gray = fg(fmt::color::light_gray); -fmt::text_style blue = fg(fmt::color::dodger_blue); -fmt::text_style violet = fg(fmt::color::fuchsia); - -[[nodiscard]] std::string DataTypeValueToString(const void* value, uint32_t index, DsVeosCoSim_DataType dataType) { - switch (dataType) { - case DsVeosCoSim_DataType_Bool: - return std::to_string(static_cast(value)[index]); - case DsVeosCoSim_DataType_Int8: - return std::to_string(static_cast(value)[index]); - case DsVeosCoSim_DataType_Int16: - return std::to_string(static_cast(value)[index]); - case DsVeosCoSim_DataType_Int32: - return std::to_string(static_cast(value)[index]); - case DsVeosCoSim_DataType_Int64: - return std::to_string(static_cast(value)[index]); - case DsVeosCoSim_DataType_UInt8: - return std::to_string(static_cast(value)[index]); - case DsVeosCoSim_DataType_UInt16: - return std::to_string(static_cast(value)[index]); - case DsVeosCoSim_DataType_UInt32: - return std::to_string(static_cast(value)[index]); - case DsVeosCoSim_DataType_UInt64: - return std::to_string(static_cast(value)[index]); - case DsVeosCoSim_DataType_Float32: - return std::to_string(static_cast(value)[index]); - case DsVeosCoSim_DataType_Float64: - return std::to_string(static_cast(value)[index]); - case DsVeosCoSim_DataType_INT_MAX_SENTINEL_DO_NOT_USE_: - break; - } - - throw std::runtime_error("Invalid data type."); -} - -[[nodiscard]] std::string ValueToString(const void* value, uint32_t length, DsVeosCoSim_DataType dataType) { - std::ostringstream oss; - for (uint32_t i = 0; i < length; i++) { - if (i > 0) { - oss << " "; - } - - oss << DataTypeValueToString(value, i, dataType); - } - - return oss.str(); -} } // namespace @@ -110,118 +61,6 @@ void OnLogCallback(DsVeosCoSim_Severity severity, std::string_view message) { } } -void LogIoSignal(const DsVeosCoSim_IoSignal& ioSignal) { - LogTrace(" {} (id: {}, data type: {}, size kind: {}, length: {})", - ioSignal.name, - ioSignal.id, - ToString(ioSignal.dataType), - ToString(ioSignal.sizeKind), - ioSignal.length); -} - -void LogIoData(DsVeosCoSim_SimulationTime simulationTime, - const DsVeosCoSim_IoSignal& ioSignal, - uint32_t length, - const void* value) { - print(violet, - "{},{},{},{}\n", - DSVEOSCOSIM_SIMULATION_TIME_TO_SECONDS(simulationTime), - ioSignal.name, - length, - ValueToString(value, length, ioSignal.dataType)); -} - -void LogCanController(const DsVeosCoSim_CanController& controller) { - LogTrace(" {} (id: {}, Size: {}, BitsPerSecond: {}, CAN FD BitsPerSecond: {}, Channel: {}, Cluster: {})", - controller.name, - controller.id, - controller.queueSize, - controller.bitsPerSecond, - controller.flexibleDataRateBitsPerSecond, - controller.channelName, - controller.clusterName); -} - -void LogEthController(const DsVeosCoSim_EthController& controller) { - LogTrace(" {} (id: {}, Size: {}, BitsPerSecond: {}, MAC address: {}, Channel: {}, Cluster: {})", - controller.name, - controller.id, - controller.queueSize, - controller.bitsPerSecond, - DataToString(controller.macAddress, EthAddressLength, ':'), - controller.channelName, - controller.clusterName); -} - -void LogLinController(const DsVeosCoSim_LinController& controller) { - LogTrace(" {} (id: {}, Size: {}, BitsPerSecond: {}, Type: {}, Channel: {}, Cluster: {})", - controller.name, - controller.id, - controller.queueSize, - controller.bitsPerSecond, - ToString(controller.type), - controller.channelName, - controller.clusterName); -} - -void LogCanMessage(DsVeosCoSim_SimulationTime simulationTime, - const DsVeosCoSim_CanController& controller, - const DsVeosCoSim_CanMessage& message) { - print(blue, - "{},{},{},{},{},CAN,{}\n", - DSVEOSCOSIM_SIMULATION_TIME_TO_SECONDS(simulationTime), - controller.name, - message.id, - message.length, - DataToString(message.data, message.length, '-'), - CanMessageFlagsToString(message.flags)); -} - -void LogEthMessage(DsVeosCoSim_SimulationTime simulationTime, - const DsVeosCoSim_EthController& controller, - const DsVeosCoSim_EthMessage& message) { - const uint8_t* data = message.data; - const uint32_t length = message.length; - - if (length >= 14) { - const std::string macAddress1 = DataToString(message.data, 6, ':'); - const std::string macAddress2 = DataToString(message.data + 6, 6, ':'); - const std::string ethernetType = DataToString(message.data + 12, 2); - - print(cyan, - "{},{},{}-{},{},{},ETH,{},{}\n", - DSVEOSCOSIM_SIMULATION_TIME_TO_SECONDS(simulationTime), - controller.name, - macAddress2, - macAddress1, - length - 14, - DataToString(data + 14, length - 14, '-'), - ethernetType, - EthMessageFlagsToString(message.flags)); - } else { - print(cyan, - "{},{},{},{},ETH,{}\n", - DSVEOSCOSIM_SIMULATION_TIME_TO_SECONDS(simulationTime), - controller.name, - length, - DataToString(data, length, '-'), - EthMessageFlagsToString(message.flags)); - } -} - -void LogLinMessage(DsVeosCoSim_SimulationTime simulationTime, - const DsVeosCoSim_LinController& controller, - const DsVeosCoSim_LinMessage& message) { - print(green, - "{},{},{},{},{},LIN,{}\n", - DSVEOSCOSIM_SIMULATION_TIME_TO_SECONDS(simulationTime), - controller.name, - message.id, - message.length, - DataToString(message.data, message.length, '-'), - LinMessageFlagsToString(message.flags)); -} - void ClearLastMessage() { g_lastMessage = ""; } diff --git a/shared/LogHelper.h b/shared/LogHelper.h index a1372dd..27535ee 100644 --- a/shared/LogHelper.h +++ b/shared/LogHelper.h @@ -33,26 +33,5 @@ void LogTrace(fmt::format_string format, T&&... args) { void OnLogCallback(DsVeosCoSim_Severity severity, std::string_view message); -void LogIoSignal(const DsVeosCoSim_IoSignal& ioSignal); - -void LogIoData(DsVeosCoSim_SimulationTime simulationTime, - const DsVeosCoSim_IoSignal& ioSignal, - uint32_t length, - const void* value); - -void LogCanController(const DsVeosCoSim_CanController& controller); -void LogEthController(const DsVeosCoSim_EthController& controller); -void LogLinController(const DsVeosCoSim_LinController& controller); - -void LogCanMessage(DsVeosCoSim_SimulationTime simulationTime, - const DsVeosCoSim_CanController& controller, - const DsVeosCoSim_CanMessage& message); -void LogEthMessage(DsVeosCoSim_SimulationTime simulationTime, - const DsVeosCoSim_EthController& controller, - const DsVeosCoSim_EthMessage& message); -void LogLinMessage(DsVeosCoSim_SimulationTime simulationTime, - const DsVeosCoSim_LinController& controller, - const DsVeosCoSim_LinMessage& message); - void ClearLastMessage(); [[nodiscard]] std::string GetLastMessage(); diff --git a/src/BusBuffer.h b/src/BusBuffer.h index bfc038e..4bba0aa 100644 --- a/src/BusBuffer.h +++ b/src/BusBuffer.h @@ -2,11 +2,9 @@ #pragma once -#include #include #include #include -#include #include #include "Channel.h" @@ -23,26 +21,6 @@ namespace DsVeosCoSim { -template -concept ControllerExtern = requires(TControllerExtern controllerExtern) { - { controllerExtern.queueSize } -> std::same_as; - { controllerExtern.name } -> std::same_as; -}; - -template -concept MessageExtern = requires(TMessageExtern messageExtern) { - { messageExtern.controllerId } -> std::same_as; -}; - -template -concept Message = - requires(TMessage& message, TMessageExtern& messageExtern, ChannelWriter& writer, ChannelReader& reader) { - { std::as_const(message).SerializeTo(writer) }; - { message.DeserializeFrom(reader) }; - { std::as_const(message).WriteTo(messageExtern) }; - { message.ReadFrom(std::as_const(messageExtern)) }; - }; - struct CanMessage { DsVeosCoSim_SimulationTime timestamp{}; DsVeosCoSim_BusControllerId controllerId{}; @@ -102,7 +80,7 @@ struct LinMessage { void CheckMaxLength() const; }; -template +template class BusProtocolBufferBase { protected: using Callback = std::function; @@ -225,7 +203,7 @@ class BusProtocolBufferBase { std::mutex _mutex; }; -template TMessage, ControllerExtern TControllerExtern> +template class RemoteBusProtocolBuffer final : public BusProtocolBufferBase { using Base = BusProtocolBufferBase; using Extension = typename Base::ControllerExtension; @@ -349,7 +327,7 @@ class RemoteBusProtocolBuffer final : public BusProtocolBufferBase TMessage, ControllerExtern TControllerExtern> +template class LocalBusProtocolBuffer final : public BusProtocolBufferBase { using Base = BusProtocolBufferBase; using Extension = typename Base::ControllerExtension; diff --git a/src/CoSimClient.cpp b/src/CoSimClient.cpp index 9dd9506..4df3ae7 100644 --- a/src/CoSimClient.cpp +++ b/src/CoSimClient.cpp @@ -172,7 +172,7 @@ void CoSimClient::SetCallbacks(const Callbacks& callbacks) { SetCallbacks(callbacks); - if (!RunCallbackBasedCoSimulationInternal()) [[unlikely]] { + if (!RunCallbackBasedCoSimulationInternal()) { CloseConnection(); return false; } @@ -197,7 +197,7 @@ void CoSimClient::StartPollingBasedCoSimulation(const Callbacks& callbacks) { throw CoSimException("Call to FinishCommand() for last command is missing."); } - if (!PollCommandInternal(simulationTime, command, returnOnPing)) [[unlikely]] { + if (!PollCommandInternal(simulationTime, command, returnOnPing)) { CloseConnection(); return false; } @@ -213,7 +213,7 @@ void CoSimClient::StartPollingBasedCoSimulation(const Callbacks& callbacks) { throw CoSimException("Call to PollCommand(...) is missing."); } - if (!FinishCommandInternal()) [[unlikely]] { + if (!FinishCommandInternal()) { CloseConnection(); return false; } diff --git a/src/CoSimTypes.h b/src/CoSimTypes.h index c389389..52f50e6 100644 --- a/src/CoSimTypes.h +++ b/src/CoSimTypes.h @@ -2,10 +2,11 @@ #pragma once +#include + #include #include #include -#include #include #include #include @@ -20,7 +21,28 @@ constexpr uint32_t LinMessageMaxLength = DSVEOSCOSIM_LIN_MESSAGE_MAX_LENGTH; // constexpr uint32_t EthAddressLength = DSVEOSCOSIM_ETH_ADDRESS_LENGTH; [[nodiscard]] inline std::string SimulationTimeToString(DsVeosCoSim_SimulationTime simulationTime) { - return std::to_string(DSVEOSCOSIM_SIMULATION_TIME_TO_SECONDS(simulationTime)) + " s"; + return std::to_string(DSVEOSCOSIM_SIMULATION_TIME_TO_SECONDS(simulationTime)); +} + +[[nodiscard]] inline std::string ToString(DsVeosCoSim_Result result) { + switch (result) { + case DsVeosCoSim_Result_Ok: + return "Ok"; + case DsVeosCoSim_Result_Error: + return "Error"; + case DsVeosCoSim_Result_Empty: + return "Empty"; + case DsVeosCoSim_Result_Full: + return "Full"; + case DsVeosCoSim_Result_InvalidArgument: + return "InvalidArgument"; + case DsVeosCoSim_Result_Disconnected: + return "Disconnected"; + case DsVeosCoSim_Result_INT_MAX_SENTINEL_DO_NOT_USE_: + break; + } + + return ""; } enum class CoSimType { @@ -203,6 +225,52 @@ enum class Command { return ""; } +[[nodiscard]] inline std::string DataTypeValueToString(DsVeosCoSim_DataType dataType, + uint32_t index, + const void* value) { + switch (dataType) { + case DsVeosCoSim_DataType_Bool: + return std::to_string(static_cast(value)[index]); + case DsVeosCoSim_DataType_Int8: + return std::to_string(static_cast(value)[index]); + case DsVeosCoSim_DataType_Int16: + return std::to_string(static_cast(value)[index]); + case DsVeosCoSim_DataType_Int32: + return std::to_string(static_cast(value)[index]); + case DsVeosCoSim_DataType_Int64: + return std::to_string(static_cast(value)[index]); + case DsVeosCoSim_DataType_UInt8: + return std::to_string(static_cast(value)[index]); + case DsVeosCoSim_DataType_UInt16: + return std::to_string(static_cast(value)[index]); + case DsVeosCoSim_DataType_UInt32: + return std::to_string(static_cast(value)[index]); + case DsVeosCoSim_DataType_UInt64: + return std::to_string(static_cast(value)[index]); + case DsVeosCoSim_DataType_Float32: + return std::to_string(static_cast(value)[index]); + case DsVeosCoSim_DataType_Float64: + return std::to_string(static_cast(value)[index]); + case DsVeosCoSim_DataType_INT_MAX_SENTINEL_DO_NOT_USE_: + break; + } + + throw std::runtime_error("Invalid data type."); +} + +[[nodiscard]] inline std::string ValueToString(DsVeosCoSim_DataType dataType, uint32_t length, const void* value) { + std::ostringstream oss; + for (uint32_t i = 0; i < length; i++) { + if (i > 0) { + oss << " "; + } + + oss << DataTypeValueToString(dataType, i, value); + } + + return oss.str(); +} + [[nodiscard]] inline std::string ToString(DsVeosCoSim_LinControllerType type) { switch (type) { case DsVeosCoSim_LinControllerType_Responder: @@ -217,10 +285,28 @@ enum class Command { } enum class SimulationState { + Unloaded, + Stopped, + Running, + Paused, + Terminated }; [[nodiscard]] inline std::string ToString([[maybe_unused]] SimulationState simulationState) { - return ""; + switch (simulationState) { + case SimulationState::Unloaded: + return "Unloaded"; + case SimulationState::Stopped: + return "Stopped"; + case SimulationState::Running: + return "Running"; + case SimulationState::Paused: + return "Paused"; + case SimulationState::Terminated: + return "Terminated"; + } + + return ""; } enum class Mode { @@ -357,6 +443,14 @@ enum class Mode { return oss.str(); } +[[nodiscard]] inline std::string IoDataToString(DsVeosCoSim_SimulationTime simulationTime, + const DsVeosCoSim_IoSignal& ioSignal, + uint32_t length, + const void* value) { + return DsVeosCoSim_SimulationTimeToString(simulationTime) + "," + ioSignal.name + "," + + std::to_string(length) + "," + DsVeosCoSim_ValueToString(ioSignal.dataType, length, value); +} + struct IoSignal { DsVeosCoSim_IoSignalId id{}; uint32_t length{}; @@ -375,7 +469,7 @@ struct IoSignal { } }; -[[nodiscard]] inline std::string ToString(const IoSignal& signal) { +[[nodiscard]] inline std::string ToString(const DsVeosCoSim_IoSignal& signal) { std::string str = "{Id: " + std::to_string(signal.id) + ", Length: " + std::to_string(signal.length) + ", DataType: " + ToString(signal.dataType) + ", SizeKind: " + ToString(signal.sizeKind) + ", Name: \"" + signal.name + "\"}"; @@ -413,6 +507,14 @@ struct IoSignal { return ioSignals; } +[[nodiscard]] inline std::string CanMessageToString(DsVeosCoSim_SimulationTime simulationTime, + const DsVeosCoSim_CanController& controller, + const DsVeosCoSim_CanMessage& message) { + return DsVeosCoSim_SimulationTimeToString(simulationTime) + "," + controller.name + "," + + std::to_string(message.id) + "," + std::to_string(message.length) + "," + + DataToString(message.data, message.length, '-') + ",CAN," + CanMessageFlagsToString(message.flags); +} + struct CanController { DsVeosCoSim_BusControllerId id{}; uint32_t queueSize{}; @@ -435,7 +537,7 @@ struct CanController { } }; -[[nodiscard]] inline std::string ToString(const CanController& controller) { +[[nodiscard]] inline std::string ToString(const DsVeosCoSim_CanController& controller) { std::string str = "{Id: " + std::to_string(controller.id) + ", QueueSize: " + std::to_string(controller.queueSize) + ", BitsPerSecond: " + std::to_string(controller.bitsPerSecond) + ", FlexibleDataRateBitsPerSecond: " + std::to_string(controller.flexibleDataRateBitsPerSecond) + @@ -475,6 +577,28 @@ struct CanController { return canControllers; } +[[nodiscard]] inline std::string EthMessageToString(DsVeosCoSim_SimulationTime simulationTime, + const DsVeosCoSim_EthController& controller, + const DsVeosCoSim_EthMessage& message) { + const uint8_t* data = message.data; + const uint32_t length = message.length; + + if (length >= 14) { + const std::string macAddress1 = DataToString(message.data, 6, ':'); + const std::string macAddress2 = DataToString(message.data + 6, 6, ':'); + const std::string ethernetType = DataToString(message.data + 12, 2); + + return DsVeosCoSim_SimulationTimeToString(simulationTime) + "," + controller.name + "," + + macAddress2 + "-" + macAddress1 + "," + std::to_string(length - 14) + "," + + DataToString(data + 14, length - 14, '-') + ",ETH," + ethernetType + "," + + EthMessageFlagsToString(message.flags); + } + + return DsVeosCoSim_SimulationTimeToString(simulationTime) + "," + controller.name + "," + + std::to_string(length) + "," + DataToString(data, length, '-') + ",ETH," + + EthMessageFlagsToString(message.flags); +} + struct EthController { DsVeosCoSim_BusControllerId id{}; uint32_t queueSize{}; @@ -497,10 +621,10 @@ struct EthController { } }; -[[nodiscard]] inline std::string ToString(const EthController& controller) { +[[nodiscard]] inline std::string ToString(const DsVeosCoSim_EthController& controller) { std::string str = "{Id: " + std::to_string(controller.id) + ", QueueSize: " + std::to_string(controller.queueSize) + ", BitsPerSecond: " + std::to_string(controller.bitsPerSecond) + ", MacAddress: [" + - DataToString(controller.macAddress.data(), controller.macAddress.size(), ':') + "], Name: \"" + + DataToString(controller.macAddress, sizeof(controller.macAddress), ':') + "], Name: \"" + controller.name + "\", ChannelName: \"" + controller.channelName + "\", ClusterName: \"" + controller.clusterName + "\"}"; @@ -537,6 +661,14 @@ struct EthController { return ethControllers; } +[[nodiscard]] inline std::string LinMessageToString(DsVeosCoSim_SimulationTime simulationTime, + const DsVeosCoSim_LinController& controller, + const DsVeosCoSim_LinMessage& message) { + return DsVeosCoSim_SimulationTimeToString(simulationTime) + "," + controller.name + "," + + std::to_string(message.id) + "," + std::to_string(message.length) + "," + + DataToString(message.data, message.length, '-') + ",LIN," + LinMessageFlagsToString(message.flags); +} + struct LinController { DsVeosCoSim_BusControllerId id{}; uint32_t queueSize{}; @@ -559,7 +691,7 @@ struct LinController { } }; -[[nodiscard]] inline std::string ToString(const LinController& controller) { +[[nodiscard]] inline std::string ToString(const DsVeosCoSim_LinController& controller) { std::string str = "{Id: " + std::to_string(controller.id) + ", QueueSize: " + std::to_string(controller.queueSize) + ", BitsPerSecond: " + std::to_string(controller.bitsPerSecond) + ", Type: " + ToString(controller.type) + ", Name: \"" + controller.name + "\", ChannelName: \"" + diff --git a/src/DsVeosCoSim.cpp b/src/DsVeosCoSim.cpp index 5ce6b08..286a57c 100644 --- a/src/DsVeosCoSim.cpp +++ b/src/DsVeosCoSim.cpp @@ -491,7 +491,171 @@ DsVeosCoSim_Result DsVeosCoSim_TransmitLinMessage(DsVeosCoSim_Handle handle, con } } -#ifdef __cplusplus +DsVeosCoSim_Result DsVeosCoSim_StartSimulation(DsVeosCoSim_Handle handle) { + CheckNotNull(handle); + + auto* const client = static_cast(handle); + + try { + client->Start(); + + return DsVeosCoSim_Result_Ok; + } catch (const std::exception& e) { + LogError(e.what()); + + return DsVeosCoSim_Result_Error; + } +} + +DsVeosCoSim_Result DsVeosCoSim_StopSimulation(DsVeosCoSim_Handle handle) { + CheckNotNull(handle); + + auto* const client = static_cast(handle); + + try { + client->Stop(); + + return DsVeosCoSim_Result_Ok; + } catch (const std::exception& e) { + LogError(e.what()); + + return DsVeosCoSim_Result_Error; + } +} + +DsVeosCoSim_Result DsVeosCoSim_PauseSimulation(DsVeosCoSim_Handle handle) { + CheckNotNull(handle); + + auto* const client = static_cast(handle); + + try { + client->Pause(); + + return DsVeosCoSim_Result_Ok; + } catch (const std::exception& e) { + LogError(e.what()); + + return DsVeosCoSim_Result_Error; + } +} + +DsVeosCoSim_Result DsVeosCoSim_ContinueSimulation(DsVeosCoSim_Handle handle) { + CheckNotNull(handle); + + auto* const client = static_cast(handle); + + try { + client->Continue(); + + return DsVeosCoSim_Result_Ok; + } catch (const std::exception& e) { + LogError(e.what()); + + return DsVeosCoSim_Result_Error; + } +} + +DsVeosCoSim_Result DsVeosCoSim_TerminateSimulation(DsVeosCoSim_Handle handle, + DsVeosCoSim_TerminateReason terminateReason) { + CheckNotNull(handle); + + auto* const client = static_cast(handle); + + try { + client->Terminate(terminateReason); + + return DsVeosCoSim_Result_Ok; + } catch (const std::exception& e) { + LogError(e.what()); + + return DsVeosCoSim_Result_Error; + } +} + +std::string DsVeosCoSim_SimulationTimeToString(DsVeosCoSim_SimulationTime simulationTime) { + return SimulationTimeToString(simulationTime); +} + +std::string DsVeosCoSim_ResultToString(DsVeosCoSim_Result result) { + return ToString(result); +} + +std::string DsVeosCoSim_CommandToString(DsVeosCoSim_Command command) { + return ToString(static_cast(command)); +} + +std::string DsVeosCoSim_SeverityToString(DsVeosCoSim_Severity severity) { + return ToString(severity); +} + +std::string DsVeosCoSim_TerminateReasonToString(DsVeosCoSim_TerminateReason terminateReason) { + return ToString(terminateReason); +} + +std::string DsVeosCoSim_ConnectionStateToString(DsVeosCoSim_ConnectionState connectionState) { + return ToString(connectionState); +} + +std::string DsVeosCoSim_DataTypeToString(DsVeosCoSim_DataType dataType) { + return ToString(dataType); +} + +std::string DsVeosCoSim_SizeKindToString(DsVeosCoSim_SizeKind sizeKind) { + return ToString(sizeKind); +} + +std::string DsVeosCoSim_IoSignalToString(const DsVeosCoSim_IoSignal& ioSignal) { + return ToString(ioSignal); +} + +std::string DsVeosCoSim_CanControllerToString(const DsVeosCoSim_CanController& controller) { + return ToString(controller); +} + +std::string DsVeosCoSim_EthControllerToString(const DsVeosCoSim_EthController& controller) { + return ToString(controller); +} + +std::string DsVeosCoSim_LinControllerToString(const DsVeosCoSim_LinController& controller) { + return ToString(controller); +} + +std::string DsVeosCoSim_ValueToString(DsVeosCoSim_DataType dataType, uint32_t length, const void* value) { + return ValueToString(dataType, length, value); +} + +std::string DsVeosCoSim_DataToString(const uint8_t* data, size_t dataLength, char separator) { + return DataToString(data, dataLength, separator); +} + +std::string DsVeosCoSim_IoDataToString(DsVeosCoSim_SimulationTime simulationTime, + const DsVeosCoSim_IoSignal& ioSignal, + uint32_t length, + const void* value) { + return IoDataToString(simulationTime, ioSignal, length, value); +} + +std::string DsVeosCoSim_CanMessageToString(DsVeosCoSim_SimulationTime simulationTime, + const DsVeosCoSim_CanController& controller, + const DsVeosCoSim_CanMessage& message) { + return CanMessageToString(simulationTime, controller, message); +} + +std::string DsVeosCoSim_EthMessageToString(DsVeosCoSim_SimulationTime simulationTime, + const DsVeosCoSim_EthController& controller, + const DsVeosCoSim_EthMessage& message) { + return EthMessageToString(simulationTime, controller, message); +} + +std::string DsVeosCoSim_LinMessageToString(DsVeosCoSim_SimulationTime simulationTime, + const DsVeosCoSim_LinController& controller, + const DsVeosCoSim_LinMessage& message) { + return LinMessageToString(simulationTime, controller, message); +} + +std::string DsVeosCoSim_LinControllerTypeToString(DsVeosCoSim_LinControllerType linControllerType) { + return ToString(linControllerType); +} std::string DsVeosCoSim_CanMessageFlagsToString(DsVeosCoSim_CanMessageFlags flags) { return CanMessageFlagsToString(flags); @@ -505,4 +669,6 @@ std::string DsVeosCoSim_LinMessageFlagsToString(DsVeosCoSim_LinMessageFlags flag return LinMessageFlagsToString(flags); } -#endif +size_t DsVeosCoSim_GetDataTypeSize(DsVeosCoSim_DataType dataType) { + return GetDataTypeSize(dataType); +} diff --git a/src/Helpers/CoSimHelper.h b/src/Helpers/CoSimHelper.h index 71aae67..8e16a15 100644 --- a/src/Helpers/CoSimHelper.h +++ b/src/Helpers/CoSimHelper.h @@ -21,17 +21,17 @@ void LogProtocolEndTrace(const std::string& message); #define CheckResultWithMessage(result, message) \ do { \ - if (!(result)) [[unlikely]] { \ + if (!(result)) { \ LogTrace(message); \ return false; \ } \ } while (0) -#define CheckResult(result) \ - do { \ - if (!(result)) [[unlikely]] { \ - return false; \ - } \ +#define CheckResult(result) \ + do { \ + if (!(result)) { \ + return false; \ + } \ } while (0) [[nodiscard]] std::string GetSystemErrorMessage(int32_t errorCode); diff --git a/src/IoBuffer.cpp b/src/IoBuffer.cpp index 9c40c4b..2c634af 100644 --- a/src/IoBuffer.cpp +++ b/src/IoBuffer.cpp @@ -40,7 +40,7 @@ IoPartBufferBase::IoPartBufferBase(CoSimType coSimType, const std::vector #else #include -#include #include #include #include @@ -29,6 +28,7 @@ #include #include #include +#include #endif #ifdef _WIN32 @@ -702,7 +702,7 @@ void Socket::Listen() const { receivedSize = static_cast(::recv(_socket, destination, size, MSG_NOSIGNAL)); #endif - if (receivedSize > 0) [[likely]] { + if (receivedSize > 0) { return true; } @@ -733,7 +733,7 @@ void Socket::Listen() const { sentSize = static_cast(::send(_socket, source, size, MSG_NOSIGNAL)); #endif - if (sentSize > 0) [[likely]] { + if (sentSize > 0) { return true; } @@ -758,7 +758,7 @@ void Socket::Listen() const { } void Socket::EnsureIsValid() const { - if (!IsValid()) [[unlikely]] { + if (!IsValid()) { throw CoSimException("Socket is not valid."); } } diff --git a/src/Protocol.cpp b/src/Protocol.cpp index df27227..55c58e3 100644 --- a/src/Protocol.cpp +++ b/src/Protocol.cpp @@ -2,7 +2,6 @@ #include "Protocol.h" -#include #include #include @@ -375,7 +374,7 @@ namespace Protocol { #ifdef DSVEOSCOSIM_ENABLE_TRACING LogProtocolBeginTrace( "SendConnectOk(ProtocolVersion: " + std::to_string(protocolVersion) + ", ClientMode: " + ToString(clientMode) + - ", StepSize: " + SimulationTimeToString(stepSize) + ", SimulationState: " + ToString(simulationState) + + ", StepSize: " + SimulationTimeToString(stepSize) + " s, SimulationState: " + ToString(simulationState) + ", IncomingSignals: " + ToString(incomingSignals) + ", OutgoingSignals: " + ToString(outgoingSignals) + ", CanControllers: " + ToString(canControllers) + ", EthControllers: " + ToString(ethControllers) + ", LinControllers: " + ToString(linControllers) + ")"); @@ -427,7 +426,7 @@ namespace Protocol { #ifdef DSVEOSCOSIM_ENABLE_TRACING LogProtocolEndTrace( "ReadConnectOk(ProtocolVersion: " + std::to_string(protocolVersion) + ", ClientMode: " + ToString(clientMode) + - ", StepSize: " + SimulationTimeToString(stepSize) + ", SimulationState: " + ToString(simulationState) + + ", StepSize: " + SimulationTimeToString(stepSize) + " s, SimulationState: " + ToString(simulationState) + ", IncomingSignals: " + ToString(incomingSignals) + ", OutgoingSignals: " + ToString(outgoingSignals) + ", CanControllers: " + ToString(canControllers) + ", EthControllers: " + ToString(ethControllers) + ", LinControllers: " + ToString(linControllers) + ")"); @@ -438,7 +437,7 @@ namespace Protocol { [[nodiscard]] bool SendStart(ChannelWriter& writer, DsVeosCoSim_SimulationTime simulationTime) { #ifdef DSVEOSCOSIM_ENABLE_TRACING - LogProtocolBeginTrace("SendStart(SimulationTime: " + SimulationTimeToString(simulationTime) + ")"); + LogProtocolBeginTrace("SendStart(SimulationTime: " + SimulationTimeToString(simulationTime) + " s)"); #endif CheckResult(WriteHeader(writer, FrameKind::Start)); @@ -460,7 +459,7 @@ namespace Protocol { CheckResultWithMessage(reader.Read(simulationTime), "Could not read simulation time."); #ifdef DSVEOSCOSIM_ENABLE_TRACING - LogProtocolEndTrace("ReadStart(SimulationTime: " + SimulationTimeToString(simulationTime) + ")"); + LogProtocolEndTrace("ReadStart(SimulationTime: " + SimulationTimeToString(simulationTime) + " s)"); #endif return true; @@ -468,7 +467,7 @@ namespace Protocol { [[nodiscard]] bool SendStop(ChannelWriter& writer, DsVeosCoSim_SimulationTime simulationTime) { #ifdef DSVEOSCOSIM_ENABLE_TRACING - LogProtocolBeginTrace("SendStop(SimulationTime: " + SimulationTimeToString(simulationTime) + ")"); + LogProtocolBeginTrace("SendStop(SimulationTime: " + SimulationTimeToString(simulationTime) + " s)"); #endif CheckResult(WriteHeader(writer, FrameKind::Stop)); @@ -490,7 +489,7 @@ namespace Protocol { CheckResultWithMessage(reader.Read(simulationTime), "Could not read simulation time."); #ifdef DSVEOSCOSIM_ENABLE_TRACING - LogProtocolEndTrace("ReadStop(SimulationTime: " + SimulationTimeToString(simulationTime) + ")"); + LogProtocolEndTrace("ReadStop(SimulationTime: " + SimulationTimeToString(simulationTime) + " s)"); #endif return true; @@ -501,7 +500,7 @@ namespace Protocol { DsVeosCoSim_TerminateReason reason) { #ifdef DSVEOSCOSIM_ENABLE_TRACING LogProtocolBeginTrace("SendTerminate(SimulationTime: " + SimulationTimeToString(simulationTime) + - ", Reason: " + ToString(reason) + ")"); + " s, Reason: " + ToString(reason) + ")"); #endif CheckResult(WriteHeader(writer, FrameKind::Terminate)); @@ -528,7 +527,7 @@ namespace Protocol { #ifdef DSVEOSCOSIM_ENABLE_TRACING LogProtocolEndTrace("ReadTerminate(SimulationTime: " + SimulationTimeToString(simulationTime) + - ", Reason: " + ToString(reason) + ")"); + " s, Reason: " + ToString(reason) + ")"); #endif return true; @@ -536,7 +535,7 @@ namespace Protocol { [[nodiscard]] bool SendPause(ChannelWriter& writer, DsVeosCoSim_SimulationTime simulationTime) { #ifdef DSVEOSCOSIM_ENABLE_TRACING - LogProtocolBeginTrace("SendPause(SimulationTime: " + SimulationTimeToString(simulationTime) + ")"); + LogProtocolBeginTrace("SendPause(SimulationTime: " + SimulationTimeToString(simulationTime) + " s)"); #endif CheckResult(WriteHeader(writer, FrameKind::Pause)); @@ -558,7 +557,7 @@ namespace Protocol { CheckResultWithMessage(reader.Read(simulationTime), "Could not read simulation time."); #ifdef DSVEOSCOSIM_ENABLE_TRACING - LogProtocolEndTrace("ReadPause(SimulationTime: " + SimulationTimeToString(simulationTime) + ")"); + LogProtocolEndTrace("ReadPause(SimulationTime: " + SimulationTimeToString(simulationTime) + " s)"); #endif return true; @@ -566,7 +565,7 @@ namespace Protocol { [[nodiscard]] bool SendContinue(ChannelWriter& writer, DsVeosCoSim_SimulationTime simulationTime) { #ifdef DSVEOSCOSIM_ENABLE_TRACING - LogProtocolBeginTrace("SendContinue(SimulationTime: " + SimulationTimeToString(simulationTime) + ")"); + LogProtocolBeginTrace("SendContinue(SimulationTime: " + SimulationTimeToString(simulationTime) + " s)"); #endif CheckResult(WriteHeader(writer, FrameKind::Continue)); @@ -588,7 +587,7 @@ namespace Protocol { CheckResultWithMessage(reader.Read(simulationTime), "Could not read simulation time."); #ifdef DSVEOSCOSIM_ENABLE_TRACING - LogProtocolEndTrace("SendStep(SimulationTime: " + SimulationTimeToString(simulationTime) + ")"); + LogProtocolEndTrace("SendStep(SimulationTime: " + SimulationTimeToString(simulationTime) + " s)"); #endif return true; @@ -599,7 +598,7 @@ namespace Protocol { const IoBuffer& ioBuffer, const BusBuffer& busBuffer) { #ifdef DSVEOSCOSIM_ENABLE_TRACING - LogProtocolBeginTrace("SendStep(SimulationTime: " + SimulationTimeToString(simulationTime) + ")"); + LogProtocolBeginTrace("SendStep(SimulationTime: " + SimulationTimeToString(simulationTime) + " s)"); #endif CheckResult(WriteHeader(writer, FrameKind::Step)); @@ -634,7 +633,7 @@ namespace Protocol { CheckResultWithMessage(busBuffer.Deserialize(reader, simulationTime, callbacks), "Could not read bus buffer data."); #ifdef DSVEOSCOSIM_ENABLE_TRACING - LogProtocolEndTrace("ReadStep(SimulationTime: " + SimulationTimeToString(simulationTime) + ")"); + LogProtocolEndTrace("ReadStep(SimulationTime: " + SimulationTimeToString(simulationTime) + " s)"); #endif return true; @@ -647,7 +646,7 @@ namespace Protocol { const BusBuffer& busBuffer) { #ifdef DSVEOSCOSIM_ENABLE_TRACING LogProtocolBeginTrace("SendStepOk(NextSimulationTime: " + SimulationTimeToString(nextSimulationTime) + - ", Command: " + ToString(command) + ")"); + " s, Command: " + ToString(command) + ")"); #endif CheckResult(WriteHeader(writer, FrameKind::StepOk)); @@ -688,7 +687,7 @@ namespace Protocol { #ifdef DSVEOSCOSIM_ENABLE_TRACING LogProtocolEndTrace("ReadStepOk(NextSimulationTime: " + SimulationTimeToString(nextSimulationTime) + - ", Command: " + ToString(command) + ")"); + " s, Command: " + ToString(command) + ")"); #endif return true; @@ -818,6 +817,4 @@ namespace Protocol { } // namespace Protocol -static_assert(std::endian::native == std::endian::little, "Only supported on little endian platforms."); - } // namespace DsVeosCoSim diff --git a/test/Communication/TestLocalChannel.cpp b/test/Communication/TestLocalChannel.cpp index d23c6a6..0d7e6c4 100644 --- a/test/Communication/TestLocalChannel.cpp +++ b/test/Communication/TestLocalChannel.cpp @@ -38,7 +38,9 @@ TEST_F(TestLocalChannel, ConnectWithoutStart) { // Arrange const std::string name = GenerateName(); - { LocalChannelServer server(name); } + { + LocalChannelServer server(name); + } // Act std::optional connectedChannel = TryConnectToLocalChannel(name); @@ -221,7 +223,7 @@ TEST_F(TestLocalChannel, Stream) { LocalChannel connectedChannel = ConnectToLocalChannel(name); LocalChannel acceptedChannel = Accept(server); - std::jthread thread(StreamClient, std::ref(connectedChannel)); + std::thread thread(StreamClient, std::ref(connectedChannel)); // Act and assert for (uint32_t i = 0; i < BigNumber; i++) { @@ -229,6 +231,8 @@ TEST_F(TestLocalChannel, Stream) { } ASSERT_TRUE(acceptedChannel.GetWriter().EndWrite()); + + thread.join(); } void ReceiveBigElement(LocalChannel& channel) { @@ -249,7 +253,7 @@ TEST_F(TestLocalChannel, SendAndReceiveBigElement) { LocalChannel connectedChannel = ConnectToLocalChannel(name); LocalChannel acceptedChannel = Accept(server); - std::jthread thread(ReceiveBigElement, std::ref(connectedChannel)); + std::thread thread(ReceiveBigElement, std::ref(connectedChannel)); const auto sendArray = std::make_unique>(); for (size_t i = 0; i < sendArray->size(); i++) { @@ -259,6 +263,8 @@ TEST_F(TestLocalChannel, SendAndReceiveBigElement) { // Act and assert ASSERT_TRUE(acceptedChannel.GetWriter().Write(sendArray.get(), sendArray->size() * 4)); ASSERT_TRUE(acceptedChannel.GetWriter().EndWrite()); + + thread.join(); } } // namespace diff --git a/test/Communication/TestTcpChannel.cpp b/test/Communication/TestTcpChannel.cpp index e59791b..b40f6ec 100644 --- a/test/Communication/TestTcpChannel.cpp +++ b/test/Communication/TestTcpChannel.cpp @@ -328,7 +328,7 @@ TEST_P(TestTcpChannel, Stream) { SocketChannel connectedChannel = ConnectToTcpChannel(ipAddress, port); SocketChannel acceptedChannel = Accept(server); - std::jthread thread(StreamClient, std::ref(connectedChannel)); + std::thread thread(StreamClient, std::ref(connectedChannel)); // Act and assert for (uint32_t i = 0; i < BigNumber; i++) { @@ -336,6 +336,8 @@ TEST_P(TestTcpChannel, Stream) { } ASSERT_TRUE(acceptedChannel.GetWriter().EndWrite()); + + thread.join(); } void ReceiveBigElement(SocketChannel& channel) { @@ -358,7 +360,7 @@ TEST_P(TestTcpChannel, SendAndReceiveBigElement) { SocketChannel connectedChannel = ConnectToTcpChannel(ipAddress, port); SocketChannel acceptedChannel = Accept(server); - std::jthread thread(ReceiveBigElement, std::ref(connectedChannel)); + std::thread thread(ReceiveBigElement, std::ref(connectedChannel)); const auto sendArray = std::make_unique>(); for (size_t i = 0; i < sendArray->size(); i++) { @@ -368,6 +370,8 @@ TEST_P(TestTcpChannel, SendAndReceiveBigElement) { // Act and assert ASSERT_TRUE(acceptedChannel.GetWriter().Write(sendArray.get(), sendArray->size() * 4)); ASSERT_TRUE(acceptedChannel.GetWriter().EndWrite()); + + thread.join(); } } // namespace diff --git a/test/Communication/TestUdsChannel.cpp b/test/Communication/TestUdsChannel.cpp index f1924fd..7d24e13 100644 --- a/test/Communication/TestUdsChannel.cpp +++ b/test/Communication/TestUdsChannel.cpp @@ -36,7 +36,9 @@ TEST_F(TestUdsChannel, ConnectWithoutStart) { // Arrange std::string name = GenerateName(); - { UdsChannelServer server(name); } + { + UdsChannelServer server(name); + } // Act std::optional connectedChannel = TryConnectToUdsChannel(name); @@ -219,7 +221,7 @@ TEST_F(TestUdsChannel, Stream) { SocketChannel connectedChannel = ConnectToUdsChannel(name); SocketChannel acceptedChannel = Accept(server); - std::jthread thread(StreamClient, std::ref(connectedChannel)); + std::thread thread(StreamClient, std::ref(connectedChannel)); // Act and assert for (uint32_t i = 0; i < BigNumber; i++) { @@ -227,6 +229,8 @@ TEST_F(TestUdsChannel, Stream) { } ASSERT_TRUE(acceptedChannel.GetWriter().EndWrite()); + + thread.join(); } void ReceiveBigElement(SocketChannel& channel) { @@ -247,7 +251,7 @@ TEST_F(TestUdsChannel, SendAndReceiveBigElement) { SocketChannel connectedChannel = ConnectToUdsChannel(name); SocketChannel acceptedChannel = Accept(server); - std::jthread thread(ReceiveBigElement, std::ref(connectedChannel)); + std::thread thread(ReceiveBigElement, std::ref(connectedChannel)); const auto sendArray = std::make_unique>(); for (size_t i = 0; i < sendArray->size(); i++) { @@ -257,6 +261,8 @@ TEST_F(TestUdsChannel, SendAndReceiveBigElement) { // Act and assert ASSERT_TRUE(acceptedChannel.GetWriter().Write(sendArray.get(), sendArray->size() * 4)); ASSERT_TRUE(acceptedChannel.GetWriter().EndWrite()); + + thread.join(); } } // namespace diff --git a/test/OsAbstraction/TestNamedEvent.cpp b/test/OsAbstraction/TestNamedEvent.cpp index d8cb4ab..d7f6412 100644 --- a/test/OsAbstraction/TestNamedEvent.cpp +++ b/test/OsAbstraction/TestNamedEvent.cpp @@ -185,13 +185,16 @@ TEST_F(TestNamedEvent, SetAndWaitInDifferentThreads) { NamedEvent event1 = NamedEvent::CreateOrOpen(firstName); NamedEvent event2 = NamedEvent::CreateOrOpen(secondName); - std::jthread thread(WaitAndSet, firstName, secondName); + std::thread thread(WaitAndSet, firstName, secondName); // Act ASSERT_NO_THROW(event1.Set()); ASSERT_NO_THROW(event2.Wait()); // Assert + + // Cleanup + thread.join(); } } // namespace diff --git a/test/TestBusBuffer.cpp b/test/TestBusBuffer.cpp index 497c3ac..4076784 100644 --- a/test/TestBusBuffer.cpp +++ b/test/TestBusBuffer.cpp @@ -1,9 +1,9 @@ // Copyright dSPACE GmbH. All rights reserved. +#include #include #include #include -#include #include #include #include @@ -59,12 +59,14 @@ void Transfer(ConnectionKind connectionKind, BusBuffer& senderBusBuffer, BusBuff #endif } - std::jthread thread([&] { + std::thread thread([&] { ASSERT_TRUE(receiverBusBuffer.Deserialize(receiverChannel->GetReader(), {}, {})); }); ASSERT_TRUE(senderBusBuffer.Serialize(senderChannel->GetWriter())); ASSERT_TRUE(senderChannel->GetWriter().EndWrite()); + + thread.join(); } template diff --git a/test/TestCoSim.cpp b/test/TestCoSim.cpp index 51b9c4b..281a28c 100644 --- a/test/TestCoSim.cpp +++ b/test/TestCoSim.cpp @@ -4,7 +4,6 @@ #include #include -#include "BackgroundService.h" #include "CoSimClient.h" #include "CoSimServer.h" #include "CoSimTypes.h" @@ -15,6 +14,41 @@ using namespace DsVeosCoSim; namespace { +class BackgroundThread final { +public: + explicit BackgroundThread(DsVeosCoSim::CoSimServer& coSimServer) : _coSimServer(coSimServer) { + _thread = std::thread([this] { + while (!_stopEvent.Wait(1)) { + try { + _coSimServer.BackgroundService(); + } catch (const std::exception& e) { + LogError(e.what()); + } + } + }); + } + + ~BackgroundThread() noexcept { + _stopEvent.Set(); + if (std::this_thread::get_id() == _thread.get_id()) { + _thread.detach(); + } else { + _thread.join(); + } + } + + BackgroundThread(const BackgroundThread&) = delete; + BackgroundThread& operator=(const BackgroundThread&) = delete; + + BackgroundThread(BackgroundThread&&) = delete; + BackgroundThread& operator=(BackgroundThread&&) = delete; + +private: + DsVeosCoSim::CoSimServer& _coSimServer; + DsVeosCoSim::Event _stopEvent; + std::thread _thread; +}; + auto connectionKinds = testing::Values(ConnectionKind::Local, ConnectionKind::Remote); [[nodiscard]] CoSimServerConfig CreateServerConfig(bool isClientOptional = false) { @@ -187,7 +221,7 @@ TEST_P(TestCoSim, ConnectToServerWithOptionalClient) { CoSimServer server; server.Load(config); - BackgroundService backgroundService(server); + BackgroundThread backgroundThread(server); uint16_t port = server.GetLocalPort(); @@ -207,7 +241,7 @@ TEST_P(TestCoSim, ConnectToServerWithMandatoryClient) { CoSimServer server; server.Load(config); - BackgroundService backgroundService(server); + BackgroundThread backgroundThread(server); uint16_t port = server.GetLocalPort(); @@ -232,7 +266,7 @@ TEST_P(TestCoSim, DisconnectFromServerWithMandatoryClient) { CoSimServer server; server.Load(config); - BackgroundService backgroundService(server); + BackgroundThread backgroundThread(server); uint16_t port = server.GetLocalPort(); diff --git a/test/TestIoBuffer.cpp b/test/TestIoBuffer.cpp index 6c74045..f71ee66 100644 --- a/test/TestIoBuffer.cpp +++ b/test/TestIoBuffer.cpp @@ -1,9 +1,8 @@ // Copyright dSPACE GmbH. All rights reserved. -#include #include + #include -#include #include #include @@ -19,11 +18,9 @@ using namespace DsVeosCoSim; using namespace testing; -namespace { - auto coSimTypes = testing::Values(CoSimType::Client, CoSimType::Server); -auto connectionKinds = testing::Values(ConnectionKind::Local, ConnectionKind::Remote); +auto ioBufferConnectionKinds = testing::Values(ConnectionKind::Local, ConnectionKind::Remote); auto dataTypes = testing::Values(DsVeosCoSim_DataType_Bool, DsVeosCoSim_DataType_Int8, @@ -44,12 +41,14 @@ void Transfer(IoBuffer& writerIoBuffer, IoBuffer& readerIoBuffer) { SocketChannel senderChannel = ConnectToTcpChannel("127.0.0.1", port); SocketChannel receiverChannel = Accept(server); - std::jthread thread([&] { + std::thread thread([&] { ASSERT_TRUE(readerIoBuffer.Deserialize(receiverChannel.GetReader(), GenerateI64(), {})); }); ASSERT_TRUE(writerIoBuffer.Serialize(senderChannel.GetWriter())); ASSERT_TRUE(senderChannel.GetWriter().EndWrite()); + + thread.join(); } struct EventData { @@ -109,7 +108,7 @@ class TestIoBufferWithCoSimType : public testing::TestWithParam>& info) { return fmt::format("{}_{}", ToString(std::get<0>(info.param)), @@ -136,7 +135,7 @@ class TestIoBuffer : public testing::TestWithParam>& info) { return fmt::format("{}_{}_{}", ToString(std::get<0>(info.param)), @@ -176,103 +175,6 @@ TEST_P(TestIoBuffer, CreateWithMultipleIoSignalInfos) { {outgoingSignal1, outgoingSignal2})); } -#ifdef EXCEPTION_TESTS -TEST_P(TestIoBuffer, DuplicatedReadIds) { - // Arrange - auto [coSimType, connectionKind, dataType] = GetParam(); - - std::string name = GenerateString("IoBuffer名前"); - - IoSignal signal = CreateSignal(dataType); - - std::vector incomingSignals = {signal, signal}; - std::vector outgoingSignals; - SwitchSignals(incomingSignals, outgoingSignals, coSimType); - - // Act and assert - ASSERT_THAT( - [&]() { - IoBuffer(coSimType, connectionKind, name, incomingSignals, outgoingSignals); - }, - ThrowsMessage(fmt::format("Duplicated IO signal id {}.", signal.id))); -} -#endif - -#ifdef EXCEPTION_TESTS -TEST_P(TestIoBuffer, DuplicatedWriteIds) { - // Arrange - auto [coSimType, connectionKind, dataType] = GetParam(); - - std::string name = GenerateString("IoBuffer名前"); - - IoSignal signal = CreateSignal(dataType); - - std::vector incomingSignals; - std::vector outgoingSignals = {signal, signal}; - SwitchSignals(incomingSignals, outgoingSignals, coSimType); - - // Act and assert - ASSERT_THAT( - [&]() { - IoBuffer(coSimType, connectionKind, name, incomingSignals, outgoingSignals); - }, - ThrowsMessage(fmt::format("Duplicated IO signal id {}.", signal.id))); -} -#endif - -#ifdef EXCEPTION_TESTS -TEST_P(TestIoBuffer, ReadInvalidId) { - // Arrange - auto [coSimType, connectionKind, dataType] = GetParam(); - - std::string name = GenerateString("IoBuffer名前"); - - IoSignal signal = CreateSignal(dataType); - - std::vector incomingSignals = {signal}; - std::vector outgoingSignals; - SwitchSignals(incomingSignals, outgoingSignals, coSimType); - - IoBuffer ioBuffer(coSimType, connectionKind, name, incomingSignals, outgoingSignals); - - uint32_t readLength{}; - std::vector readValue = CreateZeroedIoData(signal); - - // Act and assert - ASSERT_THAT( - [&]() { - ioBuffer.Read(signal.id + 1, readLength, readValue.data()); - }, - ThrowsMessage(fmt::format("IO signal id {} is unknown.", signal.id + 1))); -} -#endif - -#ifdef EXCEPTION_TESTS -TEST_P(TestIoBuffer, WriteInvalidId) { - // Arrange - auto [coSimType, connectionKind, dataType] = GetParam(); - - std::string name = GenerateString("IoBuffer名前"); - - IoSignal signal = CreateSignal(dataType); - - std::vector incomingSignals; - std::vector outgoingSignals = {signal}; - SwitchSignals(incomingSignals, outgoingSignals, coSimType); - - IoBuffer ioBuffer(coSimType, connectionKind, name, incomingSignals, outgoingSignals); - - std::vector writeValue = GenerateIoData(signal); - - // Act and assert - ASSERT_THAT( - [&]() { - ioBuffer.Write(signal.id + 1, signal.length, writeValue.data()); - }, - ThrowsMessage(fmt::format("IO signal id {} is unknown.", signal.id + 1))); -} -#endif - TEST_P(TestIoBuffer, InitialDataOfFixedSizedSignal) { // Arrange auto [coSimType, connectionKind, dataType] = GetParam(); @@ -328,62 +230,6 @@ TEST_P(TestIoBuffer, InitialDataOfVariableSizedSignal) { ASSERT_EQ(expectedReadLength, readLength); } -#ifdef EXCEPTION_TESTS -TEST_P(TestIoBuffer, WriteWrongSizeForFixedSizedLength) { - // Arrange - auto [coSimType, connectionKind, dataType] = GetParam(); - - std::string name = GenerateString("IoBuffer名前"); - - IoSignal signal = CreateSignal(dataType, DsVeosCoSim_SizeKind_Fixed); - - std::vector incomingSignals; - std::vector outgoingSignals = {signal}; - SwitchSignals(incomingSignals, outgoingSignals, coSimType); - - IoBuffer ioBuffer(coSimType, connectionKind, name, incomingSignals, outgoingSignals); - - std::vector writeValue = GenerateIoData(signal); - - // Act and assert - ASSERT_THAT( - [&]() { - ioBuffer.Write(signal.id, signal.length + 1, writeValue.data()); - }, - ThrowsMessage(fmt::format("Length of fixed sized IO signal '{}' must be {} but was {}.", - signal.name, - signal.length, - signal.length + 1))); -} -#endif - -#ifdef EXCEPTION_TESTS -TEST_P(TestIoBuffer, WriteWrongVariableSizedLength) { - // Arrange - auto [coSimType, connectionKind, dataType] = GetParam(); - - std::string name = GenerateString("IoBuffer名前"); - - IoSignal signal = CreateSignal(dataType, DsVeosCoSim_SizeKind_Variable); - - std::vector incomingSignals; - std::vector outgoingSignals = {signal}; - SwitchSignals(incomingSignals, outgoingSignals, coSimType); - - IoBuffer ioBuffer(coSimType, connectionKind, name, incomingSignals, outgoingSignals); - - std::vector writeValue = GenerateIoData(signal); - - // Act and assert - ASSERT_THAT( - [&]() { - ioBuffer.Write(signal.id, signal.length + 1, writeValue.data()); - }, - ThrowsMessage( - fmt::format("Length of variable sized IO signal '{}' exceeds max size.", signal.name))); -} -#endif - TEST_P(TestIoBuffer, WriteFixedSizedData) { // Arrange auto [coSimType, connectionKind, dataType] = GetParam(); @@ -707,5 +553,3 @@ TEST_P(TestIoBuffer, NoNewEventIfVariableSizedDataDoesNotChangeWithSharedMemory) // Act and assert TransferWithEvents(writerIoBuffer, readerIoBuffer, {}); } - -} // namespace diff --git a/third_party/CMakeLists.txt b/third_party/CMakeLists.txt index 0e86938..e70d63f 100644 --- a/third_party/CMakeLists.txt +++ b/third_party/CMakeLists.txt @@ -11,10 +11,10 @@ if(DSVEOSCOSIM_BUILD_TESTS) endif() if(DSVEOSCOSIM_BUILD_BENCHMARKS) -set(BENCHMARK_ENABLE_INSTALL OFF) -set(BENCHMARK_INSTALL_DOCS OFF) -set(BENCHMARK_ENABLE_GTEST_TESTS OFF) -set(BENCHMARK_USE_BUNDLED_GTEST OFF) + set(BENCHMARK_ENABLE_INSTALL OFF) + set(BENCHMARK_INSTALL_DOCS OFF) + set(BENCHMARK_ENABLE_GTEST_TESTS OFF) + set(BENCHMARK_USE_BUNDLED_GTEST OFF) -add_subdirectory(benchmark) + add_subdirectory(benchmark) endif() diff --git a/utilities/TestClient/CMakeLists.txt b/utilities/TestClient/CMakeLists.txt index 7f06915..cd87eea 100644 --- a/utilities/TestClient/CMakeLists.txt +++ b/utilities/TestClient/CMakeLists.txt @@ -13,5 +13,5 @@ target_sources( target_link_libraries( TestClient DsVeosCoSim - shared + fmt::fmt ) diff --git a/utilities/TestClient/Program.cpp b/utilities/TestClient/Program.cpp index 55aaf5e..4da64b3 100644 --- a/utilities/TestClient/Program.cpp +++ b/utilities/TestClient/Program.cpp @@ -1,5 +1,16 @@ // Copyright dSPACE GmbH. All rights reserved. +#include + +#ifdef _WIN32 +#include +#include +#else +#include +#include +#include +#endif + #include #include #include @@ -8,181 +19,470 @@ #include #include -#include "ClientServerTestHelper.h" -#include "CoSimClient.h" -#include "CoSimHelper.h" -#include "CoSimTypes.h" -#include "Helper.h" -#include "LogHelper.h" - -using namespace DsVeosCoSim; +#include "DsVeosCoSim/DsVeosCoSim.h" namespace { -std::unique_ptr g_coSimClient; +void InitializeOutput() { +#if _WIN32 + (void)::SetConsoleOutputCP(CP_UTF8); + (void)::setvbuf(stdout, nullptr, _IONBF, 0); + + HANDLE console = ::GetStdHandle(STD_OUTPUT_HANDLE); + + DWORD dwMode = 0; + if (::GetConsoleMode(console, &dwMode) != 0) { + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + (void)::SetConsoleMode(console, dwMode); + } +#endif +} + +[[nodiscard]] int32_t GetChar() { +#ifdef _WIN32 + return _getch(); +#else + termios oldt{}; + tcgetattr(STDIN_FILENO, &oldt); + + termios newt = oldt; + newt.c_lflag &= ~(ICANON | ECHO); + + tcsetattr(STDIN_FILENO, TCSANOW, &newt); + + int32_t character = getchar(); + tcsetattr(STDIN_FILENO, TCSANOW, &oldt); + return character; +#endif +} + +#ifndef CTRL +#define CTRL(c) ((c) & 037) +#endif + +DsVeosCoSim_Handle handle; + +std::thread simulationThread; + +bool sendIoData; +bool sendCanMessages; +bool sendEthMessages; +bool sendLinMessages; + +uint32_t canControllersCount; +const DsVeosCoSim_CanController* canControllers; + +uint32_t ethControllersCount; +const DsVeosCoSim_EthController* ethControllers; + +uint32_t linControllersCount; +const DsVeosCoSim_LinController* linControllers; + +uint32_t incomingSignalsCount; +const DsVeosCoSim_IoSignal* incomingSignals; + +uint32_t outgoingSignalsCount; +const DsVeosCoSim_IoSignal* outgoingSignals; + +void OnLogCallback(DsVeosCoSim_Severity severity, const char* message) { + switch (severity) { + case DsVeosCoSim_Severity_Error: + fmt::print(fmt::fg(fmt::color::red), "{}\n", message); + break; + case DsVeosCoSim_Severity_Warning: + fmt::print(fmt::fg(fmt::color::yellow), "{}\n", message); + break; + case DsVeosCoSim_Severity_Info: + fmt::print(fmt::fg(fmt::color::white), "{}\n", message); + break; + case DsVeosCoSim_Severity_Trace: + fmt::print(fmt::fg(fmt::color::light_gray), "{}\n", message); + break; + case DsVeosCoSim_Severity_INT_MAX_SENTINEL_DO_NOT_USE_: + break; + } +} + +void LogError(std::string_view message) { + OnLogCallback(DsVeosCoSim_Severity_Error, message.data()); +} + +void LogInfo(std::string_view message) { + OnLogCallback(DsVeosCoSim_Severity_Info, message.data()); +} + +void LogTrace(std::string_view message) { + OnLogCallback(DsVeosCoSim_Severity_Trace, message.data()); +} + +#define CheckResult(expression) \ + do { \ + DsVeosCoSim_Result _result = expression; \ + if (_result != DsVeosCoSim_Result_Ok) { \ + return _result; \ + } \ + } while (0) + +#define CheckResultWithMessage(expression, message) \ + do { \ + DsVeosCoSim_Result _result = expression; \ + if (_result != DsVeosCoSim_Result_Ok) { \ + LogTrace(message); \ + return _result; \ + } \ + } while (0) + +void PrintStatus(bool value, const std::string& what) { + if (value) { + LogInfo("Enabled sending " + what); + } else { + LogInfo("Disabled sending " + what); + } +} + +void SwitchSendingIoSignals() { + sendIoData = !sendIoData; + PrintStatus(sendIoData, "IO data"); +} + +void SwitchSendingCanMessages() { + sendCanMessages = !sendCanMessages; + PrintStatus(sendCanMessages, "CAN messages"); +} + +void SwitchSendingEthMessages() { + sendEthMessages = !sendEthMessages; + PrintStatus(sendEthMessages, "ETH messages"); +} + +void SwitchSendingLinMessages() { + sendLinMessages = !sendLinMessages; + PrintStatus(sendLinMessages, "LIN messages"); +} + +[[nodiscard]] int32_t Random(int32_t min, int32_t max) { + static bool first = true; + if (first) { + srand(21); + first = false; + } + + const int32_t diff = max + 1 - min; + + return min + rand() % diff; +} + +[[nodiscard]] uint32_t GenerateU32(uint32_t min, uint32_t max) { + return static_cast(Random(static_cast(min), static_cast(max))); +} + +[[nodiscard]] uint8_t GenerateU8() { + return Random(static_cast(0U), static_cast(UINT8_MAX)); +} + +[[nodiscard]] uint32_t GenerateU32() { + return GenerateU32(0, INT32_MAX); +} + +[[nodiscard]] int64_t GenerateI64() { + return (static_cast(GenerateU32()) << sizeof(uint32_t)) + static_cast(GenerateU32()); +} + +[[nodiscard]] std::vector GenerateBytes(size_t length) { + std::vector data; + data.resize(length); + for (size_t i = 0; i < length; i++) { + data[i] = GenerateU8(); + } + + return data; +} + +[[nodiscard]] DsVeosCoSim_Result WriteOutGoingSignal(const DsVeosCoSim_IoSignal& ioSignal) { + size_t length = DsVeosCoSim_GetDataTypeSize(ioSignal.dataType) * ioSignal.length; + std::vector data = GenerateBytes(length); + + CheckResultWithMessage(DsVeosCoSim_WriteOutgoingSignal(handle, ioSignal.id, ioSignal.length, data.data()), + "Could not write outgoing signal."); + + return DsVeosCoSim_Result_Ok; +} + +[[nodiscard]] DsVeosCoSim_Result TransmitCanMessage(const DsVeosCoSim_CanController& controller) { + const uint32_t length = GenerateU32(1, 8); + std::vector data = GenerateBytes(length); + + DsVeosCoSim_CanMessage message{}; + message.controllerId = controller.id; + message.id = GenerateU32(); + message.timestamp = GenerateI64(); + message.length = length; + message.data = data.data(); + + CheckResultWithMessage(DsVeosCoSim_TransmitCanMessage(handle, &message), "Could not transmit CAN message."); + + return DsVeosCoSim_Result_Ok; +} + +[[nodiscard]] DsVeosCoSim_Result TransmitEthMessage(const DsVeosCoSim_EthController& controller) { + const uint32_t length = GenerateU32(15, 28); + std::vector data = GenerateBytes(length); + + DsVeosCoSim_EthMessage message{}; + message.controllerId = controller.id; + message.timestamp = GenerateI64(); + message.length = length; + message.data = data.data(); -RunTimeInfo g_runTimeInfo; + CheckResultWithMessage(DsVeosCoSim_TransmitEthMessage(handle, &message), "Could not transmit ETH message."); -std::thread g_simulationThread; + return DsVeosCoSim_Result_Ok; +} + +[[nodiscard]] DsVeosCoSim_Result TransmitLinMessage(const DsVeosCoSim_LinController& controller) { + const uint32_t length = GenerateU32(1, DSVEOSCOSIM_LIN_MESSAGE_MAX_LENGTH); + std::vector data = GenerateBytes(length); + + DsVeosCoSim_LinMessage message{}; + message.controllerId = controller.id; + message.id = GenerateU32(0, 63); + message.timestamp = GenerateI64(); + message.length = length; + message.data = data.data(); + + CheckResultWithMessage(DsVeosCoSim_TransmitLinMessage(handle, &message), "Could not transmit LIN message."); -void OnSimulationPostStepCallback(DsVeosCoSim_SimulationTime simulationTime) { - (void)SendSomeData(simulationTime, g_runTimeInfo); + return DsVeosCoSim_Result_Ok; +} + +[[nodiscard]] DsVeosCoSim_Result SendSomeData(DsVeosCoSim_SimulationTime simulationTime) { + static int64_t lastHalfSecond = -1; + static int64_t counter = 0; + const int64_t currentHalfSecond = simulationTime / 500000000; + if (currentHalfSecond == lastHalfSecond) { + return DsVeosCoSim_Result_Ok; + } + + lastHalfSecond = currentHalfSecond; + counter++; + + if (sendIoData && ((counter % 4) == 0)) { + for (uint32_t i = 0; i < outgoingSignalsCount; i++) { + const DsVeosCoSim_IoSignal& ioSignal = outgoingSignals[i]; + CheckResult(WriteOutGoingSignal(ioSignal)); + } + } + + if (sendCanMessages && ((counter % 4) == 1)) { + for (uint32_t i = 0; i < canControllersCount; i++) { + const DsVeosCoSim_CanController& controller = canControllers[i]; + CheckResult(TransmitCanMessage(controller)); + } + } + + if (sendEthMessages && ((counter % 4) == 2)) { + for (uint32_t i = 0; i < ethControllersCount; i++) { + const DsVeosCoSim_EthController& controller = ethControllers[i]; + CheckResult(TransmitEthMessage(controller)); + } + } + + if (sendLinMessages && ((counter % 4) == 3)) { + for (uint32_t i = 0; i < linControllersCount; i++) { + const DsVeosCoSim_LinController& controller = linControllers[i]; + CheckResult(TransmitLinMessage(controller)); + } + } + + return DsVeosCoSim_Result_Ok; +} + +void LogIoData(DsVeosCoSim_SimulationTime simulationTime, + const DsVeosCoSim_IoSignal* ioSignal, + uint32_t length, + const void* value, + [[maybe_unused]] void* userData) { + fmt::print(fmt::fg(fmt::color::fuchsia), "{}\n", DsVeosCoSim_IoDataToString(simulationTime, *ioSignal, length, value)); +} + +void LogCanMessage(DsVeosCoSim_SimulationTime simulationTime, + const DsVeosCoSim_CanController* controller, + const DsVeosCoSim_CanMessage* message, + [[maybe_unused]] void* userData) { + fmt::print(fmt::fg(fmt::color::dodger_blue), "{}\n", DsVeosCoSim_CanMessageToString(simulationTime, *controller, *message)); +} + +void LogEthMessage(DsVeosCoSim_SimulationTime simulationTime, + const DsVeosCoSim_EthController* controller, + const DsVeosCoSim_EthMessage* message, + [[maybe_unused]] void* userData) { + fmt::print(fmt::fg(fmt::color::cyan), "{}\n", DsVeosCoSim_EthMessageToString(simulationTime, *controller, *message)); +} + +void LogLinMessage(DsVeosCoSim_SimulationTime simulationTime, + const DsVeosCoSim_LinController* controller, + const DsVeosCoSim_LinMessage* message, + [[maybe_unused]] void* userData) { + fmt::print(fmt::fg(fmt::color::lime), "{}\n", DsVeosCoSim_LinMessageToString(simulationTime, *controller, *message)); +} + +void OnSimulationPostStepCallback(DsVeosCoSim_SimulationTime simulationTime, [[maybe_unused]] void* userData) { + (void)SendSomeData(simulationTime); } void StartSimulationThread(const std::function& function) { - g_simulationThread = std::thread(function); - g_simulationThread.detach(); + simulationThread = std::thread(function); + simulationThread.detach(); } -void OnSimulationStartedCallback(DsVeosCoSim_SimulationTime simulationTime) { - LogInfo("Simulation started at {} s.", DSVEOSCOSIM_SIMULATION_TIME_TO_SECONDS(simulationTime)); +void OnSimulationStartedCallback(DsVeosCoSim_SimulationTime simulationTime, [[maybe_unused]] void* userData) { + LogInfo("Simulation started at " + DsVeosCoSim_SimulationTimeToString(simulationTime) + " s."); } -void OnSimulationStoppedCallback(DsVeosCoSim_SimulationTime simulationTime) { - LogInfo("Simulation stopped at {} s.", DSVEOSCOSIM_SIMULATION_TIME_TO_SECONDS(simulationTime)); +void OnSimulationStoppedCallback(DsVeosCoSim_SimulationTime simulationTime, [[maybe_unused]] void* userData) { + LogInfo("Simulation stopped at " + DsVeosCoSim_SimulationTimeToString(simulationTime) + " s."); } -void OnSimulationTerminatedCallback(DsVeosCoSim_SimulationTime simulationTime, DsVeosCoSim_TerminateReason reason) { - LogInfo("Simulation terminated with reason {} at {} s.", - ToString(reason), - DSVEOSCOSIM_SIMULATION_TIME_TO_SECONDS(simulationTime)); +void OnSimulationTerminatedCallback(DsVeosCoSim_SimulationTime simulationTime, + DsVeosCoSim_TerminateReason reason, + [[maybe_unused]] void* userData) { + LogInfo("Simulation terminated with reason " + DsVeosCoSim_TerminateReasonToString(reason) + " at " + + DsVeosCoSim_SimulationTimeToString(simulationTime) + " s."); } -void OnSimulationPausedCallback(DsVeosCoSim_SimulationTime simulationTime) { - LogInfo("Simulation paused at {} s.", DSVEOSCOSIM_SIMULATION_TIME_TO_SECONDS(simulationTime)); +void OnSimulationPausedCallback(DsVeosCoSim_SimulationTime simulationTime, [[maybe_unused]] void* userData) { + LogInfo("Simulation paused at " + DsVeosCoSim_SimulationTimeToString(simulationTime) + " s."); } -void OnSimulationContinuedCallback(DsVeosCoSim_SimulationTime simulationTime) { - LogInfo("Simulation continued at {} s.", DSVEOSCOSIM_SIMULATION_TIME_TO_SECONDS(simulationTime)); +void OnSimulationContinuedCallback(DsVeosCoSim_SimulationTime simulationTime, [[maybe_unused]] void* userData) { + LogInfo("Simulation continued at " + DsVeosCoSim_SimulationTimeToString(simulationTime) + " s."); } -[[nodiscard]] bool Connect(std::string_view host, std::string_view serverName) { +[[nodiscard]] DsVeosCoSim_Result Connect(std::string_view host, std::string_view serverName) { LogInfo("Connecting ..."); - if (g_coSimClient->GetConnectionState() == DsVeosCoSim_ConnectionState_Connected) { + + DsVeosCoSim_ConnectionState connectionState{}; + CheckResultWithMessage(DsVeosCoSim_GetConnectionState(handle, &connectionState), "Could not get connection state."); + + if (connectionState == DsVeosCoSim_ConnectionState_Connected) { LogInfo("Already connected."); - return true; + return DsVeosCoSim_Result_Ok; } - ConnectConfig connectConfig{}; + DsVeosCoSim_ConnectConfig connectConfig{}; connectConfig.clientName = "Example Test Client"; - connectConfig.serverName = serverName; - connectConfig.remoteIpAddress = host; - CheckResultWithMessage(g_coSimClient->Connect(connectConfig), "Could not connect."); + connectConfig.serverName = serverName.data(); + connectConfig.remoteIpAddress = host.data(); + + CheckResultWithMessage(DsVeosCoSim_Connect(handle, connectConfig), "Could not connect."); + LogTrace(""); - LogTrace("Step size: {}", g_coSimClient->GetStepSize()); + DsVeosCoSim_SimulationTime stepSize{}; + CheckResultWithMessage(DsVeosCoSim_GetStepSize(handle, &stepSize), "Could not get step size."); + LogTrace("Step size: " + DsVeosCoSim_SimulationTimeToString(stepSize) + " s"); LogTrace(""); - g_runTimeInfo.canControllers = g_coSimClient->GetCanControllers(); - if (!g_runTimeInfo.canControllers.empty()) { + CheckResultWithMessage(DsVeosCoSim_GetCanControllers(handle, &canControllersCount, &canControllers), + "Could not get CAN controllers."); + if (canControllersCount > 0) { LogTrace("Found the following CAN controllers:"); - for (const CanController& controller : g_runTimeInfo.canControllers) { - LogCanController(controller); + for (uint32_t i = 0; i < canControllersCount; i++) { + LogTrace(" " + DsVeosCoSim_CanControllerToString(canControllers[i])); } LogTrace(""); } - g_runTimeInfo.ethControllers = g_coSimClient->GetEthControllers(); - if (!g_runTimeInfo.ethControllers.empty()) { - LogTrace("Found the following ethernet controllers:"); - for (const EthController& controller : g_runTimeInfo.ethControllers) { - LogEthController(controller); + CheckResultWithMessage(DsVeosCoSim_GetEthControllers(handle, ðControllersCount, ðControllers), + "Could not get ETH controllers."); + if (ethControllersCount > 0) { + LogTrace("Found the following ETH controllers:"); + for (uint32_t i = 0; i < ethControllersCount; i++) { + LogTrace(" " + DsVeosCoSim_EthControllerToString(ethControllers[i])); } LogTrace(""); } - g_runTimeInfo.linControllers = g_coSimClient->GetLinControllers(); - if (!g_runTimeInfo.linControllers.empty()) { + CheckResultWithMessage(DsVeosCoSim_GetLinControllers(handle, &linControllersCount, &linControllers), + "Could not get LIN controllers."); + if (linControllersCount > 0) { LogTrace("Found the following LIN controllers:"); - for (const LinController& controller : g_runTimeInfo.linControllers) { - LogLinController(controller); + for (uint32_t i = 0; i < linControllersCount; i++) { + LogTrace(" " + DsVeosCoSim_LinControllerToString(linControllers[i])); } LogTrace(""); } - g_runTimeInfo.incomingSignals = g_coSimClient->GetIncomingSignals(); - if (!g_runTimeInfo.incomingSignals.empty()) { - LogTrace("Found the following read signals:"); - for (const IoSignal& signal : g_runTimeInfo.incomingSignals) { - LogIoSignal(signal); + CheckResultWithMessage(DsVeosCoSim_GetIncomingSignals(handle, &incomingSignalsCount, &incomingSignals), + "Could not get incoming signals."); + if (incomingSignalsCount > 0) { + LogTrace("Found the following incoming signals:"); + for (uint32_t i = 0; i < incomingSignalsCount; i++) { + LogTrace(" " + DsVeosCoSim_IoSignalToString(incomingSignals[i])); } LogTrace(""); } - g_runTimeInfo.outgoingSignals = g_coSimClient->GetOutgoingSignals(); - if (!g_runTimeInfo.outgoingSignals.empty()) { - LogTrace("Found the following write signals:"); - for (const IoSignal& signal : g_runTimeInfo.outgoingSignals) { - LogIoSignal(signal); + CheckResultWithMessage(DsVeosCoSim_GetOutgoingSignals(handle, &outgoingSignalsCount, &outgoingSignals), + "Could not get outgoing signals."); + if (outgoingSignalsCount > 0) { + LogTrace("Found the following outgoing signals:"); + for (uint32_t i = 0; i < outgoingSignalsCount; i++) { + LogTrace(" " + DsVeosCoSim_IoSignalToString(outgoingSignals[i])); } LogTrace(""); } - g_runTimeInfo.transmitCan = [&](const DsVeosCoSim_CanMessage& message) { - return g_coSimClient->Transmit(message); - }; - g_runTimeInfo.transmitEth = [&](const DsVeosCoSim_EthMessage& message) { - return g_coSimClient->Transmit(message); - }; - g_runTimeInfo.transmitLin = [&](const DsVeosCoSim_LinMessage& message) { - return g_coSimClient->Transmit(message); - }; - g_runTimeInfo.write = [&](DsVeosCoSim_IoSignalId signalId, uint32_t length, const void* value) { - return g_coSimClient->Write(signalId, length, value); - }; - LogInfo("Connected."); - return true; + return DsVeosCoSim_Result_Ok; } -void Disconnect() { +[[nodiscard]] DsVeosCoSim_Result Disconnect() { LogInfo("Disconnecting ..."); - g_coSimClient->Disconnect(); + CheckResultWithMessage(DsVeosCoSim_Disconnect(handle), "Could not disconnect."); LogInfo("Disconnected."); + + return DsVeosCoSim_Result_Ok; } void RunCallbackBasedCoSimulation() { - try { - Callbacks callbacks{}; - callbacks.simulationStartedCallback = OnSimulationStartedCallback; - callbacks.simulationStoppedCallback = OnSimulationStoppedCallback; - callbacks.simulationTerminatedCallback = OnSimulationTerminatedCallback; - callbacks.simulationPausedCallback = OnSimulationPausedCallback; - callbacks.simulationContinuedCallback = OnSimulationContinuedCallback; - callbacks.simulationEndStepCallback = OnSimulationPostStepCallback; - callbacks.incomingSignalChangedCallback = LogIoData; - callbacks.canMessageReceivedCallback = LogCanMessage; - callbacks.ethMessageReceivedCallback = LogEthMessage; - callbacks.linMessageReceivedCallback = LogLinMessage; - - LogInfo("Running callback-based co-simulation ..."); - if (g_coSimClient->RunCallbackBasedCoSimulation(callbacks)) { - exit(0); - } - - exit(1); - } catch (const std::exception& e) { - LogError(e.what()); + DsVeosCoSim_Callbacks callbacks{}; + callbacks.simulationStartedCallback = OnSimulationStartedCallback; + callbacks.simulationStoppedCallback = OnSimulationStoppedCallback; + callbacks.simulationTerminatedCallback = OnSimulationTerminatedCallback; + callbacks.simulationPausedCallback = OnSimulationPausedCallback; + callbacks.simulationContinuedCallback = OnSimulationContinuedCallback; + callbacks.simulationEndStepCallback = OnSimulationPostStepCallback; + callbacks.incomingSignalChangedCallback = LogIoData; + callbacks.canMessageReceivedCallback = LogCanMessage; + callbacks.ethMessageReceivedCallback = LogEthMessage; + callbacks.linMessageReceivedCallback = LogLinMessage; + + LogInfo("Running callback-based co-simulation ..."); + DsVeosCoSim_Result result = DsVeosCoSim_RunCallbackBasedCoSimulation(handle, callbacks); + if ((result == DsVeosCoSim_Result_Disconnected) || (result == DsVeosCoSim_Result_Ok)) { + exit(0); } + + LogError("DsVeosCoSim_RunCallbackBasedCoSimulation finished with the following error code: " + + DsVeosCoSim_ResultToString(result) + "."); + exit(1); } -void HostClient(std::string_view host, std::string_view name) { - if (!Connect(host, name)) { - return; - } +[[nodiscard]] DsVeosCoSim_Result HostClient(std::string_view host, std::string_view name) { + CheckResult(Connect(host, name)); StartSimulationThread(RunCallbackBasedCoSimulation); while (true) { switch (GetChar()) { case CTRL('c'): - Disconnect(); - return; + return Disconnect(); case '1': SwitchSendingIoSignals(); break; @@ -196,19 +496,20 @@ void HostClient(std::string_view host, std::string_view name) { SwitchSendingLinMessages(); break; case 's': - g_coSimClient->Start(); + CheckResultWithMessage(DsVeosCoSim_StartSimulation(handle), "Could not start simulation"); break; case 'o': - g_coSimClient->Stop(); + CheckResultWithMessage(DsVeosCoSim_StopSimulation(handle), "Could not stop simulation"); break; case 'p': - g_coSimClient->Pause(); + CheckResultWithMessage(DsVeosCoSim_PauseSimulation(handle), "Could not pause simulation"); break; case 't': - g_coSimClient->Terminate(DsVeosCoSim_TerminateReason_Error); + CheckResultWithMessage(DsVeosCoSim_TerminateSimulation(handle, DsVeosCoSim_TerminateReason_Error), + "Could not terminate simulation"); break; case 'n': - g_coSimClient->Continue(); + CheckResultWithMessage(DsVeosCoSim_ContinueSimulation(handle), "Could not pause simulation"); break; default: LogError("Unknown key."); @@ -220,9 +521,7 @@ void HostClient(std::string_view host, std::string_view name) { } // namespace int32_t main(int32_t argc, char** argv) { - if (!StartUp()) { - return 1; - } + InitializeOutput(); std::string host; std::string name = "CoSimTest"; @@ -247,12 +546,17 @@ int32_t main(int32_t argc, char** argv) { } } - g_coSimClient = std::make_unique(); + DsVeosCoSim_SetLogCallback(OnLogCallback); + + handle = DsVeosCoSim_Create(); + if (!handle) { + LogError("Could not create handle."); + return 1; + } - HostClient(host, name); + DsVeosCoSim_Result result = HostClient(host, name); - Disconnect(); - g_coSimClient.reset(); + DsVeosCoSim_Destroy(handle); - return 0; + return result == DsVeosCoSim_Result_Ok ? 0 : 1; } diff --git a/utilities/TestServer/CMakeLists.txt b/utilities/TestServer/CMakeLists.txt index adf3e79..b958e9e 100644 --- a/utilities/TestServer/CMakeLists.txt +++ b/utilities/TestServer/CMakeLists.txt @@ -10,8 +10,17 @@ target_sources( Program.cpp ) +target_include_directories( + TestServer + PUBLIC + ../../src + ../../src/Communication + ../../src/Helpers + ../../src/OsAbstraction +) + target_link_libraries( TestServer DsVeosCoSim - shared + fmt::fmt ) diff --git a/utilities/TestServer/Program.cpp b/utilities/TestServer/Program.cpp index 9e97a5a..c4008a3 100644 --- a/utilities/TestServer/Program.cpp +++ b/utilities/TestServer/Program.cpp @@ -1,5 +1,16 @@ // Copyright dSPACE GmbH. All rights reserved. +#include + +#ifdef _WIN32 +#include +#include +#else +#include +#include +#include +#endif + #include #include #include @@ -7,191 +18,417 @@ #include #include -#include "BackgroundService.h" -#include "ClientServerTestHelper.h" -#include "CoSimHelper.h" #include "CoSimServer.h" #include "CoSimTypes.h" -#include "Generator.h" -#include "Helper.h" -#include "LogHelper.h" +#include "DsVeosCoSim/DsVeosCoSim.h" using namespace DsVeosCoSim; - using namespace std::chrono_literals; namespace { -enum class State { - Unloaded, - Stopped, - Running, - Paused, - Terminated -}; - -bool g_stopSimulationThread; -std::thread g_simulationThread; - -DsVeosCoSim_SimulationTime g_currentTime; - -RunTimeInfo g_runTimeInfo; - -std::unique_ptr g_server; -std::unique_ptr g_backgroundService; -State g_state; - -std::thread::id g_simulationThreadId; - -[[nodiscard]] std::string ToString(State state) { - switch (state) { - case State::Unloaded: - return "Unloaded"; - case State::Stopped: - return "Stopped"; - case State::Running: - return "Running"; - case State::Paused: - return "Paused"; - case State::Terminated: - return "Terminated"; +void InitializeOutput() { +#if _WIN32 + (void)::SetConsoleOutputCP(CP_UTF8); + (void)::setvbuf(stdout, nullptr, _IONBF, 0); + + HANDLE console = ::GetStdHandle(STD_OUTPUT_HANDLE); + + DWORD dwMode = 0; + if (::GetConsoleMode(console, &dwMode) != 0) { + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + (void)::SetConsoleMode(console, dwMode); + } +#endif +} + +[[nodiscard]] int32_t GetChar() { +#ifdef _WIN32 + return _getch(); +#else + termios oldt{}; + tcgetattr(STDIN_FILENO, &oldt); + + termios newt = oldt; + newt.c_lflag &= ~(ICANON | ECHO); + + tcsetattr(STDIN_FILENO, TCSANOW, &newt); + + int32_t character = getchar(); + tcsetattr(STDIN_FILENO, TCSANOW, &oldt); + return character; +#endif +} + +#ifndef CTRL +#define CTRL(c) ((c) & 037) +#endif + +void OnLogCallback(DsVeosCoSim_Severity severity, std::string_view message) { + switch (severity) { + case DsVeosCoSim_Severity_Error: + fmt::print(fmt::fg(fmt::color::red), "{}\n", message); + break; + case DsVeosCoSim_Severity_Warning: + fmt::print(fmt::fg(fmt::color::yellow), "{}\n", message); + break; + case DsVeosCoSim_Severity_Info: + fmt::print(fmt::fg(fmt::color::white), "{}\n", message); + break; + case DsVeosCoSim_Severity_Trace: + fmt::print(fmt::fg(fmt::color::light_gray), "{}\n", message); + break; + case DsVeosCoSim_Severity_INT_MAX_SENTINEL_DO_NOT_USE_: + break; + } +} + +bool sendIoData; +bool sendCanMessages; +bool sendEthMessages; +bool sendLinMessages; + +bool stopSimulationThread; +std::thread simulationThread; + +DsVeosCoSim_SimulationTime currentTime; + +std::unique_ptr server; +CoSimServerConfig config; +SimulationState state; + +Event stopBackgroundThread; +std::thread backgroundThread; + +std::thread::id simulationThreadId; + +void PrintStatus(bool value, const std::string& what) { + if (value) { + LogInfo("Enabled sending " + what); + } else { + LogInfo("Disabled sending " + what); + } +} + +void SwitchSendingIoSignals() { + sendIoData = !sendIoData; + PrintStatus(sendIoData, "IO data"); +} + +void SwitchSendingCanMessages() { + sendCanMessages = !sendCanMessages; + PrintStatus(sendCanMessages, "CAN messages"); +} + +void SwitchSendingEthMessages() { + sendEthMessages = !sendEthMessages; + PrintStatus(sendEthMessages, "ETH messages"); +} + +void SwitchSendingLinMessages() { + sendLinMessages = !sendLinMessages; + PrintStatus(sendLinMessages, "LIN messages"); +} + +void LogCanMessage(DsVeosCoSim_SimulationTime simulationTime, + const DsVeosCoSim_CanController& controller, + const DsVeosCoSim_CanMessage& message) { + fmt::print(fmt::fg(fmt::color::dodger_blue), "{}\n", CanMessageToString(simulationTime, controller, message)); +} + +void LogEthMessage(DsVeosCoSim_SimulationTime simulationTime, + const DsVeosCoSim_EthController& controller, + const DsVeosCoSim_EthMessage& message) { + fmt::print(fmt::fg(fmt::color::cyan), "{}\n", EthMessageToString(simulationTime, controller, message)); +} + +void LogLinMessage(DsVeosCoSim_SimulationTime simulationTime, + const DsVeosCoSim_LinController& controller, + const DsVeosCoSim_LinMessage& message) { + fmt::print(fmt::fg(fmt::color::lime), "{}\n", LinMessageToString(simulationTime, controller, message)); +} + +[[nodiscard]] int32_t Random(int32_t min, int32_t max) { + static bool first = true; + if (first) { + srand(42); + first = false; + } + + const int32_t diff = max + 1 - min; + + return min + rand() % diff; +} + +[[nodiscard]] uint32_t GenerateU32(uint32_t min, uint32_t max) { + return static_cast(Random(static_cast(min), static_cast(max))); +} + +[[nodiscard]] uint8_t GenerateU8() { + return Random(static_cast(0U), static_cast(UINT8_MAX)); +} + +[[nodiscard]] uint32_t GenerateU32() { + return GenerateU32(0, INT32_MAX); +} + +[[nodiscard]] int64_t GenerateI64() { + return (static_cast(GenerateU32()) << sizeof(uint32_t)) + static_cast(GenerateU32()); +} + +[[nodiscard]] std::vector GenerateBytes(size_t length) { + std::vector data; + data.resize(length); + for (size_t i = 0; i < length; i++) { + data[i] = GenerateU8(); + } + + return data; +} + +void WriteOutGoingSignal(const IoSignal& ioSignal) { + size_t length = GetDataTypeSize(ioSignal.dataType) * ioSignal.length; + std::vector data = GenerateBytes(length); + + server->Write(ioSignal.id, static_cast(length), data.data()); +} + +[[nodiscard]] bool TransmitCanMessage(const CanController& controller) { + const uint32_t length = GenerateU32(1, 8); + std::vector data = GenerateBytes(length); + + DsVeosCoSim_CanMessage message{}; + message.controllerId = controller.id; + message.id = GenerateU32(0, 127); + message.timestamp = GenerateI64(); + message.length = length; + message.data = data.data(); + + return server->Transmit(message); +} + +[[nodiscard]] bool TransmitEthMessage(const DsVeosCoSim_EthController& controller) { + const uint32_t length = GenerateU32(15, 28); + std::vector data = GenerateBytes(length); + + DsVeosCoSim_EthMessage message{}; + message.controllerId = controller.id; + message.timestamp = GenerateI64(); + message.length = length; + message.data = data.data(); + + return server->Transmit(message); +} + +[[nodiscard]] bool TransmitLinMessage(const DsVeosCoSim_LinController& controller) { + const uint32_t length = GenerateU32(1, DSVEOSCOSIM_LIN_MESSAGE_MAX_LENGTH); + std::vector data = GenerateBytes(length); + + DsVeosCoSim_LinMessage message{}; + message.controllerId = controller.id; + message.id = GenerateU32(0, 63); + message.timestamp = GenerateI64(); + message.length = length; + message.data = data.data(); + + return server->Transmit(message); +} + +[[nodiscard]] bool SendSomeData(DsVeosCoSim_SimulationTime simulationTime) { + static int64_t lastHalfSecond = -1; + static int64_t counter = 0; + const int64_t currentHalfSecond = simulationTime / 500000000; + if (currentHalfSecond == lastHalfSecond) { + return true; + } + + lastHalfSecond = currentHalfSecond; + counter++; + + if (sendIoData && ((counter % 4) == 0)) { + for (const IoSignal& signal : config.incomingSignals) { + WriteOutGoingSignal(signal); + } + } + + if (sendCanMessages && ((counter % 4) == 1)) { + for (const CanController& controller : config.canControllers) { + CheckResult(TransmitCanMessage(controller)); + } + } + + if (sendEthMessages && ((counter % 4) == 2)) { + for (const EthController& controller : config.ethControllers) { + CheckResult(TransmitEthMessage(controller)); + } + } + + if (sendLinMessages && ((counter % 4) == 3)) { + for (const LinController& controller : config.linControllers) { + CheckResult(TransmitLinMessage(controller)); + } + } + + return true; +} + +void StartBackgroundThread() { + backgroundThread = std::thread([] { + while (!stopBackgroundThread.Wait(1)) { + try { + server->BackgroundService(); + } catch (const std::exception& e) { + LogError(e.what()); + } + } + }); +} + +void StopBackgroundThread() { + if (!backgroundThread.joinable()) { + return; } - return ""; + stopBackgroundThread.Set(); + if (std::this_thread::get_id() == backgroundThread.get_id()) { + backgroundThread.detach(); + } else { + backgroundThread.join(); + } } void DoSimulation() { - g_backgroundService.reset(); + StopBackgroundThread(); - g_simulationThreadId = std::this_thread::get_id(); - while (!g_stopSimulationThread) { - if (!SendSomeData(g_currentTime, g_runTimeInfo)) { + simulationThreadId = std::this_thread::get_id(); + while (!stopSimulationThread) { + if (!SendSomeData(currentTime)) { break; } DsVeosCoSim_SimulationTime nextSimulationTime{}; - g_server->Step(g_currentTime, nextSimulationTime); + server->Step(currentTime, nextSimulationTime); - if (nextSimulationTime > g_currentTime) { - g_currentTime = nextSimulationTime; + if (nextSimulationTime > currentTime) { + currentTime = nextSimulationTime; } else { - g_currentTime += 1000000; + currentTime += 1000000; } } - g_backgroundService = std::make_unique(*g_server); + StartBackgroundThread(); } void StopSimulationThread() { - g_stopSimulationThread = true; + stopSimulationThread = true; - if (g_simulationThreadId == std::this_thread::get_id()) { + if (simulationThreadId == std::this_thread::get_id()) { // It's called from inside the simulation thread. That won't work. So let the next simulation thread starter // join this thread return; } - if (g_simulationThread.joinable()) { - g_simulationThread.join(); + if (simulationThread.joinable()) { + simulationThread.join(); } - g_simulationThread = {}; - g_simulationThreadId = {}; + simulationThread = {}; + simulationThreadId = {}; } void StartSimulationThread() { StopSimulationThread(); - g_stopSimulationThread = false; - g_simulationThread = std::thread(DoSimulation); + stopSimulationThread = false; + simulationThread = std::thread(DoSimulation); } void StartSimulation() { - if (g_state == State::Running) { + if (state == SimulationState::Running) { return; } - if (g_state != State::Stopped) { - LogError("Could not start in state {}.", ToString(g_state)); + if (state != SimulationState::Stopped) { + LogError("Could not start in state " + ToString(state) + "."); return; } - g_currentTime = 0; + currentTime = 0; LogInfo("Starting ..."); - g_backgroundService.reset(); + StopBackgroundThread(); - g_server->Start(g_currentTime); + server->Start(currentTime); StartSimulationThread(); - g_state = State::Running; + state = SimulationState::Running; LogInfo("Started."); } void StopSimulation() { - if (g_state == State::Stopped) { + if (state == SimulationState::Stopped) { return; } - if ((g_state != State::Running) && (g_state != State::Paused)) { - LogError("Could not stop in state {}.", ToString(g_state)); + if ((state != SimulationState::Running) && (state != SimulationState::Paused)) { + LogError("Could not stop in state " + ToString(state) + "."); return; } LogInfo("Stopping ..."); StopSimulationThread(); - g_server->Stop(g_currentTime); - g_state = State::Stopped; + server->Stop(currentTime); + state = SimulationState::Stopped; LogInfo("Stopped."); } void PauseSimulation() { - if (g_state == State::Paused) { + if (state == SimulationState::Paused) { return; } - if (g_state != State::Running) { - LogError("Could not pause in state {}.", ToString(g_state)); + if (state != SimulationState::Running) { + LogError("Could not pause in state " + ToString(state) + "."); return; } LogInfo("Pausing ..."); StopSimulationThread(); - g_server->Pause(g_currentTime); - g_state = State::Paused; + server->Pause(currentTime); + state = SimulationState::Paused; LogInfo("Paused."); } void ContinueSimulation() { - if (g_state == State::Running) { + if (state == SimulationState::Running) { return; } - if (g_state != State::Paused) { - LogError("Could not start in state {}.", ToString(g_state)); + if (state != SimulationState::Paused) { + LogError("Could not start in state " + ToString(state) + "."); return; } LogInfo("Continuing ..."); - g_server->Continue(g_currentTime); + server->Continue(currentTime); StartSimulationThread(); - g_state = State::Running; + state = SimulationState::Running; LogInfo("Continued."); } void TerminateSimulation() { - if (g_state == State::Terminated) { + if (state == SimulationState::Terminated) { return; } - if (g_state == State::Unloaded) { - LogError("Could not terminate in state {}.", ToString(g_state)); + if (state == SimulationState::Unloaded) { + LogError("Could not terminate in state " + ToString(state) + "."); return; } @@ -199,8 +436,8 @@ void TerminateSimulation() { StopSimulationThread(); - g_server->Terminate(g_currentTime, DsVeosCoSim_TerminateReason_Error); - g_state = State::Terminated; + server->Terminate(currentTime, DsVeosCoSim_TerminateReason_Error); + state = SimulationState::Terminated; LogInfo("Terminated."); } @@ -231,16 +468,90 @@ void OnSimulationTerminatedCallback([[maybe_unused]] DsVeosCoSim_SimulationTime TerminateSimulation(); } +[[nodiscard]] std::vector CreateCanControllers() { + std::vector controllers; + + CanController controller{}; + controller.id = 1; + controller.queueSize = 512; + controller.bitsPerSecond = 1000; + controller.flexibleDataRateBitsPerSecond = 1000; + controller.name = "CanController1"; + controller.channelName = "CanChannel1"; + controller.clusterName = "CanCluster1"; + controllers.push_back(controller); + + return controllers; +} + +[[nodiscard]] std::vector CreateEthControllers() { + std::vector controllers; + + EthController controller{}; + controller.id = 1; + controller.queueSize = 512; + controller.bitsPerSecond = 1000; + controller.macAddress = {0, 1, 2, 3, 4, 5}; + controller.name = "EthController1"; + controller.channelName = "EthChannel1"; + controller.clusterName = "EthCluster1"; + controllers.push_back(controller); + + return controllers; +} + +[[nodiscard]] std::vector CreateLinControllers() { + std::vector controllers; + + LinController controller{}; + controller.id = 1; + controller.queueSize = 512; + controller.bitsPerSecond = 1000; + controller.type = DsVeosCoSim_LinControllerType_Responder; + controller.name = "LinController1"; + controller.channelName = "LinChannel1"; + controller.clusterName = "LinCluster1"; + controllers.push_back(controller); + + return controllers; +} + +[[nodiscard]] std::vector CreateIncomingSignals() { + std::vector signals; + + IoSignal signal{}; + signal.id = 1; + signal.length = 4; + signal.dataType = DsVeosCoSim_DataType_UInt8; + signal.sizeKind = DsVeosCoSim_SizeKind_Variable; + signal.name = "IncomingIoSignal1"; + signals.push_back(signal); + + return signals; +} + +[[nodiscard]] std::vector CreateOutgoingSignals() { + std::vector signals; + + IoSignal signal{}; + signal.id = 1; + signal.length = 4; + signal.dataType = DsVeosCoSim_DataType_UInt8; + signal.sizeKind = DsVeosCoSim_SizeKind_Variable; + signal.name = "OutgoingIoSignal1"; + signals.push_back(signal); + + return signals; +} + void LoadSimulation(bool isClientOptional, std::string_view name) { LogInfo("Loading ..."); - if (g_state != State::Unloaded) { - LogError("Could not load in state {}.", ToString(g_state)); + if (state != SimulationState::Unloaded) { + LogError("Could not load in state " + ToString(state) + "."); return; } - CoSimServerConfig config{}; - config.serverName = name; config.logCallback = OnLogCallback; config.isClientOptional = isClientOptional; @@ -254,35 +565,17 @@ void LoadSimulation(bool isClientOptional, std::string_view name) { config.canMessageReceivedCallback = LogCanMessage; config.ethMessageReceivedCallback = LogEthMessage; config.linMessageReceivedCallback = LogLinMessage; - config.canControllers = CreateCanControllers(1); - config.ethControllers = CreateEthControllers(1); - config.linControllers = CreateLinControllers(1); - config.incomingSignals = CreateSignals(1); - config.outgoingSignals = CreateSignals(1); - - g_server = std::make_unique(); - g_server->Load(config); - g_state = State::Stopped; - - g_runTimeInfo.canControllers = config.canControllers; - g_runTimeInfo.ethControllers = config.ethControllers; - g_runTimeInfo.linControllers = config.linControllers; - g_runTimeInfo.incomingSignals = config.outgoingSignals; - g_runTimeInfo.outgoingSignals = config.incomingSignals; - g_runTimeInfo.transmitCan = [&](const DsVeosCoSim_CanMessage& message) { - return g_server->Transmit(message); - }; - g_runTimeInfo.transmitEth = [&](const DsVeosCoSim_EthMessage& message) { - return g_server->Transmit(message); - }; - g_runTimeInfo.transmitLin = [&](const DsVeosCoSim_LinMessage& message) { - return g_server->Transmit(message); - }; - g_runTimeInfo.write = [&](DsVeosCoSim_IoSignalId signalId, uint32_t length, const void* value) { - return g_server->Write(signalId, length, value); - }; - - g_backgroundService = std::make_unique(*g_server); + config.canControllers = CreateCanControllers(); + config.ethControllers = CreateEthControllers(); + config.linControllers = CreateLinControllers(); + config.incomingSignals = CreateIncomingSignals(); + config.outgoingSignals = CreateOutgoingSignals(); + + server = std::make_unique(); + server->Load(config); + state = SimulationState::Stopped; + + StartBackgroundThread(); LogInfo("Loaded."); } @@ -291,9 +584,9 @@ void UnloadSimulation() { LogInfo("Unloading ..."); StopSimulationThread(); - g_backgroundService.reset(); - g_server.reset(); - g_state = State::Unloaded; + StopBackgroundThread(); + server.reset(); + state = SimulationState::Unloaded; LogInfo("Unloaded."); } @@ -348,9 +641,7 @@ void HostServer(bool isClientOptional, std::string_view name) { } // namespace int32_t main(int32_t argc, char** argv) { - if (!StartUp()) { - return 1; - } + InitializeOutput(); std::string name = "CoSimTest"; bool isClientOptional = false;