Files
BionxControl/bcdrivertinycan.cpp

270 lines
6.8 KiB
C++
Raw Normal View History

2025-12-26 14:07:55 +01:00
/***************************************************************************
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
***************************************************************************/
2025-12-20 16:33:00 +01:00
#include <QDebug>
2025-12-30 14:42:49 +01:00
2025-12-30 10:12:01 +01:00
#include <bcdrivertinycan.h>
2025-12-20 16:33:00 +01:00
#include <can_drv.h>
2025-12-22 12:39:38 +01:00
2026-01-01 00:40:27 +01:00
#include <expected>
2025-12-20 16:33:00 +01:00
2025-12-30 10:12:01 +01:00
BCDriverTinyCan::BCDriverTinyCan( QObject* parent )
: BCDriver(parent )
2025-12-20 16:33:00 +01:00
{
}
2026-01-01 00:40:27 +01:00
void BCDriverTinyCan::loadDriver()
2025-12-20 16:33:00 +01:00
{
2026-01-01 00:40:27 +01:00
using Result=std::expected<DriverState,QString>;
auto callLoadDriver = []() -> Result
{
if( ::LoadDriver( NULL ) < 0 )
return std::unexpected(QString("Driver Error: 'LoadDriver'"));
return DriverState::Loaded;
};
2025-12-20 16:33:00 +01:00
2026-01-01 00:40:27 +01:00
auto callInitDriver = [](DriverState state) -> Result
{
Q_UNUSED(state)
if( ::CanInitDriver( NULL ) < 0 )
return std::unexpected(QString("Driver Error: 'InitDriver'"));
return DriverState::Initialized;
};
2025-12-20 16:33:00 +01:00
2026-01-01 00:40:27 +01:00
auto callOpenDevice = [](DriverState state) -> Result
{
Q_UNUSED(state)
if( ::CanDeviceOpen( 0, NULL ) < 0 )
return std::unexpected(QString("Driver Error: 'DeviceOpen'"));
return DriverState::Opended;
};
2025-12-20 16:33:00 +01:00
2026-01-01 00:40:27 +01:00
auto callSetDeviceMode = [](DriverState state) -> Result
{
Q_UNUSED(state)
::TDeviceStatus deviceStatus;
2025-12-21 18:31:16 +01:00
2026-01-01 00:40:27 +01:00
::CanSetSpeed( 0, CAN_125K_BIT );
::CanSetMode( 0, OP_CAN_START, CAN_CMD_ALL_CLEAR );
::CanGetDeviceStatus( 0, &deviceStatus );
2025-12-20 16:33:00 +01:00
2026-01-01 00:40:27 +01:00
if( deviceStatus.DrvStatus < DRV_STATUS_CAN_OPEN )
std::unexpected(QString("Driver Error: could not open device." ));
2025-12-20 16:33:00 +01:00
2026-01-01 00:40:27 +01:00
if( deviceStatus.CanStatus == CAN_STATUS_BUS_OFF )
{
::CanSetMode( 0, OP_CAN_RESET, CAN_CMD_NONE );
std::unexpected(QString("Driver Error: CAN Status 'BusOff'" ));
}
return BCDriver::DriverState::Ready;
};
2025-12-20 16:33:00 +01:00
2026-01-01 00:40:27 +01:00
auto newDriverState = callLoadDriver()
.and_then( callInitDriver )
.and_then( callOpenDevice )
.and_then( callSetDeviceMode );
2025-12-21 18:31:16 +01:00
2026-01-01 00:40:27 +01:00
_driverState = DriverState::Error;
QString message("Driver Ready.");
2025-12-20 16:33:00 +01:00
2026-01-01 00:40:27 +01:00
if(newDriverState)
_driverState = *newDriverState;
else
message = newDriverState.error();
2025-12-20 16:33:00 +01:00
2026-01-01 00:40:27 +01:00
emit driverStateChanged( _driverState, message );
}
2025-12-20 16:33:00 +01:00
2026-01-01 00:40:27 +01:00
void BCDriverTinyCan::initDriver()
{
2025-12-20 16:33:00 +01:00
}
/*
try
{
2026-01-01 00:40:27 +01:00
loadAndInitDriver();
2025-12-20 16:33:00 +01:00
initBCDevice::ID::Console();
}
catch( std::exception& except )
{
::CanDownDriver();
2026-01-01 00:40:27 +01:00
::UnloadAndInitDriver();
2025-12-20 16:33:00 +01:00
// re-throw
2025-12-21 20:46:16 +01:00
throw BCException( except.what() );
2025-12-20 16:33:00 +01:00
}
*/
2026-01-01 00:40:27 +01:00
/*
2025-12-30 10:12:01 +01:00
BCDriver::DriverState BCDriverTinyCan::initDriver()
2025-12-20 16:33:00 +01:00
{
2025-12-24 12:11:59 +01:00
uint32_t console = static_cast<uint32_t>(BCDevice::ID::Console);
uint8_t slaveFlag = static_cast<uint8_t>(BC::ID::Cons_Status_Slave);
2025-12-30 10:12:01 +01:00
qDebug() << "XXX BCDriverTinyCan::Driver Init: putting BCDevice::ID::Console in slave mode ... ";
2025-12-20 16:33:00 +01:00
// BCDevice::ID::Console already in slave mode. good!
2025-12-24 12:11:59 +01:00
if( readRawByte( console, slaveFlag ) )
2025-12-21 18:31:16 +01:00
return DriverState::Ready;
2025-12-20 16:33:00 +01:00
2025-12-30 10:12:01 +01:00
qDebug() << "BCDriverTinyCan::BCDriverTinyCan::XXX Driver Init: putting BCDevice::ID::Console in slave mode ... ";
2025-12-20 16:33:00 +01:00
2025-12-24 12:11:59 +01:00
unsigned int retry = cTimeOuts;
2025-12-20 16:33:00 +01:00
emit statusHint( "Driver Init: putting BCDevice::ID::Console in slave mode ... " );
2025-12-23 14:58:54 +01:00
uint32_t isSlave = 0;
2025-12-20 16:33:00 +01:00
do
{
2025-12-24 12:11:59 +01:00
writeRawByte( console, slaveFlag, 1 );
isSlave = readRawByte( console, slaveFlag );
2025-12-20 16:33:00 +01:00
bc::delay_millis( 200 );
} while( retry-- && !isSlave );
bc::delay_millis( 500 ); // give the Console some time to settle
//if( !isSlave )
emit statusHint( QString("putting BCDevice::ID::Console in slave mode ") + (isSlave ? "done" : "failed") );
2025-12-21 18:31:16 +01:00
2025-12-20 16:33:00 +01:00
// ist das jetzt irgendwie schlimm, wenn wir keine slave BCDevice::ID::Console haben
2025-12-30 10:12:01 +01:00
//return isSlave ? BCDriver::connected
2025-12-20 16:33:00 +01:00
2025-12-21 18:31:16 +01:00
return DriverState::Ready;
2025-12-20 16:33:00 +01:00
}
2026-01-01 00:40:27 +01:00
*/
2025-12-20 16:33:00 +01:00
2025-12-30 10:12:01 +01:00
uint32_t BCDriverTinyCan::readRawByte( uint32_t deviceID, uint8_t registerID ) const
2025-12-20 16:33:00 +01:00
{
2025-12-21 18:31:16 +01:00
if( getState() != DriverState::Ready)
throw BCException( "readRawValue error: driver not loaded." );
2025-12-31 17:27:50 +01:00
::TCanMsg msg;
2025-12-20 16:33:00 +01:00
// msg verpacken
msg.MsgFlags = 0L;
2025-12-24 12:11:59 +01:00
msg.Id = deviceID;
2025-12-20 16:33:00 +01:00
msg.MsgLen = 2;
msg.MsgData[0] = 0x00;
2025-12-24 12:11:59 +01:00
msg.MsgData[1] = registerID;
2025-12-20 16:33:00 +01:00
// msg verschicken
::CanTransmit( 0, &msg, 1 );
2025-12-24 12:11:59 +01:00
int retries = cRetries; // 5?
// cTimeOuts (== 20) mal cTIMEOUT_MS (== 10 ms ) Versuche ...
int timeOuts = cTimeOuts; // 20 ?
2025-12-20 16:33:00 +01:00
// ... warten bis der Sendepuffer leer ist
while( timeOuts-- && ::CanTransmitGetCount( 0 ) )
bc::delay_millis( cTIMEOUT_MS );
if( timeOuts == -1 )
2025-12-21 18:31:16 +01:00
throw BCException( "readRawValue error: could not send value" );
2025-12-20 16:33:00 +01:00
retry:
2025-12-24 12:11:59 +01:00
// cTimeOuts (== 20) mal cTIMEOUT_MS (== 10 ms ) Versuche ...
timeOuts = cTimeOuts;
2025-12-20 16:33:00 +01:00
// ... warten, bis der Empfangspuffer nicht mehr leer ist
while( timeOuts-- && !::CanReceiveGetCount( 0 ) )
bc::delay_millis( cTIMEOUT_MS );
if( timeOuts == -1 )
2025-12-21 20:46:16 +01:00
throw BCException( "getValue error: no response from node" );
2025-12-20 16:33:00 +01:00
// message empfangen
int err = ::CanReceive( 0, &msg, 1 );
2025-12-24 12:11:59 +01:00
qDebug() << "HÄÄ ?" << err << "reg: "<< registerID <<" timeOuts: " << timeOuts;
2025-12-20 16:33:00 +01:00
if( err < 0 )
2025-12-21 20:46:16 +01:00
//throw BCException( "getValue error: could not receive value" );
2025-12-20 16:33:00 +01:00
qDebug( "getValue error: could not receive value" );
qDebug() << "HÄÄ 2" <<msg.Id;
qDebug() << "HÄÄ 2" <<msg.MsgLen;
qDebug() << "HÄÄ 2" <<msg.MsgData[1];
//if( err > 0 )
2025-12-24 12:11:59 +01:00
if( --retries && ( msg.Id != BIB || msg.MsgLen != 4 || msg.MsgData[1] != registerID ) )
2025-12-20 16:33:00 +01:00
goto retry;
if( !timeOuts )
2025-12-21 20:46:16 +01:00
throw BCException( "CAN --response errror" );
2025-12-20 16:33:00 +01:00
2025-12-23 14:58:54 +01:00
return (uint32_t) msg.MsgData[3];
2025-12-21 14:40:38 +01:00
2025-12-20 16:33:00 +01:00
}
2025-12-30 10:12:01 +01:00
// void BCDriverTinyCan::setValue( unsigned char receipient, unsigned char reg, unsigned char value )
void BCDriverTinyCan::writeRawByte( uint32_t deviceID, uint8_t registerID ,uint8_t value ) const
2025-12-20 16:33:00 +01:00
{
2025-12-21 18:31:16 +01:00
if( getState() != DriverState::Ready)
throw BCException( "writeRawValue error: driver not loaded." );
2025-12-30 10:12:01 +01:00
qDebug() << " --- BCDriverTinyCan writeRawValue: " << value;
2025-12-22 12:39:38 +01:00
return;
2025-12-20 16:33:00 +01:00
2025-12-31 17:27:50 +01:00
::TCanMsg msg;
2025-12-20 16:33:00 +01:00
int timeout_count = cTIMEOUT_COUNT;
msg.MsgFlags = 0L;
2025-12-24 12:11:59 +01:00
msg.Id = deviceID;
2025-12-20 16:33:00 +01:00
msg.MsgLen = 4;
msg.MsgData[0] = 0x00;
2025-12-24 12:11:59 +01:00
msg.MsgData[1] = registerID;
2025-12-20 16:33:00 +01:00
msg.MsgData[2] = 0x00;
msg.MsgData[3] = value;
::CanTransmit( 0, &msg, 1 );
while( timeout_count-- && ::CanTransmitGetCount( 0 ) )
bc::delay_millis( cTIMEOUT_MS );
if( timeout_count == -1 )
2025-12-24 12:11:59 +01:00
emit statusHint( QString( "error: could not send value to %1" ).arg( deviceID ) );
2025-12-20 16:33:00 +01:00
}