Files
BionxControl/bcxmlloader.cpp

253 lines
7.0 KiB
C++
Raw Normal View History

2025-12-15 23:05:48 +01:00
/***************************************************************************
2025-12-15 20:57:09 +01:00
2025-12-26 14:07:55 +01:00
BionxControl
2026-01-03 23:51:14 +01:00
© 2025 -2026 christoph holzheuer
2025-12-26 14:07:55 +01:00
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 <info@bigxionflasher.org>
@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
2025-12-15 23:05:48 +01:00
***************************************************************************/
#include <QFile>
#include <QFileDialog>
#include <QMessageBox>
2026-01-03 02:50:28 +01:00
#include <QMetaEnum>
#include <QHash>
2025-12-19 13:24:18 +01:00
2025-12-31 16:30:03 +01:00
#include <bcxmlloader.h>
2025-12-16 18:33:44 +01:00
2026-01-03 02:50:28 +01:00
using namespace Qt::StringLiterals;
2025-12-19 21:20:14 +01:00
2025-12-31 16:30:03 +01:00
BCXmlLoader::BCXmlLoader(QObject *parent)
2025-12-19 13:24:18 +01:00
: QObject(parent)
2025-12-16 18:33:44 +01:00
{
2025-12-28 22:48:18 +01:00
//qRegisterMetaType<BCValue*>("BCValue*");
//qRegisterMetaType<BCValue*>();
2025-12-16 18:33:44 +01:00
}
2025-12-31 16:30:03 +01:00
void BCXmlLoader::loadXmlBikeData( const QString& fileName )
2025-12-15 23:05:48 +01:00
{
2025-12-16 18:33:44 +01:00
auto printAttrs = [](const QXmlStreamReader& xml)
{
QStringList parts;
for (const auto &attr : xml.attributes()) {
parts << attr.name().toString() + "=\"" + attr.value().toString() + "\"";
}
qDebug().noquote() << parts.join(" ");
};
2026-01-06 13:58:02 +01:00
2025-12-16 18:33:44 +01:00
2025-12-31 16:30:03 +01:00
QMetaEnum bcDeviceEnum{QMetaEnum::fromType<BCDevice::ID>()};
2025-12-26 23:09:53 +01:00
QFile file(fileName);
2025-12-16 18:33:44 +01:00
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
// __fix throw
QMessageBox::warning(nullptr, "Fehler", "Datei konnte nicht geöffnet werden.");
return;
}
_xml.setDevice(&file);
if (_xml.readNextStartElement())
{
if (_xml.name() != "Bike"_L1 )
// fix throw
_xml.raiseError(QObject::tr("The file is not an 'Bike' file."));
}
// ??
Q_ASSERT(_xml.isStartElement() && _xml.name() == "Bike"_L1);
while (!_xml.atEnd() && !_xml.hasError())
{
QXmlStreamReader::TokenType token = _xml.readNext();
if (token == QXmlStreamReader::StartElement)
{
2025-12-16 22:42:35 +01:00
QString deviceType = _xml.attributes().value("Type"_L1).toString();
2026-01-06 13:58:02 +01:00
//printAttrs (_xml);
2025-12-26 23:09:53 +01:00
// Wir wollen die Device-ID aus dem XML Tag ermitteln
2025-12-16 18:33:44 +01:00
const char* deviceKey = _xml.attributes().value("Type"_L1).toLatin1().constData();
bool ok;
2025-12-31 16:30:03 +01:00
auto optDeviceID = bcDeviceEnum.keyToValue(deviceKey,&ok);
//_currentDeviceID = BCDevice::ID( deviceID.value_or( BCDevice::ID::Invalid ) );
//if( optDeviceID.has_value())
if(ok)
{
qDebug() << " --- Device: " << _xml.name() << ": " << deviceType << " : " << optDeviceID;
//BCDevice::ID currentDeviceID = BCDevice::ID( optDeviceID.value() );
BCDevice::ID currentDeviceID = BCDevice::ID( optDeviceID );
loadXmlBikeDeviceData(currentDeviceID);
}
2025-12-15 23:05:48 +01:00
}
2025-12-16 18:33:44 +01:00
}
}
2026-01-07 22:20:39 +01:00
2026-01-06 13:58:02 +01:00
/**
* @brief Lädt deie Daten des BionX eBikes
* @param deviceID
*/
2025-12-31 16:30:03 +01:00
void BCXmlLoader::loadXmlBikeDeviceData(BCDevice::ID deviceID)
2025-12-16 18:33:44 +01:00
{
auto printAttrs = [](const QXmlStreamReader& xml)
{
QStringList parts;
for (const auto &attr : xml.attributes()) {
parts << attr.name().toString() + "=\"" + attr.value().toString() + "\"";
}
qDebug().noquote() << parts.join(" ");
};
2025-12-16 22:42:35 +01:00
printAttrs (_xml);
2025-12-16 18:33:44 +01:00
Q_ASSERT(_xml.isStartElement() && _xml.name() == "Device"_L1);
2026-01-06 13:58:02 +01:00
2025-12-16 18:33:44 +01:00
2025-12-27 18:43:15 +01:00
// temporäre Wertliste für neues Device
BCValueList currentValues;
2025-12-16 18:33:44 +01:00
while( _xml.readNextStartElement() )
{
2025-12-16 21:21:59 +01:00
if( _xml.attributes().hasAttribute(BCTags::ID) )
{
2025-12-16 22:42:35 +01:00
//qDebug() << " --- found: " << _xml.name() << " : " << _xml.attributes().value(BCTags::ID);
2026-01-03 02:50:28 +01:00
2025-12-26 23:09:53 +01:00
// füllen des Parameter packs
2026-01-03 02:50:28 +01:00
BCValueParams params
2025-12-16 22:42:35 +01:00
{
2026-01-03 02:50:28 +01:00
.ID = _xml.attributes().value(BCTags::ID).toString(),
.Label = _xml.attributes().value(BCTags::Label).toString(),
.UnitLabel = _xml.attributes().value(BCTags::UnitLabel).toString(),
.Factor = _xml.attributes().value(BCTags::Factor).toString(),
.Min = _xml.attributes().value(BCTags::Min).toString(),
.Max = _xml.attributes().value(BCTags::Max).toString(),
.IsWord = _xml.attributes().value(BCTags::IsWord).toString(),
.ValueType = _xml.attributes().value(BCTags::ValueType).toString(),
2025-12-16 22:42:35 +01:00
};
2025-12-26 23:09:53 +01:00
// nur gültige Werte sind vorhanden und können gespeichert werden
2026-01-03 02:50:28 +01:00
std::optional<BCValuePtr> newValue = makeValue( deviceID, params );
2025-12-20 01:23:57 +01:00
if(newValue)
2025-12-29 13:05:35 +01:00
{
// wir merken uns gleich den index in der Werteliste
2026-01-02 01:43:49 +01:00
(*newValue)->indexRow = currentValues.size();
2025-12-27 18:43:15 +01:00
currentValues.push_back( *newValue );
2025-12-29 13:05:35 +01:00
}
2025-12-16 21:21:59 +01:00
}
2025-12-26 23:09:53 +01:00
// weiter zum nächsten Element
2025-12-16 18:33:44 +01:00
_xml.skipCurrentElement();
}
2025-12-26 23:09:53 +01:00
// Wenn dieses Device fertig geladen wurde, soll das MainWindow es abholen
2025-12-27 18:43:15 +01:00
if( !currentValues.isEmpty() )
emit valueListReady( deviceID, currentValues );
2025-12-26 23:09:53 +01:00
2025-12-16 18:33:44 +01:00
}
2026-01-07 22:20:39 +01:00
/**
* @brief Erzeugt einen BCValue für die DeviceID aus dem gegebenen parameter pack
*/
2026-01-03 02:50:28 +01:00
std::optional<BCValuePtr> BCXmlLoader::makeValue( BCDevice::ID deviceID, const BCValueParams& params )
2025-12-19 13:24:18 +01:00
{
2025-12-20 01:23:57 +01:00
static QHash<QString,BCValue::ValueType> s_valueTypes
{
{ "Plain", BCValue::ValueType::Plain },
{ "Bool", BCValue::ValueType::Bool },
{ "Number", BCValue::ValueType::Number },
{ "Float", BCValue::ValueType::Float }
};
2026-01-03 02:50:28 +01:00
auto setIfExists = [&]<typename T>( QStringView source, T& target )
2025-12-20 01:23:57 +01:00
{
if( !source.isEmpty() )
2026-01-07 17:13:35 +01:00
{
bool ok;
double testVal = source.toDouble(&ok);
if (ok)
target = testVal;
}
2025-12-20 01:23:57 +01:00
};
2026-01-07 22:20:39 +01:00
// Wir brauchen:
// - einen gültige ID String um die enum ID herauszufinden.
// - einen gültige UnitType String um den ValueType herauszufinden.
2025-12-19 13:24:18 +01:00
2026-01-02 16:25:21 +01:00
// geht nicht auf qt6.8 von debian trixie
//std::optional<quint64> IDVal = s_bcValueEnum.keyToValue64( params.ID.toLatin1().constData() );
2026-01-02 16:25:21 +01:00
bool ok;
static QMetaEnum s_bcValueEnum{QMetaEnum::fromType<BC::ID>()};
int IDVal = s_bcValueEnum.keyToValue( params.ID.toLatin1().constData(), &ok );
2026-01-03 02:50:28 +01:00
qDebug() << " --- should create: " << params.Label;
//if( IDVal.has_value() )
2026-01-02 16:25:21 +01:00
if( ok )
2025-12-20 01:23:57 +01:00
{
BCValuePtr newValuePtr = std::make_shared<BCValue>( deviceID, static_cast<BC::ID>(IDVal) );
BCValue& newValue = *newValuePtr.get();
setIfExists( params.Factor, newValue.factor );
2026-01-06 18:47:08 +01:00
setIfExists( params.Min, newValue.optMin );
setIfExists( params.Max, newValue.optMax );
2026-01-07 17:13:35 +01:00
//setIfExists( params.IsWord, newValue.isWord );
2026-01-02 01:43:49 +01:00
2026-01-03 13:15:15 +01:00
newValue.label = params.Label;
newValue.unitLabel = params.UnitLabel;
if( s_valueTypes.contains( params.ValueType ) )
newValue.valueType = s_valueTypes[params.ValueType];
2025-12-19 13:24:18 +01:00
2026-01-03 02:50:28 +01:00
/*
QString ID;
QString Label;
QString UnitLabel;
QString Factor;
QString Min;
QString Max;
QString IsWord;
QString ValueType;
2026-01-03 13:15:15 +01:00
*/
2025-12-15 23:05:48 +01:00
2026-01-03 02:50:28 +01:00
qDebug() << " --- created: " << params.Label;
2026-01-03 13:15:15 +01:00
newValue.dumpValue();
2025-12-15 23:05:48 +01:00
return std::optional<BCValuePtr>( newValuePtr );
2026-01-03 02:50:28 +01:00
}
2025-12-15 23:05:48 +01:00
2026-01-03 02:50:28 +01:00
return std::nullopt;
}
2025-12-15 23:05:48 +01:00
2025-12-17 17:50:24 +01:00