From c4e88dc3f440942d7c64b72ff14ebae9fcc58d4f Mon Sep 17 00:00:00 2001 From: Konrad Breitsprecher Date: Fri, 15 Nov 2024 12:43:14 +0100 Subject: [PATCH] demos: Reorganized common CAN behavior; Review suggestions --- Demos/Can/CanBehavior.hpp | 91 ------------------------------- Demos/Can/CanDemoCommon.hpp | 46 ++++++++++++++++ Demos/Can/CanReaderDemo.cpp | 11 ++-- Demos/Can/CanWriterDemo.cpp | 57 ++++++++++++++----- Demos/include/ApplicationBase.hpp | 26 ++------- 5 files changed, 101 insertions(+), 130 deletions(-) delete mode 100644 Demos/Can/CanBehavior.hpp create mode 100644 Demos/Can/CanDemoCommon.hpp diff --git a/Demos/Can/CanBehavior.hpp b/Demos/Can/CanBehavior.hpp deleted file mode 100644 index 931a32675..000000000 --- a/Demos/Can/CanBehavior.hpp +++ /dev/null @@ -1,91 +0,0 @@ -// SPDX-FileCopyrightText: 2024 Vector Informatik GmbH -// -// SPDX-License-Identifier: MIT - -#include "silkit/services/can/all.hpp" -#include "silkit/services/can/string_utils.hpp" -#include "silkit/services/logging/ILogger.hpp" - -using namespace SilKit::Services::Can; - -std::ostream& operator<<(std::ostream& out, std::chrono::nanoseconds timestamp) -{ - auto seconds = std::chrono::duration_cast>>(timestamp); - out << seconds.count() << "s"; - return out; -} - -// This is the common behavior used in CanReaderDemo and CanWriterDemo -namespace CanDemoBehavior { - -void FrameTransmitHandler(const CanFrameTransmitEvent& canFrameAck, ILogger* logger) -{ - // Log - std::stringstream buffer; - buffer << "Ack CAN frame, canId=" << canFrameAck.canId << ", status='" << canFrameAck.status << "'"; - logger->Info(buffer.str()); -} - -void FrameHandler(const CanFrameEvent& canFrameEvent, ILogger* logger) -{ - // Indicate frame type in log message - std::string frameTypeHint = ""; - if ((canFrameEvent.frame.flags & static_cast(CanFrameFlag::Fdf)) != 0) - { - frameTypeHint = "FD "; - } - else if ((canFrameEvent.frame.flags & static_cast(CanFrameFlag::Xlf)) != 0) - { - frameTypeHint = "XL "; - } - - // Log - std::string payloadStr(canFrameEvent.frame.dataField.begin(), canFrameEvent.frame.dataField.end()); - std::stringstream buffer; - buffer << "Receive CAN " << frameTypeHint << "frame, canId=" << canFrameEvent.frame.canId << ", data ='" - << payloadStr; - logger->Info(buffer.str()); -} - -void SendFrame(ICanController* canController, ILogger* logger) -{ - // Count up message id per frame - static uint64_t messageId = 0; - messageId++; - - // Build a CAN frame - CanFrame canFrame{}; - canFrame.canId = 3; - - // Cycle between normal, FD and XL frames - std::string frameTypeHint = ""; - if (messageId % 3 == 1) - { - canFrame.flags = static_cast(CanFrameFlag::Fdf) // FD Format Indicator - | static_cast(CanFrameFlag::Brs); // Bit Rate Switch (for FD Format only) - frameTypeHint = "FD "; - } - else if (messageId % 3 == 2) - { - canFrame.flags = static_cast(CanFrameFlag::Xlf); // XL Format Indicator - frameTypeHint = "XL "; - } - - // Build a payload with the message Id - std::stringstream payloadBuilder; - payloadBuilder << "Hello CAN Bus, this is frame #" << messageId; - auto payloadStr = payloadBuilder.str(); - std::vector payloadBytes(payloadStr.begin(), payloadStr.end()); - canFrame.dataField = payloadBytes; - canFrame.dlc = static_cast(canFrame.dataField.size()); - - // Log - std::stringstream buffer; - buffer << "Send CAN " << frameTypeHint << "frame, canId = " << canFrame.canId << ", data = '" << payloadStr << "' "; - logger->Info(buffer.str()); - - // Send - canController->SendFrame(std::move(canFrame)); -} - -} // namespace CanDemoBehavior diff --git a/Demos/Can/CanDemoCommon.hpp b/Demos/Can/CanDemoCommon.hpp new file mode 100644 index 000000000..ded4f6b54 --- /dev/null +++ b/Demos/Can/CanDemoCommon.hpp @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2024 Vector Informatik GmbH +// +// SPDX-License-Identifier: MIT + +#include "silkit/services/can/all.hpp" +#include "silkit/services/can/string_utils.hpp" +#include "silkit/services/logging/ILogger.hpp" + +using namespace SilKit::Services::Can; + +std::ostream& operator<<(std::ostream& out, std::chrono::nanoseconds timestamp) +{ + auto seconds = std::chrono::duration_cast>>(timestamp); + out << seconds.count() << "s"; + return out; +} + +// This is the common behavior used in CanReaderDemo and CanWriterDemo +namespace CanDemoCommon { + +void FrameTransmitHandler(const CanFrameTransmitEvent& canFrameAck, ILogger* logger) +{ + // Log + std::stringstream buffer; + buffer << "Ack CAN frame, canId=" << canFrameAck.canId << ", status='" << canFrameAck.status << "'"; + logger->Info(buffer.str()); +} + +void FrameHandler(const CanFrameEvent& canFrameEvent, ILogger* logger) +{ + // Indicate frame type in log message + std::string frameTypeHint = ""; + if ((canFrameEvent.frame.flags & static_cast(CanFrameFlag::Fdf)) != 0) + { + frameTypeHint = "FD "; + } + + // Log + std::string payloadStr(canFrameEvent.frame.dataField.begin(), canFrameEvent.frame.dataField.end()); + std::stringstream buffer; + buffer << "Receive CAN " << frameTypeHint << "frame, canId=" << canFrameEvent.frame.canId << ", data ='" + << payloadStr << "'"; + logger->Info(buffer.str()); +} + +} // namespace CanDemoBehavior diff --git a/Demos/Can/CanReaderDemo.cpp b/Demos/Can/CanReaderDemo.cpp index 05586d7ee..2dbb9f677 100644 --- a/Demos/Can/CanReaderDemo.cpp +++ b/Demos/Can/CanReaderDemo.cpp @@ -3,12 +3,11 @@ // SPDX-License-Identifier: MIT #include "ApplicationBase.hpp" -#include "CanBehavior.hpp" +#include "CanDemoCommon.hpp" using namespace std::chrono_literals; - -class CanApplication : public ApplicationBase +class CanReader: public ApplicationBase { public: // Inherit constructors @@ -35,10 +34,10 @@ class CanApplication : public ApplicationBase _canController = GetParticipant()->CreateCanController("CanController1", networkName); _canController->AddFrameTransmitHandler([this](ICanController* /*ctrl*/, const CanFrameTransmitEvent& ack) { - CanDemoBehavior::FrameTransmitHandler(ack, GetLogger()); + CanDemoCommon::FrameTransmitHandler(ack, GetLogger()); }); _canController->AddFrameHandler([this](ICanController* /*ctrl*/, const CanFrameEvent& frameEvent) { - CanDemoBehavior::FrameHandler(frameEvent, GetLogger()); + CanDemoCommon::FrameHandler(frameEvent, GetLogger()); }); } @@ -61,7 +60,7 @@ class CanApplication : public ApplicationBase int main(int argc, char** argv) { - CanApplication app{"CanReader"}; + CanReader app{"CanReader"}; app.SetupCommandLineArgs(argc, argv); diff --git a/Demos/Can/CanWriterDemo.cpp b/Demos/Can/CanWriterDemo.cpp index bd4888dc9..e413691df 100644 --- a/Demos/Can/CanWriterDemo.cpp +++ b/Demos/Can/CanWriterDemo.cpp @@ -3,12 +3,11 @@ // SPDX-License-Identifier: MIT #include "ApplicationBase.hpp" -#include "CanBehavior.hpp" +#include "CanDemoCommon.hpp" using namespace std::chrono_literals; - -class CanApplication : public ApplicationBase +class CanWriter: public ApplicationBase { public: // Inherit constructors @@ -34,10 +33,10 @@ class CanApplication : public ApplicationBase _canController = GetParticipant()->CreateCanController("CanController1", networkName); _canController->AddFrameTransmitHandler([this](ICanController* /*ctrl*/, const CanFrameTransmitEvent& ack) { - CanDemoBehavior::FrameTransmitHandler(ack, GetLogger()); + CanDemoCommon::FrameTransmitHandler(ack, GetLogger()); }); _canController->AddFrameHandler([this](ICanController* /*ctrl*/, const CanFrameEvent& frameEvent) { - CanDemoBehavior::FrameHandler(frameEvent, GetLogger()); + CanDemoCommon::FrameHandler(frameEvent, GetLogger()); }); } @@ -47,26 +46,58 @@ class CanApplication : public ApplicationBase _canController->Start(); } - void DoWorkSync(std::chrono::nanoseconds /*now*/) override + void SendFrame() { - DoWork(); + // Count up message id per frame + static uint64_t messageId = 0; + messageId++; + + // Build a CAN frame + CanFrame canFrame{}; + canFrame.canId = 3; + + // Cycle between normal and FD frames + std::string frameTypeHint = ""; + if (messageId % 2 == 1) + { + canFrame.flags = static_cast(CanFrameFlag::Fdf) // FD Format Indicator + | static_cast(CanFrameFlag::Brs); // Bit Rate Switch (for FD Format only) + frameTypeHint = "FD "; + } + + // Build a payload with the message Id + std::stringstream payloadBuilder; + payloadBuilder << "Hello CAN Bus, this is frame #" << messageId; + auto payloadStr = payloadBuilder.str(); + std::vector payloadBytes(payloadStr.begin(), payloadStr.end()); + canFrame.dataField = payloadBytes; + canFrame.dlc = static_cast(canFrame.dataField.size()); + + // Log + std::stringstream buffer; + buffer << "Send CAN " << frameTypeHint << "frame, canId = " << canFrame.canId << ", data = '" << payloadStr + << "' "; + GetLogger()->Info(buffer.str()); + + // Send + _canController->SendFrame(std::move(canFrame)); } - void DoWorkAsync() override + void DoWorkSync(std::chrono::nanoseconds /*now*/) override { - DoWork(); + SendFrame(); } -private: - void DoWork() + void DoWorkAsync() override { - CanDemoBehavior::SendFrame(_canController, GetLogger()); + SendFrame(); } + }; int main(int argc, char** argv) { - CanApplication app{"CanWriter"}; + CanWriter app{"CanWriter"}; app.SetupCommandLineArgs(argc, argv); diff --git a/Demos/include/ApplicationBase.hpp b/Demos/include/ApplicationBase.hpp index 274ac8cd4..fa5ee60d6 100644 --- a/Demos/include/ApplicationBase.hpp +++ b/Demos/include/ApplicationBase.hpp @@ -69,7 +69,7 @@ class ApplicationBase std::shared_ptr _commandLineParser; // Default command line argument identifiers (to allow exclusion) - enum DefaultArg + enum struct DefaultArg { Name, Uri, @@ -108,7 +108,7 @@ class ApplicationBase ITimeSyncService* _timeSyncService{nullptr}; // For sync: wait for sil-kit-system-controller start/abort or manual user abort - enum SystemControllerResult + enum struct SystemControllerResult { Unknown, CoordinatedStart, @@ -198,7 +198,7 @@ class ApplicationBase auto ToLowerCase(std::string s) -> std::string { - std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return (unsigned char)std::tolower(c); }); + std::for_each(s.begin(), s.end(), [](char& c) { c = std::tolower(c); }); return s; } auto IsValidLogLevel(const std::string& levelStr) -> bool @@ -261,7 +261,7 @@ class ApplicationBase if (hasAsyncFlag && hasDurationOption) { - std::cerr << "Error: Options '--async' and '--step' cannot be used simultaneously" << std::endl; + std::cerr << "Error: Options '--async' and '--duration' cannot be used simultaneously" << std::endl; _commandLineParser->PrintUsageInfo(std::cerr, executableName); exit(-1); } @@ -311,13 +311,6 @@ class ApplicationBase { _arguments.participantConfiguration = SilKit::Config::ParticipantConfigurationFromFile(configFileName); } - catch (const SilKit::SilKitError& error) - { - std::cerr << "Error: Failed to load configuration '" << configFileName << "', " << error.what() - << std::endl; - - exit(-2); - } catch (const SilKit::ConfigurationError& error) { std::cerr << "Error: Failed to load configuration '" << configFileName << "', " << error.what() @@ -337,8 +330,7 @@ class ApplicationBase { std::cerr << "Error: Argument of the '--log' option must be one of 'trace', 'debug', 'warn', 'info', " - "'error', " - "'critical', or 'off'" + "'error', 'critical', or 'off'" << std::endl; exit(-1); } @@ -366,12 +358,6 @@ class ApplicationBase { _arguments.participantConfiguration = SilKit::Config::ParticipantConfigurationFromString(configString); } - catch (const SilKit::SilKitError& error) - { - std::cerr << "Error: Failed to set configuration from string '" << configString << "', " << error.what() - << std::endl; - exit(-2); - } catch (const SilKit::ConfigurationError& error) { std::cerr << "Error: Failed to set configuration from string '" << configString << "', " << error.what() @@ -564,7 +550,7 @@ class ApplicationBase { AddCommandLineArgs(); } - catch (const std::runtime_error& e) + catch (const std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; exit(-1);