mirror of
https://github.com/eclipse-openvehicle-api/openvehicle-api.git
synced 2026-04-21 11:38:16 +00:00
334
examples/system_demo_example/example_app/console.cpp
Normal file
334
examples/system_demo_example/example_app/console.cpp
Normal file
@@ -0,0 +1,334 @@
|
||||
#include "console.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <conio.h> // Needed for _kbhit
|
||||
#else
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include "vss_vehiclechassisrearaxlerowwheel_bs_tx.h"
|
||||
#include "vss_vehiclechassissteeringwheelangle_bs_rx.h"
|
||||
#include "vss_vehiclesoftwareapplicationisactivecounter_bs_tx.h"
|
||||
#include "vss_vehiclespeed_bs_rx.h"
|
||||
|
||||
/**
|
||||
* @brief Key hit check. Windows uses the _kbhit function; POSIX emulates this.
|
||||
* @return Returns whether a key has been pressed.
|
||||
*/
|
||||
inline bool KeyHit()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return _kbhit();
|
||||
#elif __unix__
|
||||
int ch = getchar();
|
||||
if (ch != EOF) {
|
||||
ungetc(ch, stdin);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the character from the keyboard buffer if pressed.
|
||||
* @return Returns the character from the keyboard buffer.
|
||||
*/
|
||||
char GetChar()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return static_cast<char>(_getch());
|
||||
#else
|
||||
return getchar();
|
||||
#endif
|
||||
}
|
||||
|
||||
const CConsole::SConsolePos g_sTitle{ 1, 1 };
|
||||
const CConsole::SConsolePos g_sSeparator1{ 2, 1 };
|
||||
const CConsole::SConsolePos g_sDLDescription{ 4, 1 };
|
||||
const CConsole::SConsolePos g_sDLSteeringWheel{ 6, 3 };
|
||||
const CConsole::SConsolePos g_sDLVehicleSpeed{ 7, 3 };
|
||||
const CConsole::SConsolePos g_sDLRearAxle{ 6, 41 };
|
||||
const CConsole::SConsolePos g_sDLAliveCounter{ 7, 41 };
|
||||
const CConsole::SConsolePos g_sSeparator2{ 9, 1 };
|
||||
const CConsole::SConsolePos g_sBSDescription{ 11, 1 };
|
||||
const CConsole::SConsolePos g_sBSSteeringWheel{ 13, 3 };
|
||||
const CConsole::SConsolePos g_sBSVehicleSpeed{ 14, 3 };
|
||||
const CConsole::SConsolePos g_sSeparator3{ 16, 1 };
|
||||
const CConsole::SConsolePos g_sCSDescription{ 18, 1 };
|
||||
const CConsole::SConsolePos g_sCSActivated{ 20, 3 };
|
||||
const CConsole::SConsolePos g_sCSActive{ 21, 3 };
|
||||
const CConsole::SConsolePos g_sCSRearAxle{ 20, 41 };
|
||||
const CConsole::SConsolePos g_sSeparator4{ 23, 1 };
|
||||
const CConsole::SConsolePos g_sControlDescription{ 25, 1 };
|
||||
const CConsole::SConsolePos g_sCursor{ 26, 1 };
|
||||
|
||||
CConsole::CConsole(bool bMonitorDatalink) : m_bMonitorDatalink(bMonitorDatalink)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// Enable ANSI escape codes
|
||||
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (hStdOut != INVALID_HANDLE_VALUE && GetConsoleMode(hStdOut, &m_dwConsoleOutMode))
|
||||
SetConsoleMode(hStdOut, m_dwConsoleOutMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||
HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
|
||||
if (hStdIn != INVALID_HANDLE_VALUE && GetConsoleMode(hStdIn, &m_dwConsoleInMode))
|
||||
SetConsoleMode(hStdIn, m_dwConsoleInMode & ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT));
|
||||
#elif defined __unix__
|
||||
// Disable echo
|
||||
tcgetattr(STDIN_FILENO, &m_sTermAttr);
|
||||
struct termios sTermAttrTemp = m_sTermAttr;
|
||||
sTermAttrTemp.c_lflag &= ~(ICANON | ECHO);
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &sTermAttrTemp);
|
||||
m_iFileStatus = fcntl(STDIN_FILENO, F_GETFL, 0);
|
||||
fcntl(STDIN_FILENO, F_SETFL, m_iFileStatus | O_NONBLOCK);
|
||||
#else
|
||||
#error The OS is not supported!
|
||||
#endif
|
||||
}
|
||||
|
||||
CConsole::~CConsole()
|
||||
{
|
||||
SetCursorPos(g_sCursor);
|
||||
|
||||
#ifdef _WIN32
|
||||
// Return to the stored console mode
|
||||
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (hStdOut != INVALID_HANDLE_VALUE)
|
||||
SetConsoleMode(hStdOut, m_dwConsoleOutMode);
|
||||
HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
|
||||
if (hStdIn != INVALID_HANDLE_VALUE)
|
||||
SetConsoleMode(hStdIn, m_dwConsoleInMode);
|
||||
#elif defined __unix__
|
||||
// Return the previous file status flags.
|
||||
fcntl(STDIN_FILENO, F_SETFL, m_iFileStatus);
|
||||
|
||||
// Return to previous terminal state
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &m_sTermAttr);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CConsole::PrintHeader(const bool bServer, const bool bSimulate)
|
||||
{
|
||||
// Clear the screen...
|
||||
std::cout << "\x1b[2J";
|
||||
|
||||
// Create titles
|
||||
std::string title = "System demo example";
|
||||
std::string dataLinkTitle = "Data link signal values:";
|
||||
if (bServer)
|
||||
title.append(" - Connected to running server");
|
||||
else
|
||||
{
|
||||
if (bSimulate)
|
||||
{
|
||||
title.append(" - run as standalone application, simulation mode");
|
||||
dataLinkTitle = "Dispatch service signal values:";
|
||||
}
|
||||
else
|
||||
{
|
||||
title.append(" - run as standalone application including data link");
|
||||
}
|
||||
}
|
||||
|
||||
// Print the titles
|
||||
PrintText(g_sTitle, title);
|
||||
PrintText(g_sSeparator1, "============================================================================");
|
||||
PrintText(g_sDLDescription, dataLinkTitle.c_str());
|
||||
PrintText(g_sSeparator2, "----------------------------------------------------------------------------");
|
||||
PrintText(g_sBSDescription, "Basic services event values:");
|
||||
PrintText(g_sSeparator3, "----------------------------------------------------------------------------");
|
||||
PrintText(g_sCSDescription, "Counter steering example service values:");
|
||||
PrintText(g_sSeparator4, "============================================================================");
|
||||
PrintText(g_sControlDescription, "Press 'X' to quit; 'T' to toggle the service activity...");
|
||||
}
|
||||
|
||||
bool CConsole::PrepareDataConsumers()
|
||||
{
|
||||
//////////////////////////////////////
|
||||
// DATA LINK
|
||||
|
||||
// Request the data link signals from the dispatch service. This only works for standalone applications, since the data dispatch
|
||||
// service needs to be accessible from within the same process (no IPC marshalling is provided). For server based applications,
|
||||
// the data link layer is inacessible by any application (and complex service), hence data cannot be received if connected to a
|
||||
// server. The m_bMonitorDataLink flag determines whether data from the data link should can be received or not.
|
||||
// NOTE: registering signals and timer for data link data can only occur during configuration time. During the execution, no new
|
||||
// signals can be registered.
|
||||
if (m_bMonitorDatalink)
|
||||
{
|
||||
sdv::core::CDispatchService dispatch;
|
||||
m_signalRearAxleAngle = dispatch.RegisterTxSignal(demo::dsAxleAngle, 0);
|
||||
m_signalCounter = dispatch.RegisterTxSignal(demo::dsLiveCounter, 0);
|
||||
m_signalSteeringWheel = dispatch.Subscribe(demo::dsWheelAngle, [&](sdv::any_t value) { DataLinkCallbackSteeringWheelAngle(value); });
|
||||
m_signalSpeed = dispatch.Subscribe(demo::dsVehicleSpeed, [&](sdv::any_t value) { DataLinkCallbackVehicleSpeed(value); });
|
||||
if (!m_signalRearAxleAngle || !m_signalCounter || !m_signalSteeringWheel || !m_signalSpeed)
|
||||
{
|
||||
std::cerr << "Console ERROR: TX register and RX subscription failed" << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////
|
||||
// BASIC SERVICES
|
||||
|
||||
// Request the basic service for the steering wheel.
|
||||
auto pSteeringWheelSvc = sdv::core::GetObject("Vehicle.Chassis.SteeringWheel.Angle_Service").GetInterface<vss::Vehicle::Chassis::SteeringWheel::AngleService::IVSS_GetSteeringWheel>();
|
||||
if (!pSteeringWheelSvc)
|
||||
{
|
||||
std::cerr << "Console ERROR: Could not get basic service interface 'IVSS_SetSteeringAngle'" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Request the basic service for the vehicle speed.
|
||||
auto pVehSpeedSvc = sdv::core::GetObject("Vehicle.Speed_Service").GetInterface<vss::Vehicle::SpeedService::IVSS_GetSpeed>();
|
||||
if (!pVehSpeedSvc)
|
||||
{
|
||||
std::cerr << "Console ERROR: Could not get basic service interface 'IVSS_SetSpeed'" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Register steering wheel change event handler.
|
||||
pSteeringWheelSvc->RegisterOnSignalChangeOfWheelAngle(static_cast<vss::Vehicle::Chassis::SteeringWheel::AngleService::IVSS_SetSteeringWheel_Event*> (this));
|
||||
|
||||
// Register vehicle speed change event handler.
|
||||
pVehSpeedSvc->RegisterOnSignalChangeOfVehicleSpeed(static_cast<vss::Vehicle::SpeedService::IVSS_SetSpeed_Event*> (this));
|
||||
|
||||
|
||||
//////////////////////////////////////
|
||||
// COMPLEX SERVICE
|
||||
|
||||
m_pCounterSteeringSvc = sdv::core::GetObject("Counter Steering Example Service").GetInterface<ICounterSteeringService>();
|
||||
if (!m_pCounterSteeringSvc)
|
||||
{
|
||||
std::cerr << "Console ERROR: Could not get complex service interface 'ICounterSteeringService'" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void CConsole::RunUntilBreak()
|
||||
{
|
||||
// Run until break
|
||||
bool bRunning = true;
|
||||
while (bRunning)
|
||||
{
|
||||
// Update and display the data from data link, basic services and complex service.
|
||||
UpdateData();
|
||||
|
||||
// Check for a key
|
||||
if (!KeyHit())
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get a keyboard value (if there is any).
|
||||
char c = GetChar();
|
||||
switch (c)
|
||||
{
|
||||
case 't':
|
||||
case 'T':
|
||||
if (m_pCounterSteeringSvc) m_pCounterSteeringSvc->ActivateService(!m_pCounterSteeringSvc->IsActivated());
|
||||
break;
|
||||
case 'x':
|
||||
case 'X':
|
||||
bRunning = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the cursor position at the end
|
||||
SetCursorPos(g_sCursor);
|
||||
|
||||
// Unregister the data link signalss
|
||||
if (m_signalSteeringWheel) m_signalSteeringWheel.Reset();
|
||||
if (m_signalSpeed) m_signalSpeed.Reset();
|
||||
if (m_signalRearAxleAngle) m_signalRearAxleAngle.Reset();
|
||||
if (m_signalCounter) m_signalCounter.Reset();
|
||||
}
|
||||
|
||||
void CConsole::DataLinkCallbackSteeringWheelAngle(sdv::any_t value)
|
||||
{
|
||||
m_fDLSteeringWheelAngle = value.get<float>();
|
||||
}
|
||||
|
||||
void CConsole::DataLinkCallbackVehicleSpeed(sdv::any_t value)
|
||||
{
|
||||
m_fDLVehicleSpeed = value.get<float>();
|
||||
}
|
||||
|
||||
void CConsole::UpdateData()
|
||||
{
|
||||
// Print data link data
|
||||
if (m_bMonitorDatalink)
|
||||
{
|
||||
PrintValue(g_sDLSteeringWheel, "Steering Angle RX", m_fDLSteeringWheelAngle, "rad");
|
||||
PrintValue(g_sDLVehicleSpeed, "Vehicle Speed RX", m_fDLVehicleSpeed, "m/s");
|
||||
PrintValue(g_sDLRearAxle, "Rear axle angle TX", m_signalRearAxleAngle.Read().get<float>(), "deg");
|
||||
PrintValue(g_sDLAliveCounter, "Alive counter TX", m_signalCounter.Read().get<float>(), "");
|
||||
}
|
||||
else
|
||||
PrintText(g_sDLSteeringWheel, "Data link signals are unavailable!");
|
||||
|
||||
// Print basic service event values
|
||||
PrintValue(g_sBSSteeringWheel, "Steering Angle", m_fSteeringWheelAngle * 57.296f , "deg");
|
||||
PrintValue(g_sBSVehicleSpeed, "Vehicle Speed RX", m_fVehicleSpeed * 3.6f , "km/h");
|
||||
|
||||
// Get complex service information
|
||||
if (m_pCounterSteeringSvc)
|
||||
{
|
||||
PrintValue(g_sCSActivated, "Service activated", m_pCounterSteeringSvc->IsActivated(), "");
|
||||
PrintValue(g_sCSActive, "Counter steering active", m_pCounterSteeringSvc->CounterSteeringActive(), "");
|
||||
PrintValue(g_sCSRearAxle, "Rear axle angle", m_pCounterSteeringSvc->RearAxleAngle(), "deg");
|
||||
}
|
||||
}
|
||||
|
||||
void CConsole::SetSteeringWheel(float value)
|
||||
{
|
||||
m_fSteeringWheelAngle = value;
|
||||
}
|
||||
|
||||
void CConsole::SetSpeed(float value)
|
||||
{
|
||||
m_fVehicleSpeed = value;
|
||||
}
|
||||
|
||||
CConsole::SConsolePos CConsole::GetCursorPos() const
|
||||
{
|
||||
SConsolePos sPos{};
|
||||
std::cout << "\033[6n";
|
||||
|
||||
char buff[128];
|
||||
int indx = 0;
|
||||
for(;;) {
|
||||
int cc = std::cin.get();
|
||||
buff[indx] = (char)cc;
|
||||
indx++;
|
||||
if(cc == 'R') {
|
||||
buff[indx + 1] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
int iRow = 0, iCol = 0;
|
||||
sscanf(buff, "\x1b[%d;%dR", &iRow, &iCol);
|
||||
sPos.uiRow = static_cast<uint32_t>(iRow);
|
||||
sPos.uiCol = static_cast<uint32_t>(iCol);
|
||||
fseek(stdin, 0, SEEK_END);
|
||||
|
||||
return sPos;
|
||||
}
|
||||
|
||||
void CConsole::SetCursorPos(SConsolePos sPos)
|
||||
{
|
||||
std::cout << "\033[" << sPos.uiRow << ";" << sPos.uiCol << "H";
|
||||
}
|
||||
|
||||
void CConsole::PrintText(SConsolePos sPos, const std::string& rssText)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mtxPrintToConsole);
|
||||
SetCursorPos(sPos);
|
||||
std::cout << rssText;
|
||||
}
|
||||
202
examples/system_demo_example/example_app/console.h
Normal file
202
examples/system_demo_example/example_app/console.h
Normal file
@@ -0,0 +1,202 @@
|
||||
#ifndef CONSOLE_OUTPUT_H
|
||||
#define CONSOLE_OUTPUT_H
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <support/signal_support.h>
|
||||
#include <support/app_control.h>
|
||||
#include <support/component_impl.h>
|
||||
#include <support/timer.h>
|
||||
#include "signal_names.h"
|
||||
|
||||
#ifdef __unix__
|
||||
#include <termios.h> // Needed for tcgetattr and fcntl
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
// VSS interfaces - located in ../generated/vss_files/include
|
||||
#include "vss_vehiclechassisrearaxlerowwheel_bs_tx.h"
|
||||
#include "vss_vehiclechassissteeringwheelangle_bs_rx.h"
|
||||
#include "vss_vehiclesoftwareapplicationisactivecounter_bs_tx.h"
|
||||
#include "vss_vehiclespeed_bs_rx.h"
|
||||
|
||||
// Complex service counter steering interface - located in ../generated/example_service
|
||||
#include "countersteering.h"
|
||||
|
||||
/**
|
||||
* @brief Console operation class.
|
||||
* @details This class retrieves data from the data link, basix services and complex service and presents it in a regular interval.
|
||||
* Furthermore, it runs in a loop and allows interaction with the complex service.
|
||||
*/
|
||||
class CConsole :
|
||||
public vss::Vehicle::Chassis::SteeringWheel::AngleService::IVSS_SetSteeringWheel_Event, // Basic service interface
|
||||
public vss::Vehicle::SpeedService::IVSS_SetSpeed_Event // Basic service interface
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Screen position structure
|
||||
*/
|
||||
struct SConsolePos
|
||||
{
|
||||
uint32_t uiRow; ///< Row position (starts at 1)
|
||||
uint32_t uiCol; ///< Column position (starts at 1)
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @attention Monitoring the data link can only occur when running as standalone. When connecting to a server, the datalink is
|
||||
* not accessible from the application due to safety and security reasons.
|
||||
* @param[in] bMonitorDatalink When set, register the signals to monitor the datalink.
|
||||
*/
|
||||
CConsole(bool bMonitorDatalink);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~CConsole();
|
||||
|
||||
/**
|
||||
* @brief Print the header.
|
||||
* @param[in] bServer if true onnected to a running server, otherwise the application is running standalone
|
||||
* @param[in] bSimulate if true signals are simulated, otherwise the signal came from data link
|
||||
*/
|
||||
void PrintHeader(const bool bServer, const bool bSimulate);
|
||||
|
||||
/**
|
||||
* @brief Prepare the data consumers..
|
||||
* @details Normally the application communicates through the complex services. As an example of how it could work, three levels
|
||||
* of data consumers are prepared (as an example of how this could work): data link (if the monitor-data-link flag is set),
|
||||
* basic service and complex service.
|
||||
* @return Returns whether the preparation of the data consumers was successful or not.
|
||||
*/
|
||||
bool PrepareDataConsumers();
|
||||
|
||||
/**
|
||||
* @brief Block this thread until CTRL+C is pressed.
|
||||
*/
|
||||
void RunUntilBreak();
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Callback function when steering wheel signal has changed in disptach service.
|
||||
* @remarks Only called when m_bMonitorDatalink is enabled (when running as standalone).
|
||||
* @param[in] value The value of the signal to update.
|
||||
*/
|
||||
void DataLinkCallbackSteeringWheelAngle(sdv::any_t value);
|
||||
|
||||
/**
|
||||
* @brief Callback function when speed signal has changed in disptach service.
|
||||
* @remarks Only called when m_bMonitorDatalink is enabled (when running as standalone).
|
||||
* @param[in] value The value of the signal to update.
|
||||
*/
|
||||
void DataLinkCallbackVehicleSpeed(sdv::any_t value);
|
||||
|
||||
/**
|
||||
* @brief Read the data link TX signals, the basic service event values and the complex service values and print them into the
|
||||
* console.
|
||||
* @remarks Data link data is only shown when m_bMonitorDatalink is enabled (when running as standalone).
|
||||
*/
|
||||
void UpdateData();
|
||||
|
||||
/**
|
||||
* @brief Set steering angle event. Overload of
|
||||
* vss::Vehicle::Chassis::SteeringWheel::AngleService::IVSS_SetSteeringWheel_Event::SetSteeringWheel.
|
||||
* @remarks This is an event function of the steering wheel basic service.
|
||||
* @param[in] value Steering wheel angle in radials (-16...16 rad)
|
||||
*/
|
||||
virtual void SetSteeringWheel(float value) override;
|
||||
|
||||
/**
|
||||
* @brief Speed event. Overload of vss::Vehicle::SpeedService::IVSS_SetSpeed_Event::SetSpeed.
|
||||
* @remarks This is an event function of the vehicle speed service.
|
||||
* @param[in] value Vehicle speed in m/s (0... 128 m/s)
|
||||
*/
|
||||
virtual void SetSpeed(float value) override;
|
||||
|
||||
/**
|
||||
* @brief Get the cursor position of the console.
|
||||
* @return The cursor position.
|
||||
*/
|
||||
SConsolePos GetCursorPos() const;
|
||||
|
||||
/**
|
||||
* @brief Set the current cursor position for the console.
|
||||
* @param[in] sPos Console position to place the current cursor at.
|
||||
*/
|
||||
void SetCursorPos(SConsolePos sPos);
|
||||
|
||||
/**
|
||||
* @brief Print text at a specific location.
|
||||
* @param[in] sPos The location to print text at.
|
||||
* @param[in] rssText Reference to the text to print.
|
||||
*/
|
||||
void PrintText(SConsolePos sPos, const std::string& rssText);
|
||||
|
||||
/**
|
||||
* @brief Print a value string at a specific location.
|
||||
* @tparam TValue Type of value.
|
||||
* @param[in] sPos The location to print the value at.
|
||||
* @param[in] rssName Reference to the value.
|
||||
* @param[in] tValue The value.
|
||||
* @param[in] rssUnits Units the value is in.
|
||||
*/
|
||||
template <typename TValue>
|
||||
void PrintValue(SConsolePos sPos, const std::string& rssName, TValue tValue, const std::string& rssUnits);
|
||||
|
||||
/**
|
||||
* @brief Align string between name and value.
|
||||
* @param[in] message Reference to the message to align.
|
||||
* @param[in] desiredLength The desired length or 0 when no length is specified.
|
||||
* @return The aligned string.
|
||||
*/
|
||||
std::string AlignString(const std::string& message, uint32_t desiredLength = 0);
|
||||
|
||||
mutable std::mutex m_mtxPrintToConsole; ///< Mutex to print complete message
|
||||
bool m_bMonitorDatalink = false; ///< When set, the console output monitors datalink data.
|
||||
sdv::core::CSignal m_signalSteeringWheel; ///< steering wheel angle (input) - datalink monitoring
|
||||
sdv::core::CSignal m_signalSpeed; ///< speed (input) - datalink monitoring
|
||||
sdv::core::CSignal m_signalRearAxleAngle; ///< rear angle (output) - datalink monitoring
|
||||
sdv::core::CSignal m_signalCounter; ///< simple counter (output) - datalink monitoring
|
||||
|
||||
float m_fDLSteeringWheelAngle = 0.0f; ///< default value (input signal) - datalink monitoring
|
||||
float m_fDLVehicleSpeed = 0.0f; ///< default value (input signal) - datalink monitoring
|
||||
|
||||
float m_fSteeringWheelAngle = 0.0f; ///< Steering wheel angle - basic service event value
|
||||
float m_fVehicleSpeed = 0.0f; ///< Vehicle speed - basic service event value
|
||||
|
||||
ICounterSteeringService* m_pCounterSteeringSvc = nullptr; ///< Counter steering service interface pointer.
|
||||
|
||||
#ifdef _WIN32
|
||||
DWORD m_dwConsoleOutMode = 0u; ///< The console mode before switching on ANSI support.
|
||||
DWORD m_dwConsoleInMode = 0u; ///< The console mode before switching on ANSI support.
|
||||
#elif defined __unix__
|
||||
struct termios m_sTermAttr{}; ///< The terminal attributes before disabling echo.
|
||||
int m_iFileStatus = 0; ///< The file status flags for STDIN.
|
||||
#else
|
||||
#error The OS is not supported!
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
template <typename TValue>
|
||||
inline void CConsole::PrintValue(SConsolePos sPos, const std::string& rssName, TValue tValue, const std::string& rssUnits)
|
||||
{
|
||||
const size_t nValueNameLen = 26;
|
||||
std::stringstream sstreamValueText;
|
||||
sstreamValueText << rssName <<
|
||||
std::string(nValueNameLen - std::min(rssName.size(), static_cast<size_t>(nValueNameLen - 1)) - 1, '.') <<
|
||||
" " << std::fixed << std::setprecision(2) << tValue << " " << rssUnits << " ";
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_mtxPrintToConsole);
|
||||
SetCursorPos(sPos);
|
||||
std::cout << sstreamValueText.str();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void CConsole::PrintValue<bool>(SConsolePos sPos, const std::string& rssName, bool bValue, const std::string& rssUnits)
|
||||
{
|
||||
PrintValue(sPos, rssName, bValue ? "yes" : "no", rssUnits);
|
||||
}
|
||||
|
||||
#endif // !define CONSOLE_OUTPUT_H
|
||||
222
examples/system_demo_example/example_app/control.cpp
Normal file
222
examples/system_demo_example/example_app/control.cpp
Normal file
@@ -0,0 +1,222 @@
|
||||
#include "control.h"
|
||||
|
||||
CExampleControl::~CExampleControl()
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
bool CExampleControl::Initialize()
|
||||
{
|
||||
if (m_bInitialized) return true;
|
||||
|
||||
// Set the SDV V-API framework directory.
|
||||
if (!m_pathFramework.empty())
|
||||
m_appcontrol.SetFrameworkRuntimeDirectory(m_pathFramework);
|
||||
|
||||
// Start the framework
|
||||
std::stringstream sstreamAppConfig;
|
||||
sstreamAppConfig << "[Application]" << std::endl;
|
||||
sstreamAppConfig << "Mode=\"" << (RunAsStandaloneApp() ? "Standalone" : "External") << "\"" << std::endl;
|
||||
sstreamAppConfig << "Instance=" << m_uiInstance << std::endl;
|
||||
sstreamAppConfig << "Retries=" << 6 << std::endl;
|
||||
sstreamAppConfig << "[Console]" << std::endl;
|
||||
sstreamAppConfig << "Report=";
|
||||
switch (m_eReporting)
|
||||
{
|
||||
case EAppControlReporting::normal:
|
||||
sstreamAppConfig << "\"Normal\"";
|
||||
break;
|
||||
case EAppControlReporting::verbose:
|
||||
sstreamAppConfig << "\"Verbose\"";
|
||||
break;
|
||||
default:
|
||||
sstreamAppConfig << "\"Silent\"";
|
||||
break;
|
||||
}
|
||||
sstreamAppConfig << std::endl;
|
||||
if (!m_appcontrol.Startup(sstreamAppConfig.str())) return false;
|
||||
|
||||
// Local configurations only when running as standalone.
|
||||
if (RunAsStandaloneApp())
|
||||
{
|
||||
// Start in configuration mode.
|
||||
m_appcontrol.SetConfigMode();
|
||||
if (!m_appcontrol.AddConfigSearchDir("config"))
|
||||
{
|
||||
m_appcontrol.Shutdown();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_bInitialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CExampleControl::Shutdown()
|
||||
{
|
||||
if (!m_bInitialized)
|
||||
m_appcontrol.Shutdown();
|
||||
m_bInitialized = false;
|
||||
}
|
||||
|
||||
bool CExampleControl::IsInitialized() const
|
||||
{
|
||||
return m_bInitialized;
|
||||
}
|
||||
|
||||
bool CExampleControl::LoadConfigFile(const std::string& inputMsg, const std::string& configFileName)
|
||||
{
|
||||
if (!m_bInitialized && m_eRunAs == ERunAs::standalone) return false;
|
||||
|
||||
std::string msg = inputMsg;
|
||||
if (m_appcontrol.LoadConfig(configFileName) == sdv::core::EConfigProcessResult::successful)
|
||||
{
|
||||
msg.append("ok\n");
|
||||
std::cout << msg.c_str();
|
||||
return true;
|
||||
}
|
||||
|
||||
msg.append("FAILED.\n");
|
||||
std::cout << msg.c_str();
|
||||
return false;
|
||||
}
|
||||
|
||||
void CExampleControl::StartTestRun()
|
||||
{
|
||||
if (!m_bInitialized) return;
|
||||
|
||||
// Switch to running mode.
|
||||
m_appcontrol.SetRunningMode();
|
||||
|
||||
// Should the datalink be simulated?
|
||||
if (m_eRunAs != ERunAs::standalone_simulated) return;
|
||||
|
||||
// Start the simulated datalink
|
||||
m_bRunning = true;
|
||||
m_threadSimulateDatalink = std::thread(&CExampleControl::SimulateDatalinkThreadFunc, this);
|
||||
}
|
||||
|
||||
void CExampleControl::StopTestRun()
|
||||
{
|
||||
// Stop running and wait for any thread to finalize
|
||||
m_bRunning = false;
|
||||
if (m_threadSimulateDatalink.joinable())
|
||||
m_threadSimulateDatalink.join();
|
||||
}
|
||||
|
||||
bool CExampleControl::HasCommandLineError() const
|
||||
{
|
||||
return m_bCmdLnError;
|
||||
}
|
||||
|
||||
bool CExampleControl::HasRequestedCommandLineHelp() const
|
||||
{
|
||||
return m_bCmdLnHelp;
|
||||
}
|
||||
|
||||
CExampleControl::ERunAs CExampleControl::GetAppOperation() const
|
||||
{
|
||||
return m_eRunAs;
|
||||
}
|
||||
|
||||
bool CExampleControl::IsSimulationMode() const
|
||||
{
|
||||
return m_eRunAs == ERunAs::standalone_simulated;
|
||||
}
|
||||
|
||||
bool CExampleControl::RunAsStandaloneApp() const
|
||||
{
|
||||
return m_eRunAs == ERunAs::standalone || m_eRunAs == ERunAs::standalone_simulated;
|
||||
}
|
||||
|
||||
bool CExampleControl::RunAsServerApp() const
|
||||
{
|
||||
return m_eRunAs == ERunAs::server_connect;
|
||||
}
|
||||
|
||||
bool CExampleControl::RegisterSignalsSimDatalink()
|
||||
{
|
||||
if (!m_bInitialized) return false;
|
||||
if (m_eRunAs != ERunAs::standalone_simulated) return true; // Nothing to do...
|
||||
|
||||
std::string msg = "Register all signals: ";
|
||||
sdv::core::CDispatchService dispatch;
|
||||
|
||||
m_signalSteeringWheel = dispatch.RegisterRxSignal(demo::dsWheelAngle);
|
||||
m_signalSpeed = dispatch.RegisterRxSignal(demo::dsVehicleSpeed);
|
||||
m_signalRearAngle = dispatch.RegisterTxSignal(demo::dsAxleAngle, 0);
|
||||
m_signalCounter = dispatch.RegisterTxSignal(demo::dsLiveCounter, 0);
|
||||
|
||||
if (m_signalSteeringWheel && m_signalSpeed && m_signalRearAngle && m_signalCounter)
|
||||
std::cout << "Registration was successful\n";
|
||||
else
|
||||
std::cout << "ATTENTION! Registration failed\n";
|
||||
|
||||
auto allSignals = dispatch.GetRegisteredSignals();
|
||||
msg.append("(number of signals == ");
|
||||
msg.append(std::to_string(allSignals.size()));
|
||||
msg.append(") ok\n");
|
||||
std::cout << msg.c_str();
|
||||
return true;
|
||||
}
|
||||
|
||||
void CExampleControl::ResetSignalsSimDatalink()
|
||||
{
|
||||
if (m_eRunAs != ERunAs::standalone_simulated) return; // Nothing to do...
|
||||
|
||||
if (m_signalSteeringWheel)
|
||||
m_signalSteeringWheel.Reset();
|
||||
if (m_signalSpeed)
|
||||
m_signalSpeed.Reset();
|
||||
if (m_signalRearAngle)
|
||||
m_signalRearAngle.Reset();
|
||||
if (m_signalCounter)
|
||||
m_signalCounter.Reset();
|
||||
}
|
||||
|
||||
void CExampleControl::SimulateDatalinkThreadFunc()
|
||||
{
|
||||
if (m_eRunAs != ERunAs::standalone_simulated) return; // Nothing to do...
|
||||
|
||||
// Send fSteeringWheelAngle wheel angel from -16 to 16 radians and vice versa
|
||||
// Send fVehicleSpeed from 0 to 12 m/s (43.2 km/h) and vice versa
|
||||
|
||||
float fSteeringWheelAngle = 0.0f;
|
||||
float fVehicleSpeed = 0.0f;
|
||||
m_signalSpeed.Write(fVehicleSpeed);
|
||||
m_signalSteeringWheel.Write(fSteeringWheelAngle);
|
||||
|
||||
float fDeltaSteering = 0.1f;
|
||||
float fDeltaSpeed = 0.1f;
|
||||
|
||||
while (m_bRunning)
|
||||
{
|
||||
fSteeringWheelAngle += fDeltaSteering;
|
||||
if (fSteeringWheelAngle >= 15.999f)
|
||||
{
|
||||
fSteeringWheelAngle = 16.0f;
|
||||
fDeltaSteering = -0.1f;
|
||||
}
|
||||
else if (fSteeringWheelAngle <= -16.0f)
|
||||
{
|
||||
fSteeringWheelAngle = -16.0f;
|
||||
fDeltaSteering = 0.1f;
|
||||
}
|
||||
|
||||
fVehicleSpeed += fDeltaSpeed;
|
||||
if (fVehicleSpeed >= 12.0f)
|
||||
{
|
||||
fVehicleSpeed = 12.0f;
|
||||
fDeltaSpeed = -1.0f;
|
||||
}
|
||||
else if (fVehicleSpeed <= 0.0f)
|
||||
{
|
||||
fVehicleSpeed = 0.0f;
|
||||
fDeltaSpeed = 0.1f;
|
||||
}
|
||||
|
||||
m_signalSteeringWheel.Write(fSteeringWheelAngle);
|
||||
m_signalSpeed.Write(fVehicleSpeed);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(300));
|
||||
}
|
||||
}
|
||||
330
examples/system_demo_example/example_app/control.h
Normal file
330
examples/system_demo_example/example_app/control.h
Normal file
@@ -0,0 +1,330 @@
|
||||
#ifndef EXMAPLE_UTILITY_H
|
||||
#define EXMAPLE_UTILITY_H
|
||||
|
||||
#include <string>
|
||||
#include <support/app_control.h>
|
||||
#include <support/signal_support.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <codecvt>
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996)
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "signal_names.h"
|
||||
|
||||
/**
|
||||
* @brief Utility handler for example demos
|
||||
*/
|
||||
class CExampleControl
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor with the command line arguments.
|
||||
* @tparam TCharType Character type of the command line arguments.
|
||||
* @param[in] iArgs Amount of arguments.
|
||||
* @param[in] rgszArgs Array of argument strings. The first argument represents the application name.
|
||||
*/
|
||||
template <typename TCharType>
|
||||
CExampleControl(int iArgs, const TCharType rgszArgs[]);
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
~CExampleControl();
|
||||
|
||||
/**
|
||||
* @brief Initialize application control based on the command line arguments provided through the constructor.
|
||||
* @return Return true on success; false when not.
|
||||
*/
|
||||
bool Initialize();
|
||||
|
||||
/**
|
||||
* @brief Shutdown the system.
|
||||
*/
|
||||
void Shutdown();
|
||||
|
||||
/**
|
||||
* @brief Is the control initialized?
|
||||
* @return Returns whether control is initialized.
|
||||
*/
|
||||
bool IsInitialized() const;
|
||||
|
||||
/**
|
||||
* @brief Register signals, required by the vehicle devices.
|
||||
* @remarks Only valid for standalone applications.
|
||||
* @pre Initialization must be done before.
|
||||
* @param[in] inputMsg message string to be printed on console in case of success and failure
|
||||
* @param[in] configFileName config toml file name
|
||||
* @return Return true on success otherwise false
|
||||
*/
|
||||
bool LoadConfigFile(const std::string& inputMsg, const std::string& configFileName);
|
||||
|
||||
/**
|
||||
* @brief Start the test run if not running before.
|
||||
* @details Write the input signals. In case of data link the signals are written from a asc file by the can_com_sim.sdv component.
|
||||
* Otherwise the signals are create and can be written directly.
|
||||
*/
|
||||
void StartTestRun();
|
||||
|
||||
/**
|
||||
* @brief Stops a test run if currently running.
|
||||
*/
|
||||
void StopTestRun();
|
||||
|
||||
/**
|
||||
* @brief Did a command line error occur?
|
||||
* @return Returns whether a command line error occurred.
|
||||
*/
|
||||
bool HasCommandLineError() const;
|
||||
|
||||
/**
|
||||
* @brief Was command line help requested?
|
||||
* @return Returns whether a command line help was requested.
|
||||
*/
|
||||
bool HasRequestedCommandLineHelp() const;
|
||||
|
||||
/**
|
||||
* @brief Application operation.
|
||||
*/
|
||||
enum class ERunAs
|
||||
{
|
||||
standalone, ///< This application runs as standalone using data link and can_com_sim.sdv which reads the CAN messages from an asc file.
|
||||
standalone_simulated, ///< This application runs as standalone simulating data read/write without datalink.
|
||||
server_connect, ///< Connect to a server and run as a client application.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Get the current application operation (retrieved from command line).
|
||||
* @return The application operation.
|
||||
*/
|
||||
ERunAs GetAppOperation() const;
|
||||
|
||||
/**
|
||||
* @brief Is the simulation mode activated
|
||||
* @return Returns whether simulation or data link is active.
|
||||
*/
|
||||
bool IsSimulationMode() const;
|
||||
|
||||
/**
|
||||
* @brief Does the application run as a standalone application?
|
||||
* @return Returns whether the application runs as a standalone application.
|
||||
*/
|
||||
bool RunAsStandaloneApp() const;
|
||||
|
||||
/**
|
||||
* @brief Does the application connect to a server and run on the server?
|
||||
* @return Returns whether the application runs on the server.
|
||||
*/
|
||||
bool RunAsServerApp() const;
|
||||
|
||||
/**
|
||||
* @brief Register signals for datalink simulation; required by the vehicle devices.
|
||||
* @return Returns 'true' on success; 'false' on failure.
|
||||
*/
|
||||
bool RegisterSignalsSimDatalink();
|
||||
|
||||
/**
|
||||
* @brief Reset signals for datalink simulation; needed for a proper shutdown.
|
||||
*/
|
||||
void ResetSignalsSimDatalink();
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Provide simulated signals until m_bRunning is disabled.
|
||||
*/
|
||||
void SimulateDatalinkThreadFunc();
|
||||
|
||||
/**
|
||||
* @brief Reporting by the SDV V-API application control.
|
||||
*/
|
||||
enum class EAppControlReporting
|
||||
{
|
||||
silent, ///< No reporting by application control (default)
|
||||
normal, ///< Normal reporting by application control
|
||||
verbose, ///< Extensive reporting by application control
|
||||
};
|
||||
|
||||
bool m_bInitialized = false; ///< Set when initialized.
|
||||
bool m_bCmdLnError = false; ///< Command line error occurred.
|
||||
bool m_bCmdLnHelp = false; ///< Command line help provided.
|
||||
bool m_bRunning = false; ///< When set, the application is running.
|
||||
ERunAs m_eRunAs = ERunAs::standalone; ///< Application operation.
|
||||
EAppControlReporting m_eReporting = EAppControlReporting::silent; ///< Application control reporting.
|
||||
uint32_t m_uiInstance = 1000u; ///< Server instance to connect to.
|
||||
std::filesystem::path m_pathFramework; ///< Path to the SDV V-API framework.
|
||||
sdv::app::CAppControl m_appcontrol; ///< App-control of SDV V-API.
|
||||
std::thread m_threadSimulateDatalink; ///< Simulation datalink thread.
|
||||
sdv::core::CSignal m_signalSteeringWheel; ///< Steering wheel angle signal (input) - simulated datalink
|
||||
sdv::core::CSignal m_signalSpeed; ///< Speed signal (input) - simulated datalink
|
||||
sdv::core::CSignal m_signalRearAngle; ///< Rear angle signal (output) - simulated datalink
|
||||
sdv::core::CSignal m_signalCounter; ///< Simple counter signal (output) - simulated datalink
|
||||
};
|
||||
|
||||
template <typename TCharType>
|
||||
CExampleControl::CExampleControl(int iArgs, const TCharType rgszArgs[])
|
||||
{
|
||||
bool bStandalone = false;
|
||||
bool bStandaloneSimulated = false;
|
||||
bool bServerConnect = false;
|
||||
bool bSilent = false;
|
||||
bool bNormal = false;
|
||||
bool bVerbose = false;
|
||||
for (int i = 1; i < iArgs; i++)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
std::wstring wide_string = rgszArgs[i];
|
||||
size_t size_needed = std::wcstombs(nullptr, wide_string.c_str(), 0);
|
||||
std::string ssArg(size_needed, 0);
|
||||
std::wcstombs(&ssArg[0], wide_string.c_str(), size_needed);
|
||||
#else
|
||||
std::string ssArg = rgszArgs[i];
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
if (ssArg == "/?" || ssArg == "--help" || ssArg == "-?")
|
||||
#else
|
||||
if (ssArg == "--help" || ssArg == "-?")
|
||||
#endif
|
||||
{
|
||||
m_bCmdLnHelp = true;
|
||||
continue;
|
||||
}
|
||||
if (ssArg.substr(0, 10) == "--instance")
|
||||
{
|
||||
m_uiInstance = std::stoul(ssArg.substr(10));
|
||||
continue;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
if (ssArg.substr(0, 2) == "/f" || ssArg.substr(0, 2) == "-f")
|
||||
#else
|
||||
if (ssArg.substr(0, 2) == "-f")
|
||||
#endif
|
||||
{
|
||||
m_pathFramework = std::filesystem::u8path(ssArg.substr(2));
|
||||
continue;
|
||||
}
|
||||
if (ssArg == "--standalone")
|
||||
{
|
||||
bStandalone = true;
|
||||
continue;
|
||||
}
|
||||
if (ssArg == "--connect")
|
||||
{
|
||||
bServerConnect = true;
|
||||
continue;
|
||||
}
|
||||
if (ssArg == "--simulate")
|
||||
{
|
||||
bStandaloneSimulated = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (ssArg == "/s" || ssArg == "-s" || ssArg == "--silent")
|
||||
#else
|
||||
if (ssArg == "-s" || ssArg == "--silent")
|
||||
#endif
|
||||
{
|
||||
bSilent = true;
|
||||
continue;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
if (ssArg == "/n" || ssArg == "-n" || ssArg == "--normal")
|
||||
#else
|
||||
if (ssArg == "-n" || ssArg == "--normal")
|
||||
#endif
|
||||
{
|
||||
bSilent = true;
|
||||
continue;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
if (ssArg == "/v" || ssArg == "-v" || ssArg == "--verbose")
|
||||
#else
|
||||
if (ssArg == "-v" || ssArg == "--verbose")
|
||||
#endif
|
||||
{
|
||||
bVerbose = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Argument not known
|
||||
std::cerr << "ERROR: unknown argument '" << ssArg << "'" << std::endl;
|
||||
m_bCmdLnError = true;
|
||||
}
|
||||
|
||||
// Check for an invalid flag.
|
||||
if (!m_bCmdLnError && (bStandalone || bStandaloneSimulated) && bServerConnect)
|
||||
{
|
||||
std::cerr << "ERROR: the application can run either as standalone application of connect to a server.";
|
||||
m_bCmdLnError = true;
|
||||
}
|
||||
|
||||
// Set to server connect if requested.
|
||||
if (bServerConnect)
|
||||
m_eRunAs = ERunAs::server_connect;
|
||||
if (bStandaloneSimulated)
|
||||
m_eRunAs = ERunAs::standalone_simulated;
|
||||
|
||||
// Check console output flags
|
||||
if ((bSilent && bNormal) ||
|
||||
(bSilent && bVerbose) ||
|
||||
(bNormal && bSilent))
|
||||
{
|
||||
std::cerr << "ERROR: multiple settings for the SDV V-API application control console output.";
|
||||
m_bCmdLnError = true;
|
||||
}
|
||||
|
||||
// Set control app reporting mode if requested.
|
||||
if (bNormal)
|
||||
m_eReporting = EAppControlReporting::normal;
|
||||
if (bVerbose)
|
||||
m_eReporting = EAppControlReporting::verbose;
|
||||
|
||||
// Check for the framework runtime location
|
||||
if (!m_bCmdLnError && m_pathFramework.empty())
|
||||
{
|
||||
const char* szSDVFramework = std::getenv("SDV_FRAMEWORK_RUNTIME");
|
||||
if (szSDVFramework)
|
||||
m_pathFramework = std::filesystem::u8path(szSDVFramework);
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: Missing path to SDV V-API framework. Use commandline argument -f or set "
|
||||
"SDV_FRAMEWORK_RUNTIME environment variable." << std::endl;
|
||||
m_bCmdLnError = true;
|
||||
}
|
||||
}
|
||||
if (!m_bCmdLnError && !std::filesystem::is_directory(m_pathFramework) && !std::filesystem::exists(m_pathFramework / "core_services.sdv"))
|
||||
{
|
||||
std::cerr << "ERROR: Invalid path to SDV V-API framework." << std::endl;
|
||||
m_bCmdLnError = true;
|
||||
}
|
||||
|
||||
// Print help or error information
|
||||
if (m_bCmdLnHelp || m_bCmdLnError)
|
||||
{
|
||||
std::cout << R"text(
|
||||
Usage: system_demo_example <options>
|
||||
|
||||
--help, -? Show help
|
||||
--instance<no> Set instance number for server connection (default = 1000).
|
||||
-f<framework_location> Location of SDV V-API framework if SDV_FRAMEWORK_RUNTIME hasn't been set.
|
||||
--standalone Run as standalone application (data link layer through can_com_sim.sdv which reads the CAN messages from an asc file).
|
||||
--simulate Run as standalone application and simulate the data link layer.
|
||||
--connect Connect to running server.
|
||||
--silent, -s Start the SDV application control with console output in silent mode (default).
|
||||
--normal, -n Start the SDV application control with console output in normal mode.
|
||||
--verbose, -v Start the SDV application control with console output in verbose mode.
|
||||
|
||||
)text";
|
||||
}}
|
||||
|
||||
|
||||
#endif // ! defined EXMAPLE_UTILITY_H
|
||||
25
examples/system_demo_example/example_app/signal_names.h
Normal file
25
examples/system_demo_example/example_app/signal_names.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* namespace for the signal names
|
||||
* in case /generated/vss_files/signal_identifier.h
|
||||
* exists, use the file, otherwise define the namespace
|
||||
*/
|
||||
|
||||
#ifndef SIGNAL_NAMES_H
|
||||
#define SIGNAL_NAMES_H
|
||||
|
||||
#ifdef __has_include
|
||||
#if __has_include("../generated/vss_files/signal_identifier.h")
|
||||
#include "../generated/vss_files/signal_identifier.h"
|
||||
#else
|
||||
namespace demo
|
||||
{
|
||||
static std::string dsWheelAngle = "CAN_Input.SteeringWheel"; ///< float RX Vehicle.Chassis.SteeringWheel.Angle
|
||||
static std::string dsVehicleSpeed = "CAN_Input.Speed"; ///< float RX Vehicle.Speed
|
||||
static std::string dsAxleAngle = "CAN_Output.RearAngle"; ///< float TX Vehicle.Chassis.RearAxle.Row.Wheel
|
||||
static std::string dsLiveCounter = "CAN_Output.IsActiveCounter"; ///< uint8_t TX Vehicle.Software.Application.IsActiveCounter
|
||||
} // demo
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // ! defined SIGNAL_NAMES_H
|
||||
|
||||
180
examples/system_demo_example/example_app/system_demo_example.cpp
Normal file
180
examples/system_demo_example/example_app/system_demo_example.cpp
Normal file
@@ -0,0 +1,180 @@
|
||||
#ifdef __unix__
|
||||
#include <semaphore.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
#include <cstdlib>
|
||||
#include "control.h"
|
||||
#include "console.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
// Some old MinGW/CYGWIN distributions don't define this:
|
||||
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
|
||||
#endif
|
||||
|
||||
static HANDLE stdoutHandle, stdinHandle;
|
||||
static DWORD outModeInit, inModeInit;
|
||||
|
||||
void setupConsole(void) {
|
||||
DWORD outMode = 0, inMode = 0;
|
||||
stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
stdinHandle = GetStdHandle(STD_INPUT_HANDLE);
|
||||
|
||||
if(stdoutHandle == INVALID_HANDLE_VALUE || stdinHandle == INVALID_HANDLE_VALUE) {
|
||||
exit(GetLastError());
|
||||
}
|
||||
|
||||
if(!GetConsoleMode(stdoutHandle, &outMode) || !GetConsoleMode(stdinHandle, &inMode)) {
|
||||
exit(GetLastError());
|
||||
}
|
||||
|
||||
outModeInit = outMode;
|
||||
inModeInit = inMode;
|
||||
|
||||
// Enable ANSI escape codes
|
||||
outMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
|
||||
// Set stdin as no echo and unbuffered
|
||||
inMode &= ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT);
|
||||
|
||||
if(!SetConsoleMode(stdoutHandle, outMode) || !SetConsoleMode(stdinHandle, inMode)) {
|
||||
exit(GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
void restoreConsole(void) {
|
||||
// Reset colors
|
||||
printf("\x1b[0m");
|
||||
|
||||
// Reset console mode
|
||||
if(!SetConsoleMode(stdoutHandle, outModeInit) || !SetConsoleMode(stdinHandle, inModeInit)) {
|
||||
exit(GetLastError());
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
static struct termios orig_term;
|
||||
static struct termios new_term;
|
||||
|
||||
void setupConsole(void) {
|
||||
tcgetattr(STDIN_FILENO, &orig_term);
|
||||
new_term = orig_term;
|
||||
|
||||
new_term.c_lflag &= ~(ICANON | ECHO);
|
||||
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &new_term);
|
||||
}
|
||||
|
||||
void restoreConsole(void) {
|
||||
// Reset colors
|
||||
printf("\x1b[0m");
|
||||
|
||||
// Reset console mode
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &orig_term);
|
||||
}
|
||||
#endif
|
||||
|
||||
void getCursorPosition(int *row, int *col) {
|
||||
printf("\x1b[6n");
|
||||
char buff[128];
|
||||
int indx = 0;
|
||||
for(;;) {
|
||||
int cc = getchar();
|
||||
buff[indx] = (char)cc;
|
||||
indx++;
|
||||
if(cc == 'R') {
|
||||
buff[indx + 1] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
sscanf(buff, "\x1b[%d;%dR", row, col);
|
||||
fseek(stdin, 0, SEEK_END);
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && defined(_UNICODE)
|
||||
extern "C" int wmain(int argc, wchar_t* argv[])
|
||||
{
|
||||
#else
|
||||
extern "C" int main(int argc, char* argv[])
|
||||
{
|
||||
#endif
|
||||
|
||||
std::cout << "System demo example" << std::endl;
|
||||
std::cout << "----------------------------------------------------------------------------" << std::endl;
|
||||
|
||||
// Start application control
|
||||
CExampleControl control(argc, argv);
|
||||
if (control.HasCommandLineError()) return -1; // Command line error occurred; cannot continue.
|
||||
if (control.HasRequestedCommandLineHelp()) return 0; // Command line help requested; job done.
|
||||
if (!control.Initialize())
|
||||
{
|
||||
std::cerr << "ERROR: Failed to initialize application control." << std::endl;
|
||||
return -2;
|
||||
}
|
||||
|
||||
// The console provides output.
|
||||
CConsole console(control.RunAsStandaloneApp());
|
||||
|
||||
// Load configuration files when running as standalone
|
||||
if (control.RunAsStandaloneApp())
|
||||
{
|
||||
bool bResult = control.LoadConfigFile("Load dispatch example: ", "data_dispatch_example.toml");
|
||||
bResult &= control.LoadConfigFile("Load task timer: ", "task_timer_example.toml");
|
||||
if (control.GetAppOperation() == CExampleControl::ERunAs::standalone)
|
||||
{
|
||||
std::cout << "Datalink enabled, load CAN Simulation device and datalink component." << std::endl;
|
||||
bResult &= control.LoadConfigFile("Load can_com_simulation: ", "can_com_simulation.toml");
|
||||
bResult &= control.LoadConfigFile("Load data link: ", "data_link_example.toml");
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Datalink disabled, register the required signals for a simulated datalink." << std::endl;
|
||||
control.RegisterSignalsSimDatalink();
|
||||
}
|
||||
|
||||
bResult &= control.LoadConfigFile("Load vehicle_devices_basic_services_example: ", "vehicle_devices_basic_services_example.toml");
|
||||
bResult &= control.LoadConfigFile("Load complex_service_example: ", "complex_service_example.toml");
|
||||
if (!bResult)
|
||||
{
|
||||
std::cerr << std::endl << "ERROR: One or more configurations were not able to load. Cannot continue." << std::endl;
|
||||
control.Shutdown();
|
||||
return -3;
|
||||
}
|
||||
}
|
||||
|
||||
// Print the application header
|
||||
console.PrintHeader(control.RunAsServerApp(), control.IsSimulationMode());
|
||||
|
||||
// Prepare for data consumption.
|
||||
if (!console.PrepareDataConsumers())
|
||||
{
|
||||
std::cerr << std::endl << "ERROR: Cannot instantiate the data consumers. Cannot continue." << std::endl;
|
||||
control.Shutdown();
|
||||
return -4;
|
||||
}
|
||||
|
||||
// Start the test run
|
||||
control.StartTestRun();
|
||||
|
||||
// Run until break.
|
||||
console.RunUntilBreak();
|
||||
|
||||
// Finish test run
|
||||
control.StopTestRun();
|
||||
|
||||
// Reset the signals for a simulated datalink
|
||||
if (control.GetAppOperation() == CExampleControl::ERunAs::standalone_simulated)
|
||||
control.ResetSignalsSimDatalink();
|
||||
|
||||
// Shutdown the example control
|
||||
control.Shutdown();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
#include "control.h"
|
||||
#include "countersteering.h"
|
||||
|
||||
/**
|
||||
* @brief check if SDV_FRAMEWORK_RUNTIME environment variable exists
|
||||
* @return Return true if environment variable is found otherwise false
|
||||
*/
|
||||
bool IsSDVFrameworkEnvironmentSet()
|
||||
{
|
||||
const char* envVariable = std::getenv("SDV_FRAMEWORK_RUNTIME");
|
||||
if (envVariable)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && defined(_UNICODE)
|
||||
extern "C" int wmain()
|
||||
#else
|
||||
extern "C" int main()
|
||||
#endif
|
||||
{
|
||||
uint32_t uiInstance = 3001;
|
||||
sdv::app::CAppControl appcontrol;
|
||||
if (!IsSDVFrameworkEnvironmentSet())
|
||||
{
|
||||
// if SDV_FRAMEWORK_RUNTIME environment variable is not set we need to set the Framework Runtime directory
|
||||
appcontrol.SetFrameworkRuntimeDirectory("../../bin");
|
||||
}
|
||||
|
||||
appcontrol.AddModuleSearchDir("../../bin");
|
||||
|
||||
std::stringstream sstreamAppConfig;
|
||||
sstreamAppConfig << "[Application]" << std::endl;
|
||||
sstreamAppConfig << "Mode=\"External\"" << std::endl;
|
||||
sstreamAppConfig << "Instance=" << uiInstance << std::endl;
|
||||
sstreamAppConfig << "Retries=" << 10 << std::endl;
|
||||
sstreamAppConfig << "[Console]" << std::endl;
|
||||
sstreamAppConfig << "Report=\"Verbose\"" << std::endl;
|
||||
|
||||
// Start the framework as external application, which wants to connect to instance 3001
|
||||
if (!appcontrol.Startup(sstreamAppConfig.str()))
|
||||
{
|
||||
std::cout << "appcontrol.Startup() failed." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto pCounterSteeringSvc = sdv::core::GetObject("Counter Steering Example Service").GetInterface<ICounterSteeringService>();
|
||||
if (!pCounterSteeringSvc)
|
||||
{
|
||||
std::cout << "\nERROR: Could not get 'ICounterSteeringService', connection to " << std::to_string (uiInstance) << "probably failed.\n" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << "\nSUCCESS: Got 'ICounterSteeringService', could connect to instance." << std::to_string (uiInstance) << "\n" << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user