Before git init

This commit is contained in:
2026-02-01 18:58:43 +01:00
committed by sani7
parent d41f40dd25
commit b211ebc0c1
20 changed files with 1313 additions and 2 deletions
-2
View File
@@ -34,5 +34,3 @@
.vscode/ .vscode/
build/ build/
log-sim_us.txt
+107
View File
@@ -0,0 +1,107 @@
cmake_minimum_required(VERSION 3.5)
project(Simulator-CVS_I10 VERSION 0.1 LANGUAGES CXX)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
include(FetchContent)
FetchContent_Declare(magic_enum URL https://github.com/Neargye/magic_enum/releases/download/v0.9.6/magic_enum-v0.9.6.tar.gz DOWNLOAD_EXTRACT_TIMESTAMP TRUE)
FetchContent_MakeAvailable(magic_enum)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Svg WebSockets)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Svg WebSockets)
add_subdirectory(qwt)
set(PROJECT_SOURCES
sim-cvs_i10.h
sim-cvs_i10.cpp
sim-cvs_i10_helper.cpp
sim-cvs_i10.ui
sim-can_debugger.h
sim-can_debugger.cpp
sim-can_debugger.ui
sim-scope_mux_tester.h
sim-scope_mux_tester.cpp
sim-scope_mux_tester.ui
simulatorbase.h
simulatorbase.cpp
helpers.h
helpers.cpp
IterableEnum.hpp
better_radiobutton.h
better_radiobutton.cpp
networkerror.h
networkerror.cpp
networkerror.ui
mainwindow.h
mainwindow.cpp
mainwindow.ui
main.cpp
)
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
qt_add_executable(Simulator-CVS_I10
MANUAL_FINALIZATION
${PROJECT_SOURCES}
)
# Define target properties for Android with Qt 6 as:
# set_property(TARGET Simulator-CVS_I10 APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
# ${CMAKE_CURRENT_SOURCE_DIR}/android)
# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation
else()
if(ANDROID)
add_library(Simulator-CVS_I10 SHARED
${PROJECT_SOURCES}
)
# Define properties for Android with Qt 5 after find_package() calls as:
# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
else()
add_executable(Simulator-CVS_I10
${PROJECT_SOURCES}
)
endif()
endif()
target_include_directories(Simulator-CVS_I10
PUBLIC
${PROJECT_BINARY_DIR}/
)
target_link_libraries(Simulator-CVS_I10 PRIVATE qwt Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::WebSockets)
# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
# If you are developing for iOS or macOS you should consider setting an
# explicit, fixed bundle identifier manually though.
if(${QT_VERSION} VERSION_LESS 6.1.0)
set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.example.Simulator-CVS_I10)
endif()
set_target_properties(Simulator-CVS_I10 PROPERTIES
${BUNDLE_ID_OPTION}
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
MACOSX_BUNDLE TRUE
WIN32_EXECUTABLE TRUE
)
include(GNUInstallDirs)
install(TARGETS Simulator-CVS_I10
BUNDLE DESTINATION .
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
if(QT_VERSION_MAJOR EQUAL 6)
qt_finalize_executable(Simulator-CVS_I10)
endif()
+120
View File
@@ -0,0 +1,120 @@
/*
A way to iterate over enumerations as C++ template.
Copyright (c) 2023 Sander Speetjens
Licensed under the terms of the MIT license (given below).
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#pragma once
#define ITERABLE_ENUM_BEGIN(name) enum class name : int {
#define ITERABLE_ENUM_END ,end, begin = 0 }
template <class T>
class Iterable
{
public:
Iterable(T value = T::begin) : mValue(value) {}
Iterable(const Iterable& other) : mValue(other.mValue) {}
Iterable& operator++()
{
assert(mValue >= T::begin && mValue < T::end);
mValue = static_cast<T>(static_cast<int>(mValue) + 1);
return *this;
}
Iterable operator++(int)
{
Iterable prev = *this;
mValue = static_cast<T>(static_cast<int>(mValue) + 1);
return prev;
}
Iterable& operator--()
{
assert(mValue >= T::end && mValue < T::begin);
mValue = static_cast<T>(static_cast<int>(mValue) - 1);
return *this;
}
Iterable operator--(int)
{
Iterable prev = *this;
mValue = static_cast<T>(static_cast<int>(mValue) - 1);
return prev;
}
Iterable operator+(int i)
{
return static_cast<T>(static_cast<int>(mValue) + i);
}
Iterable operator+(T i)
{
return static_cast<T>(static_cast<int>(mValue) + static_cast<int>(i));
}
Iterable operator-(int i)
{
return static_cast<T>(static_cast<int>(mValue) - i);
}
Iterable operator-(T i)
{
return static_cast<T>(static_cast<int>(mValue) - static_cast<int>(i));
}
bool operator >(const T& other) const
{
return static_cast<int>(mValue) > static_cast<int>(other);
}
bool operator >=(const T& other) const
{
return static_cast<int>(mValue) >= static_cast<int>(other);
}
bool operator <(const T& other) const
{
return static_cast<int>(mValue) < static_cast<int>(other);
}
bool operator <=(const T& other) const
{
return static_cast<int>(mValue) <= static_cast<int>(other);
}
bool operator ==(const T& other) const
{
return static_cast<int>(mValue) == static_cast<int>(other);
}
bool valid() const { return mValue != T::end; }
operator T() const { return mValue; }
operator T&() { return mValue; }
T val() const { return mValue; }
private:
T mValue;
};
+38
View File
@@ -0,0 +1,38 @@
#include "better_radiobutton.h"
Better_Radiobutton::Better_Radiobutton(QWidget* parent) :
QWidget{parent},
m_radiobuttons{}
{
}
Better_Radiobutton::Better_Radiobutton(std::vector<QString> names, QWidget* parent) :
QWidget{parent},
m_v_layout{new QVBoxLayout(this)},
m_radiobuttons{},
m_checked{""}
{
for (const auto& name : names) {
add_radiobutton(name);
}
}
void Better_Radiobutton::add_radiobutton(QString name)
{
auto radiobutton = new QRadioButton(name, this);
m_radiobuttons.push_back(radiobutton);
m_v_layout->addWidget(radiobutton);
connect(radiobutton, &QRadioButton::toggled, this, [this, name, radiobutton] {
emit toggled(name);
if (radiobutton->isChecked()) {
m_checked = name;
emit checked(name);
}
});
}
QString Better_Radiobutton::isChecked() const
{
return m_checked;
}
+25
View File
@@ -0,0 +1,25 @@
#ifndef BETTER_RADIOBUTTON_H
#define BETTER_RADIOBUTTON_H
#include <QVBoxLayout>
#include <QRadioButton>
class Better_Radiobutton : public QWidget {
Q_OBJECT
public:
explicit Better_Radiobutton(QWidget* parent = nullptr);
explicit Better_Radiobutton(std::vector<QString>names, QWidget* partent = nullptr);
void add_radiobutton(QString name);
QString isChecked() const;
signals:
void toggled(QString name);
void checked(QString name);
private:
QVBoxLayout* m_v_layout;
std::vector<QRadioButton*> m_radiobuttons;
QString m_checked;
};
#endif // BETTER_RADIOBUTTON_H
+102
View File
@@ -0,0 +1,102 @@
#include "helpers.h"
void create_dial_needle(QwtDial* dial)
{
QwtDialSimpleNeedle* needle = new QwtDialSimpleNeedle(
QwtDialSimpleNeedle::Arrow, true, Qt::yellow,
QColor( Qt::gray ).lighter( 130 ) );
needle->setWidth(2);
dial->setNeedle( needle );
}
void set_thermo_color(QwtSlider* slider, QColor color, QColor bg)
{
QString style = QString("#%1 { background-color: %2; color: %3;}").arg(slider->objectName(), bg.name(), color.name());
slider->setStyleSheet(style);
}
void set_button_color(QPushButton* button, QColor color, QColor bg)
{
QString style = QString("#%1 { background-color: %2; color: %3;}").arg(button->objectName(), bg.name(), color.name());
button->setStyleSheet(style);
}
void set_button_color(QPushButton* button, QString color, QString bg)
{
QString style = QString("#%1 { background-color: %2; color: %3;}").arg(button->objectName(), bg, color);
button->setStyleSheet(style);
}
QColor button_bg_color(QPushButton* button)
{
std::string input = button->styleSheet().toStdString();
QColor background_color;
// Find the position of "background-color:"
size_t bg_pos = input.find("background-color:");
if (bg_pos != std::string::npos) {
// Find the end position of the background color value
size_t bg_value_start = bg_pos + 17; // Length of "background-color:" is 17
size_t bg_value_end = input.find(";", bg_value_start);
if (bg_value_end != std::string::npos) {
background_color = QColor(input.substr(bg_value_start, bg_value_end - bg_value_start).c_str());
}
}
return background_color;
}
QColor button_color(QPushButton* button)
{
std::string input = button->styleSheet().toStdString();
QColor color;
// Find the position of "color:"
size_t color_pos = input.find(" color:");
if (color_pos != std::string::npos) {
// Find the end position of the text color value
size_t color_value_start = color_pos + 7; // Length of "color:" is 7
size_t color_value_end = input.find(";", color_value_start);
if (color_value_end != std::string::npos) {
color = QColor(input.substr(color_value_start, color_value_end - color_value_start).c_str());
}
}
return color;
}
void reset_button_color(QPushButton* button)
{
button->setStyleSheet("");
}
bool is_read_only(QWidget* widget)
{
return widget->testAttribute(Qt::WA_TransparentForMouseEvents) || (widget->focusPolicy() == Qt::NoFocus);
}
void set_read_only(QWidget* widget, bool read_only)
{
widget->setAttribute(Qt::WA_TransparentForMouseEvents, read_only);
widget->setFocusPolicy(read_only ? Qt::NoFocus : Qt::StrongFocus);
}
QString network_reply_to_fix(QNetworkReply::NetworkError error)
{
switch (error) {
case QNetworkReply::NetworkError::ConnectionRefusedError:
return "Make sure the server is started ($ systemctl status unocan_server)";
break;
case QNetworkReply::NetworkError::HostNotFoundError:
return "Make sure the simulator is turned on";
break;
case QNetworkReply::NetworkError::InternalServerError:
return "Server had an oopsie, restart the client and if it fails again restart the server";
break;
default:
return "";
break;
}
}
+26
View File
@@ -0,0 +1,26 @@
#ifndef HELPERS_H
#define HELPERS_H
#include <QtWidgets>
#include <qwt_color_map.h>
#include <qwt_dial.h>
#include <qwt_dial_needle.h>
#include <qwt_plot.h>
#include <qwt_plot_curve.h>
#include <qwt_slider.h>
#include <qwt_series_data.h>
#include <QNetworkReply>
void create_dial_needle(QwtDial* dial);
void set_thermo_color(QwtSlider* slider, QColor color, QColor bg);
void set_button_color(QPushButton* button, QColor color, QColor bg);
void set_button_color(QPushButton* button, QString color, QString bg);
QColor button_bg_color(QPushButton* button);
QColor button_color(QPushButton* button);
void reset_button_color(QPushButton* button);
void set_read_only(QWidget* widget, bool readOnly = true);
bool is_read_only(QWidget* widget);
QString network_reply_to_fix(QNetworkReply::NetworkError error);
#endif // HELPERS_H
+11
View File
@@ -0,0 +1,11 @@
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
+169
View File
@@ -0,0 +1,169 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "sim-scope_mux_tester.h"
#include "sim-can_debugger.h"
#include "sim-cvs_i10.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
api(new OpenAPI::OAICANApiApi()),
error_dialog(new NetworkError(this)),
sims{{"CANDebugger", new Can_Debugger(api, this)},
{"Scope_Mux_Tester", new Scope_Mux_Tester(api, this)},
{"CVS_I10", new CVS_I10(api, this)}}
{
ui->setupUi(this);
this->setWindowTitle("Simulator Selector");
connect(this, &MainWindow::quit, this, &QCoreApplication::quit, Qt::QueuedConnection);
api->setNewServerForAllOperations(
//QUrl("http://localhost:1880"),
QUrl("https://cvs-i10.local/api"),
"No description provided",
QMap<QString, OpenAPI::OAIServerVariable>());
api->apiCanapiSimsGet();
//Default sim
defaultSim("CVS_I10");
connect(ui->pushButton, &QPushButton::clicked, this, [=]{open_sim(ui->comboBox->currentText());});
}
MainWindow::~MainWindow()
{
delete ui;
delete api;
delete error_dialog;
}
void MainWindow::setup_cb(void)
{
connect(api, &OpenAPI::OAICANApiApi::apiCanapiSimsGetSignal, this, [=](QList<QString> summary){Parse_Sims(summary);});
connect(api, &OpenAPI::OAICANApiApi::apiCanapiSimsGetSignalError, this, [=](QList<QString> summary, QNetworkReply::NetworkError error_type, const QString &error_str){Parse_Sims(summary, error_type, error_str);});
connect(api, &OpenAPI::OAICANApiApi::apiCanapiCurrentsimPutSignal, this, [this](bool output){apiCanapiUielements_bool_cb(output);});
connect(api, &OpenAPI::OAICANApiApi::apiCanapiCurrentsimPutSignalError, this, [this](bool output, QNetworkReply::NetworkError error_type, QString error_str){
apiCanapiUielements_bool_cb(false, error_type, error_str);});
connect(api, &OpenAPI::OAICANApiApi::apiCanapiCurrentsimGetSignal, this, [this](OpenAPI::OAISimulatorInfo summary){apiCanapiCurrentsimGet_cb(summary);});
connect(api, &OpenAPI::OAICANApiApi::apiCanapiCurrentsimGetSignalError, this, [this](OpenAPI::OAISimulatorInfo summary, QNetworkReply::NetworkError error_type, QString error_str){apiCanapiCurrentsimGet_cb(OpenAPI::OAISimulatorInfo(), error_type, error_str);});
}
void MainWindow::showEvent( QShowEvent* event )
{
QWidget::showEvent( event );
setup_cb();
}
void MainWindow::hideEvent(QHideEvent* event)
{
QWidget::hideEvent(event);
disconnect(api, nullptr, nullptr, nullptr);
}
void MainWindow::defaultSim(QString name)
{
this->selected_sim_name = name;
this->default_sim = true;
}
void MainWindow::Parse_Sims(QList<QString> sims, QNetworkReply::NetworkError error_type, const QString error_str)
{
if (error_type) {
QD << "( " << error_type << "," << error_str << ")";
error_dialog->set_error(error_str + "\n" + network_reply_to_fix(error_type));
error_dialog->open();
return;
} if (sims.empty()) {
QD << " got called with invalid data and no error!";
error_dialog->set_error(QString(__FUNCTION__) + " got called with invalid data and no error!");
error_dialog->open();
return;
}
for (size_t i = 0; i < sims.length(); i++)
{
ui->comboBox->addItem(sims[i]);
}
QThread::msleep(30);
if (this->default_sim)
{
ui->comboBox->setCurrentText(this->selected_sim_name);
open_sim(this->selected_sim_name);
}
}
void MainWindow::open_sim(QString sim_name)
{
try
{
selected_sim = sims.at(sim_name);
this->selected_sim_name = sim_name;
}
catch (const std::out_of_range& ex)
{
QD << "out_of_range::what(): " << ex.what();
return;
}
api->apiCanapiCurrentsimGet();
}
void MainWindow::open_sim_window(void)
{
this->hide();
selected_sim->show();
}
void MainWindow::apiCanapiUielements_bool_cb(bool output, QNetworkReply::NetworkError error_type, QString error_str)
{
if (error_type) {
QD << "( " << Qt::hex << output << "," << error_type << "," << error_str << ")";
error_dialog->set_error(error_str + "\n" + network_reply_to_fix(error_type));
error_dialog->open();
return;
} if (!output) {
QD << " got called with invalid data and no error!";
error_dialog->set_error(QString(__FUNCTION__) + " got called with invalid data and no error!");
error_dialog->open();
return;
}
open_sim_window();
}
void MainWindow::apiCanapiCurrentsimGet_cb(OpenAPI::OAISimulatorInfo summary, QNetworkReply::NetworkError error_type, QString error_str)
{
if (error_type) {
QD << "( " << summary.asJson() << "," << error_type << "," << error_str << ")";
error_dialog->set_error(error_str + "\n" + network_reply_to_fix(error_type));
error_dialog->open();
return;
} if (!summary.isValid()) {
QD << " got called with invalid data and no error!";
error_dialog->set_error(QString(__FUNCTION__) + " got called with invalid data and no error!");
error_dialog->open();
return;
}
if (!summary.is_name_Set())
{
QD << "Name not set";
api->apiCanapiCurrentsimPut(selected_sim_name);
return;
}
QD << "Current sim:" << summary.getName();
if (summary.getName() == selected_sim_name)
{
QD << "Name set and right";
open_sim_window();
return;
}
QD << "Name set and wrong";
api->apiCanapiCurrentsimPut(selected_sim_name);
}
+47
View File
@@ -0,0 +1,47 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <map>
#include <QMainWindow>
#include "OAICANApiApi.h"
#include "networkerror.h"
#include "simulatorbase.h"
#include "helpers.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
void defaultSim(QString name);
void Parse_Sims(QList<QString> sims, QNetworkReply::NetworkError error_type = QNetworkReply::NetworkError::NoError, QString error_str = QString());
void apiCanapiUielements_bool_cb(bool ret, QNetworkReply::NetworkError error_type = QNetworkReply::NetworkError::NoError, QString error_str = QString());
void apiCanapiCurrentsimGet_cb(OpenAPI::OAISimulatorInfo summary, QNetworkReply::NetworkError error_type = QNetworkReply::NetworkError::NoError, QString error_str = QString());
void open_sim_window(void);
void open_sim(QString sim_name);
void setup_cb(void);
signals:
void quit(void);
private:
void showEvent( QShowEvent* event );
void hideEvent(QHideEvent* event);
bool default_sim = false;
QString selected_sim_name;
QMainWindow* selected_sim;
Ui::MainWindow *ui;
OpenAPI::OAICANApiApi *api;
NetworkError* error_dialog;
std::map<QString, SimulatorBase*> sims;
};
#endif // MAINWINDOW_H
+43
View File
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QComboBox" name="comboBox"/>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Open</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actiontest">
<property name="text">
<string>test</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>
+19
View File
@@ -0,0 +1,19 @@
#include "networkerror.h"
#include "ui_networkerror.h"
NetworkError::NetworkError(QWidget* parent) : QDialog(parent), ui(new Ui::NetworkError) {
ui->setupUi(this);
connect(ui->exit, &QPushButton::clicked, this, &QCoreApplication::quit, Qt::QueuedConnection);
connect(ui->close, &QPushButton::clicked, this, [=]{this->close();});
this->setWindowTitle("Error");
}
void NetworkError::set_error(QString error)
{
ui->Error->setText(error);
}
NetworkError::~NetworkError() {
delete ui;
}
+22
View File
@@ -0,0 +1,22 @@
#ifndef NETWORKERROR_H
#define NETWORKERROR_H
#include <QDialog>
namespace Ui {
class NetworkError;
}
class NetworkError : public QDialog {
Q_OBJECT
public:
explicit NetworkError(QWidget* parent = nullptr);
void set_error(QString error);
~NetworkError();
private:
Ui::NetworkError* ui;
};
#endif // NETWORKERROR_H
+69
View File
@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NetworkError</class>
<widget class="QDialog" name="NetworkError">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="title">
<property name="font">
<font>
<pointsize>16</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Oops, an error occured</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="Error">
<property name="text">
<string>Error...</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="close">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="exit">
<property name="text">
<string>Exit Application</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
Submodule
+1
Submodule Qt/qwt added at aab5a9927c
+13
View File
@@ -0,0 +1,13 @@
#include "sim-can_debugger.h"
#include "ui_sim-can_debugger.h"
Can_Debugger::Can_Debugger(OpenAPI::OAICANApiApi* api, QWidget *parent) :
SimulatorBase(api, parent),
ui(new Ui::Can_Debugger) {
ui->setupUi(this);
this->setWindowTitle("CAN Debugger");
}
Can_Debugger::~Can_Debugger() {
delete ui;
}
+22
View File
@@ -0,0 +1,22 @@
#ifndef SIM_CAN_DEBUGGER_H
#define SIM_CAN_DEBUGGER_H
#include <QMainWindow>
#include "simulatorbase.h"
namespace Ui {
class Can_Debugger;
}
class Can_Debugger : public SimulatorBase {
Q_OBJECT
public:
explicit Can_Debugger(OpenAPI::OAICANApiApi* api, QWidget *parent = nullptr);
~Can_Debugger();
private:
Ui::Can_Debugger* ui;
};
#endif // SIM_CAN_DEBUGGER_H
+31
View File
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Can_Debugger</class>
<widget class="QMainWindow" name="Can_Debugger">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget"/>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>23</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
+388
View File
@@ -0,0 +1,388 @@
#include "simulatorbase.h"
SimulatorBase::SimulatorBase(OpenAPI::OAICANApiApi* api, QWidget* parent) :
QMainWindow{parent},
error_dialog(new NetworkError(this))
{
this->api = api;
timer_update = new QTimer(this);
timer_update->connect(timer_update, &QTimer::timeout, this, [=]{sim_update();});
refresh_rate = 100;
}
void SimulatorBase::sim_update(void)
{
api->apiCanapiCurrentsimGet();
}
void SimulatorBase::showEvent( QShowEvent* event )
{
QWidget::showEvent( event );
QD << "Starting refresh timer";
setup_cb();
this->timer_update->start(refresh_rate);
closed = false;
}
void SimulatorBase::closeEvent(QCloseEvent* event)
{
if (!closed)
{
QD << "Disconnecting callbacks";
QWidget::closeEvent(event);
this->timer_update->stop();
disconnect(api, nullptr, nullptr, nullptr);
this->parentWidget()->show();
}
closed = true;
}
void SimulatorBase::setup_cb(void)
{
connect(api, &OpenAPI::OAICANApiApi::apiCanapiUielementsPushbuttonPostSignal, this, [this](bool output){apiCanapiUielements_bool_cb(output);});
connect(api, &OpenAPI::OAICANApiApi::apiCanapiUielementsPushbuttonPostSignalError, this, [this](bool output, QNetworkReply::NetworkError error_type, QString error_str){apiCanapiUielements_bool_cb(false, false, error_type, error_str);});
connect(api, &OpenAPI::OAICANApiApi::apiCanapiUielementsPushbuttonarrayPostSignal, this, [this](bool output){apiCanapiUielements_bool_cb(output);});
connect(api, &OpenAPI::OAICANApiApi::apiCanapiUielementsPushbuttonarrayPostSignalError, this, [this](bool output, QNetworkReply::NetworkError error_type, QString error_str){apiCanapiUielements_bool_cb(false, false, error_type, error_str);});
connect(api, &OpenAPI::OAICANApiApi::apiCanapiUielementsTextboxPostSignal, this, [this](bool output){apiCanapiUielements_bool_cb(output);});
connect(api, &OpenAPI::OAICANApiApi::apiCanapiUielementsTextboxPostSignalError, this, [this](bool output, QNetworkReply::NetworkError error_type, QString error_str){apiCanapiUielements_bool_cb(false, false, error_type, error_str);});
connect(api, &OpenAPI::OAICANApiApi::apiCanapiUielementsSliderPostSignal, this, [this](bool output){apiCanapiUielements_bool_cb(output);});
connect(api, &OpenAPI::OAICANApiApi::apiCanapiUielementsSliderPostSignalError, this, [this](bool output, QNetworkReply::NetworkError error_type, QString error_str){apiCanapiUielements_bool_cb(false, false, error_type, error_str);});
connect(api, &OpenAPI::OAICANApiApi::apiCanapiUielementsTogglearrayPostSignal, this, [this](bool output){apiCanapiUielements_bool_cb(output);});
connect(api, &OpenAPI::OAICANApiApi::apiCanapiUielementsTogglearrayPostSignalError, this, [this](bool output, QNetworkReply::NetworkError error_type, QString error_str){apiCanapiUielements_bool_cb(false, false, error_type, error_str);});
connect(api, &OpenAPI::OAICANApiApi::apiCanapiCurrentsimGetSignal, this, [this](OpenAPI::OAISimulatorInfo summary){apiCanapiCurrentsimGet_cb(summary);});
connect(api, &OpenAPI::OAICANApiApi::apiCanapiCurrentsimGetSignalError, this, [this](OpenAPI::OAISimulatorInfo summary, QNetworkReply::NetworkError error_type, QString error_str){apiCanapiCurrentsimGet_cb(OpenAPI::OAISimulatorInfo(), error_type, error_str);});
}
void SimulatorBase::apiCanapiUielements_bool_cb(bool output, bool currentsim, QNetworkReply::NetworkError error_type, QString error_str)
{
if (error_type) {
QD << "( " << Qt::hex << output << "," << error_type << "," << error_str << ")";
error_dialog->set_error(error_str + "\n" + network_reply_to_fix(error_type));
error_dialog->open();
return;
} if (!output) {
QD << " got called with invalid data and no error!";
error_dialog->set_error(QString(__FUNCTION__) + " got called with invalid data and no error!");
error_dialog->open();
return;
}
}
void SimulatorBase::apiCanapiCurrentsimGet_cb(OpenAPI::OAISimulatorInfo summary, QNetworkReply::NetworkError error_type, QString error_str)
{
if (error_type) {
QD << "( " << summary.asJson() << "," << error_type << "," << error_str << ")";
error_dialog->set_error(error_str + "\n" + network_reply_to_fix(error_type));
error_dialog->open();
return;
} if (!summary.isValid()) {
QD << " got called with invalid data and no error!";
error_dialog->set_error(QString(__FUNCTION__) + " got called with invalid data and no error!");
error_dialog->open();
return;
}
OAISimulatorInfo_parser(summary);
}
void SimulatorBase::OAISimulatorInfo_parser(OpenAPI::OAISimulatorInfo input)
{
const OpenAPI::OAIClientUIItem* uiItem;
for (size_t i = 0; i < input.getUiItems().count(); i++)
{
uiItem = &(input.getUiItems().at(i));
if (uiItem->getType() == "UIButtonArray")
{
process_ui_button_array(uiItem);
continue;
}
if (uiItem->getType() == "UILedArray")
{
process_ui_led_array(uiItem);
continue;
}
if (uiItem->getType() == "UISlider")
{
process_ui_slider(uiItem);
continue;
}
if (uiItem->getType() == "UITextbox")
{
process_ui_textbox(uiItem);
continue;
}
if (uiItem->getType() == "UILabel")
{
process_ui_label(uiItem);
continue;
}
if (uiItem->getType() == "UICombobox")
{
process_ui_combobox(uiItem);
continue;
}
if (uiItem->getType() == "UIRadioButton")
{
process_ui_radiobutton(uiItem);
continue;
}
}
}
void SimulatorBase::process_ui_button_array(const OpenAPI::OAIClientUIItem* uiItem)
{
QJsonObject state = uiItem->getState().asJsonObject();
QJsonArray state_array = state["buttonArray"].toArray();
for (size_t i = 0; i < state_array.count(); i++)
{
process_ui_button_array_element(state_array[i].toObject());
}
}
void SimulatorBase::process_ui_led_array(const OpenAPI::OAIClientUIItem* uiItem)
{
QJsonObject state = uiItem->getState().asJsonObject();
QJsonArray state_array = state["ledArray"].toArray();
for (size_t i = 0; i < state_array.count(); i++)
{
process_ui_led_array_element(state_array[i].toObject());
}
}
void SimulatorBase::process_ui_label(const OpenAPI::OAIClientUIItem* uiItem)
{
QLabel* label = id_to_label(uiItem->getName());
if (label == nullptr)
{
QD << "id_to_label returned null on " << uiItem->getName();
return;
}
QString value = uiItem->getState().asJsonObject()["textString"].toString();
if (label->text() != value)
{
label->setText(value);
}
}
void SimulatorBase::process_ui_slider(const OpenAPI::OAIClientUIItem* uiItem)
{
if (uiItem->getName().startsWith('t'))
{
QwtSlider* slider = id_to_slider(uiItem->getName());
QLabel* label = id_to_slider_label(uiItem->getName());
if (slider == nullptr)
{
QD << "id_to_slider returned null on " << uiItem->getName();
return;
}
double value = uiItem->getState().asJsonObject()["currentValue"].toDouble();
bool enable = uiItem->getState().asJsonObject()["enable"].toBool();
bool visible = uiItem->getState().asJsonObject()["visible"].toBool();
if (slider->value() != value)
{
if (label != nullptr)
{
label->setText(format_slider_value(uiItem->getName(), value));
}
slider->setValue(value);
}
if (slider->isReadOnly() != !enable)
{
slider->setReadOnly(!enable);
}
if (slider->isVisible() != visible)
{
slider->setVisible(visible);
}
//TODO: Add color for scale
return;
}
if (uiItem->getName().startsWith('d'))
{
QwtDial* dial = id_to_dial(uiItem->getName());
QLabel* label = id_to_dial_label(uiItem->getName());
if (dial == nullptr)
{
QD << "id_to_dial returned null on " << uiItem->getName();
return;
}
double value = uiItem->getState().asJsonObject()["currentValue"].toDouble();
bool visible = uiItem->getState().asJsonObject()["visible"].toBool();
if (dial->value() != value)
{
if (label != nullptr)
{
label->setText(format_dial_value(uiItem->getName(), value));
}
dial->setValue(value);
}
if (dial->isVisible() != visible)
{
dial->setVisible(visible);
}
return;
}
}
void SimulatorBase::process_ui_textbox(const OpenAPI::OAIClientUIItem* uiItem)
{
QD << "Not implemented";
emit quit();
}
void SimulatorBase::process_ui_combobox(const OpenAPI::OAIClientUIItem* uiItem)
{
QComboBox* combobox = id_to_combobox(uiItem->getName());
if (combobox == nullptr)
{
QD << "id_to_combobox returned null on " << uiItem->getName();
return;
}
QJsonObject state = uiItem->getState().asJsonObject();
QString selected = state["selected"].toString();
QJsonArray toggleArray = state["toggleArray"].toArray();
for (size_t i = 0; i < toggleArray.count(); i++)
{
QString item = toggleArray[i].toObject()["id"].toString();
if (combobox->findText(item) == -1)
combobox->addItem(item);
}
if (combobox->currentText() != selected)
{
combobox->setCurrentText(selected);
}
}
void SimulatorBase::process_ui_radiobutton(const OpenAPI::OAIClientUIItem* uiItem)
{
QD << "Not implemented";
emit quit();
}
void SimulatorBase::process_ui_button_array_element(QJsonObject jsonObject)
{
//TODO: fix bgcolor and color
QPushButton* button = id_to_button(jsonObject["id"].toString());
if (button == nullptr)
{
QD << "id_to_button returned null on " << jsonObject["id"].toString();
return;
}
QColor bg_color = QColor(jsonObject["color"].toString());
QString text = jsonObject["title"].toString();
bool enabled = jsonObject["enable"].toBool();
if (button->text() != text)
{
button->setText(text);
}
if (button->isEnabled() != enabled)
{
button->setEnabled(enabled);
}
if (bg_color == QColor(0x83, 0x91, 0x92))
{
reset_button_color(button);
return;
}
if (bg_color == QColor(0xFF, 0x00, 0x00))
{
set_button_color(button, QString("black"), QString("darkred"));
return;
}
if (bg_color == QColor(0x00, 0xFF, 0x00))
{
set_button_color(button, QString("white"), QString("darkgreen"));
return;
}
if (bg_color == QColor(0xFF8800))
{
set_button_color(button, QString("darkred"), QString("darkorange"));
return;
}
if (bg_color != button_bg_color(button))
{
set_button_color(button, QColor(), bg_color);
}
}
void SimulatorBase::process_ui_led_array_element(QJsonObject jsonObject)
{
QPushButton* led = id_to_led(jsonObject["id"].toString());
if (led == nullptr)
{
QD << "id_to_led returned null on " << jsonObject["id"].toString();
return;
}
QColor bg_color = QColor(jsonObject["state"].toString());
QColor color = QColor(~bg_color.red(), ~bg_color.green(), ~bg_color.blue());
QString text = jsonObject["title"].toString();
if (false == is_read_only(led))
{
set_read_only(led);
}
if (text != led->text())
{
led->setText(text);
}
if (bg_color == QColor(0x83, 0x91, 0x92))
{
reset_button_color(led);
return;
}
if (bg_color == QColor(0xFF, 0x00, 0x00))
{
set_button_color(led, QString("black"), QString("darkred"));
return;
}
if (bg_color == QColor(0x00, 0xFF, 0x00))
{
set_button_color(led, QString("white"), QString("darkgreen"));
return;
}
if (bg_color == QColor(0xFF8800))
{
set_button_color(led, QString("darkred"), QString("darkorange"));
return;
}
if (bg_color != button_bg_color(led))
{
set_button_color(led, color, bg_color);
}
}
+60
View File
@@ -0,0 +1,60 @@
#ifndef SIMULATORBASE_H
#define SIMULATORBASE_H
#include <QMainWindow>
#include <QWidget>
#include "OAICANApiApi.h"
#include "networkerror.h"
#include "helpers.h"
#include <magic_enum.hpp>
#include "IterableEnum.hpp"
#define QD qDebug() << "Debug:" << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << ":"
class SimulatorBase : public QMainWindow {
Q_OBJECT
public:
explicit SimulatorBase(OpenAPI::OAICANApiApi* api, QWidget* parent = nullptr);
void setup_cb(void);
void sim_update(void);
virtual QLabel* id_to_label(QString name) {return nullptr;}
virtual QPushButton* id_to_led(QString name) {return nullptr;}
virtual QPushButton* id_to_button(QString name) {return nullptr;}
virtual QwtSlider* id_to_slider(QString name) {return nullptr;}
virtual QLabel* id_to_slider_label(QString name) {return nullptr;}
virtual QString format_slider_value(QString name, double val) {return QString();}
virtual QwtDial* id_to_dial(QString name) {return nullptr;}
virtual QLabel* id_to_dial_label(QString name) {return nullptr;}
virtual QString format_dial_value(QString name, double val) {return QString();}
virtual QComboBox* id_to_combobox(QString name) {return nullptr;}
virtual QTextEdit* id_to_textbox(QString name) {return nullptr;}
signals:
void quit();
protected:
void apiCanapiUielements_bool_cb(bool ret, bool currentsim = false, QNetworkReply::NetworkError error_type = QNetworkReply::NetworkError::NoError, QString error_str = QString());
void apiCanapiCurrentsimGet_cb(OpenAPI::OAISimulatorInfo output, QNetworkReply::NetworkError error_type = QNetworkReply::NetworkError::NoError, QString error_str = QString());
void OAISimulatorInfo_parser(OpenAPI::OAISimulatorInfo input);
void process_ui_button_array(const OpenAPI::OAIClientUIItem* uiItem);
void process_ui_led_array(const OpenAPI::OAIClientUIItem* uiItem);
void process_ui_label(const OpenAPI::OAIClientUIItem* uiItem);
void process_ui_slider(const OpenAPI::OAIClientUIItem* uiItem);
void process_ui_textbox(const OpenAPI::OAIClientUIItem* uiItem);
void process_ui_combobox(const OpenAPI::OAIClientUIItem* uiItem);
void process_ui_radiobutton(const OpenAPI::OAIClientUIItem* uiItem);
void process_ui_button_array_element(QJsonObject jsonObject);
void process_ui_led_array_element(QJsonObject jsonObject);
void showEvent(QShowEvent* event);
void closeEvent(QCloseEvent* event);
OpenAPI::OAICANApiApi* api;
QTimer* timer_update;
uint32_t refresh_rate;
NetworkError* error_dialog;
bool closed = false;
};
#endif // SIMULATORBASE_H