From 554c4a96cb6273b0222fbe5984461c61a62a4e7f Mon Sep 17 00:00:00 2001 From: "PANIK\\chris" Date: Sat, 20 Dec 2025 01:23:57 +0100 Subject: [PATCH] Crash protection. part I --- BionxControl.pro | 6 +- bc.h | 12 +- bcitemdelegate.cpp | 3 +- bcmainwindow.cpp | 3 +- bcvalue.cpp | 36 ++-- bcvalue.h | 40 +++-- bcvaluemanager.cpp | 264 ++++++++++++---------------- bcvaluemanager.h | 14 +- bcdatamodel.cpp => bcvaluemodel.cpp | 15 +- bcdatamodel.h => bcvaluemodel.h | 6 +- data/bikeinfo.xml | 22 +-- 11 files changed, 202 insertions(+), 219 deletions(-) rename bcdatamodel.cpp => bcvaluemodel.cpp (91%) rename bcdatamodel.h => bcvaluemodel.h (95%) diff --git a/BionxControl.pro b/BionxControl.pro index fd55afc..a8767eb 100644 --- a/BionxControl.pro +++ b/BionxControl.pro @@ -26,9 +26,9 @@ windows SOURCES += \ bc.cpp \ - bcdatamodel.cpp \ bcitemdelegate.cpp \ bctransmitter.cpp \ + bcvaluemodel.cpp \ lib/can_drv_win.c \ bccandriver.cpp \ bccandrivertinycan.cpp \ @@ -41,12 +41,12 @@ HEADERS += \ bc.h \ bccandriver.h \ bccandrivertinycan.h \ - bcdatamodel.h \ bcitemdelegate.h \ bcmainwindow.h \ bctransmitter.h \ bcvalue.h \ - bcvaluemanager.h + bcvaluemanager.h \ + bcvaluemodel.h FORMS += \ bcmainwindow.ui diff --git a/bc.h b/bc.h index 4219366..0bb7f58 100644 --- a/bc.h +++ b/bc.h @@ -35,7 +35,7 @@ #include #include // Nötig für Q_GADGET/Q_ENUM Makros -namespace cbc +namespace bc { [[maybe_unused]] constexpr static double UNLIMITED_SPEED_VALUE = 70; // Km/h // UNLIMITED_MIN_SPEED_VALUE = 30; // Km/h @@ -63,9 +63,10 @@ namespace cbc void delay_seconds( uint32_t ); void delay_millis( uint32_t ); void delay_micros( uint32_t ); + void processEventsFor(int milliseconds); QString formatInt( int count, int len ); -} // namespace cbc +} // namespace bc // abbreviations: // SOC = State Of Charge @@ -102,6 +103,13 @@ struct BC public: + enum class OpID : uint8_t + { + ReadValue, + WriteValue, + }; + Q_ENUM(OpID) + enum class ID : uint8_t { //{%Region Console} diff --git a/bcitemdelegate.cpp b/bcitemdelegate.cpp index 33176aa..5b9554d 100644 --- a/bcitemdelegate.cpp +++ b/bcitemdelegate.cpp @@ -272,7 +272,8 @@ void BCItemDelegate::clearAllHighlights() void BCItemDelegate::updateRow(int row) { - if (_view && row >= 0) { + if (_view && _view->model() && row >= 0) + { QModelIndex idx = _view->model()->index(row, 0); QRect rect = _view->visualRect(idx); if (!rect.isEmpty()) { diff --git a/bcmainwindow.cpp b/bcmainwindow.cpp index 1714ff6..132306e 100644 --- a/bcmainwindow.cpp +++ b/bcmainwindow.cpp @@ -55,11 +55,12 @@ BCMainWindow::BCMainWindow(QWidget *parent) // Highlight mit Fade-Out: _delegate->onHighlightRow(2); // 2 Sekunden Fade + BCTransmitter* transmitter = _valueManager.getTransmitter(); // besser: model::emit dataChanged // also: emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole, ValueRole}); connect( &_valueManager, &BCValueManager::valueTouched, _delegate, &BCItemDelegate::onHighlightRow ); - connect( _connectButton, &QPushButton::clicked, &_valueManager, &BCValueManager::onToggleConnectionState ); + connect( _connectButton, &QPushButton::clicked, transmitter, &BCTransmitter::onToggleConnectionState ); connect( _syncButton, &QPushButton::clicked, &_valueManager, &BCValueManager::onSyncFromDevice ); } diff --git a/bcvalue.cpp b/bcvalue.cpp index 1bcc83f..79eab21 100644 --- a/bcvalue.cpp +++ b/bcvalue.cpp @@ -31,27 +31,25 @@ #include +BCValueType::BCValueType() +{ + +} + +BCValue::BCValue() +{ + +} + + +BCValue::BCValue(const BCValueType& valueType_, BCDevice::ID deviceID_, BC::ID targetID_) + : valueType{valueType_}, deviceID{deviceID_}, targetID{targetID_} +{ + +} BCValueType::BCValueType( TypeID ID_, QString unitLabel_, optDouble factor_, optDouble min_, optDouble max_ ) - : ID{ID_}, unitLabel{unitLabel_},factor{factor_},min{min_},max{max_} + : ID{ID_}, unitLabel{unitLabel_}, factor{factor_}, min{min_}, max{max_} { } - - - -BCValue::BCValue(BCDevice::ID deviceID_, BC::ID targetID_) - : deviceID{deviceID_}, targetID{targetID_} -{ -} - -void BCValue::setLongValue( uint8_t value) -{ - -} - -uint8_t BCValue::getLongValue() -{ - return 0; -} - diff --git a/bcvalue.h b/bcvalue.h index b2a3771..2185afd 100644 --- a/bcvalue.h +++ b/bcvalue.h @@ -31,6 +31,7 @@ #ifndef BCVALUE_H #define BCVALUE_H +#include "qnamespace.h" #include #include #include @@ -68,6 +69,9 @@ public: Text, Number, Float, + Byte, + Word, + Quad, Percent, KWh, Watt, @@ -83,9 +87,10 @@ public: }; Q_ENUM(TypeID) + BCValueType(); BCValueType( TypeID ID_, QString unitLabel_="", optDouble factor_=std::nullopt, optDouble min_=std::nullopt, optDouble max_= std::nullopt ); - TypeID ID; + TypeID ID{TypeID::Invalid}; QString unitLabel; optDouble factor; optDouble min; @@ -93,26 +98,28 @@ public: }; +using BCValueTypeCRef = std::optional>; + + class BCValue { public: - BCValue() = default; - BCValue( BCDevice::ID deviceID, BC::ID targetID ); + BCValue(); + BCValue( const BCValueType& valueType_, BCDevice::ID deviceID_, BC::ID targetID_ ); - void setLongValue( uint8_t value); - uint8_t getLongValue(); + BCValueTypeCRef valueType; + BCDevice::ID deviceID{BCDevice::ID::Invalid}; + BC::ID targetID{BC::ID::Invalid}; + int rowInModel{-1}; + QString label; + QVariant value; + QVariant defaultValue; + bool inSync{false}; + bool readOnly{false}; - BCDevice::ID deviceID{BCDevice::ID::Invalid}; - BC::ID targetID{BC::ID::Invalid}; - BCValueType::TypeID typeID{BCValueType::TypeID::Invalid};; - int rowInModel{-1}; - QString label; - QVariant value; - QVariant defaultValue; - bool inSync{false}; - bool readOnly{false}; + // void reset() }; // Damit QVariant dieses Struct transportieren kann: @@ -124,12 +131,7 @@ struct BCValueParams QString ID; QString Label; QString Default; - QString Current; - QString Enabled; QString UnitType; - QString Min; - QString Max; - QString Factor; }; // abbreviations: diff --git a/bcvaluemanager.cpp b/bcvaluemanager.cpp index 668fd24..b611e76 100644 --- a/bcvaluemanager.cpp +++ b/bcvaluemanager.cpp @@ -43,20 +43,11 @@ using namespace Qt::StringLiterals; -void processEventsFor(int milliseconds) -{ - QElapsedTimer timer; - timer.start(); - - while (timer.elapsed() < milliseconds) { - QApplication::processEvents(QEventLoop::AllEvents, 50); - } -} BCValueManager::BCValueManager(QObject *parent) : QObject(parent) { - loadTypeData(); + createValueTypes(); qRegisterMetaType("BCValue"); @@ -65,7 +56,7 @@ BCValueManager::BCValueManager(QObject *parent) // 4. Verbindungen herstellen (Signal/Slot über Thread-Grenzen) // A) Befehl senden (Manager -> Runner) - connect(this, &BCValueManager::valueCreated, &_transmitter, &BCTransmitter::enqueueValue); + connect(this, &BCValueManager::sendValueCommand, &_transmitter, &BCTransmitter::enqueueValueCommand); // B) Ergebnisse empfangen (Runner -> Manager) //connect(&_transmitter, &BCTransmitter::commandFinished, this, &BCValueManager::onCommandFinished); @@ -88,6 +79,49 @@ BCValueManager::~BCValueManager() } +void BCValueManager::createValueTypes() +{ + /* + Invalid = 0x0, + "Text" + "Number" + "Float" + "Percent" + "KWh" + "Watt" + "Km" + "Kmh" + "Mm" + "Sec" + "SoC" + "Odo" + "Date" + + */ + //_valueTypes.insert( { BCValueType::TypeID::Invalid, "Invalid" } ); + + _valueTypes.insert( "Invalid", { BCValueType::TypeID::Invalid, "Invalid" } ); + _valueTypes.insert( "Text", { BCValueType::TypeID::Text } ); + _valueTypes.insert( "Number", { BCValueType::TypeID::Number } ); + + _valueTypes.insert( "Byte", { BCValueType::TypeID::Byte } ); + _valueTypes.insert( "Word", { BCValueType::TypeID::Word } ); + _valueTypes.insert( "Quad", { BCValueType::TypeID::Quad } ); + + _valueTypes.insert( "Float", { BCValueType::TypeID::Float, "", 1.5625} ); + _valueTypes.insert( "Percent",{ BCValueType::TypeID::Percent, "%", 1.5625 } ); + _valueTypes.insert( "KWh", { BCValueType::TypeID::KWh, "kwh", 1.5625 } ); + _valueTypes.insert( "Watt", { BCValueType::TypeID::Watt, "w", 1.5625 } ); + _valueTypes.insert( "Km", { BCValueType::TypeID::Km, "km", 1.5625 } ); + _valueTypes.insert( "Kmh", { BCValueType::TypeID::Kmh, "km/h", 0.1 } ); + _valueTypes.insert( "Mm", { BCValueType::TypeID::Mm, "mm", 1.5625 } ); + _valueTypes.insert( "Sec", { BCValueType::TypeID::Sec, "s", 1.5625 } ); + _valueTypes.insert( "SoC", { BCValueType::TypeID::SoC, "%", 1.5625 } ); + _valueTypes.insert( "Odo", { BCValueType::TypeID::Odo, "km", 1.5625 } ); + _valueTypes.insert( "Assist", { BCValueType::TypeID::Assist, "", 0 ,4 } ); + _valueTypes.insert( "Assist", { BCValueType::TypeID::AssistFac, "%" } ); + _valueTypes.insert( "Date", { BCValueType::TypeID::Date } ); +} void BCValueManager::onCommandFinished(int id, bool success) { @@ -100,75 +134,40 @@ void BCValueManager::onRunnerMessage(const QString &msg) } -void BCValueManager::onToggleConnectionState( bool connect ) -{ - if( connect ) - { - if( BCCanDriver::sIdle == _canDriver.getState() ) - _canDriver.onStartDriver(); - - int hwVersion = _canDriver.getValue( BCDevice::ID::Console, BC::ID::Cons_Rev_Hw); - - if (hwVersion == 0) - { - qDebug() << "Console not responding"; - } - else - { - /* - swVersion = getValue(CONSOLE, CONSOLE_REF_SW); - printf( "Console information:" _NL - " hardware version ........: %02d" _NL - " software version ........: %02d" _NL - " assistance level ........: %d" _NL, - hwVersion, swVersion, - getValue(CONSOLE, CONSOLE_ASSIST_INITLEVEL) - ); - - if (!gNoSerialNumbers) - printf( " part number .............: %05d" _NL - " item number .............: %05d" _NL _NL, - ((getValue(CONSOLE, CONSOLE_SN_PN_HI) << 8) + getValue(CONSOLE, CONSOLE_SN_PN_LO)), - ((getValue(CONSOLE, CONSOLE_SN_ITEM_HI) << 8) + getValue(CONSOLE, CONSOLE_SN_ITEM_LO)) - ); - */ - - } - - qDebug() << " ---HAIL to the kings: " << hwVersion; - } -} - void BCValueManager::onSyncFromDevice() { qDebug() << " ---Syncing"; - if( _currentDeviceID != BCDevice::ID::Invalid) + if( _currentDeviceID != BCDevice::ID::Invalid ) { - - BCValueList& currentList = _valueModels[_currentDeviceID]->getValueList(); - - BCValue& value = currentList[4]; - - for( const BCValue& value : currentList ) + if( _valueModels.contains(_currentDeviceID) ) { - qDebug() << " --- value: " << value.label; - // statt '_transmitter.enqueueValue( value )' entkoppeln - // wir das eleganter über emit valueCreated() + BCValueModel* model = _valueModels[_currentDeviceID]; + BCValueList& currentList = model->getValueList(); - //_transmitter.enqueueValue( value ); - emit valueCreated(value); + //BCValue& value = currentList[4]; - emit valueTouched( value.rowInModel ); + for( const BCValue& value : currentList ) + { + qDebug() << " --- value: " << value.label; - processEventsFor(500); - //QApplication::processEvents(); - // Thread schlafen lassen (Simulation einer blockierenden Operation) - //QThread::msleep(500); + // statt '_transmitter.enqueueValueCommand( value )' entkoppeln + // wir das eleganter über emit sendValueCommand() - } + //_transmitter.enqueueValueCommand( value ); + emit sendValueCommand( BC::OpID::ReadValue, value); + emit valueTouched( value.rowInModel ); + + bc::processEventsFor(500); + + //QApplication::processEvents(); + // Thread schlafen lassen (Simulation einer blockierenden Operation) + //QThread::msleep(500); + + } + } // if contains } } @@ -179,6 +178,11 @@ std::optional BCValueManager::getModel(BCDevice::ID deviceID ) return std::nullopt; } +BCTransmitter* BCValueManager::getTransmitter() +{ + return &_transmitter; +}; + void BCValueManager::loadBikeData() { auto printAttrs = [](const QXmlStreamReader& xml) @@ -229,7 +233,7 @@ void BCValueManager::loadBikeData() qDebug() << " --- Device: " << _xml.name() << ": " << deviceType << " : " << deviceID; _currentDeviceID = BCDevice::ID( deviceID.value() ); - BCValueList parsedValues; + BCValueList parsedValues; loadDeviceData( parsedValues ); if( parsedValues.count() ) { @@ -288,19 +292,16 @@ void BCValueManager::loadDeviceData( BCValueList& parsedValues ) .ID = id, .Label = _xml.attributes().value(BCTags::Label).toString(), .Default = _xml.attributes().value(BCTags::Default).toString(), - .Current = _xml.attributes().value(BCTags::Current).toString(), - .Enabled = _xml.attributes().value(BCTags::Enabled).toString(), .UnitType = _xml.attributes().value(BCTags::UnitType).toString(), - .Min = _xml.attributes().value(BCTags::Min).toString(), - .Max = _xml.attributes().value(BCTags::Max).toString(), - .Factor = _xml.attributes().value(BCTags::Factor).toString() }; // __fix! können ungültige werte erzeugt werden ? //BCValue newValue = BCValue::makeValue( _currentDeviceID, params ); //if(newValue) // parsedValues.push_back( newValue ); - parsedValues.push_back( makeValue( _currentDeviceID, params ) ); + std::optional newValue = makeValue( _currentDeviceID, params ); + if(newValue) + parsedValues.push_back( *newValue ); } //printAttrs (_xml); @@ -308,48 +309,57 @@ void BCValueManager::loadDeviceData( BCValueList& parsedValues ) } } -void BCValueManager::loadTypeData() +std::optional BCValueManager::makeValue( BCDevice::ID deviceID, const BCValueParams& params ) { + /* - Invalid = 0x0, - "Text" - "Number" - "Float" - "Percent" - "KWh" - "Watt" - "Km" - "Kmh" - "Mm" - "Sec" - "SoC" - "Odo" - "Date" + auto setIfExists = [&]( QStringView source, optDouble& target ) + { + if( !source.isEmpty() ) + { + bool ok; + double testVal = source.toDouble(&ok); + if (ok) + target = testVal; + } + }; + */ + + static QMetaEnum s_bcValueEnum{QMetaEnum::fromType()}; + + /* + Wir brauchen: + - einen gültige ID String um die enum ID herauszufinden. + - einen gültige UnitType String um den ValueType herauszufinden. */ - //_valueTypes.insert( { BCValueType::TypeID::Invalid, "Invalid" } ); - _valueTypes.insert( "Invalid", { BCValueType::TypeID::Invalid, "Invalid" } ); - _valueTypes.insert( "Text", { BCValueType::TypeID::Text } ); - _valueTypes.insert( "Number", { BCValueType::TypeID::Number } ); + std::optional newValue; - _valueTypes.insert( "Float", { BCValueType::TypeID::Float, "", 1.5625} ); - _valueTypes.insert( "Percent",{ BCValueType::TypeID::Percent, "%", 1.5625 } ); - _valueTypes.insert( "KWh", { BCValueType::TypeID::KWh, "kwh", 1.5625 } ); - _valueTypes.insert( "Watt", { BCValueType::TypeID::Watt, "w", 1.5625 } ); - _valueTypes.insert( "Km", { BCValueType::TypeID::Km, "km", 1.5625 } ); - _valueTypes.insert( "Kmh", { BCValueType::TypeID::Kmh, "km/h", 0.1 } ); - _valueTypes.insert( "Mm", { BCValueType::TypeID::Mm, "mm", 1.5625 } ); - _valueTypes.insert( "Sec", { BCValueType::TypeID::Sec, "s", 1.5625 } ); - _valueTypes.insert( "SoC", { BCValueType::TypeID::SoC, "%", 1.5625 } ); - _valueTypes.insert( "Odo", { BCValueType::TypeID::Odo, "km", 1.5625 } ); - _valueTypes.insert( "Assist", { BCValueType::TypeID::Assist, "", 0 ,4 } ); - _valueTypes.insert( "Assist", { BCValueType::TypeID::AssistFac, "%" } ); - _valueTypes.insert( "Date", { BCValueType::TypeID::Date } ); + std::optional IDVal = s_bcValueEnum.keyToValue64( params.ID.toLatin1().constData() ); + if( IDVal.has_value() ) + { + if( _valueTypes.contains( params.UnitType ) ) + { + const BCValueType& valueType = _valueTypes[params.UnitType]; + newValue = BCValue( valueType, deviceID, static_cast(IDVal.value()) ); + /* + setIfExists( params.Factor, newValue.factor ); + setIfExists( params.Min, newValue.min ); + setIfExists( params.Max, newValue.max ); + */ + newValue->label = params.Label; + newValue->defaultValue = params.Default; + /* + //qDebug() << " --- created: " << params.Label; + */ + } + } + return newValue; } // --- NEU: Speichern mit QXmlStreamWriter --- @@ -394,43 +404,3 @@ void BCValueManager::saveBikeData() -BCValue BCValueManager::makeValue( BCDevice::ID deviceID, const BCValueParams& params ) -{ - - auto setIfExists = [&]( QStringView source, optDouble& target ) - { - if( !source.isEmpty() ) - { - bool ok; - double testVal = source.toDouble(&ok); - if (ok) - target = testVal; - } - }; - - static QMetaEnum s_bcValueEnum{QMetaEnum::fromType()}; - - /* - Wir brauchen: - - eine gültige ID - - */ - BCValue newValue{}; - - auto IDVal = s_bcValueEnum.keyToValue64( params.ID.toLatin1().constData() ); - if( IDVal.has_value() ) - { - newValue = BCValue( deviceID, BC::ID( IDVal.value() ) ); - /* - setIfExists( params.Factor, newValue.factor ); - setIfExists( params.Min, newValue.min ); - setIfExists( params.Max, newValue.max ); - */ - newValue.defaultValue.setValue( params.Label ); - newValue.value.setValue( params.Current ); - newValue.label = params.Label; - //qDebug() << " --- created: " << params.Label; - } - - return newValue; -} diff --git a/bcvaluemanager.h b/bcvaluemanager.h index 26c0f54..4c2ccdb 100644 --- a/bcvaluemanager.h +++ b/bcvaluemanager.h @@ -37,8 +37,8 @@ #include #include -#include -#include +#include + #include class BCValueManager : public QObject @@ -51,20 +51,20 @@ public: virtual ~BCValueManager(); std::optional getModel(BCDevice::ID deviceID ); + BCTransmitter* getTransmitter(); - BCValue makeValue(BCDevice::ID deviceID, const BCValueParams& params ); + std::optional makeValue( BCDevice::ID deviceID, const BCValueParams& params ); public slots: void loadBikeData(); void saveBikeData(); - void onToggleConnectionState( bool connect ); void onSyncFromDevice(); signals: // Internes Signal, um Daten an den Worker Thread zu senden - void valueCreated(const BCValue& cmd); + void sendValueCommand( BC::OpID, const BCValue& cmd); //void valuedTouched(const BCValue& cmd); void valueTouched(int rowInModel ); @@ -76,7 +76,7 @@ private slots: protected: - void loadTypeData(); + void createValueTypes(); void loadDeviceData( BCValueList& parsedValues ); using BCDeviceModels = QMap; @@ -88,8 +88,6 @@ protected: BCDevice::ID _currentDeviceID{BCDevice::ID::Invalid}; QMetaEnum _bcDeviceEnum{QMetaEnum::fromType()}; - BCCanDriverTinyCan _canDriver; - QThread _worker; BCTransmitter _transmitter; diff --git a/bcdatamodel.cpp b/bcvaluemodel.cpp similarity index 91% rename from bcdatamodel.cpp rename to bcvaluemodel.cpp index 69bf55c..855e222 100644 --- a/bcdatamodel.cpp +++ b/bcvaluemodel.cpp @@ -28,7 +28,7 @@ ***************************************************************************/ -#include +#include @@ -77,21 +77,26 @@ QVariant BCValueModel::data(const QModelIndex& index, int role) const return QVariant(); } + Qt::ItemFlags BCValueModel::flags(const QModelIndex &index) const { - if (!index.isValid()) return Qt::NoItemFlags; - // ItemIsEditable ist Pflicht für Persistent Editors + if (!index.isValid()) + return Qt::NoItemFlags; + return QAbstractListModel::flags(index) | Qt::ItemIsEditable; } + bool BCValueModel::setData(const QModelIndex &index, const QVariant &value, int role) { - if (index.isValid() && role == Qt::EditRole) { + if (index.isValid() && role == Qt::EditRole) + { BCValue item = _valueList[index.row()]; // Wir erwarten hier nur den Value-Teil (vom Slider/Editor) // Checken ob Int oder Double - if (value.canConvert()) { + if (value.canConvert()) + { item.value = value; } diff --git a/bcdatamodel.h b/bcvaluemodel.h similarity index 95% rename from bcdatamodel.h rename to bcvaluemodel.h index 78da93b..2a7a201 100644 --- a/bcdatamodel.h +++ b/bcvaluemodel.h @@ -28,8 +28,8 @@ ***************************************************************************/ -#ifndef BCDATAMODEL_H -#define BCDATAMODEL_H +#ifndef BCVALUEMODEL_H +#define BCVALUEMODEL_H #include @@ -62,4 +62,4 @@ private: }; -#endif // BCDATAMODEL_H +#endif // BCVALUEMODEL_H diff --git a/data/bikeinfo.xml b/data/bikeinfo.xml index 8a3a081..2196263 100644 --- a/data/bikeinfo.xml +++ b/data/bikeinfo.xml @@ -4,10 +4,10 @@ - - - - + + + + @@ -15,17 +15,17 @@ - - + + - - + + - - + + - +