Precommit (#1)

* first commit

* cleanup
This commit is contained in:
tompzf
2025-11-04 13:28:06 +01:00
committed by GitHub
parent dba45dc636
commit 6ed4b1534e
898 changed files with 256340 additions and 0 deletions

View File

@@ -0,0 +1,309 @@
#include "console.h"
#ifdef _WIN32
#include <conio.h> // Needed for _kbhit
#else
#include <fcntl.h>
#endif
const CConsole::SConsolePos g_sTitle{ 1, 1 };
const CConsole::SConsolePos g_sSubTitle{ 3, 1 };
const CConsole::SConsolePos g_sSeparator1{ 5, 1 };
const CConsole::SConsolePos g_sDataLink{ 7, 1 };
const CConsole::SConsolePos g_sDataLinkSpeed{ 8, 1 };
const CConsole::SConsolePos g_sSeparator2{ 10, 1 };
const CConsole::SConsolePos g_sVehicleDevice{ 12, 1 };
const CConsole::SConsolePos g_sVehicleDeviceSpeed{ 13, 1 };
const CConsole::SConsolePos g_sSeparator3{ 15, 1 };
const CConsole::SConsolePos g_sBasicService{ 17, 1 };
const CConsole::SConsolePos g_sBasicServiceSpeed{ 18, 1 };
const CConsole::SConsolePos g_sSeparator4{ 20, 1 };
const CConsole::SConsolePos g_sComment1{ 22, 1 };
const CConsole::SConsolePos g_sComment2{ 23, 1 };
const CConsole::SConsolePos g_sComment3{ 24, 1 };
const CConsole::SConsolePos g_sComment4{ 25, 1 };
const CConsole::SConsolePos g_sComment5{ 26, 1 };
const CConsole::SConsolePos g_sSeparator5{ 28, 1 };
const CConsole::SConsolePos g_sComplexServcie1{ 30, 1 };
const CConsole::SConsolePos g_sComplexServcie2{ 31, 1 };
const CConsole::SConsolePos g_sSeparator6{ 33, 1 };
const CConsole::SConsolePos g_sControlDescription{ 35, 1 };
const CConsole::SConsolePos g_sCursor{ 36, 1 };
CConsole::CConsole()
{
#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(uint32_t uiInstance)
{
// Clear the screen...
std::cout << "\x1b[2J";
std::string subTtitle = "Standalone application, this is not Mixed-Critical mode!";
if (uiInstance != 0)
{
subTtitle = "Connected to core instance ";
subTtitle.append(std::to_string(uiInstance));
subTtitle.append(", this is NOT Mixed-Critical mode yet!");
}
// Print the titles
PrintText(g_sTitle, "Open Trunk example: Open trunk when vehicle is not moving");
PrintText(g_sSubTitle, subTtitle);
PrintText(g_sSeparator1, "============================================================================");
PrintText(g_sDataLink, "Data dispatch service:");
PrintText(g_sDataLinkSpeed, "Data Link not available");
PrintText(g_sSeparator2, "----------------------------------------------------------------------------");
PrintText(g_sVehicleDevice, "Vehicle Device:");
PrintText(g_sVehicleDeviceSpeed, "Vehicle Device Interface not available.");
PrintText(g_sSeparator3, "----------------------------------------------------------------------------");
PrintText(g_sBasicService, "Basic Service:");
PrintText(g_sBasicServiceSpeed, "Basic Service Interface not available.");
PrintText(g_sSeparator4, "============================================================================");
PrintText(g_sComment1, "The complex service which checks the speed of the vehicle can be seen");
PrintText(g_sComment2, "as an ASIL A/B component and will block the call from QM.");
PrintText(g_sComment3, "The extern apllication can be seen as a QM function.");
PrintText(g_sComment4, "If this example would run in a mixed critical environment the connection");
PrintText(g_sComment5, "from QM to basic service interface would be forbidden.");
PrintText(g_sSeparator5, "============================================================================");
PrintText(g_sComplexServcie1, "Basic Service Interface not available.");
PrintText(g_sComplexServcie2, "Complex Service Interface not available.");
PrintText(g_sSeparator6, "----------------------------------------------------------------------------");
PrintText(g_sControlDescription, "Press 'X' to quit; 'C' to clear screen, '1' or '2' to open trunk ");
}
bool CConsole::PrepareDataConsumers()
{
// Subscribe for the speed and trunk signal
sdv::core::CDispatchService dispatch;
m_SignalSpeed = dispatch.Subscribe(trunk::dsVehicleSpeed, [&](sdv::any_t value) { CallbackSpeed(value); });
if (m_SignalSpeed)
PrintValue(g_sDataLinkSpeed, "Vehicle Speed RX", m_SpeedDL, "m/s");
// Registrate for the vehicle device & basic service of the speed.
auto vehicleDevice = sdv::core::GetObject("Vehicle.Speed_Device").GetInterface<vss::Vehicle::SpeedDevice::IVSS_Speed>();
if (vehicleDevice)
{
PrintValue(g_sVehicleDeviceSpeed, "Vehicle Speed RX", m_SpeedVD, "m/s");
vehicleDevice->RegisterSpeedEvent(dynamic_cast<vss::Vehicle::SpeedDevice::IVSS_WriteSpeed_Event*> (this));
}
auto basicService = sdv::core::GetObject("Vehicle.Speed_Service").GetInterface<vss::Vehicle::SpeedService::IVSS_GetSpeed>();
if (basicService)
{
PrintValue(g_sBasicServiceSpeed, "Vehicle Speed RX", m_SpeedBS, "km/h");
basicService->RegisterOnSignalChangeOfVehicleSpeed(dynamic_cast<vss::Vehicle::SpeedService::IVSS_SetSpeed_Event*> (this));
}
// Request the basic service for opening the drunk.
m_pTrunkSvc = sdv::core::GetObject("Vehicle.Body.Trunk_Service").GetInterface<vss::Vehicle::Body::TrunkService::IVSS_SetOpen>();
if (m_pTrunkSvc)
PrintText(g_sComplexServcie1, "Basic Service available");
m_pITrunkComplexService = sdv::core::GetObject("Open Trunk Service").GetInterface<ITrunkKitService>();
if (m_pITrunkComplexService)
PrintText(g_sComplexServcie2, "Complex Service available");
return true;
}
void CConsole::ResetSignals()
{
// Set the cursor position at the end
SetCursorPos(g_sCursor);
auto vehicleDevice = sdv::core::GetObject("Vehicle.Speed_Device").GetInterface<vss::Vehicle::SpeedDevice::IVSS_Speed>();
if (vehicleDevice)
vehicleDevice->UnregisterSpeedEvent(dynamic_cast<vss::Vehicle::SpeedDevice::IVSS_WriteSpeed_Event*> (this));
auto basicService = sdv::core::GetObject("Vehicle.Speed_Service").GetInterface<vss::Vehicle::SpeedService::IVSS_GetSpeed>();
if (basicService)
basicService->UnregisterOnSignalChangeOfVehicleSpeed(dynamic_cast<vss::Vehicle::SpeedService::IVSS_SetSpeed_Event*> (this));
// Unregister the data link signalss
if (m_SignalSpeed)
m_SignalSpeed.Reset();
}
void CConsole::CallbackSpeed(sdv::any_t value)
{
if (m_SpeedDL != value.get<float>())
{
m_SpeedDL = value.get<float>();
PrintValue(g_sDataLinkSpeed, "Vehicle Speed RX", m_SpeedDL, "m/s");
}
}
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)
{
auto text = rssText;
while (text.length() < 76)
text.append(" ");
std::lock_guard<std::mutex> lock(m_mtxPrintToConsole);
SetCursorPos(sPos);
std::cout << text;
}
void CConsole::WriteSpeed(float value)
{
if (m_SpeedVD != value)
{
m_SpeedVD = value;
PrintValue(g_sVehicleDeviceSpeed, "Vehicle Speed RX", m_SpeedVD, "m/s");
}
}
void CConsole::SetSpeed(float value)
{
if (m_SpeedBS != value)
{
m_SpeedBS = value;
PrintValue(g_sBasicServiceSpeed, "Vehicle Speed RX", m_SpeedBS * 3.6f, "km/h");
}
}
bool CConsole::KeyHit()
{
#ifdef _WIN32
return _kbhit();
#elif __unix__
int ch = getchar();
if (ch != EOF) {
ungetc(ch, stdin);
return true;
}
return false;
#endif
}
char CConsole::GetChar()
{
#ifdef _WIN32
return static_cast<char>(_getch());
#else
return getchar();
#endif
}
void CConsole::RunUntilBreak()
{
bool bRunning = true;
while (bRunning)
{
// 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 'c':
case 'C':
PrintText(g_sComplexServcie1, " ");
PrintText(g_sComplexServcie2, " ");
break;
case '1':
if (m_pTrunkSvc)
{
if (m_pTrunkSvc->SetOpen(true))
PrintText(g_sComplexServcie1, "Open trunk via basic service - will not be available in Mixed-Critical mode!");
else
PrintText(g_sComplexServcie1, "Open trunk via basic service failed.");
}
break;
case '2':
if (m_pITrunkComplexService)
{
if (m_pITrunkComplexService->PopTrunk())
PrintText(g_sComplexServcie2, "Safety open trunk via complex service.");
else
PrintText(g_sComplexServcie2, "Safety open trunk via complex service failed, car is moving");
}
break;
case 'x':
case 'X':
bRunning = false;
break;
default:
break;
}
}
}

