From 3a132bb584f076fc53b806cb69b3eda125a9ab28 Mon Sep 17 00:00:00 2001 From: "PANIK\\chris" Date: Sat, 3 Jan 2026 20:10:30 +0100 Subject: [PATCH] Reworked driver code, again. --- bcdriver.cpp | 41 +----- bcdriver.h | 27 ++-- bcdrivertinycan.cpp | 132 +++++++++++++------- bcdrivertinycan.h | 18 ++- bclegacy.cpp | 35 ++++-- bcmainwindow.cpp | 2 +- bctransmitter.cpp | 62 ++++++--- bctransmitter.h | 17 ++- bcvalue.h | 4 - doc/Challenges.docx | Bin 0 -> 17353 bytes doc/{42 => bewerb}/Anschreiben.Weining.docx | Bin doc/{42 => bewerb}/Anschreiben.alt.docx | Bin doc/{42 => bewerb}/Anschreiben.txt | 0 doc/{42 => bewerb}/CV_C_Holzheuer.docx | Bin doc/{42 => bewerb}/CV_C_Holzheuer.pdf | Bin doc/{42 => bewerb}/Diplom_Holzheuer.pdf | Bin doc/{42 => bewerb}/Foto_C_Holzheuer.jpg | Bin doc/{42 => bewerb}/Profil_C_Holzheuer.docx | Bin doc/{42 => bewerb}/Profil_C_Holzheuer.pdf | Bin doc/challenges.txt | 74 ++++++----- doc/~$allenges.docx | Bin 0 -> 162 bytes doc/~WRL0643.tmp | Bin 0 -> 15726 bytes 22 files changed, 228 insertions(+), 184 deletions(-) create mode 100644 doc/Challenges.docx rename doc/{42 => bewerb}/Anschreiben.Weining.docx (100%) rename doc/{42 => bewerb}/Anschreiben.alt.docx (100%) rename doc/{42 => bewerb}/Anschreiben.txt (100%) rename doc/{42 => bewerb}/CV_C_Holzheuer.docx (100%) rename doc/{42 => bewerb}/CV_C_Holzheuer.pdf (100%) rename doc/{42 => bewerb}/Diplom_Holzheuer.pdf (100%) rename doc/{42 => bewerb}/Foto_C_Holzheuer.jpg (100%) rename doc/{42 => bewerb}/Profil_C_Holzheuer.docx (100%) rename doc/{42 => bewerb}/Profil_C_Holzheuer.pdf (100%) create mode 100644 doc/~$allenges.docx create mode 100644 doc/~WRL0643.tmp diff --git a/bcdriver.cpp b/bcdriver.cpp index 11fd3c8..c627d9f 100644 --- a/bcdriver.cpp +++ b/bcdriver.cpp @@ -37,12 +37,6 @@ -BCDriver::BCDriver(QObject* parent ) - : QObject{ parent } -{ - -} - BCDriver::DriverState BCDriver::getDriverState() const { return _driverState; @@ -59,47 +53,16 @@ BCDriver::DriverState BCDriver::getDriverState() const * aber die Console noch nicht eingeschaltet war. */ -void BCDriverDummy::onStartDriver() +BCDriver::DriverStateResult BCDriverDummy::loadAndStartDriver() { _driverState = DriverState::DeviceReady; - emit driverStateChanged( DriverState::DeviceReady, "Driver Ready." ); + return _driverState; } -// __Fix - /* - try - { - - // erstmal die Dll Laden: State::sIdle -> State::sLoaded - if( _driverState == DriverState::NotPresent) - _driverState = loadAndInitDriver(); - - emit stateChanged( _driverState ); - - } - catch( std::exception& except ) - { - //::CanDownDriver(); - //::UnloadAndInitDriver(); - - emit statusHint( except.what() ); - - } - */ - /// ----------------------------------------------------------------------------------- /// ----------------------------------------------------------------------------------- -/** - * @brief BCDriverDummy::BCDriverDummy - * @param parent - */ - -BCDriverDummy::BCDriverDummy( QObject* parent ) - : BCDriver(parent) -{ -} TransmitResult BCDriverDummy::readRawByte( uint32_t deviceID, uint8_t registerID ) const { diff --git a/bcdriver.h b/bcdriver.h index 9363b9a..e18b29e 100644 --- a/bcdriver.h +++ b/bcdriver.h @@ -84,9 +84,9 @@ class BCDriverStatus; */ -class BCDriver : public QObject +class BCDriver { - Q_OBJECT + Q_GADGET public: @@ -95,21 +95,23 @@ public: enum class DriverState { - NotPresent, - Error, + NotPresent, Loaded, Initialized, Opened, // bis hierher: dll vorhanden, Treiber geladen - DeviceReady // hier: devices connectable, wir können arbeiten. + DeviceReady, // hier: devices connectable, wir können arbeiten. + Error, }; Q_ENUM(DriverState) // Enthält den Treiberzustand oder einen Fehlerstring using DriverStateResult = std::expected; - explicit BCDriver( QObject* parent = nullptr ); + explicit BCDriver() = default; virtual ~BCDriver() = default; + virtual BCDriver::DriverStateResult loadAndStartDriver() = 0; + // Gibt den aktuelle Zustand des Treibers zurück. Der DriverState // muss auf DeviceReady stehen, um Werte lesen & schreiben zu können. // Dazu muss das Bionx-System eingeschaltet sein. @@ -122,14 +124,6 @@ public: virtual TransmitResult readRawByte ( uint32_t deviceID, uint8_t registerID ) const = 0; virtual TransmitResult writeRawByte( uint32_t deviceID, uint8_t registerID, uint8_t value ) const = 0; -public slots: - - virtual void onStartDriver() = 0; - -signals: - - void driverStateChanged( DriverState state, const QString& message="" ) const; - protected: DriverState _driverState{DriverState::NotPresent}; @@ -139,18 +133,15 @@ protected: class BCDriverDummy : public BCDriver { - Q_OBJECT public: - explicit BCDriverDummy( QObject* parent = nullptr ); + BCDriver::DriverStateResult loadAndStartDriver() override; TransmitResult readRawByte( uint32_t deviceID, uint8_t registerID ) const override; TransmitResult writeRawByte( uint32_t deviceID, uint8_t registerID, uint8_t value ) const override; -public slots: - virtual void onStartDriver() override; }; #endif // BCDRIVER_H diff --git a/bcdrivertinycan.cpp b/bcdrivertinycan.cpp index c166709..19de237 100644 --- a/bcdrivertinycan.cpp +++ b/bcdrivertinycan.cpp @@ -36,44 +36,56 @@ #include +/** + * @brief Destruktor. Entlädt den CAN-Bus Treiber wieder. + */ - - -BCDriverTinyCan::BCDriverTinyCan( QObject* parent ) - : BCDriver(parent ) +BCDriverTinyCan::~BCDriverTinyCan() { + resetDriver(); } +/** + * @brief BCDriverTinyCan::loadAndStartDriver + * @return + */ -void BCDriverTinyCan::onStartDriver() +BCDriver::DriverStateResult BCDriverTinyCan::loadAndStartDriver() { + DriverStateResult result; if( _driverState < DriverState::Opened) - loadDriver(); + result = loadDriver(); if( _driverState == DriverState::Opened) - _driverState = connectDriver(); + result = setConsoleSlaveMode(); + return result; } -void BCDriverTinyCan::loadDriver() +/** + * @brief BCDriverTinyCan::loadDriver + * @return + */ + +BCDriver::DriverStateResult BCDriverTinyCan::loadDriver() { - - - auto callLoadDriver = []() -> DriverStateResult + auto callLoadDriver = [&]() -> DriverStateResult { if( ::LoadDriver( NULL ) < 0 ) return std::unexpected(QString("Driver Error: 'LoadDriver'")); - return DriverState::Loaded; + _driverState = DriverState::Loaded; + return _driverState; }; - auto callInitDriver = [](DriverState state) -> DriverStateResult + auto callInitDriver = [&](DriverState state) -> DriverStateResult { Q_UNUSED(state) if( ::CanInitDriver( NULL ) < 0 ) return std::unexpected(QString("Driver Error: 'InitDriver'")); - return DriverState::Initialized; + _driverState = DriverState::Initialized; + return _driverState; }; - auto callOpenDevice = [](DriverState state) -> DriverStateResult + auto callOpenDevice = [&](DriverState state) -> DriverStateResult { Q_UNUSED(state) if( ::CanDeviceOpen( 0, NULL ) < 0 ) @@ -90,30 +102,67 @@ void BCDriverTinyCan::loadDriver() if( deviceStatus.CanStatus == CAN_STATUS_BUS_OFF ) { - ::CanSetMode( 0, OP_CAN_RESET, CAN_CMD_NONE ); - return std::unexpected(QString("Driver Error: CAN Status 'BusOff'" )); + ::CanSetMode( 0, OP_CAN_RESET, CAN_CMD_NONE ); + return std::unexpected(QString("Driver Error: CAN Status 'BusOff'" )); } - return DriverState::Opened; + _driverState = DriverState::Opened; + return _driverState; }; + + // #1. erstmal komplett zurücksetzen + resetDriver(); + // #2. Treiber laden, initialisieren und + // mit dem tinyCan Interface verbinden. auto newDriverState = callLoadDriver() .and_then( callInitDriver ) .and_then( callOpenDevice ); - _driverState = DriverState::Error; - QString message("Driver Ready."); - + // success: if(newDriverState) - _driverState = *newDriverState; - else - message = newDriverState.error(); + { + // return 'DriverState::Opened' + return _driverState; + } + // return driver error message, + // _driverState ist irgendwo unter DriverState::Opened + return newDriverState; - emit driverStateChanged( _driverState, message ); } // __fix -BCDriver::DriverState BCDriverTinyCan::connectDriver() +BCDriver::DriverStateResult BCDriverTinyCan::setConsoleSlaveMode() { + /* + consoleInSlaveMode = getValue(CONSOLE, CONSOLE_STATUS_SLAVE); + + if (consoleInSlaveMode) + { + printf("console already in salve mode. good!" _NL _NL); + } + else + { + if (gConsoleSetSlaveMode) + { + int retry = 20; + + printf("putting console in salve mode ... "); + do { + setValue(CONSOLE, CONSOLE_STATUS_SLAVE, 1); + consoleInSlaveMode = getValue(CONSOLE, CONSOLE_STATUS_SLAVE); + usleep(200000); + } while(retry-- && !consoleInSlaveMode); + + doSleep(500); // give the console some time to settle + printf("%s" _NL _NL, consoleInSlaveMode ? "done" : "failed"); + } + else + { + printf("console not in slave mode" _NL _NL); + } + } + */ + uint32_t console = static_cast(BCDevice::ID::Console); uint8_t slaveFlag = static_cast(BC::ID::Cons_Status_Slave); @@ -126,12 +175,12 @@ BCDriver::DriverState BCDriverTinyCan::connectDriver() qDebug() << "BCDriverTinyCan::BCDriverTinyCan::XXX Driver Init: putting Console in slave mode ... "; unsigned int retry = cTimeOuts; - emit driverStateChanged( _driverState, "Driver Init: putting Console in slave mode ... " ); + TransmitResult isSlave = 0; do { writeRawByte( console, slaveFlag, 1 ); - isSlave = readRawByte( console, slaveFlag ); + isSlave = readRawByte( console, slaveFlag ); bc::delay_millis( 200 ); } while( retry-- && !(*isSlave) ); @@ -145,20 +194,15 @@ BCDriver::DriverState BCDriverTinyCan::connectDriver() } - -/* - try - { - initBCDevice::ID::Console(); - } - - catch( std::exception& except ) - { - ::CanDownDriver(); - ::UnloadDriver(); - } - */ - +void BCDriverTinyCan::resetDriver() +{ + if( _driverState > DriverState::NotPresent ) + { + ::CanDownDriver(); + ::UnloadDriver(); + _driverState = DriverState::NotPresent; + } +} /** * @brief BCDriverTinyCan::readRawByte @@ -173,7 +217,7 @@ TransmitResult BCDriverTinyCan::readRawByte( uint32_t deviceID, uint8_t register //TransmitResult qDebug() << " --- BCDriverTinyCan::readRawByte DriverState: " << getDriverState(); - if( getDriverState() != DriverState::DeviceReady) + if( _driverState != DriverState::DeviceReady) return std::unexpected(QString("readRawValue error: driver not loaded." ) ); ::TCanMsg msg; @@ -238,7 +282,7 @@ retry: TransmitResult BCDriverTinyCan::writeRawByte( uint32_t deviceID, uint8_t registerID ,uint8_t value ) const { - if( getDriverState() != DriverState::DeviceReady) + if( _driverState != DriverState::DeviceReady) return std::unexpected(QString("writeRawValue error: driver not loaded." ) ); qDebug() << " --- BCDriverTinyCan writeRawValue: " << value; diff --git a/bcdrivertinycan.h b/bcdrivertinycan.h index 3b6cd77..4176a19 100644 --- a/bcdrivertinycan.h +++ b/bcdrivertinycan.h @@ -37,24 +37,22 @@ class BCDriverTinyCan : public BCDriver { - Q_OBJECT public: - explicit BCDriverTinyCan( QObject* parent=nullptr ); - virtual ~BCDriverTinyCan() = default; + + virtual ~BCDriverTinyCan(); + + BCDriver::DriverStateResult loadAndStartDriver() override; TransmitResult readRawByte ( uint32_t deviceID, uint8_t registerID ) const override; TransmitResult writeRawByte( uint32_t deviceID, uint8_t registerID, uint8_t value ) const override; -public slots: +private: - void onStartDriver() override; - -protected: - - void loadDriver(); - DriverState connectDriver(); + BCDriver::DriverStateResult loadDriver(); + BCDriver::DriverStateResult setConsoleSlaveMode(); + void resetDriver(); //const char* CBCDLL_LIN = "libmhstcan.so"; //const char* CBCDLL_WIN = "mhstcan.dll"; diff --git a/bclegacy.cpp b/bclegacy.cpp index 26fe6f6..b4632a9 100644 --- a/bclegacy.cpp +++ b/bclegacy.cpp @@ -727,24 +727,30 @@ int xmain(int argc, char **argv) CanSetMode(0, OP_CAN_START, CAN_CMD_ALL_CLEAR); CanGetDeviceStatus(0, &status); - if (status.DrvStatus >= DRV_STATUS_CAN_OPEN) { - if (status.CanStatus == CAN_STATUS_BUS_OFF) { + if (status.DrvStatus >= DRV_STATUS_CAN_OPEN) + { + if (status.CanStatus == CAN_STATUS_BUS_OFF) + { printf("CAN Status BusOff" _NL); CanSetMode(0, OP_CAN_RESET, CAN_CMD_NONE); } - } else { + } + else + { printf("error: could not open device" _NL); goto error; } - - - consoleInSlaveMode = getValue(CONSOLE, CONSOLE_STATUS_SLAVE); - if (consoleInSlaveMode) { + + if (consoleInSlaveMode) + { printf("console already in salve mode. good!" _NL _NL); - } else { - if (gConsoleSetSlaveMode) { + } + else + { + if (gConsoleSetSlaveMode) + { int retry = 20; printf("putting console in salve mode ... "); @@ -756,16 +762,21 @@ int xmain(int argc, char **argv) doSleep(500); // give the console some time to settle printf("%s" _NL _NL, consoleInSlaveMode ? "done" : "failed"); - } else + } + else + { printf("console not in slave mode" _NL _NL); + } } - if (gAssistInitLevel != -1) { + if (gAssistInitLevel != -1) + { printf("setting initial assistance level to %d" _NL, gAssistInitLevel); setValue(CONSOLE, CONSOLE_ASSIST_INITLEVEL, gAssistInitLevel); } - if (gSetSpeedLimit > 0) { + if (gSetSpeedLimit > 0) + { printf("set speed limit to %0.2f km/h" _NL, gSetSpeedLimit); setSpeedLimit(gSetSpeedLimit); doShutdown = 1; diff --git a/bcmainwindow.cpp b/bcmainwindow.cpp index 5564c50..658031a 100644 --- a/bcmainwindow.cpp +++ b/bcmainwindow.cpp @@ -143,7 +143,7 @@ void BCMainWindow::initMainWindow() */ // besser: model::emit dataChanged // also: emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole, ValueRole}); - connect( _connectButton, &QToolButton::clicked, &_transmitter, &BCTransmitter::onToggleConnectionState ); + connect( _connectButton, &QToolButton::clicked, &_transmitter, &BCTransmitter::onToggleDriverConnection ); connect( _syncButton, &QToolButton::clicked, this, &BCMainWindow::onSyncDeviceView ); connect( &_transmitter, &BCTransmitter::valueUpdated, this, &BCMainWindow::onValueUpdated ); diff --git a/bctransmitter.cpp b/bctransmitter.cpp index 4cd1815..e3a8d80 100644 --- a/bctransmitter.cpp +++ b/bctransmitter.cpp @@ -35,37 +35,61 @@ #include +/** + * @brief Kosntruktion. Aktiviert erstmal den Dummy-Driver. + */ + BCTransmitter::BCTransmitter(QObject *parent) : QObject(parent), _isBusy(false) { //_canDriver = new BCDriverTinyCan{this}; - _canDriver = new BCDriverDummy{this}; - // forward driver state - connect( _canDriver, &BCDriver::driverStateChanged, this, &BCTransmitter::driverStateChanged ); + _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 + * false: Disconnect & Cleanup + */ -void BCTransmitter::onToggleConnectionState( bool connect ) +void BCTransmitter::onToggleDriverConnection( bool connect ) { - if( connect ) + qDebug() << " --- onToggleDriverConnection: " << connect; + // FIX! Ende der current op abwarten! + // weitere operation stoppen + _isBusy = true; + + connect ? connectCanDriver() : disconnectCanDriver(); + +} + +void BCTransmitter::connectCanDriver() +{ + // hier gehts nur um den echten Treiber + + // Treiber laden und/oder starten: + if( _tinyCanDriver.getDriverState() != BCDriver::DriverState::DeviceReady ) + _tinyCanDriver.loadAndStartDriver(); + + // hat geklappt + if( _tinyCanDriver.getDriverState() == BCDriver::DriverState::DeviceReady ) { - if( _canDriver->getDriverState() != BCDriver::DriverState::DeviceReady ) - _canDriver->onStartDriver(); + uint32_t console = static_cast(BCDevice::ID::Console); + uint8_t hwRev = static_cast (BC::ID::Cons_Rev_Hw); - // __fix! - TransmitResult hwVersion = _canDriver->readRawByte( (uint32_t)BCDevice::ID::Console, (uint8_t)BC::ID::Cons_Rev_Hw); - if(!hwVersion) - { - qDebug() << "Console not responding"; - } + TransmitResult hwVersion = _tinyCanDriver.readRawByte( console, hwRev); + if( hwVersion.has_value() ) + qDebug() << " ---- HAIL to the king!"; else - { - - - } - - qDebug() << " ---HAIL to the kings: " << hwVersion.value(); + qDebug() << "Console not responding"; } + +} + +void BCTransmitter::disconnectCanDriver() +{ + } diff --git a/bctransmitter.h b/bctransmitter.h index 08f57b2..e67038d 100644 --- a/bctransmitter.h +++ b/bctransmitter.h @@ -60,12 +60,9 @@ public: explicit BCTransmitter(QObject *parent = nullptr); - //TransmitResult readByte( uint32_t deviceID, uint8_t registerID ) const override; - //TransmitResult writeByte( uint32_t deviceID, uint8_t registerID, uint8_t value ) const override; - public slots: - void onToggleConnectionState( bool connect ); + void onToggleDriverConnection( bool connect ); void enqueueValue(BCValuePtrConst value ); void processValue(); @@ -76,11 +73,11 @@ signals: private: + void connectCanDriver(); + void disconnectCanDriver(); + TransmitResult readByteValue( uint32_t deviceID, uint8_t registerID ); TransmitResult readWordValue( uint32_t deviceID, uint8_t registerID ); - //TransmitResult writeByteValue( uint32_t deviceID, uint8_t registerID ); - //TransmitResult writeWordValue( uint32_t deviceID, uint8_t registerID ); - using BCDataQueue = QQueue; @@ -88,8 +85,10 @@ private: QMutex _mutex; std::atomic _isBusy{ false }; - // __fix! set two - BCDriver* _canDriver{}; + // __fix! + BCDriver* _canDriver{}; + BCDriverTinyCan _tinyCanDriver{}; + BCDriverDummy _dummyDriver{}; }; diff --git a/bcvalue.h b/bcvalue.h index f22b24b..40a9d6d 100644 --- a/bcvalue.h +++ b/bcvalue.h @@ -56,8 +56,6 @@ - */ - - using OptDouble = std::optional; // Enthält den gelesenen Wert oder einen Fehlerstring @@ -65,8 +63,6 @@ using TransmitResult = std::expected; // Funktionsobject, um Werte aus der Transmitterschicht zu holden //using ReadValueFunc = std::function; - - class BCValue { diff --git a/doc/Challenges.docx b/doc/Challenges.docx new file mode 100644 index 0000000000000000000000000000000000000000..b0c3d6f32e2901ec669806258cf33170f7d2e028 GIT binary patch literal 17353 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 literal 0 HcmV?d00001