Files
BionxControl/bcdatamanager.cpp

283 lines
7.5 KiB
C++

/***************************************************************************
BionxControl
Copyright © 2025 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 <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
***************************************************************************/
#include <QFile>
#include <QFileDialog>
#include <QTableView>
#include <QPushButton>
#include <QMessageBox>
#include <QStatusBar>
#include <QApplication>
#include <QElapsedTimer>
#include <bcdatamanager.h>
#include <bcvaluetype.h>
using namespace Qt::StringLiterals;
BCDataManager::BCDataManager(QObject *parent)
: QObject(parent)
{
//qRegisterMetaType<BCValue*>("BCValue*");
//qRegisterMetaType<BCValue*>();
}
BCDataManager::~BCDataManager()
{
}
void BCDataManager::loadXmlBikeData( const QString& fileName )
{
auto printAttrs = [](const QXmlStreamReader& xml)
{
QStringList parts;
for (const auto &attr : xml.attributes()) {
parts << attr.name().toString() + "=\"" + attr.value().toString() + "\"";
}
qDebug().noquote() << parts.join(" ");
};
/*
QString fileName = QFileDialog::getOpenFileName(this, "XML öffnen", "", "XML Files (*.xml)");
if (fileName.isEmpty())
return;
*/
QFile file(fileName);
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)
{
QString deviceType = _xml.attributes().value("Type"_L1).toString();
printAttrs (_xml);
// Wir wollen die Device-ID aus dem XML Tag ermitteln
const char* deviceKey = _xml.attributes().value("Type"_L1).toLatin1().constData();
auto optDeviceID = _bcDeviceEnum.keysToValue64(deviceKey);
//_currentDeviceID = BCDevice::ID( deviceID.value_or( BCDevice::ID::Invalid ) );
if( optDeviceID.has_value())
{
qDebug() << " --- Device: " << _xml.name() << ": " << deviceType << " : " << optDeviceID;
BCDevice::ID currentDeviceID = BCDevice::ID( optDeviceID.value() );
loadXmlBikeDeviceData(currentDeviceID);
}
}
}
/*
if (xml.hasError())
{
QMessageBox::critical(nullptr, "Parsing Fehler", xml.errorString());
}
else
{
m_model->setDevices(parsedValues);
}
*/
// create & add new model to the model map
}
void BCDataManager::loadXmlBikeDeviceData(BCDevice::ID deviceID)
{
auto printAttrs = [](const QXmlStreamReader& xml)
{
QStringList parts;
for (const auto &attr : xml.attributes()) {
parts << attr.name().toString() + "=\"" + attr.value().toString() + "\"";
}
qDebug().noquote() << parts.join(" ");
};
printAttrs (_xml);
Q_ASSERT(_xml.isStartElement() && _xml.name() == "Device"_L1);
qDebug() << " XXX ---------------";
// temporäre Wertliste für neues Device
BCValueList currentValues;
while( _xml.readNextStartElement() )
{
if( _xml.attributes().hasAttribute(BCTags::ID) )
{
//qDebug() << " --- found: " << _xml.name() << " : " << _xml.attributes().value(BCTags::ID);
QString id = _xml.attributes().value(BCTags::ID).toString();
// füllen des Parameter packs
BCDataParams params
{
.ID = id,
.Label = _xml.attributes().value(BCTags::Label).toString(),
.Default = _xml.attributes().value(BCTags::Default).toString(),
.UnitType = _xml.attributes().value(BCTags::UnitType).toString(),
};
// nur gültige Werte sind vorhanden und können gespeichert werden
std::optional<BCValue> newValue = makeDataValue( deviceID, params );
if(newValue)
{
// wir merken uns gleich den index in der Werteliste
(*newValue).indexRow = currentValues.size();
currentValues.push_back( *newValue );
}
}
// weiter zum nächsten Element
_xml.skipCurrentElement();
}
// Wenn dieses Device fertig geladen wurde, soll das MainWindow es abholen
if( !currentValues.isEmpty() )
emit valueListReady( deviceID, currentValues );
}
std::optional<BCValue> BCDataManager::makeDataValue( BCDevice::ID deviceID, const BCDataParams& 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<BC::ID>()};
/*
Wir brauchen:
- einen gültige ID String um die enum ID herauszufinden.
- einen gültige UnitType String um den ValueType herauszufinden.
*/
std::optional<BCValue> newValue;
std::optional<quint64> IDVal = s_bcValueEnum.keysToValue64( params.ID.toLatin1().constData() );
qDebug() << " --- should create: " << params.Label << ": " << params.UnitType;
if( IDVal.has_value() )
{
auto valueType = BCValueType::fetchValueType(params.UnitType);
if( valueType.has_value() )
{
newValue = BCValue( *valueType, deviceID, static_cast<BC::ID>(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 ---
void BCDataManager::saveBikeData()
{
/*
QString fileName = QFileDialog::getSaveFileName(this, "XML speichern", "", "XML Files (*.xml)");
if (fileName.isEmpty()) return;
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QMessageBox::warning(this, "Fehler", "Datei konnte nicht zum Schreiben geöffnet werden.");
return;
}
QXmlStreamWriter xml(&file);
xml.setAutoFormatting(true); // Sorgt für schöne Einrückungen (Tabs/Spaces)
xml.writeStartDocument();
xml.writeStartElement("devices");
// Daten vom Model holen
const QList<Device> &devices = m_model->getDevices();
for (const Device &d : devices) {
xml.writeStartElement("device");
xml.writeAttribute("name", d.name);
xml.writeAttribute("ip", d.ip);
xml.writeEndElement(); // </device>
}
xml.writeEndElement(); // </devices>
xml.writeEndDocument();
// Prüfen ob alles geschrieben wurde
if (file.error() != QFile::NoError) {
QMessageBox::critical(this, "Fehler", "Fehler beim Schreiben der Datei.");
} else {
statusBar()->showMessage("Datei erfolgreich gespeichert!", 3000);
}
*/
}