2 Commits

Author SHA1 Message Date
4545bf81c3 Visual Cleanups. 2026-01-03 00:09:26 +01:00
f5ad48faf2 Reworked transmitter. 2026-01-02 22:15:50 +01:00
12 changed files with 179 additions and 134 deletions

View File

@@ -52,6 +52,9 @@ BCMainWindow::BCMainWindow(QWidget *parent)
setupUi(this); setupUi(this);
// den pimp-my-ride-button schalten wir vorerst aus.
_pimpButton->hide();
// Wir schreiben den 'initMainWindow()' Aufruf mit Hilfe des // Wir schreiben den 'initMainWindow()' Aufruf mit Hilfe des
// timers in die Event-Queue, damit er erst ausgeführt wird, // timers in die Event-Queue, damit er erst ausgeführt wird,
// wenn das Fenster sichtbar ist. // wenn das Fenster sichtbar ist.
@@ -74,17 +77,6 @@ BCMainWindow::~BCMainWindow()
_worker.wait(); // Warten bis Thread wirklich fertig ist _worker.wait(); // Warten bis Thread wirklich fertig ist
} }
/**
* @brief Setzt den Headerlabel ( == die Device-Bezeichnung )
* @param headerLabel Der headerLabel
*/
void BCMainWindow::setHeaderLabel( const QString& headerText)
{
_headerLabel->setText( " BionxControl: " + headerText );
}
/** /**
* @brief Initialisiert alle Komponenten des MainWindows. * @brief Initialisiert alle Komponenten des MainWindows.
*/ */
@@ -95,10 +87,8 @@ void BCMainWindow::initMainWindow()
// Lambda um die buttons mit ihren Actions zu verbinden // Lambda um die buttons mit ihren Actions zu verbinden
auto configureAction = [&]( QToolButton* button, QAction* action, BCDevice::ID deviceID ) auto configureAction = [&]( QToolButton* button, QAction* action, BCDevice::ID deviceID )
{ {
// Action an den Button binden // Action an den Button binden
button->setDefaultAction( action); button->setDefaultAction( action);
// new way: die DeviceID muss aber explizit vom Lambda eingefanden werden. // new way: die DeviceID muss aber explizit vom Lambda eingefanden werden.
connect( action, &QAction::triggered, this, [this,deviceID]() connect( action, &QAction::triggered, this, [this,deviceID]()
{ {
@@ -121,14 +111,15 @@ void BCMainWindow::initMainWindow()
_devicePanels[BCDevice::ID::Console] = _consolePanel; _devicePanels[BCDevice::ID::Console] = _consolePanel;
_devicePanels[BCDevice::ID::Battery] = _batteryPanel; _devicePanels[BCDevice::ID::Battery] = _batteryPanel;
_devicePanels[BCDevice::ID::Motor] = _motorPanel; _devicePanels[BCDevice::ID::Motor] = _motorPanel;
_devicePanels[BCDevice::ID::Pimp] = _pimpPanel; //_devicePanels[BCDevice::ID::Pimp] = _pimpPanel;
// Die actions an die Buttons binden // Die actions an die Buttons binden
configureAction(_motorButton, _motorAction, BCDevice::ID::Motor ); configureAction(_motorButton, _motorAction, BCDevice::ID::Motor );
configureAction(_consoleButton, _consoleAction, BCDevice::ID::Console ); configureAction(_consoleButton, _consoleAction, BCDevice::ID::Console );
configureAction(_batteryButton, _batteryAction, BCDevice::ID::Battery ); configureAction(_batteryButton, _batteryAction, BCDevice::ID::Battery );
configureAction(_pimpButton, _pimpAction, BCDevice::ID::Pimp ); //configureAction(_pimpButton, _pimpAction, BCDevice::ID::Pimp );
/*
bool m_isDarkMode = false; bool m_isDarkMode = false;
QString icon = m_isDarkMode ? "☀️" : "🌙"; QString icon = m_isDarkMode ? "☀️" : "🌙";
fitzeButton->setText(icon); fitzeButton->setText(icon);
@@ -149,7 +140,7 @@ void BCMainWindow::initMainWindow()
.arg(m_isDarkMode ? "#3A3A3A" : "#F9F9F9"); .arg(m_isDarkMode ? "#3A3A3A" : "#F9F9F9");
fitzeButton->setStyleSheet(style); fitzeButton->setStyleSheet(style);
*/
// besser: model::emit dataChanged // besser: model::emit dataChanged
// also: emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole, ValueRole}); // also: emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole, ValueRole});
connect( _connectButton, &QToolButton::clicked, &_transmitter, &BCTransmitter::onToggleConnectionState ); connect( _connectButton, &QToolButton::clicked, &_transmitter, &BCTransmitter::onToggleConnectionState );
@@ -161,17 +152,22 @@ void BCMainWindow::initMainWindow()
connect(this, &BCMainWindow::requestValueUpdate, &_transmitter, &BCTransmitter::enqueueValue); connect(this, &BCMainWindow::requestValueUpdate, &_transmitter, &BCTransmitter::enqueueValue);
connect(&_worker, &QThread::finished, &_transmitter, &QObject::deleteLater); connect(&_worker, &QThread::finished, &_transmitter, &QObject::deleteLater);
connect( &_transmitter, &BCTransmitter::driverStateChanged, this, &BCMainWindow::onDriverStateChanged );
// transmitter starten
_worker.start(); _worker.start();
// die Daten des eBikes laden // die Daten des eBikes laden
_dataManager.loadXmlBikeData(":/bikeinfo.xml"_L1); _dataManager.loadXmlBikeData(":/bikeinfo.xml"_L1);
_consoleAction->trigger(); //_consoleAction->trigger();
_batteryAction->trigger();
}
// --- STATUSBAR SETUP --- void BCMainWindow::initStatusBar()
{
// __fix
QStatusBar *statBar = statusBar(); QStatusBar *statBar = statusBar();
// Optional: Normale Nachricht links // Optional: Normale Nachricht links
@@ -199,6 +195,29 @@ void BCMainWindow::initMainWindow()
} }
/**
* @brief Setzt den Headerlabel ( == die Device-Bezeichnung )
* @param headerLabel Der headerLabel
*/
void BCMainWindow::setHeaderLabel( const QString& headerText)
{
_headerLabel->setText( " BionxControl: " + headerText );
}
void BCMainWindow::autoConnect()
{
// __fix!
// if( !connect)
// fallBack
}
void BCMainWindow::onDriverStateChanged( BCDriver::DriverState state, const QString& message )
{
qDebug() << " --- on DriverStatusChanged: " << state << ":" << message;
}
void BCMainWindow::onShowDevicePanel( BCDevice::ID deviceID ) void BCMainWindow::onShowDevicePanel( BCDevice::ID deviceID )
{ {
qDebug() << " --- onShowDevicePanel:" << deviceID; qDebug() << " --- onShowDevicePanel:" << deviceID;

View File

@@ -56,6 +56,7 @@ public slots:
//void onValueListReady( BCDevice::ID deviceID ); //void onValueListReady( BCDevice::ID deviceID );
void onShowDevicePanel( BCDevice::ID deviceID ); void onShowDevicePanel( BCDevice::ID deviceID );
void onConnectButtonToggled(bool active ); void onConnectButtonToggled(bool active );
void onDriverStateChanged( BCDriver::DriverState state, const QString& message="" );
// Slots für Rückmeldungen vom Runner // Slots für Rückmeldungen vom Runner
void onValueUpdated( BCDevice::ID deviceID, int index, BCValue::State state, const QString& newValue="" ); void onValueUpdated( BCDevice::ID deviceID, int index, BCValue::State state, const QString& newValue="" );
@@ -69,6 +70,8 @@ signals:
protected: protected:
void initMainWindow(); void initMainWindow();
void initStatusBar();
void autoConnect();
BCXmlLoader _dataManager; BCXmlLoader _dataManager;

View File

@@ -39,8 +39,10 @@
BCTransmitter::BCTransmitter(QObject *parent) BCTransmitter::BCTransmitter(QObject *parent)
: QObject(parent), _isBusy(false) : QObject(parent), _isBusy(false)
{ {
_canDriver = new BCDriverTinyCan{this}; //_canDriver = new BCDriverTinyCan{this};
//_canDriver = new BCDriverDummy{this}; _canDriver = new BCDriverDummy{this};
// forward driver state
connect( _canDriver, &BCDriver::driverStateChanged, this, &BCTransmitter::driverStateChanged );
} }
@@ -82,11 +84,14 @@ void BCTransmitter::enqueueValue( BCValuePtrConst value)
// invokeMethod mit QueuedConnection entkoppelt den Aufruf, // invokeMethod mit QueuedConnection entkoppelt den Aufruf,
// damit enqueueValue sofort zurückkehrt (non-blocking für den Aufrufer). // damit enqueueValue sofort zurückkehrt (non-blocking für den Aufrufer).
//QMetaObject::invokeMethod(this, "processValue", Qt::QueuedConnection); QMetaObject::invokeMethod(this, "processValue", Qt::QueuedConnection);
/*
QMetaObject::invokeMethod(this, [this]() QMetaObject::invokeMethod(this, [this]()
{ {
processValue(); processValue();
}, Qt::QueuedConnection ); }, Qt::QueuedConnection );
*/
} }
void BCTransmitter::processValue() void BCTransmitter::processValue()
@@ -114,13 +119,15 @@ void BCTransmitter::processValue()
const BCValue& value = *(valuePtr.get()); const BCValue& value = *(valuePtr.get());
// Value ist 'under construction' // Value ist 'under construction'
//emit valueUpdated( val.deviceID, val.indexRow, BCValue::State::Locked ); //emit valueUpdated( value.deviceID, value.indexRow, BCValue::State::Locked );
const BCValueType& valueType = *value.valueType; const BCValueType& valueType = *value.valueType;
uint32_t devID = static_cast<uint32_t>(value.deviceID); uint32_t devID = static_cast<uint32_t>(value.deviceID);
uint8_t regID = static_cast<uint8_t> (value.registerID); uint8_t regID = static_cast<uint8_t> (value.registerID);
QString newVisibleValue; QString newVisibleValue;
BCValue::State newState = BCValue::State::NoState;
if(value.state.testFlag( BCValue::State::WriteMe ) ) if(value.state.testFlag( BCValue::State::WriteMe ) )
{ {
@@ -135,11 +142,18 @@ void BCTransmitter::processValue()
// wir sind hier im anderen thread! nicht einfach so reinschreiben, nur lesen // wir sind hier im anderen thread! nicht einfach so reinschreiben, nur lesen
TransmitResult result = valueType.readValueFunc( *this, devID, regID ); TransmitResult result = valueType.readValueFunc( *this, devID, regID );
if( result.has_value() ) if( result.has_value() )
{
newVisibleValue = valueType.formatValue( result.value() ); newVisibleValue = valueType.formatValue( result.value() );
//emit valueUpdated( value.deviceID, value.indexRow, BCValue::State::InSync, result ); newState = BCValue::State::InSync;
}
else
{
newState = BCValue::State::Failed;
} }
// emit valueUpdated( value->deviceID, value->indexRow, BCValue::State::InSync, "fitze!"); }
emit valueUpdated( value.deviceID, value.indexRow, newState, newVisibleValue );
// __fix // __fix
bc::processEventsFor(50); bc::processEventsFor(50);

View File

@@ -86,6 +86,7 @@ private:
QMutex _mutex; QMutex _mutex;
std::atomic<bool> _isBusy{ false }; std::atomic<bool> _isBusy{ false };
// __fix! set two
BCDriver* _canDriver{}; BCDriver* _canDriver{};
}; };

View File

@@ -58,7 +58,7 @@
class BCValueType; struct BCValueType;
class BCValue class BCValue
{ {

View File

@@ -102,6 +102,7 @@ BCValueType::BCValueType()
} }
BCValueType::BCValueType(QString unitKey_, QString unitLabel_, double factor_, optDouble min_, optDouble max_ ) BCValueType::BCValueType(QString unitKey_, QString unitLabel_, double factor_, optDouble min_, optDouble max_ )
: unitLabel{unitLabel_}, factor{factor_}, min{min_}, max{max_} : unitLabel{unitLabel_}, factor{factor_}, min{min_}, max{max_}
{ {
@@ -110,28 +111,6 @@ BCValueType::BCValueType(QString unitKey_, QString unitLabel_, double factor_, o
} }
QString BCValueType::readRawValueX(const BCAbstractTransmitter& transmitter , const BCValue& value) const
{
qDebug() << " --- READ X!";
/*
uint32_t devID = static_cast<uint32_t>(deviceID);
uint8_t regID = static_cast<uint8_t> (registerID);
// wir sind hier im anderen thread! nicht einfach so reinschreiben, nur lesen
if( valueType->readValueFunc )
{
uint32_t result = valueType->readValueFunc( transmitter, devID, regID );
return valueType->formatValue( result );
}
*/
return QString();
}
void BCValueType::writeRawValueX( const BCAbstractTransmitter& transmitter, const BCValue& value ) const
{
qDebug() << " --- WRITE X!";
}
QString BCValueType::formatValue( uint32_t value ) const QString BCValueType::formatValue( uint32_t value ) const
{ {
if( factor == 1 ) if( factor == 1 )
@@ -147,17 +126,20 @@ std::optional<ReadValueFunc> BCValueType::fetchReadValueFunction( const QString&
{ {
{ "Byte", readByteValue }, { "Byte", readByteValue },
{ "Word", readWordValue }, { "Word", readWordValue },
{ "Assist", readByteValue },
{ "Kmh", readByteValue },
{ "Percent",readByteValue }, { "Percent",readByteValue },
{ "KWh", readByteValue }, { "KWh", readByteValue },
{ "Watt", readByteValue }, { "Watt", readByteValue },
{ "Km", readByteValue }, { "Km", readByteValue },
{ "Kmh", readByteValue },
{ "Mm", readByteValue }, { "Mm", readByteValue },
{ "Sec", readByteValue }, { "Sec", readByteValue },
{ "Degree", readByteValue }, { "Degree", readByteValue },
{ "SoC", readByteValue }, { "SoC", readByteValue },
{ "Odo", readByteValue }, { "Odo", readByteValue },
{ "Assist", readByteValue }
}; };
if( !s_bcReadValueFunctions.contains( unitTypeKey ) ) if( !s_bcReadValueFunctions.contains( unitTypeKey ) )
@@ -171,10 +153,11 @@ std::optional<BCValueType*> BCValueType::fetchValueType( const QString& unitType
static QHash<QString,BCValueType*> s_bcDataTypes static QHash<QString,BCValueType*> s_bcDataTypes
{ {
{ "Byte", new BCValueType( "Byte", "", 1.5625F) }, { "Byte", new BCValueType( "Byte", "", 1.5625F) },
{ "Word", new BCValueType( "Word", "", 1.5625F) } { "Word", new BCValueType( "Word", "", 1.5625F) },
{ "Percent", new BCValueType( "Byte", "%", 1.5625 ) },
{ "AssInit", new BCValueType( "Byte", "", 1.0, 0 ,4 ) },
{ "Assist", new BCValueType( "Byte", "%", 0,400 ) }
/* /*
{ "Float", new BCValueType( "", 1.5625F) },
{ "Percent",new BCValueType( "%", 1.5625 ) },
{ "KWh", new BCValueType( "kwh", 1.5625 ) }, { "KWh", new BCValueType( "kwh", 1.5625 ) },
{ "Watt", new BCValueType( "w", 1.5625 ) }, { "Watt", new BCValueType( "w", 1.5625 ) },
{ "Km", new BCValueType( "km", 1.5625 ) }, { "Km", new BCValueType( "km", 1.5625 ) },
@@ -184,7 +167,7 @@ std::optional<BCValueType*> BCValueType::fetchValueType( const QString& unitType
{ "Degree", new BCValueType( "°C", 1.0 ) }, { "Degree", new BCValueType( "°C", 1.0 ) },
{ "SoC", new BCValueType( "%", 1.5625 ) }, { "SoC", new BCValueType( "%", 1.5625 ) },
{ "Odo", new BCValueType( "km", 1.5625 ) }, { "Odo", new BCValueType( "km", 1.5625 ) },
{ "Assist", new BCValueType( "", 0 ,4 ) },
{ "Assist", new BCValueType( "%" ) }, { "Assist", new BCValueType( "%" ) },
*/ */
}; };

View File

@@ -76,9 +76,6 @@ public:
BCValueType(); BCValueType();
BCValueType( QString unitKey_, QString unitLabel_, double factor_= 1.0, optDouble min_=std::nullopt, optDouble max_= std::nullopt ); BCValueType( QString unitKey_, QString unitLabel_, double factor_= 1.0, optDouble min_=std::nullopt, optDouble max_= std::nullopt );
QString readRawValueX ( const BCAbstractTransmitter& transmitter, const BCValue& value ) const;
void writeRawValueX( const BCAbstractTransmitter& transmitter, const BCValue& value ) const;
virtual QString formatValue( uint32_t value ) const; virtual QString formatValue( uint32_t value ) const;
QString unitLabel; QString unitLabel;
@@ -86,6 +83,8 @@ public:
optDouble min; optDouble min;
optDouble max; optDouble max;
ReadValueFunc readValueFunc; ReadValueFunc readValueFunc;
//ReadValueFunc readValueFunc;
static std::optional<BCValueType*> fetchValueType( const QString& unitTypeKey ); static std::optional<BCValueType*> fetchValueType( const QString& unitTypeKey );
static std::optional<ReadValueFunc> fetchReadValueFunction( const QString& unitTypeKey ); static std::optional<ReadValueFunc> fetchReadValueFunction( const QString& unitTypeKey );

View File

@@ -103,16 +103,6 @@ void BCXmlLoader::loadXmlBikeData( const QString& fileName )
printAttrs (_xml); printAttrs (_xml);
// Wir wollen die Device-ID aus dem XML Tag ermitteln // Wir wollen die Device-ID aus dem XML Tag ermitteln
const char* deviceKey = _xml.attributes().value("Type"_L1).toLatin1().constData(); const char* deviceKey = _xml.attributes().value("Type"_L1).toLatin1().constData();
/*
auto optDeviceID = bcDeviceEnum.keyToValue64(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);
}
*/
bool ok; bool ok;
auto optDeviceID = bcDeviceEnum.keyToValue(deviceKey,&ok); auto optDeviceID = bcDeviceEnum.keyToValue(deviceKey,&ok);
//_currentDeviceID = BCDevice::ID( deviceID.value_or( BCDevice::ID::Invalid ) ); //_currentDeviceID = BCDevice::ID( deviceID.value_or( BCDevice::ID::Invalid ) );

Binary file not shown.

45
doc/challenges.txt Normal file
View File

@@ -0,0 +1,45 @@
Challenges
-------------------------------------------------------------------------------------------------
Aufgabe:
Ansatz:
-------------------------------------------------------------------------------------------------
Aufgabe:
Ansatz:
-------------------------------------------------------------------------------------------------
Aufgabe:
Ansatz:
-------------------------------------------------------------------------------------------------
Aufgabe:
Ansatz:
-------------------------------------------------------------------------------------------------
Aufgabe:
Ansatz:
-------------------------------------------------------------------------------------------------
Aufgabe:
Ansatz:
-------------------------------------------------------------------------------------------------

View File

@@ -3,33 +3,31 @@
<Bike name='franken-wheeler'> <Bike name='franken-wheeler'>
<Device Type="Console"> <Device Type="Console">
<Value ID='Cons_Rev_Hw' Label='Hardware Version' ReadOnly='true' UnitType='Byte' /> <Value ID='Cons_Rev_Hw' Label='Hardware Version' ReadOnly='true' UnitType='Byte' />
<Value ID='Cons_Rev_Sw' Label='Software Version' ReadOnly='true' UnitType='Byte' /> <Value ID='Cons_Rev_Sw' Label='Software Version' ReadOnly='true' UnitType='Byte' />
<Value ID='Cons_Sn_Product_Hi' Label='Product Number' ReadOnly='true' UnitType='Word'/> <Value ID='Cons_Sn_Product_Hi' Label='Product Number' ReadOnly='true' UnitType='Word'/>
<Value ID='Cons_Sn_Oem_Hi' Label='OEM Number' ReadOnly='true' UnitType='Word' /> <Value ID='Cons_Sn_Oem_Hi' Label='OEM Number' ReadOnly='true' UnitType='Word' />
<Value ID='Cons_Assist_Initlevel' Label='Assistance Init Level' ReadOnly='true' UnitType='Assist' /> <Value ID='Cons_Assist_Initlevel' Label='Assistance Init Level' ReadOnly='false' UnitType='AssInit'/>
<Value ID='Cons_Assist_Level_1' Label='Assistance Level 1' ReadOnly='true' UnitType='Percent' Factor='1.5625'/> <Value ID='Cons_Assist_Level_1' Label='Assistance Level 1' ReadOnly='true' UnitType='Percent' Factor='1.5625'/>
<Value ID='Cons_Assist_Level_2' Label='Assistance Level 2' ReadOnly='true' UnitType='Percent' Factor='1.5625'/> <Value ID='Cons_Assist_Level_2' Label='Assistance Level 2' ReadOnly='true' UnitType='Percent' Factor='1.5625'/>
<Value ID='Cons_Assist_Level_3' Label='Assistance Level 3' ReadOnly='true' UnitType='Percent' Factor='1.5625'/> <Value ID='Cons_Assist_Level_3' Label='Assistance Level 3' ReadOnly='true' UnitType='Percent' Factor='1.5625'/>
<Value ID='Cons_Assist_Level_4' Label='Assistance Level 4' ReadOnly='true' UnitType='Percent' Factor='1.5625'/> <Value ID='Cons_Assist_Level_4' Label='Assistance Level 4' ReadOnly='true' UnitType='Percent' Factor='1.5625'/>
<Value ID='Cons_Assist_Maxspeed_Flag' Label='Max Limit Enabled' ReadOnly='true' UnitType='Byte' /> <Value ID='Cons_Assist_Maxspeed_Flag' Label='Max Limit Enabled' ReadOnly='false' UnitType='Byte' />
<Value ID='Cons_Assist_Maxspeed_Hi' Label='Max Speed Limit' ReadOnly='true' UnitType='kmh' Factor='0.1'/> <Value ID='Cons_Assist_Maxspeed_Hi' Label='Max Speed Limit' ReadOnly='false' UnitType='Kmh' Factor='0.1'/>
<Value ID='Cons_Assist_Minspeed_Flag' Label='Min Limit Enabled' ReadOnly='true' UnitType='Byte' /> <Value ID='Cons_Assist_Minspeed_Flag' Label='Min Limit Enabled' ReadOnly='true' UnitType='Byte' />
<Value ID='Cons_Assist_Minspeed' Label='Min Speed Limit' ReadOnly='true' UnitType='kmh'/> <Value ID='Cons_Assist_Minspeed' Label='Min Speed Limit' ReadOnly='true' UnitType='Kmh'/>
<Value ID='Cons_Throttle_Maxspeed_Flag' Label='Throttle Limit Enabled' ReadOnly='true' UnitType='Byte'/> <Value ID='Cons_Throttle_Maxspeed_Flag' Label='Throttle Limit Enabled' ReadOnly='true' UnitType='Byte'/>
<Value ID='Cons_Throttle_Maxspeed_Hi' Label='Throttle Speed Limit' ReadOnly='true' UnitType='kmh' Factor='0.1'/> <Value ID='Cons_Throttle_Maxspeed_Hi' Label='Throttle Speed Limit' ReadOnly='true' UnitType='kmh' Factor='0.1'/>
<Value ID='Cons_Geometry_Circ_Hi' Label='Wheel Circumference' ReadOnly='true' UnitType='mm' /> <Value ID='Cons_Geometry_Circ_Hi' Label='Wheel Circumference' ReadOnly='true' UnitType='mm' />
<Value ID='Cons_Assist_Mountain_Cap' Label='Mountain Cap' ReadOnly='true' UnitType='Percent' Factor='1.5625' /> <Value ID='Cons_Assist_Mountain_Cap' Label='Mountain Cap' ReadOnly='true' UnitType='Percent' Factor='1.5625' />
</Device> </Device>
<Device Type="Motor"> <Device Type="Motor">
<Value ID='Motor_Rev_Hw' Label='Hardware Version' ReadOnly='true' UnitType='Byte' /> <Value ID='Motor_Rev_Hw' Label='Hardware Version' ReadOnly='true' UnitType='Byte' />
<Value ID='Motor_Rev_Sw' Label='Software Version' ReadOnly='true' UnitType='Byte' /> <Value ID='Motor_Rev_Sw' Label='Software Version' ReadOnly='true' UnitType='Byte' />
<Value ID='Motor_Status_Temperature' Label='Motor Temperature' ReadOnly='true' UnitType='Degree'/> <Value ID='Motor_Status_Temperature' Label='Motor Temperature' ReadOnly='true' UnitType='Degree'/>
@@ -37,19 +35,12 @@
<Value ID='Motor_Sn_Item_Hi' Label='Motor Part Number' ReadOnly='true' UnitType='Word'/> <Value ID='Motor_Sn_Item_Hi' Label='Motor Part Number' ReadOnly='true' UnitType='Word'/>
<Value ID='Motor_Sn_Item_Hi' Label='Motor Serial Number' ReadOnly='true' UnitType='Word' /> <Value ID='Motor_Sn_Item_Hi' Label='Motor Serial Number' ReadOnly='true' UnitType='Word' />
<Value ID='Motor_Geometry_Circ_Hi' Label='Motor Gemetry' ReadOnly='true' UnitType='Mm' /> <Value ID='Motor_Geometry_Circ_Hi' Label='Motor Gemetry' ReadOnly='true' UnitType='Mm' />
</Device> </Device>
<Device Type="Battery">
<Device Type="Battery">
<Value ID='Battery_Rev_Hw' Label='Hardware Version' ReadOnly='true' UnitType='Byte' /> <Value ID='Battery_Rev_Hw' Label='Hardware Version' ReadOnly='true' UnitType='Byte' />
<Value ID='Battery_Rev_Sw' Label='Software Version' ReadOnly='true' UnitType='Byte' /> <Value ID='Battery_Rev_Sw' Label='Software Version' ReadOnly='true' UnitType='Byte' />
</Device> </Device>
<Device Type="Sensor">
</Device>
</Bike> </Bike>