Debug updates.

This commit is contained in:
Christoph Holzheuer
2026-01-08 14:55:47 +01:00
parent c40f288aaa
commit f19a33cc5f
14 changed files with 154 additions and 138 deletions

31
bc.h
View File

@@ -73,15 +73,6 @@ namespace bc
[[maybe_unused]] constexpr static double NORMALIZED_VOLTAGE_OFFSET = 20.8333;
[[maybe_unused]] constexpr static double NORMALIZED_VOLTAGE_FAKTOR = 0.416667;
// misc
//#define cbc::Version "CanBusControl 0.0.01 / 02.07.2022"
[[maybe_unused]] constexpr static const char* Version = "BionxControl 0.1.00 / 08.11.2022 © 2022 chris@sourceworx.org";
[[maybe_unused]] constexpr static const char* OrgName = "source::worx";
[[maybe_unused]] constexpr static const char* DomainName = "sourceworx.org";
[[maybe_unused]] constexpr static const char* AppName = "BionxControl";
// timer
void delay_seconds( uint32_t );
void delay_millis( uint32_t );
@@ -91,27 +82,6 @@ namespace bc
QString formatInt( int count, int len );
} // namespace bc
// abbreviations:
// SOC = State Of Charge
// LMD = Last Measured Discharge
// NIP = ?
/*
Needed ?
#include <type_traits>
template <typename E>
constexpr auto to_u(E e) noexcept {
return static_cast<std::underlying_type_t<E>>(e);
}
// constants.h
#pragma once
#include <QLatin1StringView>
*/
struct BC
{
@@ -775,6 +745,7 @@ namespace BCTags
inline constexpr auto Label = "Label"_L1;
inline constexpr auto UnitLabel = "UnitLabel"_L1;
inline constexpr auto IsWord = "IsWord"_L1;
inline constexpr auto ReadOnly = "ReadOnly"_L1;
inline constexpr auto Default = "Default"_L1;
inline constexpr auto Current = "Current"_L1;

View File

@@ -202,13 +202,18 @@ void BCAnimatedDelegate::paint(QPainter *painter, const QStyleOptionViewItem& op
case 1:
if(_rowOpacities.contains(row))
paintHighlightRow(painter,option,index);
paintHighlightRow(painter,option,index.row());
break;
case 2:
if( row>-1 && row <= _valueList.size() )
paintSliderIndicator(painter,option,index);
{
const BCValue& bcValue = *(_valueList[ index.row()].get());
qDebug() << " --- paintSLider: " << bcValue.label << " type: " << (int)bcValue.valueType << " flags:" << bcValue.valueFlags.toInt() << " RO: " << bcValue.isReadOnly();
if( !bcValue.isReadOnly())
paintSliderIndicator(painter,option,bcValue);
}
default:
break;
@@ -216,35 +221,39 @@ void BCAnimatedDelegate::paint(QPainter *painter, const QStyleOptionViewItem& op
}
void BCAnimatedDelegate::paintHighlightRow(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
void BCAnimatedDelegate::paintHighlightRow(QPainter* painter, const QStyleOptionViewItem& option, int row) const
{
painter->save();
painter->setRenderHint(QPainter::Antialiasing);
int row = index.row();
qreal opacity =_rowOpacities.value(row);
painter->setOpacity(opacity);
// Margin von 4px
QRect itemRect = option.rect.adjusted(3, 3, -3, -3);
// Border (2px solid #2196F3)
QPen borderPen( Qt::red, 1);
// oranger rahmen
QPen borderPen( QColor(0xFF8C00), 1);
painter->setPen(borderPen);
painter->setBrush(Qt::NoBrush);
// highlight background
//QColor highlightColor = option.palette.highlight().color();
//highlightColor.setAlphaF(0.3); // 0.0 bis 1.0 (float ist oft lesbarer)
//painter->fillRect(option.rect, highlightColor);
painter->drawRoundedRect(itemRect, 2, 2);
painter->restore();
}
void BCAnimatedDelegate::paintSliderIndicator(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
void BCAnimatedDelegate::paintSliderIndicator(QPainter* painter, const QStyleOptionViewItem& option, const BCValue& bcValue) const
{
const BCValue& bcValue = *(_valueList[ index.row()].get());
qDebug() << " --- paintSLider: " << bcValue.label << ": " << (int)bcValue.valueType;
// wenn Werte readOnly sind, dann brauchen keinen EditHint
if( bcValue.flags.testFlag(BCValue::Flag::ReadOnly) )
//if( bcValue.valueFlags.testFlag(BCValue::Flag::ReadOnly) )
// || bcValue.valueType == BCValue::ValueType::Plain )
return;
// return;
// Hintergrund
if (option.state & QStyle::State_Selected)

View File

@@ -75,8 +75,8 @@ signals:
protected:
void updateRow(int row);
void paintHighlightRow(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
void paintSliderIndicator(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
void paintHighlightRow(QPainter* painter, const QStyleOptionViewItem& option, int row) const;
void paintSliderIndicator(QPainter* painter, const QStyleOptionViewItem& option, const BCValue& bcValue) const;
// Das ist ein Quickhack, der Delegate sollte
// nichts über die Originaldaten wissen. Die

View File

@@ -71,6 +71,17 @@ const BCValueList& BCDeviceView::getValueListX()
}
/**
* @brief Flag, ob diese View schonmal angezeigt wurde.
*/
bool BCDeviceView::firstExpose()
{
bool stored = _firstExpose;
_firstExpose = false;
return stored;
}
/**
* @brief SLOT, der aufgerufen wird, wenn die ValueList vom XML-Lader fertig geladen wurde.
* Die DeviceView nimmt die ValueList dann in Besitz.
@@ -93,6 +104,10 @@ void BCDeviceView::updateValue(int index, BCValue::Flag state, uint32_t rawValue
_itemDelegate->onHighlightRow( index );
}
/**
* @brief Die Spalte mit dem Label soll immer bei 60% der Gesamtbreite liegen.
* @param event
*/
void BCDeviceView::resizeEvent(QResizeEvent *event)
{

View File

@@ -54,7 +54,7 @@ public:
const BCValueList& getValueListX();
bool hasContent();
bool firstExpose();
void updateValue( int index, BCValue::Flag state, uint32_t rawValue );
@@ -66,10 +66,12 @@ protected:
void resizeEvent(QResizeEvent *event) override;
bool _firstExpose{true};
BCDevice::ID _devideID{BCDevice::ID::Invalid};
BCValueModel _valueModel;
BCAnimatedDelegate* _itemDelegate{};
};
#endif // BCDEVICEVIEW_H

View File

@@ -136,7 +136,7 @@ void BCDriverStateWidget::updateStyle()
// FLUENT GRAY (Neutral)
// Wir machen es dunkelgrau mit hellem Rand -> "Ausgeschaltet"-Look
ledStyle = "background-color: #3B3B3B; border: 1px solid #606060;";
toolTipText = "Treiber nicht geladen.";
toolTipText = "Kein Treiber geladen.";
break;
case BCDriver::DriverState::Error:
@@ -149,9 +149,9 @@ void BCDriverStateWidget::updateStyle()
case BCDriver::DriverState::Loaded:
case BCDriver::DriverState::Initialized:
case BCDriver::DriverState::Opened:
// FLUENT RED (Critical)
// ORANGE
ledStyle = "background-color: #FF8C00; border: 1px solid #A80000;";
toolTipText = "Fehler beim Laden des Treibers.";
toolTipText = "Kein Gerät verbunden.";
break;
case BCDriver::DriverState::DeviceReady:

View File

@@ -31,6 +31,7 @@
#include <QFile>
#include <QTimer>
#include <QMessageBox>
#include "qassert.h"
#include <bcmainwindow.h>
@@ -139,16 +140,27 @@ void BCMainWindow::initMainWindow()
_transmitter.moveToThread(&_worker);
_worker.start();
try
{
// die Daten des eBikes laden
_dataManager.loadXmlBikeData(":/bikeinfo.xml"_L1);
}
catch( BCException& exception )
{
QMessageBox::critical( this, "Ladefehler", exception.what() );
}
// Konsolendaten als erstes anzeigen
_consoleAction->trigger();
//_batteryAction->trigger();
/*
// Dummy sync beim starten
QTimer::singleShot(1000, this, [this]()
{
onSyncDeviceView();
});
*/
}
@@ -265,8 +277,15 @@ void BCMainWindow::onShowDevicePanel( BCDevice::ID deviceID )
{
_currentPanel = nxtPanel;
setHeaderLabel( _currentPanel->property( cBCKeyHeaderLabel ).toString() );
_stackedWidget->setCurrentWidget( nxtPanel );
_stackedWidget->setCurrentWidget( _currentPanel );
if( _currentPanel->firstExpose() )
{
// Dummy sync beim starten
QTimer::singleShot(1000, this, [this]()
{
onSyncDeviceView();
});
}
// knopf auch abschalten?
}
}
@@ -312,7 +331,7 @@ void BCMainWindow::onSyncDeviceView()
{
qDebug() << " --- ### begin sync of value: " << QThread::currentThreadId() << " : " << value->label;
// wir setzen auf 'lesen'
value->flags.setFlag( BCValue::Flag::ReadMe );
value->valueFlags.setFlag( BCValue::Flag::ReadMe );
_syncButton->setEnabled( false );

View File

@@ -179,7 +179,6 @@ void BCTransmitter::onProcessValue()
// Value ist 'under construction'
//emit valueUpdated( value.deviceID, value.indexRow, BCValue::Flag::Locked );
uint32_t devID = static_cast<uint32_t>(value.deviceID);
uint8_t regID = static_cast<uint8_t> (value.registerID);
@@ -187,7 +186,7 @@ void BCTransmitter::onProcessValue()
uint32_t newValue = value.rawValue;
BCValue::Flag newState = BCValue::Flag::Failed;;
if(value.flags.testFlag( BCValue::Flag::WriteMe ) )
if(value.valueFlags.testFlag( BCValue::Flag::WriteMe ) )
{
@@ -195,7 +194,7 @@ void BCTransmitter::onProcessValue()
// oder sollen wir hier beides erlauben ? readFlag & writeFlag ?
// Was kommt dann zuerst? Schreiben und lesen als verify ?
else if( value.flags.testFlag( BCValue::Flag::ReadMe ) )
else if( value.valueFlags.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 );

View File

@@ -55,9 +55,15 @@ QString BCValue::formatValue() const
bool BCValue::isWord() const
{
return flags.testFlag(BCValue::Flag::IsWord);
return valueFlags.testFlag(BCValue::Flag::IsWord);
}
bool BCValue::isReadOnly() const
{
return valueFlags.testFlag(BCValue::Flag::ReadOnly);
}
double BCValue::calcRatio() const
{
return 0.33;
@@ -88,7 +94,7 @@ void BCValue::dumpValue() const
qDebug() << "DeviceID: " << deviceID << " Register: " << registerID << " state:" " << state << " << " label: " << label;
qDebug() << "formattedValue: " << formatValue() << " min: " << optMin << " max: " << optMax << " factor: " << factor << " ValueType: " << (char)valueType << " ";
qDebug() << "indexRow: " << indexRow << " isWord: " << isWord();
qDebug() << "indexRow: " << indexRow << " isWord: " << isWord() << " isRO: " << isReadOnly();
qDebug();
}

View File

@@ -98,8 +98,9 @@ public:
double calcRatio() const;
void dumpValue() const;
bool isWord() const;
bool isReadOnly() const;
mutable Flags flags{BCValue::Flag::ReadOnly};
mutable Flags valueFlags{BCValue::Flag::NoFlag};
BCDevice::ID deviceID{BCDevice::ID::Invalid};
BC::ID registerID{BC::ID::Invalid};
ValueType valueType{ValueType::Plain};
@@ -113,19 +114,12 @@ public:
};
Q_DECLARE_OPERATORS_FOR_FLAGS(BCValue::Flags)
//Q_DECLARE_METATYPE(const BCValue&)
using BCValuePtr = std::shared_ptr<BCValue>;
using BCValuePtrConst = std::shared_ptr<const BCValue>;
//using BCValueList = QList<BCValue>;
using BCValueList = QList<BCValuePtr>;
Q_DECLARE_METATYPE(const BCValuePtr)
Q_DECLARE_METATYPE(BCValueList)

View File

@@ -87,7 +87,8 @@ void BCValueModel::updateValue(int row, BCValue::Flag state, uint32_t rawValue )
{
const BCValue& value = *(_valueList[row].get());
value.flags = state;
// Obacht hier!
//value.valueFlags = state;
value.rawValue = rawValue;
QModelIndex idx1 = index(row,1);

View File

@@ -54,7 +54,8 @@ void BCXmlLoader::loadXmlBikeData( const QString& fileName )
auto printAttrs = [](const QXmlStreamReader& xml)
{
QStringList parts;
for (const auto &attr : xml.attributes()) {
for (const auto &attr : xml.attributes())
{
parts << attr.name().toString() + "=\"" + attr.value().toString() + "\"";
}
qDebug().noquote() << parts.join(" ");
@@ -64,19 +65,14 @@ void BCXmlLoader::loadXmlBikeData( const QString& fileName )
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
// __fix throw
QMessageBox::warning(nullptr, "Fehler", "Datei konnte nicht geöffnet werden.");
return;
}
throw BCException( "Fehler", "Datei konnte nicht geöffnet werden.");
_xml.setDevice(&file);
if (_xml.readNextStartElement())
{
if (_xml.name() != "Bike"_L1 )
// fix throw
_xml.raiseError(QObject::tr("The file is not an 'Bike' file."));
throw BCException( "Fehler", "Falsches Datenformat.");
}
// ??
Q_ASSERT(_xml.isStartElement() && _xml.name() == "Bike"_L1);
@@ -93,26 +89,22 @@ void BCXmlLoader::loadXmlBikeData( const QString& fileName )
// Wir wollen die Device-ID aus dem XML Tag ermitteln
if( deviceType.isEmpty() )
{
printAttrs (_xml);
continue;
}
QByteArray byteArray = deviceType.toUtf8();
const char* deviceKey = byteArray.constData();
bool ok=false;
auto optDeviceID = bcDeviceEnum.keyToValue(deviceKey,&ok);
//_currentDeviceID = BCDevice::ID( deviceID.value_or( BCDevice::ID::Invalid ) );
//if( optDeviceID.has_value())
if(ok)
{
if(!ok)
throw BCException( "Fehler", QString("Devicetype %1 existiert nicht.").arg(deviceType) );
qDebug() << " --- FETCH 2: Device: " << deviceType << " : " << optDeviceID;
//BCDevice::ID currentDeviceID = BCDevice::ID( optDeviceID.value() );
BCDevice::ID currentDeviceID = BCDevice::ID( optDeviceID );
loadXmlBikeDeviceData(currentDeviceID);
}
} // if start element
}
} // if startElement
} // end while
}
@@ -126,9 +118,8 @@ void BCXmlLoader::loadXmlBikeDeviceData(BCDevice::ID deviceID)
auto printAttrs = [](const QXmlStreamReader& xml)
{
QStringList parts;
for (const auto &attr : xml.attributes()) {
for (const auto &attr : xml.attributes())
parts << attr.name().toString() + "=\"" + attr.value().toString() + "\"";
}
qDebug().noquote() << parts.join(" ");
};
@@ -154,6 +145,7 @@ void BCXmlLoader::loadXmlBikeDeviceData(BCDevice::ID deviceID)
.Min = _xml.attributes().value(BCTags::Min).toString(),
.Max = _xml.attributes().value(BCTags::Max).toString(),
.IsWord = _xml.attributes().value(BCTags::IsWord).toString(),
.ReadOnly = _xml.attributes().value(BCTags::ReadOnly).toString(),
.ValueType = _xml.attributes().value(BCTags::ValueType).toString(),
};
@@ -193,7 +185,7 @@ std::optional<BCValuePtr> BCXmlLoader::makeValue( BCDevice::ID deviceID, const B
{ "Float", BCValue::ValueType::Float }
};
auto setIfExists = [&]<typename T>( QStringView source, T& target )
auto setIfExists = [&]<typename T>( T& target, QStringView source )
{
if( !source.isEmpty() )
{
@@ -216,29 +208,36 @@ std::optional<BCValuePtr> BCXmlLoader::makeValue( BCDevice::ID deviceID, const B
int IDVal = s_bcValueEnum.keyToValue( byteArray.constData(), &ok );
qDebug() << " --- should create: " << params.Label;
//if( IDVal.has_value() )
if( ok )
{
if( !ok )
throw BCException( "Fehler", QString("Devicetype %1 existiert nicht.").arg(params.ID) );
BCValuePtr newValuePtr = std::make_shared<BCValue>( deviceID, static_cast<BC::ID>(IDVal) );
BCValue& newValue = *newValuePtr.get();
setIfExists( params.Factor, newValue.factor );
setIfExists( params.Min, newValue.optMin );
setIfExists( params.Max, newValue.optMax );
//setIfExists( params.IsWord, newValue.isWord );
// ValueType
if( !s_valueTypes.contains( params.ValueType ) )
throw BCException( "Fehler", QString("ValueType %1 existiert nicht.").arg(params.ValueType) );
newValue.valueType = s_valueTypes[params.ValueType];
newValue.label = params.Label;
newValue.unitLabel = params.UnitLabel;
if( s_valueTypes.contains( params.ValueType ) )
newValue.valueType = s_valueTypes[params.ValueType];
setIfExists( newValue.factor, params.Factor );
setIfExists( newValue.optMin, params.Min );
setIfExists( newValue.optMax, params.Max );
if( params.IsWord == "true")
newValue.valueFlags.setFlag( BCValue::Flag::IsWord, true );
if( params.ReadOnly == "true")
newValue.valueFlags.setFlag( BCValue::Flag::ReadOnly, true );
qDebug() << " --- created: " << params.Label;
newValue.dumpValue();
return std::optional<BCValuePtr>( newValuePtr );
}
return std::nullopt;
}

View File

@@ -66,6 +66,7 @@ protected:
QString Min;
QString Max;
QString IsWord;
QString ReadOnly;
QString ValueType;
};

View File

@@ -2,27 +2,28 @@
<Bike name='franken-wheeler'>
<Device Type='Battery'>
<Value ID='Battery_Rev_Hw' Label='Hardware Version' ValueType='Plain' />
<Value ID='Battery_Rev_Sw' Label='Software Version' ValueType='Plain' />
</Device>
<Device Type='Motor'>
<Value ID='Motor_Rev_Hw' Label='Hardware Version' ValueType='Plain'/>
<Value ID='Motor_Rev_Sw' Label='Software Version' ValueType='Plain'/>
<Value ID='Motor_Sn_Item_Hi' Label='Motor Part Number' ValueType='Plain' IsWord='1'/>
<Value ID='Motor_Sn_Item_Hi' Label='Motor Serial Number' ValueType='Plain' IsWord='1' />
<Value ID='Motor_Rev_Hw' Label='Hardware Version' ValueType='Plain' ReadOnly='true' />
<Value ID='Motor_Rev_Sw' Label='Software Version' ValueType='Plain' ReadOnly='true' />
<Value ID='Motor_Sn_Item_Hi' Label='Motor Part Number' ValueType='Plain' IsWord='true' ReadOnly='true' />
<Value ID='Motor_Sn_Item_Hi' Label='Motor Serial Number' ValueType='Plain' IsWord='true' ReadOnly='true' />
<Value ID='Motor_Status_Temperature' Label='Motor Temperature' ValueType='Float' UnitLabel='°C' />
<Value ID='Motor_Assist_Maxspeed' Label='Motor max. Speed' UnitLabel='km/h' Factor='0.1' Min='0' Max='70' ValueType='Float' />
<Value ID='Motor_Geometry_Circ_Hi' Label='Wheel Circumference' IsWord='1' UnitLabel='mm' Min='0' Max='2300' ValueType='Number' Factor='1.5625' />
<Value ID='Motor_Geometry_Circ_Hi' Label='Wheel Circumference' IsWord='true' UnitLabel='mm' Min='0' Max='2300' ValueType='Number' Factor='1.5625' />
</Device>
<Device Type='Battery'>
<Value ID='Reg_Battery_Rev_Hw' Label='Hardware Version' ValueType='Plain' ReadOnly='true' />
<Value ID='Reg_Battery_Rev_Sw' Label='Software Version' ValueType='Plain' ReadOnly='true' />
</Device>
<Device Type='Console'>
<Value ID='Cons_Rev_Hw' Label='Hardware Version' ValueType='Plain'/>
<Value ID='Cons_Rev_Sw' Label='Software Version' ValueType='Plain'/>
<Value ID='Cons_Rev_Hw' Label='Hardware Version' ValueType='Plain' ReadOnly='true' />
<Value ID='Cons_Rev_Sw' Label='Software Version' ValueType='Plain' ReadOnly='true' />
<Value ID='Cons_Sn_Product_Hi' Label='Product Number' IsWord='1' ValueType='Plain'/>
<Value ID='Cons_Sn_Oem_Hi' Label='OEM Number' IsWord='1' ValueType='Plain'/>
<Value ID='Cons_Sn_Product_Hi' Label='Product Number' IsWord='true' ValueType='Plain' ReadOnly='true'/>
<Value ID='Cons_Sn_Oem_Hi' Label='OEM Number' IsWord='true' ValueType='Plain' ReadOnly='true' />
<Value ID='Cons_Assist_Initlevel' Label='Assistance Init Level' Min='0' Max='4' ValueType='Number'/>
@@ -40,11 +41,10 @@
<Value ID='Cons_Throttle_Maxspeed_Flag' Label='Throttle Limit Enabled' ValueType='Bool'/>
<Value ID='Cons_Throttle_Maxspeed_Hi' Label='Throttle Speed Limit' UnitLabel='km/h' Factor='0.1' Min='0' Max='70' ValueType='Float'/>
<Value ID='Cons_Geometry_Circ_Hi' Label='Wheel Circumference' IsWord='1' UnitLabel='mm' Min='0' Max='2300' Factor='1.5625' ValueType='Number'/>
<Value ID='Cons_Geometry_Circ_Hi' Label='Wheel Circumference' IsWord='true' UnitLabel='mm' Min='0' Max='2300' Factor='1.5625' ValueType='Number'/>
<Value ID='Cons_Assist_Mountain_Cap' Label='Mountain Cap' UnitLabel='%' Factor='1.5625' ValueType='Float'/>
</Device>
</Bike>
<!--