diff --git a/BionxControl.pro b/BionxControl.pro index 0bc7ece..3706654 100644 --- a/BionxControl.pro +++ b/BionxControl.pro @@ -1,4 +1,4 @@ -QT += core gui +QT += core gui svg greaterThan(QT_MAJOR_VERSION, 4): QT += widgets @@ -12,7 +12,8 @@ QMAKE_CXXFLAGS += -std=c++23 INCLUDEPATH += . libwin -linux:contains(QT_ARCH, arm.*) { +linux:contains(QT_ARCH, arm.*) +{ message("Konfiguration für Raspberry Pi (ARM) erkannt.") # 1. Header-Dateien (z.B. für bcm2835.h oder eigene Treiber) diff --git a/bcdeviceview.cpp b/bcdeviceview.cpp index c3b1d29..790f1be 100644 --- a/bcdeviceview.cpp +++ b/bcdeviceview.cpp @@ -45,12 +45,16 @@ BCDeviceView::BCDeviceView(QWidget *parent) _itemDelegate = new BCAnimatedDelegate( _valueModel.getValueList(), this); setItemDelegate( _itemDelegate ); + qDebug() << " --- View size I: " << this->size(); + } void BCDeviceView::setDeviceID( BCDevice::ID deviceID ) { + qDebug() << " --- View size II: " << this->size(); + _devideID = deviceID; } diff --git a/bcdriver.cpp b/bcdriver.cpp index b3662ff..4e3c8c1 100644 --- a/bcdriver.cpp +++ b/bcdriver.cpp @@ -36,6 +36,9 @@ #include +/** + * @brief Gibt den Treiberstatus zurück. + */ BCDriver::DriverState BCDriver::getDriverState() const { @@ -63,6 +66,9 @@ BCDriver::DriverStateResult BCDriverDummy::loadAndStartDriver() /// ----------------------------------------------------------------------------------- /// ----------------------------------------------------------------------------------- +/** + * @brief Gibt ein Zufallsbyte zurück. + */ TransmitResult BCDriverDummy::readRawByte( uint32_t deviceID, uint8_t registerID ) const { @@ -73,6 +79,11 @@ TransmitResult BCDriverDummy::readRawByte( uint32_t deviceID, uint8_t registerID return myRandomByte; } + +/** + * @brief Simuliert erfolgreiches scheiben. Tut nix. + */ + TransmitResult BCDriverDummy::writeRawByte( uint32_t deviceID, uint8_t registerID, uint8_t value ) const { Q_UNUSED(deviceID) diff --git a/bcdriver.h b/bcdriver.h index 0d24f3e..81415d6 100644 --- a/bcdriver.h +++ b/bcdriver.h @@ -37,36 +37,6 @@ #include #include -/* -int32_t CanInitDriver(char *options); -void CanDownDriver(void); -int32_t CanSetOptions(char *options); -int32_t CanDeviceOpen(uint32_t index, char *parameter); -int32_t CanDeviceClose(uint32_t index); - -int32_t CanSetMode(uint32_t index, unsigned char can_op_mode, uint16_t can_command); - -int32_t CanTransmit(uint32_t index, struct TCanMsg *msg, int32_t count); -void CanTransmitClear(uint32_t index); -uint32_t CanTransmitGetCount(uint32_t index); -int32_t CanTransmitSet(uint32_t index, uint16_t cmd, uint32_t time); -int32_t CanReceive(uint32_t index, struct TCanMsg *msg, int32_t count); -void CanReceiveClear(uint32_t index); -uint32_t CanReceiveGetCount(uint32_t index); - -int32_t CanSetSpeed(uint32_t index, uint16_t speed); -int32_t CanSetSpeedUser(uint32_t index, uint32_t value); -char* CanDrvInfo(void); -char* CanDrvHwInfo(uint32_t index); -int32_t CanSetFilter(uint32_t index, struct TMsgFilter *msg_filter); -int32_t CanGetDeviceStatus(uint32_t index, struct TDeviceStatus *status); -void CanSetPnPEventCallback(void (DRV_CALLBACK_TYPE *event)(uint32_t index, int32_t status)); -void CanSetStatusEventCallback(void (DRV_CALLBACK_TYPE *event) (uint32_t index, struct TDeviceStatus *device_status) ); -void CanSetRxEventCallback(void (DRV_CALLBACK_TYPE *event)(uint32_t index, struct TCanMsg *msg, int32_t count) ); - -void CanSetEvents( uint16_t events ); -uint32_t CanEventStatus(void); -*/ struct CBCItem; class BCDriverStatus; diff --git a/bcdrivertinycan.cpp b/bcdrivertinycan.cpp index 4461173..33e4179 100644 --- a/bcdrivertinycan.cpp +++ b/bcdrivertinycan.cpp @@ -37,12 +37,48 @@ #if defined(Q_OS_WIN) + // Unter Windows steht der Treibername in der registry static const char* cMHS_DRIVERNAME = NULL; #elif defined(Q_OS_LINUX) -// Linux-spezifischer Code (z.B. /proc Filesystem, D-Bus) + // Unter linux(artigen) muss der Treibername explizit mit übergeben werden static const char* cMHS_DRIVERNAME = "libmhstcan.so"; #endif +/* + + // TinyCan C-Api + // ------------- + +int32_t CanInitDriver(char *options); +void CanDownDriver(void); +int32_t CanSetOptions(char *options); +int32_t CanDeviceOpen(uint32_t index, char *parameter); +int32_t CanDeviceClose(uint32_t index); + +int32_t CanSetMode(uint32_t index, unsigned char can_op_mode, uint16_t can_command); + +int32_t CanTransmit(uint32_t index, struct TCanMsg *msg, int32_t count); +void CanTransmitClear(uint32_t index); +uint32_t CanTransmitGetCount(uint32_t index); +int32_t CanTransmitSet(uint32_t index, uint16_t cmd, uint32_t time); +int32_t CanReceive(uint32_t index, struct TCanMsg *msg, int32_t count); +void CanReceiveClear(uint32_t index); +uint32_t CanReceiveGetCount(uint32_t index); + +int32_t CanSetSpeed(uint32_t index, uint16_t speed); +int32_t CanSetSpeedUser(uint32_t index, uint32_t value); +char* CanDrvInfo(void); +char* CanDrvHwInfo(uint32_t index); +int32_t CanSetFilter(uint32_t index, struct TMsgFilter *msg_filter); +int32_t CanGetDeviceStatus(uint32_t index, struct TDeviceStatus *status); +void CanSetPnPEventCallback(void (DRV_CALLBACK_TYPE *event)(uint32_t index, int32_t status)); +void CanSetStatusEventCallback(void (DRV_CALLBACK_TYPE *event) (uint32_t index, struct TDeviceStatus *device_status) ); +void CanSetRxEventCallback(void (DRV_CALLBACK_TYPE *event)(uint32_t index, struct TCanMsg *msg, int32_t count) ); + +void CanSetEvents( uint16_t events ); +uint32_t CanEventStatus(void); +*/ + /** * @brief Destruktor. Entlädt den CAN-Bus Treiber wieder. */ @@ -76,8 +112,6 @@ BCDriver::DriverStateResult BCDriverTinyCan::loadDriver() { auto callLoadDriver = [&]() -> DriverStateResult { - qDebug() << " -- Hier!"; - //if( ::LoadDriver( NULL ) < 0 ) if( ::LoadDriver( cMHS_DRIVERNAME ) < 0 ) return std::unexpected(QString("Driver Error: 'LoadDriver'")); _driverState = DriverState::Loaded; @@ -126,19 +160,20 @@ BCDriver::DriverStateResult BCDriverTinyCan::loadDriver() .and_then( callInitDriver ) .and_then( callOpenDevice ); - // success: - if(newDriverState) - { - // return 'DriverState::Opened' - return _driverState; - } - // return driver error message, - // _driverState ist irgendwo unter DriverState::Opened + // in Fehlerfall ist der Errorstring gesetzt, + // der interne _driverstate ist + // irgendwo unter DriverState::Opened return newDriverState; } -// __fix + +/** + * @brief Um mit dem Bionx eBike reden zu können, müssen wir + * die Console in den Slave-Mode setzen. + * @return Fehlerstring oder DriverState::DeviceReady + */ + BCDriver::DriverStateResult BCDriverTinyCan::setConsoleSlaveMode() { @@ -164,7 +199,6 @@ BCDriver::DriverStateResult BCDriverTinyCan::setConsoleSlaveMode() unsigned int retry = cTimeOuts; - do { writeRawByte( console, slaveFlag, 1 ); @@ -192,6 +226,7 @@ void BCDriverTinyCan::resetDriver() } } + /** * @brief BCDriverTinyCan::readRawByte * Kapselt den Treiberzugiff über die legacy C-Api. Liest ein byte, gibt dieses im std::expected aber diff --git a/bcguihelpers.cpp b/bcguihelpers.cpp index 5894ca5..59358e8 100644 --- a/bcguihelpers.cpp +++ b/bcguihelpers.cpp @@ -32,16 +32,18 @@ #include + BCThemeSwitchButton::BCThemeSwitchButton(QWidget *parent ) - : QPushButton(parent), _isDarkMode(true) + : QPushButton(parent) { - // 1. Visuelles Setup: Flach, keine Ränder, Hand-Cursor + // Visuelles Setup: Flach, keine Ränder, Hand-Cursor setFlat(true); setCursor(Qt::PointingHandCursor); setFixedSize(24, 24); // Kleiner Footprint im StatusBar // CSS: Transparent, damit es sich nahtlos in den StatusBar einfügt // Schriftgröße etwas erhöhen, damit die Emojis gut erkennbar sind + /* setStyleSheet(R"( QPushButton { border: none; @@ -53,17 +55,30 @@ BCThemeSwitchButton::BCThemeSwitchButton(QWidget *parent ) border-radius: 24px; } )"); - - // 2. Initialer Status (Startet im Dark Mode -> zeigt Mond) + */ + // Initialer Status (Startet im Dark Mode -> zeigt Mond) updateIcon(); - // 3. Klick verbinden connect(this, &QPushButton::clicked, this, &BCThemeSwitchButton::toggle); } +/** + * @brief Setzt den DarkMode + */ -void BCThemeSwitchButton::toggle() +void BCThemeSwitchButton::setDarkMode( bool isDark ) +{ + _isDarkMode = !isDark; + toggleMode(); +} + + +/** + * @brief Schaltet den akutellen Mode um. + */ + +void BCThemeSwitchButton::toggleMode() { _isDarkMode = !_isDarkMode; updateIcon(); @@ -71,13 +86,17 @@ void BCThemeSwitchButton::toggle() } +/** + * @brief Icon & Tooltip anpassen + */ + void BCThemeSwitchButton::updateIcon() { // Logik: // Ist Dark Mode an? Zeige Mond (oder Sonne, je nach Geschmack). // Hier: Zeige das Symbol des AKTUELLEN Modus. setText(_isDarkMode ? "🌙" : "☀️"); - setToolTip(_isDarkMode ? "Switch to Light Mode" : "Switch to Dark Mode"); + setToolTip(_isDarkMode ? "Zum LightMode wechseln" : "Zum DarkMode wechseln"); } @@ -85,22 +104,20 @@ void BCThemeSwitchButton::updateIcon() /// ----------------------------------------------------------------------------------- - +/** + * @brief Hilfswidget: Zeigt den DriverState als Icon an. + */ BCDriverStateWidget::BCDriverStateWidget(QWidget* parent) : QWidget(parent) { QHBoxLayout* layout = new QHBoxLayout(this); layout->setContentsMargins(10, 2, 10, 2); - layout->setSpacing(8); - - _label = new QLabel(this); - _label->setStyleSheet("font-weight: 500;"); // Medium weight + //layout->setSpacing(8); _led = new QLabel(this); _led->setFixedSize(12, 12); - layout->addWidget(_label); layout->addWidget(_led); // Startzustand @@ -115,31 +132,11 @@ void BCDriverStateWidget::onDriverStateChanged(BCDriver::DriverState state, cons { _state = state; qDebug() << " --- StateWidget: " << state << " - " << customMessage; - // Standard-Texte, falls keine Nachricht übergeben wurde - QString text = customMessage; - if (text.isEmpty()) - { - switch (_state) - { - case BCDriver::DriverState::DeviceReady: - text = "Device Ready"; - break; - - case BCDriver::DriverState::Error: - text = "Driver Error"; - break; - - default: - text = "Not Present"; - break; - } - } - _label->setText(text); updateStyle(); } - +/* void BCDriverStateWidget::updateStyle() { QString ledStyle; @@ -181,8 +178,76 @@ void BCDriverStateWidget::updateStyle() setToolTip(toolTipText); } - - - +*/ + +void BCDriverStateWidget::updateStyle() +{ + QString ledStyle; + QString toolTipText; + /* + NotPresent, + Error, + Loaded, + Initialized, + Opened, // bis hierher: dll vorhanden, Treiber geladen + DeviceReady + */ + switch (_state) + { + case BCDriver::DriverState::NotPresent: + // FLUENT GRAY (Neutral) + // Wir machen es dunkelgrau mit hellem Rand -> "Ausgeschaltet"-Look + ledStyle = "background-color: #3B3B3B; border: 1px solid #606060;"; + toolTipText = "Treiber nicht geladen."; + break; + + case BCDriver::DriverState::Error: + // FLUENT RED (Critical) + ledStyle = "background-color: #C42B1C; border: 1px solid #A80000;"; + toolTipText = "Fehler beim Laden des Treibers."; + break; + + // hier: dll vorhanden, Treiber geladen + case BCDriver::DriverState::Loaded: + case BCDriver::DriverState::Initialized: + case BCDriver::DriverState::Opened: + // FLUENT RED (Critical) + ledStyle = "background-color: #FF8C00; border: 1px solid #A80000;"; + toolTipText = "Fehler beim Laden des Treibers."; + break; + + case BCDriver::DriverState::DeviceReady: + // FLUENT GREEN (Success) + ledStyle = "background-color: #107C10; border: 1px solid #0E600E;"; + toolTipText = "Verbindung erfolgreich hergestellt."; + break; + + } + + // Styles anwenden (immer rund machen) + _led->setStyleSheet(ledStyle + "border-radius: 6px;"); + + /* + // Textfarbe setzen + _setStyleSheet(QString("color: %1; font-weight: %2;") + .arg(labelColor) + .arg(_state == BCDriver::DriverState::DeviceReady ? "bold" : "normal")); + */ + setToolTip(toolTipText); +} + +void BCDriverStateWidget::mouseReleaseEvent(QMouseEvent* event) +{ + qDebug() << " --- RELAASE!"; + + if (event->button() == Qt::LeftButton) + { + qDebug() << " --- MOO?!"; + + emit clicked(); + } + + QWidget::mouseReleaseEvent(event); +} diff --git a/bcguihelpers.h b/bcguihelpers.h index 4b2d480..8caca4a 100644 --- a/bcguihelpers.h +++ b/bcguihelpers.h @@ -36,10 +36,16 @@ #include #include #include +#include #include +/** + * @brief Einfaches Buttonwidget, um zwischen Dark- und Lightmode + * zu wechseln + */ + class BCThemeSwitchButton : public QPushButton { Q_OBJECT @@ -47,6 +53,7 @@ class BCThemeSwitchButton : public QPushButton public: explicit BCThemeSwitchButton(QWidget *parent = nullptr); + void setDarkMode( bool isDark ); signals: @@ -54,13 +61,13 @@ signals: private slots: - void toggle(); + void toggleMode(); private: void updateIcon(); - bool _isDarkMode; + bool _isDarkMode{false}; }; @@ -70,6 +77,11 @@ private: /// ----------------------------------------------------------------------------------- +/** + * @brief Einfaches Widget, um den Zustand des TinyCan Native + * Drivers anzuzeigen. + */ + class BCDriverStateWidget : public QWidget { Q_OBJECT @@ -84,12 +96,16 @@ public slots: // 'customMessage' ist optional. Wenn leer, wird ein Standardtext genommen. void onDriverStateChanged(BCDriver::DriverState state, const QString& customMessage = QString()); -private: +signals: + + void clicked(); + +protected: void updateStyle(); + void mouseReleaseEvent(QMouseEvent* event) override; QLabel* _led; - QLabel* _label; BCDriver::DriverState _state; }; diff --git a/bcmainwindow.cpp b/bcmainwindow.cpp index 5f7353f..356effa 100644 --- a/bcmainwindow.cpp +++ b/bcmainwindow.cpp @@ -29,7 +29,7 @@ ***************************************************************************/ - +#include #include #include "qassert.h" @@ -119,6 +119,7 @@ void BCMainWindow::initMainWindow() configureAction(_batteryButton, _batteryAction, BCDevice::ID::Battery ); //configureAction(_pimpButton, _pimpAction, BCDevice::ID::Pimp ); + /* bool m_isDarkMode = false; QString icon = m_isDarkMode ? "☀️" : "🌙"; @@ -165,23 +166,74 @@ void BCMainWindow::initMainWindow() } +/* +// 2. Bild für den Zustand UNCHECKED (Off) hinzufügen +// Das ist das Symbol, wenn NICHT verbunden ist (z.B. ein Stecker) +connectIcon.addFile(":/icons/plug_disconnected.svg", QSize(), QIcon::Normal, QIcon::Off); + +// 3. Bild für den Zustand CHECKED (On) hinzufügen +// Das ist das Symbol, wenn verbunden IST (z.B. Stecker in Dose) +connectIcon.addFile(":/icons/plug_connected.svg", QSize(), QIcon::Normal, QIcon::On); +*/ void BCMainWindow::initStatusBar() { QStatusBar *statBar = statusBar(); - BCDriverStateWidget* connector = new BCDriverStateWidget(this); - connect( &_transmitter, &BCTransmitter::driverStateChanged, connector, &BCDriverStateWidget::onDriverStateChanged ); - statBar->addPermanentWidget(connector); + BCDriverStateWidget* conState = new BCDriverStateWidget(this); + connect( &_transmitter, &BCTransmitter::driverStateChanged, conState, &BCDriverStateWidget::onDriverStateChanged ); + connect( conState, &BCDriverStateWidget::clicked, _connectAction, &QAction::trigger ); - statBar->showMessage("Ready"); - BCThemeSwitchButton *themeBtn = new BCThemeSwitchButton(this); + statBar->addPermanentWidget(conState); + conState->installEventFilter(this); + + BCThemeSwitchButton* themeBtn = new BCThemeSwitchButton(this); statBar->addPermanentWidget(themeBtn); connect(themeBtn, &BCThemeSwitchButton::themeChanged, this, [this](bool isDark) { QString message = isDark ? "Dark Mode Activated" : "Light Mode Activated"; statusBar()->showMessage( message, 3000); + setApplicationStyleSheet( isDark ? ":/claude_dark_mode.qss"_L1 : ":/claude_light_mode.qss"_L1 ); }); + + // Wir starten im light mode + //themeBtn->setDarkMode( false ); + + statBar->showMessage("Ready"); +} + +/* +bool BCMainWindow::eventFilter(QObject *obj, QEvent *event) +{ + if (obj == myWidget && event->type() == QEvent::MouseButtonRelease) { + QMouseEvent *mouseEvent = static_cast(event); + if (mouseEvent->button() == Qt::LeftButton) { + myAction->trigger(); + return true; // Event wurde verarbeitet + } + } + return QObject::eventFilter(obj, event); +} +*/ + +/** + * @brief Setzt das Stylesheet, hier: Dark- oder Lightmode + * @param path Der Pfad zuum Stylesheet + * @return + */ + +bool BCMainWindow::setApplicationStyleSheet( QAnyStringView path ) +{ + QFile styleFile( path.toString() ); + if (styleFile.open(QIODevice::ReadOnly | QIODevice::Text)) + { + QString style = styleFile.readAll(); + qApp->setStyleSheet(style); + styleFile.close(); + return false; + } + qWarning() << "Konnte Stylesheet nicht laden:" << styleFile.errorString(); + return true; } @@ -195,6 +247,10 @@ void BCMainWindow::setHeaderLabel( const QString& headerText) _headerLabel->setText( " BionxControl: " + headerText ); } +void BCMainWindow::onShowMessage( const QString& message, int timeOut ) +{ + _statusbar->showMessage( message, timeOut ); +} void BCMainWindow::autoConnect() { diff --git a/bcmainwindow.h b/bcmainwindow.h index 4dda74c..3b0bddc 100644 --- a/bcmainwindow.h +++ b/bcmainwindow.h @@ -60,10 +60,12 @@ public slots: void onConnectButtonToggled(bool active ); void onDriverStateChanged( BCDriver::DriverState state, const QString& message="" ); - // Slots für Rückmeldungen vom Runner + // Slots für Rückmeldungen vom Transmitter void onValueUpdated( BCDevice::ID deviceID, int index, BCValue::State state, const QString& newValue="" ); void onSyncDeviceView(); + void onShowMessage( const QString& message, int timeOut=3000); + signals: // Internes Signal, um Daten an den Worker Thread zu senden @@ -71,10 +73,13 @@ signals: protected: + bool setApplicationStyleSheet( QAnyStringView path ); void initMainWindow(); void initStatusBar(); void autoConnect(); + //bool eventFilter(QObject *obj, QEvent *event) override; + BCXmlLoader _dataManager; // Wir brauchen eine Verbindung zwischen den Views diff --git a/bcmainwindow.ui b/bcmainwindow.ui index c2af381..71e4ac3 100644 --- a/bcmainwindow.ui +++ b/bcmainwindow.ui @@ -19,6 +19,9 @@ + + + @@ -169,13 +172,6 @@ - - - - Fitze - - - @@ -318,7 +314,11 @@ - + + + background-color: #DADADA + + true diff --git a/bctransmitter.cpp b/bctransmitter.cpp index af9150b..b2c473c 100644 --- a/bctransmitter.cpp +++ b/bctransmitter.cpp @@ -44,11 +44,9 @@ BCTransmitter::BCTransmitter(QObject *parent) { //_canDriver = new BCDriverTinyCan{this}; _canDriver = &_dummyDriver; - } - /** * @brief Steuert die Verbindung mit dem 'echten' CAN-Bus Treiber. * @param connect true: Vesuche den CAN-Bus Treiber zu laden und zu verbinden @@ -59,6 +57,10 @@ void BCTransmitter::onToggleDriverConnection( bool connect ) { qDebug() << " --- onToggleDriverConnection: " << connect; // FIX! Ende der current op abwarten! + BCDriver::DriverState state = connect ? BCDriver::DriverState::DeviceReady : BCDriver::DriverState::NotPresent; + const QString& message = connect ? "Trying to connect" : " FAILED"; + emit driverStateChanged(state, message); + return; // Hier sind wir noch in GUI Thread QMutexLocker locker(&_mutex); @@ -69,7 +71,7 @@ void BCTransmitter::onToggleDriverConnection( bool connect ) } -void BCTransmitter::onStartNativeDirver() +void BCTransmitter::onStartNativeDriver() { } diff --git a/bctransmitter.h b/bctransmitter.h index f47e58c..8eb0265 100644 --- a/bctransmitter.h +++ b/bctransmitter.h @@ -65,7 +65,7 @@ public slots: void onToggleDriverConnection( bool connect ); void onEnqueueValue(BCValuePtrConst value ); void onProcessValue(); - void onStartNativeDirver(); + void onStartNativeDriver(); signals: diff --git a/doc/Challenges.docx b/doc/Challenges.docx index b0c3d6f..32177f2 100644 Binary files a/doc/Challenges.docx and b/doc/Challenges.docx differ diff --git a/main.cpp b/main.cpp index 14005cb..55f1a37 100644 --- a/main.cpp +++ b/main.cpp @@ -39,32 +39,15 @@ #include -#include -#include -bool setApplicationStyleSheet( QAnyStringView path ) -{ - QFile styleFile( path.toString() ); - if (styleFile.open(QIODevice::ReadOnly | QIODevice::Text)) - { - QString style = styleFile.readAll(); - qApp->setStyleSheet(style); - styleFile.close(); - return true; - } - qWarning() << "Konnte Stylesheet nicht laden:" << styleFile.errorString(); - return true; -} - int main(int argc, char *argv[]) { QApplication app(argc, argv); - //setApplicationStyleSheet( ":/claude_light_mode.qss"_L1 ); - /* + /* app.setStyleSheet(R"( QWidget { background-color: #F3F3F3;