232 lines
6.2 KiB
C++
232 lines
6.2 KiB
C++
/***************************************************************************
|
|
|
|
BionxControl
|
|
© 2025 -2026 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 <QThread>
|
|
#include <QDebug>
|
|
|
|
#include <bctransmitter.h>
|
|
|
|
/**
|
|
* @brief Kosntruktion. Aktiviert erstmal den Dummy-Driver.
|
|
*/
|
|
|
|
BCTransmitter::BCTransmitter(QObject *parent)
|
|
: QObject(parent), _isBusy(false)
|
|
{
|
|
//_canDriver = new BCDriverTinyCan{this};
|
|
_canDriver = &_dummyDriver;
|
|
|
|
}
|
|
|
|
/**
|
|
* @brief Steuert die Verbindung mit dem 'echten' CAN-Bus Treiber.
|
|
* @param connect true: Vesuche den CAN-Bus Treiber zu laden und zu verbinden
|
|
* false: Disconnect & Cleanup
|
|
*/
|
|
|
|
void BCTransmitter::onToggleDriverConnection( bool connect )
|
|
{
|
|
qDebug() << " --- onToggleDriverConnection: " << connect;
|
|
// FIX! Ende der current op abwarten!
|
|
|
|
// Hier sind wir noch in GUI Thread
|
|
QMutexLocker locker(&_mutex);
|
|
// weitere operation stoppen
|
|
_isBusy = true;
|
|
connect ? connectCanDriver() : disconnectCanDriver();
|
|
_isBusy = false;
|
|
}
|
|
|
|
void BCTransmitter::connectCanDriver()
|
|
{
|
|
// hier gehts nur um den echten Treiber
|
|
|
|
// Treiber laden und/oder starten:
|
|
BCDriver::DriverStateResult result; //(defaults to 'NotPresent')
|
|
if( _tinyCanDriver.getDriverState() != BCDriver::DriverState::DeviceReady )
|
|
result = _tinyCanDriver.loadAndStartDriver();
|
|
|
|
QString message("FitzeFatze!");
|
|
// hat geklappt
|
|
if( _tinyCanDriver.getDriverState() >= BCDriver::DriverState::Opened )
|
|
{
|
|
uint32_t console = static_cast<uint32_t>(BCDevice::ID::Console);
|
|
uint8_t hwRev = static_cast<uint8_t> (BC::ID::Cons_Rev_Hw);
|
|
|
|
TransmitResult hwVersion = _tinyCanDriver.readRawByte( console, hwRev);
|
|
if( hwVersion.has_value() )
|
|
{
|
|
message = " ---- HAIL to the king!";
|
|
qDebug() << message;
|
|
// swap driver
|
|
_canDriver = &_tinyCanDriver;
|
|
}
|
|
else
|
|
{
|
|
qDebug() << "Console not responding";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
message = result.error();
|
|
}
|
|
emit driverStateChanged( _tinyCanDriver.getDriverState(), message );
|
|
}
|
|
|
|
void BCTransmitter::disconnectCanDriver()
|
|
{
|
|
_tinyCanDriver.resetDriver();
|
|
_canDriver = &_dummyDriver;
|
|
emit driverStateChanged( _tinyCanDriver.getDriverState(), "Disconnected" );
|
|
}
|
|
|
|
|
|
void BCTransmitter::enqueueValue( BCValuePtrConst value)
|
|
{
|
|
// Hier sind wir noch in GUI Thread
|
|
QMutexLocker locker(&_mutex);
|
|
_valueQueue.enqueue( value );
|
|
|
|
// wir wollen nicht den ganzen Value verschicken, erstrecht
|
|
// wollen wir nicht den Value in verschiedenen Threads gleichzeitig
|
|
// in die Hand nehmen, also hantieren wir nur mit den Inidizes.
|
|
|
|
// Trigger processing im Event-Loop des Worker Threads
|
|
// invokeMethod mit QueuedConnection entkoppelt den Aufruf,
|
|
// damit enqueueValue sofort zurückkehrt (non-blocking für den Aufrufer).
|
|
|
|
QMetaObject::invokeMethod(this, "processValue", Qt::QueuedConnection);
|
|
|
|
/*
|
|
QMetaObject::invokeMethod(this, [this]()
|
|
{
|
|
processValue();
|
|
}, Qt::QueuedConnection );
|
|
*/
|
|
}
|
|
|
|
void BCTransmitter::processValue()
|
|
{
|
|
|
|
if (_isBusy)
|
|
return;
|
|
|
|
_isBusy = true;
|
|
|
|
while (true)
|
|
{
|
|
BCValuePtrConst valuePtr{};
|
|
{
|
|
QMutexLocker locker(&_mutex);
|
|
if (_valueQueue.isEmpty())
|
|
{
|
|
_isBusy = false;
|
|
break; // Schleife verlassen, warten auf neue Events
|
|
}
|
|
valuePtr =_valueQueue.dequeue();
|
|
} // Mutex wird hier freigegeben! WICHTIG: Execute ohne Lock!
|
|
|
|
// Kosmetik
|
|
const BCValue& value = *(valuePtr.get());
|
|
|
|
// Value ist 'under construction'
|
|
//emit valueUpdated( value.deviceID, value.indexRow, BCValue::State::Locked );
|
|
|
|
|
|
uint32_t devID = static_cast<uint32_t>(value.deviceID);
|
|
uint8_t regID = static_cast<uint8_t> (value.registerID);
|
|
|
|
QString newVisibleValue;
|
|
BCValue::State newState = BCValue::State::NoState;
|
|
|
|
if(value.state.testFlag( BCValue::State::WriteMe ) )
|
|
{
|
|
|
|
|
|
}
|
|
// oder sollen wir hier beides erlauben ? readFlag & writeFlag ?
|
|
// Was kommt dann zuerst? Schreiben und lesen als verify ?
|
|
|
|
else if( value.state.testFlag( BCValue::State::ReadMe ) )
|
|
{
|
|
// wir sind hier im anderen thread! nicht einfach so reinschreiben, nur lesen
|
|
TransmitResult result = value.isWord ? readWordValue( devID, regID ) : readByteValue( devID, regID );
|
|
if( result.has_value() )
|
|
{
|
|
newVisibleValue = value.formatValue( result.value() );
|
|
newState = BCValue::State::InSync;
|
|
}
|
|
else
|
|
{
|
|
newState = BCValue::State::Failed;
|
|
}
|
|
}
|
|
|
|
emit valueUpdated( value.deviceID, value.indexRow, newState, newVisibleValue );
|
|
|
|
// __fix
|
|
bc::processEventsFor(50);
|
|
|
|
//emit valueStateChanged(cmd.id, true);
|
|
//emit valueStateChanged(0, true);
|
|
}
|
|
}
|
|
|
|
|
|
TransmitResult BCTransmitter::readByteValue( uint32_t deviceID, uint8_t registerID )
|
|
{
|
|
qDebug() << " --- YES: Read ByteValue: " << registerID;
|
|
// Wir lesen nur ein Byte und gut.
|
|
return _canDriver->readRawByte( deviceID, registerID );
|
|
}
|
|
|
|
|
|
TransmitResult BCTransmitter::readWordValue( uint32_t deviceID, uint8_t registerID )
|
|
{
|
|
qDebug() << " --- YES: Read WordValue: " << registerID;
|
|
|
|
uint32_t result{};
|
|
// hi byte Leseversuch.
|
|
TransmitResult value = _canDriver->readRawByte( deviceID, registerID );
|
|
// Fehler? dann weg
|
|
if( !value)
|
|
return std::unexpected( value.error() );
|
|
// hi byte speichern
|
|
result = *value << 8;
|
|
// low byte, liegt im followup register: +1
|
|
value = _canDriver->readRawByte( deviceID, registerID+1 );
|
|
if( !value)
|
|
return std::unexpected( value.error() );
|
|
result += *value;
|
|
return result;
|
|
}
|