View File

@@ -0,0 +1,190 @@
#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"
#include <fcntl.h>
#include "../generated/vss_files/vss_vehiclebodytrunk_bs_tx.h"
#include "../generated/vss_files/vss_vehiclespeed_bs_rx.h"
#include "../generated/vss_files/vss_vehiclespeed_vd_rx.h"
// Complex service trunk interface - located in ../generated/trunk_service
#include "trunkkit.h"
#ifdef __unix__
#include <termios.h> // Needed for tcgetattr and fcntl
#include <unistd.h>
#endif
/**
* @brief Console operation class.
* @details This class retrieves RX data from the data dispatch service, vehicle device & basic service of speed on event change.
* Furthermore, it shows TX value by polling the RX signals.
*/
class CConsole : public vss::Vehicle::SpeedDevice::IVSS_WriteSpeed_Event
, public vss::Vehicle::SpeedService::IVSS_SetSpeed_Event
{
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
*/
CConsole();
/**
* @brief Destructor
*/
~CConsole();
/**
* @brief Print the header.
* @param[in] uiInstance Instance number the application will connect to. 0 will start a standalone application
*/
void PrintHeader(uint32_t uiInstance);
/**
* @brief Prepare the data consumers..
* @return Returns whether the preparation of the data consumers was successful or not.
*/
bool PrepareDataConsumers();
/**
* @brief Run loop as long as user input does not exit
* Allow user to open/close trunk.
*/
void RunUntilBreak();
/**
* @brief Write vehicleSpeed signal
* @param[in] value vehicleSpeed
*/
virtual void WriteSpeed(float value) override;
/**
* @brief Set vehicleSpeed signal
* @param[in] value vehicleSpeed
*/
virtual void SetSpeed(float value) override;
/**
* @brief For gracefully shutdown all signals need to be reset.
*/
void ResetSignals();
private:
/**
* @brief Callback function for speed.
* @param[in] value The value of the signal to update.
*/
void CallbackSpeed(sdv::any_t value);
/**
* @brief Key hit check. Windows uses the _kbhit function; POSIX emulates this.
* @return Returns whether a key has been pressed.
*/
bool KeyHit();
/**
* @brief Get the character from the keyboard buffer if pressed.
* @return Returns the character from the keyboard buffer.
*/
char GetChar();
/**
* @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] rssStatus Status, becuse we have signals of type bool
*/
template <typename TValue>
void PrintValue(SConsolePos sPos, const std::string& rssName, TValue tValue, const std::string& rssStatus);
/**
* @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_bRunning = false; ///< When set, the application is running.
mutable std::mutex m_mPrintToConsole; ///< Mutex to print complete message
sdv::core::CSignal m_SignalSpeed; ///< Speed
float m_SpeedDL = 0.0; ///< Speed Data Link
float m_SpeedVD = 0.0; ///< Speed Data Link
float m_SpeedBS = 0.0; ///< Speed Data Link
vss::Vehicle::Body::TrunkService::IVSS_SetOpen* m_pTrunkSvc = nullptr; ///< Front Left Door
ITrunkKitService* m_pITrunkComplexService = nullptr; ///< Trunk 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 = 30;
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_mPrintToConsole);
SetCursorPos(sPos);
std::cout << sstreamValueText.str();
}
template <>
inline void CConsole::PrintValue<bool>(SConsolePos sPos, const std::string& rssName, bool bValue, const std::string& rssStatus)
{;
PrintValue(sPos, rssName, bValue ? "" : "", rssStatus);
}
#endif // !define CONSOLE_OUTPUT_H

View File

@@ -0,0 +1,25 @@
/**
* namespace for the signal names
* in case /interfaces/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("../interfaces/signal_identifier.h")
#include "../interfaces/signal_identifier.h"
#else
namespace trunk
{
// Data Dispatch Service signal names to dbc variable names C-type RX/TX vss name space
static std::string dsVehicleSpeed = "CAN_Input.Speed"; ///< bool RX Vehicle.Speed
static std::string dsTrunk = "CAN_Output.OpenTrunk"; ///< bool TX Vehicle.Body.Trunk
} // trunk
#endif
#endif
#endif // SIGNAL_NAMES_H

View File

@@ -0,0 +1,98 @@
#include "trunk_application.h"
#include "signal_names.h"
#ifdef _WIN32
#include <conio.h> // Needed for _kbhit
#else
#include <fcntl.h>
#endif
bool CTrunkControl::LoadConfigFile(const std::string& inputMsg, const std::string& configFileName)
{
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;
}
bool CTrunkControl::IsSDVFrameworkEnvironmentSet()
{
const char* envVariable = std::getenv("SDV_FRAMEWORK_RUNTIME");
if (envVariable)
{
return true;
}
return false;
}
bool CTrunkControl::Initialize(uint32_t uiInstance)
{
if (m_bInitialized)
return true;
if (!IsSDVFrameworkEnvironmentSet())
{
// if SDV_FRAMEWORK_RUNTIME environment variable is not set we need to set the Framework Runtime directory
m_appcontrol.SetFrameworkRuntimeDirectory("../../bin");
}
if (uiInstance != 0)
{
std::stringstream sstreamAppConfig;
sstreamAppConfig << "[Application]" << std::endl;
sstreamAppConfig << "Mode=\"External\"" << std::endl;
sstreamAppConfig << "Instance=" << uiInstance << std::endl;
sstreamAppConfig << "Retries=" << 6 << std::endl;
sstreamAppConfig << "[Console]" << std::endl;
sstreamAppConfig << "Report=\"Silent\"" << std::endl;
if (!m_appcontrol.Startup(sstreamAppConfig.str()))
return false;
}
else
{
if (!m_appcontrol.Startup(""))
return false;
// Switch to config mode.
m_appcontrol.SetConfigMode();
bool bResult = LoadConfigFile("Load dispatch service: ", "data_dispatch_trunk.toml");
bResult &= LoadConfigFile("Load task_timer_trunk: ", "task_timer_trunk.toml");
bResult &= LoadConfigFile("Load can_com_simulation_trunk: ", "can_com_simulation_trunk.toml");
bResult &= LoadConfigFile("Load data_link_trunk: ", "data_link_trunk.toml");
bResult &= LoadConfigFile("Load trunk_vehicle_device_and_basic_service: ", "trunk_vehicle_device_and_basic_service.toml");
bResult &= LoadConfigFile("Load trunk service (complex service): ", "complex_service_trunk.toml");
if (!bResult)
{
SDV_LOG_ERROR("One or more configurations could not be loaded. Cannot continue.");
return false;
}
}
m_bInitialized = true;
return true;
}
void CTrunkControl::Shutdown()
{
if (!m_bInitialized)
m_appcontrol.Shutdown();
m_bInitialized = false;
}
void CTrunkControl::SetRunningMode()
{
m_appcontrol.SetRunningMode();
}

View File

@@ -0,0 +1,49 @@
#include <string>
#include <support/app_control.h>
#include <support/signal_support.h>
#include "vss_vehiclespeed_bs_rx.h"
/**
* @brief Application Class of the open trunk example
*/
class CTrunkControl
{
public:
/**
* @brief Start and initialize the application control and load vehicle devices and basic services
* @param[in] uiInstance Instance number the application will connect to. 0 will start a standalone application
* @return Return true on success otherwise false
*/
bool Initialize(uint32_t uiInstance);
/**
* @brief After initialization/configuration the system mode needs to be set to running mode
*/
void SetRunningMode();
/**
* @brief Shutdown the system.
*/
void Shutdown();
private:
/**
* @brief check if SDV_FRAMEWORK_RUNTIME environment variable exists
* @return Return true if environment variable is found otherwise false
*/
bool IsSDVFrameworkEnvironmentSet();
/**
* @brief Loac config file and register vehicle device and basic service.
* @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);
sdv::app::CAppControl m_appcontrol; ///< App-control of SDV V-API.
bool m_bInitialized = false; ///< Set when initialized.
};

View File

@@ -0,0 +1,60 @@
#include <iostream>
#include <cstdlib> // for std::strtol
#include "trunk_application.h"
#include "console.h"
#if defined(_WIN32) && defined(_UNICODE)
extern "C" int wmain(int argc, wchar_t* argv[])
{
uint32_t uiInstance = 0;
if (argc < 2)
{
std::cout << "Missing instance number to connect to, '0' will run as standalone application" << std::endl;
return 1;
}
try
{
uiInstance = std::stoi(argv[1]);
}
catch (const std::exception& )
{
uiInstance = 0;
}
#else
extern "C" int main(int argc, char* argv[])
{
uint32_t uiInstance = 0;
if (argc < 2)
{
std::cout << "Missing instance number to connect to, '0' will run as standalone application" << std::endl;
return 1;
}
try
{
uiInstance = std::stoi(argv[1]);
}
catch (const std::exception& )
{
uiInstance = 0;
}
#endif
CTrunkControl appobj;
if (!appobj.Initialize(uiInstance))
{
std::cout << "ERROR: Failed to initialize application control." << std::endl;
return 0;
}
CConsole visual_obj;
visual_obj.PrintHeader(uiInstance);
visual_obj.PrepareDataConsumers();
appobj.SetRunningMode();
visual_obj.RunUntilBreak();
visual_obj.ResetSignals();
appobj.Shutdown();
return 0;
}