/*************************************************************************** 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 @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 #include #include BCDriverTinyCan::BCDriverTinyCan( QObject* parent ) : BCDriver(parent ) { } BCDriver::DriverState BCDriverTinyCan::loadDriver() { //qDebug() << "CanBusControl " << cbc::Version << '\n' << "based on BigXionFlasher (c) 2011-2013 by Thomas Koenig - www.bigxionflasher.org"; struct ::TDeviceStatus canDevicestatus; if( ::LoadDriver( NULL ) < 0 ) throw BCException( "Driver Error: 'LoadDriver'" ); setState(BCDriver::DriverState::Loaded); if( ::CanInitDriver( NULL ) < 0 ) throw BCException( "Driver Error: 'InitDriver'" ); if( ::CanDeviceOpen( 0, NULL ) < 0 ) throw std::runtime_error( "Driver Error: 'DeviceOpen'" ); ::CanSetSpeed( 0, CAN_125K_BIT ); ::CanSetMode( 0, OP_CAN_START, CAN_CMD_ALL_CLEAR ); ::CanGetDeviceStatus( 0, &canDevicestatus ); setState(BCDriver::DriverState::Initialized); if( canDevicestatus.DrvStatus < DRV_STATUS_CAN_OPEN ) throw BCException( "Driver Error: could not open device." ); if( canDevicestatus.CanStatus == CAN_STATUS_BUS_OFF ) { ::CanSetMode( 0, OP_CAN_RESET, CAN_CMD_NONE ); throw BCException( "Driver Error: CAN Status 'BusOff'" ); } setState(BCDriver::DriverState::Ready); return BCDriver::DriverState::Ready; } /* try { loadDriver(); initBCDevice::ID::Console(); } catch( std::exception& except ) { ::CanDownDriver(); ::UnloadDriver(); // re-throw throw BCException( except.what() ); } */ BCDriver::DriverState BCDriverTinyCan::initDriver() { uint32_t console = static_cast(BCDevice::ID::Console); uint8_t slaveFlag = static_cast(BC::ID::Cons_Status_Slave); qDebug() << "XXX BCDriverTinyCan::Driver Init: putting BCDevice::ID::Console in slave mode ... "; // BCDevice::ID::Console already in slave mode. good! if( readRawByte( console, slaveFlag ) ) return DriverState::Ready; qDebug() << "BCDriverTinyCan::BCDriverTinyCan::XXX Driver Init: putting BCDevice::ID::Console in slave mode ... "; unsigned int retry = cTimeOuts; emit statusHint( "Driver Init: putting BCDevice::ID::Console in slave mode ... " ); uint32_t isSlave = 0; do { writeRawByte( console, slaveFlag, 1 ); isSlave = readRawByte( console, slaveFlag ); 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") ); // ist das jetzt irgendwie schlimm, wenn wir keine slave BCDevice::ID::Console haben //return isSlave ? BCDriver::connected return DriverState::Ready; } uint32_t BCDriverTinyCan::readRawByte( uint32_t deviceID, uint8_t registerID ) const { if( getState() != DriverState::Ready) throw BCException( "readRawValue error: driver not loaded." ); //uint32_t result = transmitter.readRawValue( deviceID, registerID ); //value.fromValue( myRandomByte ); TCanMsg msg; // msg verpacken msg.MsgFlags = 0L; msg.Id = deviceID; msg.MsgLen = 2; msg.MsgData[0] = 0x00; msg.MsgData[1] = registerID; // msg verschicken ::CanTransmit( 0, &msg, 1 ); int retries = cRetries; // 5? // cTimeOuts (== 20) mal cTIMEOUT_MS (== 10 ms ) Versuche ... int timeOuts = cTimeOuts; // 20 ? // ... warten bis der Sendepuffer leer ist while( timeOuts-- && ::CanTransmitGetCount( 0 ) ) bc::delay_millis( cTIMEOUT_MS ); if( timeOuts == -1 ) throw BCException( "readRawValue error: could not send value" ); retry: // cTimeOuts (== 20) mal cTIMEOUT_MS (== 10 ms ) Versuche ... timeOuts = cTimeOuts; // ... warten, bis der Empfangspuffer nicht mehr leer ist while( timeOuts-- && !::CanReceiveGetCount( 0 ) ) bc::delay_millis( cTIMEOUT_MS ); if( timeOuts == -1 ) throw BCException( "getValue error: no response from node" ); // message empfangen int err = ::CanReceive( 0, &msg, 1 ); qDebug() << "HÄÄ ?" << err << "reg: "<< registerID <<" timeOuts: " << timeOuts; if( err < 0 ) //throw BCException( "getValue error: could not receive value" ); qDebug( "getValue error: could not receive value" ); qDebug() << "HÄÄ 2" < 0 ) if( --retries && ( msg.Id != BIB || msg.MsgLen != 4 || msg.MsgData[1] != registerID ) ) goto retry; if( !timeOuts ) throw BCException( "CAN --response errror" ); return (uint32_t) msg.MsgData[3]; } // 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 { if( getState() != DriverState::Ready) throw BCException( "writeRawValue error: driver not loaded." ); qDebug() << " --- BCDriverTinyCan writeRawValue: " << value; return; struct TCanMsg msg; int timeout_count = cTIMEOUT_COUNT; msg.MsgFlags = 0L; msg.Id = deviceID; msg.MsgLen = 4; msg.MsgData[0] = 0x00; msg.MsgData[1] = registerID; 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 ) emit statusHint( QString( "error: could not send value to %1" ).arg( deviceID ) ); }