Files
BionxControl/bctransmitter.cpp

212 lines
5.8 KiB
C++
Raw Normal View History

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-20 16:33:00 +01:00
#include <QThread>
2026-01-07 22:20:39 +01:00
#include <QDebug>
2026-01-06 10:53:15 +01:00
#include <QCoreApplication>
2025-12-20 16:33:00 +01:00
#include <bctransmitter.h>
2026-01-03 20:10:30 +01:00
/**
* @brief Kosntruktion. Aktiviert erstmal den Dummy-Driver.
*/
2025-12-20 16:33:00 +01:00
BCTransmitter::BCTransmitter(QObject *parent)
2026-01-06 10:53:15 +01:00
: QObject(parent)//, _isBusy(false)
2025-12-20 16:33:00 +01:00
{
2026-01-02 22:15:50 +01:00
//_canDriver = new BCDriverTinyCan{this};
2026-01-03 20:10:30 +01:00
_canDriver = &_dummyDriver;
2025-12-20 16:33:00 +01:00
}
2026-01-05 17:57:13 +01:00
2026-01-03 20:10:30 +01:00
/**
* @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 )
{
2026-01-09 10:47:29 +01:00
if( connect )
emit driverStateChanged(BCDriver::DriverState::NotPresent, "Native Treiber wird geladen.");
/*
// kill all pending stuff
//QCoreApplication::removePostedEvents(this, QEvent::MetaCall);
2026-01-05 23:39:45 +01:00
BCDriver::DriverState state = connect ? BCDriver::DriverState::DeviceReady : BCDriver::DriverState::NotPresent;
const QString& message = connect ? "Trying to connect" : " FAILED";
emit driverStateChanged(state, message);
return;
2026-01-06 10:53:15 +01:00
*/
2026-01-05 17:57:13 +01:00
2026-01-09 10:47:29 +01:00
connect ? connectCanDriver() : disconnectCanDriver();
2026-01-05 17:57:13 +01:00
}
2026-01-09 10:47:29 +01:00
2026-01-03 20:10:30 +01:00
void BCTransmitter::connectCanDriver()
2025-12-20 16:33:00 +01:00
{
2026-01-03 20:10:30 +01:00
// hier gehts nur um den echten Treiber
// Treiber laden und/oder starten:
2026-01-03 23:51:14 +01:00
BCDriver::DriverStateResult result; //(defaults to 'NotPresent')
2026-01-03 20:10:30 +01:00
if( _tinyCanDriver.getDriverState() != BCDriver::DriverState::DeviceReady )
2026-01-03 23:51:14 +01:00
result = _tinyCanDriver.loadAndStartDriver();
2026-01-03 20:10:30 +01:00
2025-12-20 16:33:00 +01:00
2026-01-09 10:47:29 +01:00
QString message("Treiber geladen (nicht verbunden)");
// Der result-Wert im ERfolgsfall ist der driver state.
if(result.has_value() )
{
switch( result.value() )
2026-01-03 23:51:14 +01:00
{
2026-01-09 10:47:29 +01:00
case BCDriver::DriverState::Opened:
message = "Treiber geladen (Device antwortet nicht)";
break;
case BCDriver::DriverState::DeviceReady:
message = "Treiber geladen und Device verbunden.";
// swap driver
_canDriver = &_tinyCanDriver;
break;
default:
break;
2026-01-03 23:51:14 +01:00
}
2026-01-03 20:10:30 +01:00
}
2026-01-09 10:47:29 +01:00
else // Fehlerfall, wir holen die Fehlermeldung
2026-01-03 23:51:14 +01:00
{
message = result.error();
}
2026-01-09 10:47:29 +01:00
2026-01-03 23:51:14 +01:00
emit driverStateChanged( _tinyCanDriver.getDriverState(), message );
2026-01-03 20:10:30 +01:00
}
2025-12-20 16:33:00 +01:00
2026-01-09 10:47:29 +01:00
/**
* @brief Native-Treiber zurücksetzen, Dummy-Treiber wieder aktivieren.
*/
2026-01-03 20:10:30 +01:00
void BCTransmitter::disconnectCanDriver()
{
2026-01-03 23:51:14 +01:00
_tinyCanDriver.resetDriver();
_canDriver = &_dummyDriver;
2026-01-09 10:47:29 +01:00
emit driverStateChanged( _tinyCanDriver.getDriverState(), "Disconnected, Dummy Treiber aktiviert." );
2025-12-20 16:33:00 +01:00
}
2026-01-06 10:53:15 +01:00
void BCTransmitter::onUpdateValue( BCValuePtrConst valuePtr)
2025-12-20 16:33:00 +01:00
{
2026-01-06 02:07:42 +01:00
2026-01-06 10:53:15 +01:00
// wir stellen hier auf die harte Tour sicher, das onUpdateValue
2026-01-06 02:07:42 +01:00
// nicht aus dem Parent-Thread direkt sondern über die EventQueue aufgerufen wurde.
Q_ASSERT(QThread::currentThread() == this->thread());
2026-01-06 10:53:15 +01:00
// Wir arbeiten hier ohne besondere Threadsynchronisation, mutexed o.ä: Die
// entkoppelung und serialisierung passiert bereits durch die Qt-Eventqueue.
// Das klappt aber nur in der hier gewählten Konstellation mit einer Parent-Thread
// und einem Worker.
2025-12-20 16:33:00 +01:00
2026-01-08 19:05:07 +01:00
// Kosmetik
const BCValue& value = *(valuePtr.get());
2026-01-06 19:52:55 +01:00
2026-01-19 16:44:52 +01:00
uint32_t devID = static_cast<uint32_t>(value.deviceID());
uint8_t regID = static_cast<uint8_t> (value.registerID());
2025-12-20 16:33:00 +01:00
2026-01-07 17:13:35 +01:00
// Für den Fehlerfall: Wir senden den alten Wert einfach zurück
2026-01-19 16:44:52 +01:00
uint32_t newValue = value.rawValue();
2026-01-08 20:47:05 +01:00
BCValue::Flag newState = BCValue::Flag::Failed;
2025-12-20 16:33:00 +01:00
2026-01-13 16:29:02 +01:00
if(value.testFlag( BCValue::Flag::WriteMe ) )
2025-12-20 16:33:00 +01:00
{
2026-01-03 02:50:28 +01:00
2026-01-06 10:53:15 +01:00
}
// oder sollen wir hier beides erlauben ? readFlag & writeFlag ?
// Was kommt dann zuerst? Schreiben und lesen als verify ?
2026-01-02 22:15:50 +01:00
2026-01-13 16:29:02 +01:00
else if( value.testFlag( BCValue::Flag::ReadMe ) )
2026-01-06 10:53:15 +01:00
{
// wir sind hier im anderen thread! nicht einfach so reinschreiben, nur lesen
2026-01-07 17:13:35 +01:00
TransmitResult result = value.isWord() ? readWordValue( devID, regID ) : readByteValue( devID, regID );
2026-01-06 10:53:15 +01:00
if( result.has_value() )
{
2026-01-07 17:13:35 +01:00
newState = BCValue::Flag::InSync;
2026-01-18 22:47:26 +01:00
newValue = result.value();
}
2026-01-06 10:53:15 +01:00
}
2026-01-02 16:25:21 +01:00
2026-01-19 16:44:52 +01:00
emit valueUpdated( value.deviceID(), value.indexRow(), newState, newValue );
2025-12-20 16:33:00 +01:00
}
2026-01-08 19:05:07 +01:00
/**
* @brief Wenn dieser SLOT in der Event-Queue erreicht wird, dedeutet dies, das die
* Übertrgung vom Mainwindow abgeschlossen wurde. Wir schicken zur Bestätigung das
* Signal 'endOfProcessing' (Welches dann den 'Sync' - Button wieder einschaltet.
*/
void BCTransmitter::onEndOfTransmission()
{
emit endOfProcessing();
}
2026-01-06 19:52:55 +01:00
2026-01-01 23:01:31 +01:00
TransmitResult BCTransmitter::readByteValue( uint32_t deviceID, uint8_t registerID )
2026-01-02 16:25:21 +01:00
{
// Wir lesen nur ein Byte und gut.
2026-01-02 16:25:21 +01:00
return _canDriver->readRawByte( deviceID, registerID );
2025-12-21 14:40:38 +01:00
}
2025-12-20 16:33:00 +01:00
2026-01-02 16:25:21 +01:00
TransmitResult BCTransmitter::readWordValue( uint32_t deviceID, uint8_t registerID )
2025-12-21 14:40:38 +01:00
{
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;
2025-12-20 16:33:00 +01:00
}