/*************************************************************************** BionxControl © 2025 -2026 christoph holzheuer christoph.holzheuer@gmail.com Using: mhs_can_drv.c © 2011 - 2023 by MHS-Elektronik GmbH & Co. KG, Germany Klaus Demlehner, klaus@mhs-elektronik.de @see www.mhs-elektronik.de Based on Bionx data type descriptions from: BigXionFlasher USB V 0.2.4 rev. 97 © 2011-2013 by Thomas Koenig @see www.bigxionflasher.org Bionx Bike Info © 2018 Thorsten Schmidt (tschmidt@ts-soft.de) @see www.ts-soft.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. @see https://github.com/bikemike/bionx-bikeinfo ***************************************************************************/ #include #include #include #include /** * @brief Kosntruktion. Aktiviert erstmal den Dummy-Driver. */ BCTransmitter::BCTransmitter(QObject *parent) : QObject(parent)//, _isBusy(false) { //_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 * false: Disconnect & Cleanup */ void BCTransmitter::onToggleDriverConnection( bool connect ) { if( connect ) emit driverStateChanged(BCDriver::DriverState::NotPresent, "Native Treiber wird geladen."); /* // kill all pending stuff //QCoreApplication::removePostedEvents(this, QEvent::MetaCall); BCDriver::DriverState state = connect ? BCDriver::DriverState::DeviceReady : BCDriver::DriverState::NotPresent; const QString& message = connect ? "Trying to connect" : " FAILED"; emit driverStateChanged(state, message); return; */ connect ? connectCanDriver() : disconnectCanDriver(); } void BCTransmitter::connectCanDriver() { // hier gehts nur um den echten Treiber // Treiber laden und/oder starten: BCDriver::DriverStateResult result; //(defaults to 'NotPresent') if( _tinyCanDriver.getDriverState() != BCDriver::DriverState::DeviceReady ) result = _tinyCanDriver.loadAndStartDriver(); QString message("Treiber geladen (nicht verbunden)"); // Der result-Wert im ERfolgsfall ist der driver state. if(result.has_value() ) { switch( result.value() ) { case BCDriver::DriverState::Opened: message = "Treiber geladen (Device antwortet nicht)"; break; case BCDriver::DriverState::DeviceReady: message = "Treiber geladen und Device verbunden."; // swap driver _canDriver = &_tinyCanDriver; break; default: break; } } else // Fehlerfall, wir holen die Fehlermeldung { message = result.error(); } emit driverStateChanged( _tinyCanDriver.getDriverState(), message ); } /** * @brief Native-Treiber zurücksetzen, Dummy-Treiber wieder aktivieren. */ void BCTransmitter::disconnectCanDriver() { _tinyCanDriver.resetDriver(); _canDriver = &_dummyDriver; emit driverStateChanged( _tinyCanDriver.getDriverState(), "Disconnected, Dummy Treiber aktiviert." ); } void BCTransmitter::onUpdateValue( BCValuePtrConst valuePtr) { // wir stellen hier auf die harte Tour sicher, das onUpdateValue // nicht aus dem Parent-Thread direkt sondern über die EventQueue aufgerufen wurde. Q_ASSERT(QThread::currentThread() == this->thread()); // Wir arbeiten hier ohne besondere Threadsynchronisation, mutexed o.ä: Die // entkoppelung und serialisierung passiert bereits durch die Qt-Eventqueue. // Das klappt aber nur in der hier gewählten Konstellation mit einer Parent-Thread // und einem Worker. // Kosmetik const BCValue& value = *(valuePtr.get()); uint32_t devID = static_cast(value.getDeviceID()); uint8_t regID = static_cast (value.getRegisterID()); // Für den Fehlerfall: Wir senden den alten Wert einfach zurück uint32_t newValue = value.getRawValue(); BCValue::Flag newState = BCValue::Flag::Failed; if(value.testFlag( BCValue::Flag::WriteMe ) ) { } // oder sollen wir hier beides erlauben ? readFlag & writeFlag ? // Was kommt dann zuerst? Schreiben und lesen als verify ? else if( value.testFlag( BCValue::Flag::ReadMe ) ) { // wir sind hier im anderen thread! nicht einfach so reinschreiben, nur lesen TransmitResult result = value.isWord() ? readWordValue( devID, regID ) : readByteValue( devID, regID ); if( result.has_value() ) { newState = BCValue::Flag::InSync; newValue = result.value(); qDebug() << " ---- " << BCTimeStamp << " DevID: " << devID << " RegID: " << regID << " Value: " << newValue; } } emit valueUpdated( value.getDeviceID(), value.getIndexRow(), newState, newValue ); } /** * @brief Wenn dieser SLOT in der Event-Queue erreicht wird, dedeutet dies, das die * Übertrgung vom Mainwindow abgeschlossen wurde. Wir schicken zur Bestätigung das * Signal 'endOfProcessing' (Welches dann den 'Sync' - Button wieder einschaltet. */ void BCTransmitter::onEndOfTransmission() { emit endOfProcessing(); } TransmitResult BCTransmitter::readByteValue( uint32_t deviceID, uint8_t registerID ) { // Wir lesen nur ein Byte und gut. return _canDriver->readRawByte( deviceID, registerID ); } TransmitResult BCTransmitter::readWordValue( uint32_t deviceID, uint8_t registerID ) { uint32_t result{}; // hi byte Leseversuch. TransmitResult value = _canDriver->readRawByte( deviceID, registerID ); // Fehler? dann weg if( !value) return std::unexpected( value.error() ); // hi byte speichern result = *value << 8; // low byte, liegt im followup register: +1 value = _canDriver->readRawByte( deviceID, registerID+1 ); if( !value) return std::unexpected( value.error() ); result += *value; return result; }