From d438da86a60fcbb669e50cf6e3460e2d4748ad0a Mon Sep 17 00:00:00 2001 From: jimihimi Date: Thu, 2 Jul 2026 18:16:03 -0500 Subject: [PATCH 1/3] Add SSM3 ISO14230 diagnostic interface support --- src/AbstractDiagInterface.cpp | 2 ++ src/AbstractDiagInterface.h | 2 +- src/J2534DiagInterface.cpp | 31 ++++++++++++++++++++------ src/SerialPassThroughDiagInterface.cpp | 20 ++++++++++++----- 4 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/AbstractDiagInterface.cpp b/src/AbstractDiagInterface.cpp index c047b06..44efa19 100644 --- a/src/AbstractDiagInterface.cpp +++ b/src/AbstractDiagInterface.cpp @@ -125,6 +125,8 @@ std::string AbstractDiagInterface::protocolDescription(protocol_type protocol) return "SSM2 / ISO-14230"; case protocol_type::SSM2_ISO15765: return "SSM2 / ISO-15765"; + case protocol_type::SSM3_ISO14230: + return "SSM3 / ISO-14230"; default: // BUG return "UNKNOWN"; } diff --git a/src/AbstractDiagInterface.h b/src/AbstractDiagInterface.h index d656f65..762f769 100644 --- a/src/AbstractDiagInterface.h +++ b/src/AbstractDiagInterface.h @@ -30,7 +30,7 @@ class AbstractDiagInterface public: enum class interface_type { serialPassThrough, J2534, ATcommandControlled }; - enum class protocol_type { NONE, SSM1, SSM2_ISO14230, SSM2_ISO15765 }; // NOTE: when adding new protocols, also enhance protocolDescription(...) ! + enum class protocol_type { NONE, SSM1, SSM2_ISO14230, SSM2_ISO15765, SSM3_ISO14230 }; // NOTE: when adding new protocols, also enhance protocolDescription(...) ! AbstractDiagInterface(); virtual ~AbstractDiagInterface(); diff --git a/src/J2534DiagInterface.cpp b/src/J2534DiagInterface.cpp index 94a2b4c..658f7ea 100644 --- a/src/J2534DiagInterface.cpp +++ b/src/J2534DiagInterface.cpp @@ -113,9 +113,16 @@ bool J2534DiagInterface::open( std::string name ) const J2534_protocol_flags p = lib.protocols; if (bool(p & J2534_protocol_flags::iso9141) || bool(p & J2534_protocol_flags::iso14230)) + { supportedProtocols.push_back(protocol_type::SSM2_ISO14230); + } if (bool(p & J2534_protocol_flags::iso15765)) supportedProtocols.push_back(protocol_type::SSM2_ISO15765); + if (bool(p & J2534_protocol_flags::iso9141) || + bool(p & J2534_protocol_flags::iso14230)) + { + supportedProtocols.push_back(protocol_type::SSM3_ISO14230); + } setSupportedProtocols(supportedProtocols); break; } @@ -169,11 +176,13 @@ bool J2534DiagInterface::connect(AbstractDiagInterface::protocol_type protocol) if (_j2534 == NULL) return false; // CHECK PROTOCOL AND SET UP PARAMETERS - if (protocol == AbstractDiagInterface::protocol_type::SSM2_ISO14230) + if ((protocol == AbstractDiagInterface::protocol_type::SSM2_ISO14230) || + (protocol == AbstractDiagInterface::protocol_type::SSM3_ISO14230)) { ProtocolID = ISO9141; // also: ISO14230 Flags = ISO9141_NO_CHECKSUM; - BaudRate = 4800; + BaudRate = + (protocol == AbstractDiagInterface::protocol_type::SSM3_ISO14230) ? 10400 : 4800; } else if (protocol == AbstractDiagInterface::protocol_type::SSM2_ISO15765) { @@ -205,7 +214,8 @@ bool J2534DiagInterface::connect(AbstractDiagInterface::protocol_type protocol) SCONFIG CfgItems[1]; // Echo (MANDATORY): CfgItems[0].Parameter = LOOPBACK; // Echo off/on - if (protocol == AbstractDiagInterface::protocol_type::SSM2_ISO14230) + if ((protocol == AbstractDiagInterface::protocol_type::SSM2_ISO14230) || + (protocol == AbstractDiagInterface::protocol_type::SSM3_ISO14230)) CfgItems[0].Value = ON; else CfgItems[0].Value = OFF; @@ -233,7 +243,8 @@ bool J2534DiagInterface::connect(AbstractDiagInterface::protocol_type protocol) if (_j2534->libraryAPIversion() == J2534_API_version::v0202) goto err_close; } - if (protocol == AbstractDiagInterface::protocol_type::SSM2_ISO14230) + if ((protocol == AbstractDiagInterface::protocol_type::SSM2_ISO14230) || + (protocol == AbstractDiagInterface::protocol_type::SSM3_ISO14230)) { /* ----- SET CONFIGURATION (ISO-14230 specific) ----- */ // P1_MIN (min. ECU inter-byte time) @@ -505,7 +516,8 @@ bool J2534DiagInterface::read(std::vector *buffer) memset(rx_msgs, 0, num_PTMSGS * sizeof(PASSTHRU_MSG)); for (unsigned long i=0; i *buffer) } else if (rx_msgs[i].ExtraDataIndex < rx_msgs[i].DataSize) { - if ((_j2534->libraryAPIversion() == J2534_API_version::v0404) || (protocolType() != protocol_type::SSM2_ISO14230) || - ((protocolType() == protocol_type::SSM2_ISO14230) && (rx_msgs[i].ExtraDataIndex < (rx_msgs[i].DataSize - 1)))) + if ((_j2534->libraryAPIversion() == J2534_API_version::v0404) || + ((protocolType() != protocol_type::SSM2_ISO14230) && + (protocolType() != protocol_type::SSM3_ISO14230)) || + (((protocolType() == protocol_type::SSM2_ISO14230) || + (protocolType() == protocol_type::SSM3_ISO14230)) && + (rx_msgs[i].ExtraDataIndex < (rx_msgs[i].DataSize - 1)))) std::cout << " WARNING: ExtraDataIndex is smaller than expected !\n"; /* NOTE: * - 04.04-API: (SAE-J2534-1, dec 2004): ExtraDataIndex only used with J1850 PWM @@ -632,6 +648,7 @@ bool J2534DiagInterface::write(std::vector buffer) switch(protocolType()) { case AbstractDiagInterface::protocol_type::SSM2_ISO14230: + case AbstractDiagInterface::protocol_type::SSM3_ISO14230: tx_msg.ProtocolID = ISO9141; break; case AbstractDiagInterface::protocol_type::SSM2_ISO15765: diff --git a/src/SerialPassThroughDiagInterface.cpp b/src/SerialPassThroughDiagInterface.cpp index 001aa36..010286c 100644 --- a/src/SerialPassThroughDiagInterface.cpp +++ b/src/SerialPassThroughDiagInterface.cpp @@ -30,6 +30,7 @@ SerialPassThroughDiagInterface::SerialPassThroughDiagInterface() setVersion("1.0"); supportedProtocols.push_back(protocol_type::SSM1); supportedProtocols.push_back(protocol_type::SSM2_ISO14230); + supportedProtocols.push_back(protocol_type::SSM3_ISO14230); setSupportedProtocols(supportedProtocols); /* NOTE: due to the interfaces construction, we can not know which protocol it actually supports ! * One possibility would be to check for an data echo: @@ -123,12 +124,20 @@ bool SerialPassThroughDiagInterface::connect(protocol_type protocol) return true; } } - else if (protocol == AbstractDiagInterface::protocol_type::SSM2_ISO14230) + else if ((protocol == AbstractDiagInterface::protocol_type::SSM2_ISO14230) || + (protocol == AbstractDiagInterface::protocol_type::SSM3_ISO14230)) { - if (_port->SetPortSettings(4800, 8, 'N', 1)) + const unsigned int requestedBaudrate = + (protocol == AbstractDiagInterface::protocol_type::SSM3_ISO14230) ? 10400 : 4800; + if (_port->SetPortSettings(requestedBaudrate, 8, 'N', 1)) { + double actualBaudrate = 0; + if (!_port->GetPortSettings(&actualBaudrate)) + return false; + if ((actualBaudrate < (0.97*requestedBaudrate)) || (actualBaudrate > (1.03*requestedBaudrate))) + return false; setProtocolType( protocol ); - setProtocolBaudrate( 4800 ); + setProtocolBaudrate( requestedBaudrate ); _connected = true; return true; } @@ -189,9 +198,10 @@ bool SerialPassThroughDiagInterface::write(std::vector buffer) { T_Tx_min = static_cast(1000 * buffer.size() * 11 / 1953.0); } - else if (protocolType() == AbstractDiagInterface::protocol_type::SSM2_ISO14230) + else if ((protocolType() == AbstractDiagInterface::protocol_type::SSM2_ISO14230) || + (protocolType() == AbstractDiagInterface::protocol_type::SSM3_ISO14230)) { - T_Tx_min = static_cast(1000 * buffer.size() * 10 / 4800.0); + T_Tx_min = static_cast(1000 * buffer.size() * 10 / protocolBaudRate()); } time.start(); if (!_port->Write( buffer )) From 4e00dbaf65f59bde24856fea011df1148fd42b3b Mon Sep 17 00:00:00 2001 From: jimihimi Date: Thu, 2 Jul 2026 18:16:56 -0500 Subject: [PATCH 2/3] Add SSM3 TPMS protocol support --- FreeSSM.pro | 2 + src/LocalIdentifier.h | 31 ++++ src/SSM3protocolTPMS.cpp | 375 +++++++++++++++++++++++++++++++++++++++ src/SSMCUdata.h | 2 +- src/SSMprotocol.cpp | 230 ++++++++++++++++++++++++ src/SSMprotocol.h | 73 +++++++- 6 files changed, 706 insertions(+), 7 deletions(-) create mode 100644 src/LocalIdentifier.h create mode 100644 src/SSM3protocolTPMS.cpp diff --git a/FreeSSM.pro b/FreeSSM.pro index 6051663..04fbd72 100644 --- a/FreeSSM.pro +++ b/FreeSSM.pro @@ -48,6 +48,7 @@ HEADERS += src/FreeSSM.h \ src/CUcontent_DCs_engine.h \ src/CUcontent_DCs_twoMemories.h \ src/CUcontent_DCs_stopCodes.h \ + src/LocalIdentifier.h \ src/CUcontent_MBsSWs.h \ src/CUcontent_MBsSWs_tableView.h \ src/CUcontent_Adjustments.h \ @@ -89,6 +90,7 @@ SOURCES += src/main.cpp \ src/SSMP2communication_core.cpp \ src/AbstractSSMcommunication.cpp \ src/SSMprotocol.cpp \ + src/SSM3protocolTPMS.cpp \ src/SSMprotocol1.cpp \ src/SSMprotocol2.cpp \ src/AddMBsSWsDlg.cpp \ diff --git a/src/LocalIdentifier.h b/src/LocalIdentifier.h new file mode 100644 index 0000000..c260e64 --- /dev/null +++ b/src/LocalIdentifier.h @@ -0,0 +1,31 @@ +/* + * LocalIdentifier.h - Display model for KWP/SSM local identifier data + * + * Copyright (C) 2026 + * + * 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. + */ + +#ifndef LOCALIDENTIFIER_H +#define LOCALIDENTIFIER_H + + +#include +#include +#include + + +class local_identifier_section_dt +{ +public: + QString title; + QString rawValue; + QStringList columnHeaders; + std::vector rows; +}; + + +#endif diff --git a/src/SSM3protocolTPMS.cpp b/src/SSM3protocolTPMS.cpp new file mode 100644 index 0000000..7f8be2f --- /dev/null +++ b/src/SSM3protocolTPMS.cpp @@ -0,0 +1,375 @@ +#include "SSMprotocol.h" + +#include + +namespace +{ +QString formatByteValue(char value) +{ + const unsigned int byte = static_cast(value); + return QString("0x%1 (%2)").arg(byte, 2, 16, QChar('0')).arg(byte).toUpper(); +} +} + +SSM3protocolTPMS::SSM3protocolTPMS(AbstractDiagInterface *diagInterface, QString language) + : SSMprotocol3(diagInterface, language) +{ +} + +SSMprotocol::CUsetupResult_dt SSM3protocolTPMS::setupCUdata(enum CUtype CU) +{ + if ((CU != CUtype::TPMS) || (_diagInterface == NULL)) + return result_invalidCUtype; + + const AbstractDiagInterface::protocol_type protocol = _diagInterface->protocolType(); + if (protocol != AbstractDiagInterface::protocol_type::SSM3_ISO14230) + return result_invalidInterfaceConfig; + + stopKeepAlive(); + if (!startDiagnosticSession()) + return result_commError; + + std::vector identifyPayload; + identifyPayload.push_back('\x1A'); + identifyPayload.push_back('\x91'); + std::vector commonIdentifyResponse; + if (!sendRequest(identifyPayload, 0x5A, &commonIdentifyResponse) || + (commonIdentifyResponse.size() < 5) || + (static_cast(commonIdentifyResponse.at(1)) != 0x91) || + (static_cast(commonIdentifyResponse.at(2)) != 0xCC) || + (static_cast(commonIdentifyResponse.at(3)) != 0x02) || + (static_cast(commonIdentifyResponse.at(4)) != 0x00)) + return result_commError; + + identifyPayload.clear(); + identifyPayload.push_back('\x1A'); + identifyPayload.push_back('\x9A'); + std::vector identifyResponse; + if (!sendRequest(identifyPayload, 0x5A, &identifyResponse) || + (identifyResponse.size() < 6) || + (static_cast(identifyResponse.at(1)) != 0x9A)) + return result_commError; + // TPMS 0x1A/0x91 is the common family ID; 0x1A/0x9A is module-specific. + _ssmCUdata.SYS_ID.assign(identifyResponse.begin() + 2, identifyResponse.begin() + 5); + _ssmCUdata.ROM_ID.assign(identifyResponse.begin() + 2, identifyResponse.begin() + 6); + + _CU = CU; + _ifceProtocol = protocol; + _sysDescription = "Tire Pressure Monitoring System"; + _supportedDCgroups = currentDTCs_DCgroup; + _selectedDCgroups = noDCs_DCgroup; + _state = state_normal; + startKeepAlive(); + return result_success; +} + +std::string SSM3protocolTPMS::getROMID() const +{ + if (_state == state_needSetup) + return ""; + return libFSSM::StrToHexstr(_ssmCUdata.ROM_ID); +} + +bool SSM3protocolTPMS::hasClearMemory(bool *CMsup) +{ + if ((_state == state_needSetup) || (CMsup == NULL)) + return false; + *CMsup = true; + return true; +} + +bool SSM3protocolTPMS::startDCreading(int DCgroups) +{ + if ((_state != state_normal) || !(DCgroups & currentDTCs_DCgroup)) + return false; + + _selectedDCgroups = currentDTCs_DCgroup; + _state = state_DCreading; + stopKeepAlive(); + QTimer::singleShot(0, this, SLOT(readDiagnosticCodes())); + return true; +} + +bool SSM3protocolTPMS::restartDCreading() +{ + if (_state != state_DCreading) + return false; + + _state = state_normal; + return startDCreading(_selectedDCgroups); +} + +bool SSM3protocolTPMS::stopDCreading() +{ + if (_state != state_DCreading) + return false; + + _selectedDCgroups = noDCs_DCgroup; + _state = state_normal; + startKeepAlive(); + emit stoppedDCreading(); + return true; +} + +bool SSM3protocolTPMS::clearMemory(CMlevel_dt level, bool *success) +{ + if (success != NULL) + *success = false; + if ((_state != state_normal) || (level != CMlevel_1)) + return false; + + stopKeepAlive(); + std::vector payload; + payload.push_back('\x14'); + payload.push_back('\xFE'); + std::vector response; + if (!sendRequest(payload, 0x54, &response) || + (response.size() < 2) || + (static_cast(response.at(1)) != 0xFE)) + { + if (!startDiagnosticSession() || + !sendRequest(payload, 0x54, &response) || + (response.size() < 2) || + (static_cast(response.at(1)) != 0xFE)) + { + startKeepAlive(); + return false; + } + } + + if (success != NULL) + *success = true; + startKeepAlive(); + return true; +} + + +bool SSM3protocolTPMS::hasLocalIdentifierData(bool *LIsup) +{ + if ((_state == state_needSetup) || (LIsup == NULL)) + return false; + *LIsup = true; + return true; +} + + +bool SSM3protocolTPMS::readLocalIdentifierData(std::vector *sections) +{ + if ((_state != state_normal) || (sections == NULL)) + return false; + sections->clear(); + + QStringList registeredIDs; + QStringList runtimeIDs; + if (readTransmitterIDs(®isteredIDs, &runtimeIDs)) + { + local_identifier_section_dt registeredSection; + registeredSection.title = tr("Registered Transmit IDs:"); + registeredSection.columnHeaders << tr("Tire") << tr("Transmit ID"); + for (int i = 0; i < 4; i++) + registeredSection.rows.push_back(QStringList() << QString::number(i + 1) << ((i < registeredIDs.size()) ? registeredIDs.at(i) : "")); + sections->push_back(registeredSection); + + local_identifier_section_dt runtimeSection; + runtimeSection.title = tr("Runtime / Reception History IDs:"); + runtimeSection.columnHeaders << tr("Slot") << tr("Transmit ID"); + for (int i = 0; i < 4; i++) + runtimeSection.rows.push_back(QStringList() << QString::number(i + 1) << ((i < runtimeIDs.size()) ? runtimeIDs.at(i) : "")); + sections->push_back(runtimeSection); + } + else + { + local_identifier_section_dt transmitSection; + transmitSection.title = tr("Transmit IDs:"); + transmitSection.rawValue = tr("not supported or no response"); + sections->push_back(transmitSection); + } + + std::vector block10; + if (!readLocalIdentifier(0x10, 10, &block10)) + return !sections->empty(); + + local_identifier_section_dt block10Section; + block10Section.title = tr("0x21 / 0x10 Live/status block (10 bytes):"); + block10Section.rawValue = QString::fromStdString(libFSSM::StrToHexstr(block10)); + block10Section.columnHeaders << tr("Byte") << tr("Value"); + for (std::size_t i = 0; i < block10.size(); i++) + block10Section.rows.push_back(QStringList() << tr("Byte %1").arg(static_cast(i)) << formatByteValue(block10.at(i))); + sections->push_back(block10Section); + + std::vector block99; + local_identifier_section_dt block99Section; + block99Section.title = tr("0x21 / 0x99 Live/status block (8 bytes):"); + block99Section.columnHeaders << tr("Byte") << tr("Value"); + if (readLocalIdentifier(0x99, 8, &block99)) + { + block99Section.rawValue = QString::fromStdString(libFSSM::StrToHexstr(block99)); + for (std::size_t i = 0; i < block99.size(); i++) + block99Section.rows.push_back(QStringList() << tr("Byte %1").arg(static_cast(i)) << formatByteValue(block99.at(i))); + } + else + { + block99Section.rawValue = tr("not supported or no response"); + } + sections->push_back(block99Section); + + return !sections->empty(); +} + + +bool SSM3protocolTPMS::readTransmitterIDs(QStringList *registeredIDs, QStringList *runtimeIDs) +{ + if ((_state != state_normal) || (registeredIDs == NULL)) + return false; + registeredIDs->clear(); + if (runtimeIDs != NULL) + runtimeIDs->clear(); + + std::vector payload; + payload.push_back('\x21'); + payload.push_back('\x11'); + std::vector response; + if (!sendRequest(payload, 0x61, &response) || + (response.size() < 14) || + (static_cast(response.at(1)) != 0x11)) + { + if (!startDiagnosticSession() || + !sendRequest(payload, 0x61, &response) || + (response.size() < 14) || + (static_cast(response.at(1)) != 0x11)) + return false; + } + + for (unsigned int i = 0; i < 4; i++) + { + const std::size_t offset = 2 + (i * 3); + registeredIDs->append(QString::fromStdString(libFSSM::StrToHexstr(&response.at(offset), 3))); + } + if (runtimeIDs != NULL) + { + for (unsigned int i = 0; i < 4; i++) + { + const std::size_t offset = 2 + ((i + 4) * 3); + if ((offset + 3) <= response.size()) + runtimeIDs->append(QString::fromStdString(libFSSM::StrToHexstr(&response.at(offset), 3))); + else + runtimeIDs->append(""); + } + } + return true; +} + + +bool SSM3protocolTPMS::readLiveDataBlocks(QStringList *block10Values, QStringList *block99Values, + QString *block10Raw, QString *block99Raw) +{ + if ((_state != state_normal) || (block10Values == NULL) || (block99Values == NULL)) + return false; + block10Values->clear(); + block99Values->clear(); + if (block10Raw != NULL) + block10Raw->clear(); + if (block99Raw != NULL) + block99Raw->clear(); + + std::vector block10; + std::vector block99; + if (!readLocalIdentifier(0x10, 10, &block10)) + return false; + // Calsonic supports 0x21/0x10 and 0x21/0x11, but not ALPS' read-only + // 0x21/0x99 block. Leave the second table blank when it is unavailable. + readLocalIdentifier(0x99, 8, &block99); + + for (std::size_t i = 0; i < block10.size(); i++) + block10Values->append(formatByteValue(block10.at(i))); + for (std::size_t i = 0; i < block99.size(); i++) + block99Values->append(formatByteValue(block99.at(i))); + if (block10Raw != NULL) + *block10Raw = QString::fromStdString(libFSSM::StrToHexstr(block10)); + if (block99Raw != NULL) + { + if (block99.empty()) + *block99Raw = "not supported or no response"; + else + *block99Raw = QString::fromStdString(libFSSM::StrToHexstr(block99)); + } + return true; +} + + +void SSM3protocolTPMS::readDiagnosticCodes() +{ + if (_state != state_DCreading) + return; + + std::vector payload; + payload.push_back('\x17'); + payload.push_back('\xFE'); + std::vector response; + if (!sendRequest(payload, 0x57, &response) || (response.size() < 2)) + { + if (!startDiagnosticSession() || !sendRequest(payload, 0x57, &response) || (response.size() < 2)) + { + _selectedDCgroups = noDCs_DCgroup; + _state = state_normal; + startKeepAlive(); + emit commError(); + return; + } + } + + const unsigned int codeCount = static_cast(response.at(1)); + if (response.size() < (2 + codeCount)) + { + _selectedDCgroups = noDCs_DCgroup; + _state = state_normal; + emit commError(); + return; + } + + QStringList codes; + QStringList descriptions; + for (unsigned int i = 0; i < codeCount; i++) + { + const unsigned int code = static_cast(response.at(2 + i)); + codes << QString("0x%1").arg(code, 2, 16, QChar('0')).toUpper(); + descriptions << diagnosticCodeDescription(code); + } + emit currentOrTemporaryDTCs(codes, descriptions, false, false); + if (_state == state_DCreading) + QTimer::singleShot(2000, this, SLOT(readDiagnosticCodes())); +} + + +QString SSM3protocolTPMS::diagnosticCodeDescription(unsigned int code) const +{ + const unsigned int transmitter = code & 0x0F; + switch (code & 0xF0) + { + case 0x10: + if ((transmitter >= 1) && (transmitter <= 4)) + return tr("Tire pressure %1 is reduced").arg(transmitter); + break; + case 0x20: + if ((transmitter >= 1) && (transmitter <= 4)) + return tr("Data cannot be received from transmitter %1").arg(transmitter); + break; + case 0x30: + if ((transmitter >= 1) && (transmitter <= 4)) + return tr("Transmitter %1 pressure data is abnormal").arg(transmitter); + break; + case 0x40: + if ((transmitter >= 1) && (transmitter <= 4)) + return tr("Transmitter %1 function code is abnormal").arg(transmitter); + break; + case 0x50: + if ((transmitter >= 1) && (transmitter <= 4)) + return tr("Transmitter %1 battery voltage is low").arg(transmitter); + break; + case 0x60: + if (code == 0x61) + return tr("Vehicle speed signal is abnormal"); + break; + } + return tr("Unknown TPMS diagnostic code 0x%1").arg(code, 2, 16, QChar('0')).toUpper(); +} diff --git a/src/SSMCUdata.h b/src/SSMCUdata.h index 9fb844b..20ed9bd 100644 --- a/src/SSMCUdata.h +++ b/src/SSMCUdata.h @@ -24,7 +24,7 @@ #include -enum class CUtype {Engine, Transmission, CruiseControl, AirCon, FourWheelSteering, ABS, AirSuspension, PowerSteering}; +enum class CUtype {Engine, Transmission, CruiseControl, AirCon, FourWheelSteering, ABS, AirSuspension, PowerSteering, TPMS}; /*! diff --git a/src/SSMprotocol.cpp b/src/SSMprotocol.cpp index 95cc224..0bc7928 100644 --- a/src/SSMprotocol.cpp +++ b/src/SSMprotocol.cpp @@ -19,6 +19,38 @@ #include "SSMprotocol.h" +#include +#include +#include +#include + + +namespace +{ +unsigned char checksum(const std::vector& data) +{ + unsigned int sum = 0; + for (std::size_t i = 0; i < data.size(); i++) + sum += static_cast(data.at(i)); + return static_cast(sum & 0xFF); +} + +#ifdef __FSSM_DEBUG__ +void printFrame(const char *prefix, const std::vector& data) +{ + std::cout << prefix; + for (std::size_t i = 0; i < data.size(); i++) + { + const unsigned int byte = static_cast(data.at(i)); + std::cout << (i ? " " : "") << std::hex; + if (byte < 0x10) + std::cout << '0'; + std::cout << byte; + } + std::cout << std::dec << '\n'; +} +#endif +} SSMprotocol::SSMprotocol(AbstractDiagInterface *diagInterface, QString language) @@ -240,6 +272,15 @@ bool SSMprotocol::hasClearMemory2(bool *CM2sup) } +bool SSMprotocol::clearMemoryProcedure(CMprocedure_dt *procedure) +{ + if ((_state == state_needSetup) || (procedure == NULL)) + return false; + *procedure = CMprocedure_ignitionCycle; + return true; +} + + bool SSMprotocol::hasMBengineSpeed(bool *MBsup) { if (_state == state_needSetup) @@ -303,6 +344,15 @@ bool SSMprotocol::getSupportedSWs(std::vector *supportedSWs) } +bool SSMprotocol::hasLocalIdentifierData(bool *LIsup) +{ + if ((_state == state_needSetup) || (LIsup == NULL)) + return false; + *LIsup = false; + return true; +} + + bool SSMprotocol::getLastMBSWselection(std::vector *MBSWmetaList) { if (_state == state_needSetup) @@ -355,6 +405,13 @@ bool SSMprotocol::getVIN(QString *VIN) } +bool SSMprotocol::readLocalIdentifierData(std::vector *sections) +{ + (void)sections; + return false; +} + + bool SSMprotocol::startDCreading(int DCgroups) { std::vector DCqueryAddrList; @@ -1192,3 +1249,176 @@ void SSMprotocol::determineSupportedDCgroups(std::vector DCblockDat } } + +SSMprotocol3::SSMprotocol3(AbstractDiagInterface *diagInterface, QString language) + : SSMprotocol(diagInterface, language) +{ + _keepAliveTimer = new QTimer(this); + _keepAliveTimer->setInterval(2000); + connect(_keepAliveTimer, SIGNAL(timeout()), this, SLOT(keepSessionAlive())); +} + + +SSMprotocol::protocol_dt SSMprotocol3::protocolType() +{ + return SSM3; +} + + +bool SSMprotocol3::clearMemoryProcedure(CMprocedure_dt *procedure) +{ + if ((_state == state_needSetup) || (procedure == NULL)) + return false; + *procedure = CMprocedure_direct; + return true; +} + + +void SSMprotocol3::keepSessionAlive() +{ + if (_state != state_normal) + return; + + std::vector payload; + payload.push_back('\x1A'); + payload.push_back('\x9A'); + std::vector response; + if (!sendRequest(payload, 0x5A, &response)) + { + // If the compact diagnostic session already expired, reopen it silently. + startDiagnosticSession(); + } +} + + +bool SSMprotocol3::startDiagnosticSession() +{ + std::vector startPayload(1, '\x81'); + std::vector startResponse; + return sendRequest(startPayload, 0xC1, &startResponse); +} + + +void SSMprotocol3::startKeepAlive() +{ + if ((_state == state_normal) && (_keepAliveTimer != NULL) && !_keepAliveTimer->isActive()) + _keepAliveTimer->start(); +} + + +void SSMprotocol3::stopKeepAlive() +{ + if ((_keepAliveTimer != NULL) && _keepAliveTimer->isActive()) + _keepAliveTimer->stop(); +} + + +bool SSMprotocol3::sendRequest(const std::vector& payload, + unsigned char expectedService, + std::vector *responsePayload) +{ + if ((payload.size() == 0) || (payload.size() > 0x3F) || (responsePayload == NULL)) + return false; + responsePayload->clear(); + + std::vector request; + request.push_back(static_cast(0x80 + payload.size())); + request.push_back('\x38'); + request.push_back('\xF0'); + request.insert(request.end(), payload.begin(), payload.end()); + request.push_back(static_cast(checksum(request))); + +#ifdef __FSSM_DEBUG__ + printFrame("SSM3 TX: ", request); +#endif + + _diagInterface->clearSendBuffer(); + _diagInterface->clearReceiveBuffer(); + if (!_diagInterface->write(request)) + return false; + + std::vector received; + QElapsedTimer totalTimer; + QElapsedTimer interByteTimer; + totalTimer.start(); + interByteTimer.start(); + while (totalTimer.elapsed() < 2000) + { + std::vector chunk; + if (!_diagInterface->read(&chunk)) + return false; + if (!chunk.empty()) + { + received.insert(received.end(), chunk.begin(), chunk.end()); + interByteTimer.restart(); + } + else if (!received.empty() && (interByteTimer.elapsed() > 150)) + break; + QThread::msleep(10); + } + +#ifdef __FSSM_DEBUG__ + printFrame("SSM3 RX: ", received); +#endif + + for (std::size_t offset = 0; (offset + 4) <= received.size(); offset++) + { + const unsigned char header = static_cast(received.at(offset)); + if ((header & 0xC0) != 0x80) + continue; + + const std::size_t payloadLength = header & 0x3F; + const std::size_t frameLength = payloadLength + 4; + if ((offset + frameLength) > received.size()) + continue; + + std::vector frame(received.begin() + offset, + received.begin() + offset + frameLength); + std::vector frameWithoutChecksum(frame.begin(), frame.end() - 1); + if (checksum(frameWithoutChecksum) != static_cast(frame.back())) + continue; + if ((static_cast(frame.at(1)) != 0xF0) || + (static_cast(frame.at(2)) != 0x38)) + continue; + + std::vector response(frame.begin() + 3, frame.end() - 1); + if (response.empty()) + continue; + if (static_cast(response.at(0)) == 0x7F) + return false; + if (static_cast(response.at(0)) != expectedService) + continue; + + responsePayload->assign(response.begin(), response.end()); + return true; + } + return false; +} + + +bool SSMprotocol3::readLocalIdentifier(unsigned char identifier, unsigned int expectedDataSize, + std::vector *data) +{ + if (data == NULL) + return false; + data->clear(); + + std::vector payload; + payload.push_back('\x21'); + payload.push_back(static_cast(identifier)); + std::vector response; + if (!sendRequest(payload, 0x61, &response) || + (response.size() < (2 + expectedDataSize)) || + (static_cast(response.at(1)) != identifier)) + { + if (!startDiagnosticSession() || + !sendRequest(payload, 0x61, &response) || + (response.size() < (2 + expectedDataSize)) || + (static_cast(response.at(1)) != identifier)) + return false; + } + + data->assign(response.begin() + 2, response.begin() + 2 + expectedDataSize); + return true; +} + diff --git a/src/SSMprotocol.h b/src/SSMprotocol.h index 9e8b34b..6483ec8 100644 --- a/src/SSMprotocol.h +++ b/src/SSMprotocol.h @@ -31,6 +31,7 @@ #include #include "AbstractDiagInterface.h" #include "libFSSM.h" +#include "LocalIdentifier.h" #include "SSMCUdata.h" #include "AbstractSSMcommunication.h" #include "SSMDefinitionsInterface.h" @@ -38,6 +39,7 @@ enum class BlockType { MB, SW }; +class QTimer; class MBSWmetadata_dt @@ -58,12 +60,13 @@ class SSMprotocol : public QObject Q_OBJECT public: - enum protocol_dt {SSM1, SSM2}; + enum protocol_dt {SSM1, SSM2, SSM3}; enum CUsetupResult_dt {result_success, result_invalidCUtype, result_invalidInterfaceConfig, result_commError, result_noOrInvalidDefsFile, result_noDefs}; enum state_dt {state_needSetup, state_normal, state_DCreading, state_MBSWreading, state_ActTesting, state_waitingForIgnOff}; enum DCgroups_dt {noDCs_DCgroup=0, currentDTCs_DCgroup=1, temporaryDTCs_DCgroup=2, historicDTCs_DCgroup=4, memorizedDTCs_DCgroup=8, CClatestCCs_DCgroup=16, CCmemorizedCCs_DCgroup=32}; enum CMlevel_dt {CMlevel_1=1, CMlevel_2=2}; + enum CMprocedure_dt {CMprocedure_ignitionCycle, CMprocedure_direct}; enum immoTestResult_dt {immoNotShorted, immoShortedToGround, immoShortedToBattery}; SSMprotocol(AbstractDiagInterface *diagInterface, QString language="en"); @@ -75,7 +78,7 @@ class SSMprotocol : public QObject virtual protocol_dt protocolType() = 0; AbstractDiagInterface::protocol_type ifceProtocolType(); std::string getSysID() const; - std::string getROMID() const; + virtual std::string getROMID() const; bool getSystemDescription(QString *sysdescription); bool hasOBD2system(bool *OBD2); virtual bool hasVINsupport(bool *VINsup); @@ -84,6 +87,7 @@ class SSMprotocol : public QObject virtual bool hasIntegratedCC(bool *CCsup); virtual bool hasClearMemory(bool *CMsup); virtual bool hasClearMemory2(bool *CM2sup); + virtual bool clearMemoryProcedure(CMprocedure_dt *procedure); bool hasMBengineSpeed(bool *MBsup); bool hasTestMode(bool *TMsup); bool hasActuatorTests(bool *ATsup); @@ -91,15 +95,17 @@ class SSMprotocol : public QObject bool getLastDCgroupsSelection(int *DCgroups); bool getSupportedMBs(std::vector *supportedMBs); bool getSupportedSWs(std::vector *supportedSWs); + virtual bool hasLocalIdentifierData(bool *LIsup); bool getLastMBSWselection(std::vector *MBSWmetaList); bool getSupportedAdjustments(std::vector *supportedAdjustments); bool getSupportedActuatorTests(QStringList *actuatorTestTitles); bool getLastActuatorTestSelection(unsigned char *actuatorTestIndex); // COMMUNICATION BASED FUNCTIONS: virtual bool getVIN(QString *VIN); - bool startDCreading(int DCgroups); - bool restartDCreading(); - bool stopDCreading(); + virtual bool startDCreading(int DCgroups); + virtual bool readLocalIdentifierData(std::vector *sections); + virtual bool restartDCreading(); + virtual bool stopDCreading(); bool startMBSWreading(const std::vector& mbswmetaList); bool restartMBSWreading(); bool stopMBSWreading(); @@ -110,7 +116,7 @@ class SSMprotocol : public QObject bool restartActuatorTest(); bool stopActuatorTesting(); bool stopAllActuators(); - bool clearMemory(CMlevel_dt level, bool *success); + virtual bool clearMemory(CMlevel_dt level, bool *success); bool testImmobilizerCommLine(immoTestResult_dt *result); bool isEngineRunning(bool *isrunning); bool isInTestMode(bool *testmode); @@ -191,6 +197,61 @@ public slots: }; +class SSMprotocol3 : public SSMprotocol +{ + Q_OBJECT + +public: + SSMprotocol3(AbstractDiagInterface *diagInterface, QString language="en"); + + protocol_dt protocolType() override; + bool clearMemoryProcedure(CMprocedure_dt *procedure) override; + +protected slots: + void keepSessionAlive(); + +protected: + bool startDiagnosticSession(); + void startKeepAlive(); + void stopKeepAlive(); + bool sendRequest(const std::vector& payload, unsigned char expectedService, + std::vector *responsePayload); + bool readLocalIdentifier(unsigned char identifier, unsigned int expectedDataSize, + std::vector *data); + +private: + QTimer *_keepAliveTimer; +}; + + +class SSM3protocolTPMS : public SSMprotocol3 +{ + Q_OBJECT + +public: + SSM3protocolTPMS(AbstractDiagInterface *diagInterface, QString language="en"); + + CUsetupResult_dt setupCUdata(enum CUtype CU) override; + std::string getROMID() const override; + bool hasClearMemory(bool *CMsup) override; + bool startDCreading(int DCgroups) override; + bool restartDCreading() override; + bool stopDCreading() override; + bool clearMemory(CMlevel_dt level, bool *success) override; + bool hasLocalIdentifierData(bool *LIsup) override; + bool readLocalIdentifierData(std::vector *sections) override; + bool readTransmitterIDs(QStringList *registeredIDs, QStringList *runtimeIDs = NULL); + bool readLiveDataBlocks(QStringList *block10Values, QStringList *block99Values, + QString *block10Raw = NULL, QString *block99Raw = NULL); + +private slots: + void readDiagnosticCodes(); + +private: + QString diagnosticCodeDescription(unsigned int code) const; +}; + + #endif From 253b26a957b20c1b66964939b3553277e672271a Mon Sep 17 00:00:00 2001 From: jimihimi Date: Thu, 2 Jul 2026 18:17:26 -0500 Subject: [PATCH 3/3] Add TPMS control unit dialog --- FreeSSM.pro | 4 + resources/FreeSSM.qrc | 1 + resources/changelog_en.txt | 3 + .../icons/freessm/64x64/TirePressure.png | Bin 0 -> 2938 bytes src/CUcontent_DCs_abstract.cpp | 3 + src/CUcontent_LocalIdentifiers.cpp | 154 ++++++++++++++++++ src/CUcontent_LocalIdentifiers.h | 53 ++++++ src/ClearMemoryDlg.cpp | 129 +++++++++++---- src/ClearMemoryDlg.h | 13 ++ src/CmdLine.cpp | 1 + src/ControlUnitDialog.cpp | 87 +++++++++- src/ControlUnitDialog.h | 9 +- src/FreeSSM.cpp | 29 ++++ src/FreeSSM.h | 2 + src/TPMSdialog.cpp | 79 +++++++++ src/TPMSdialog.h | 59 +++++++ src/main.cpp | 2 + ui/About.ui | 27 +-- ui/FreeSSM.ui | 40 ++++- ui/small/About.ui | 2 +- ui/small/FreeSSM.ui | 39 ++++- 21 files changed, 676 insertions(+), 60 deletions(-) create mode 100644 resources/icons/freessm/64x64/TirePressure.png create mode 100644 src/CUcontent_LocalIdentifiers.cpp create mode 100644 src/CUcontent_LocalIdentifiers.h create mode 100644 src/TPMSdialog.cpp create mode 100644 src/TPMSdialog.h diff --git a/FreeSSM.pro b/FreeSSM.pro index 04fbd72..f2ed51c 100644 --- a/FreeSSM.pro +++ b/FreeSSM.pro @@ -15,6 +15,7 @@ HEADERS += src/FreeSSM.h \ src/Languages.h \ src/CmdLine.h \ src/EngineDialog.h \ + src/TPMSdialog.h \ src/TransmissionDialog.h \ src/ABSdialog.h \ src/CruiseControlDialog.h \ @@ -49,6 +50,7 @@ HEADERS += src/FreeSSM.h \ src/CUcontent_DCs_twoMemories.h \ src/CUcontent_DCs_stopCodes.h \ src/LocalIdentifier.h \ + src/CUcontent_LocalIdentifiers.h \ src/CUcontent_MBsSWs.h \ src/CUcontent_MBsSWs_tableView.h \ src/CUcontent_Adjustments.h \ @@ -70,6 +72,7 @@ SOURCES += src/main.cpp \ src/FreeSSM.cpp \ src/CmdLine.cpp \ src/EngineDialog.cpp \ + src/TPMSdialog.cpp \ src/TransmissionDialog.cpp \ src/ABSdialog.cpp \ src/CruiseControlDialog.cpp \ @@ -102,6 +105,7 @@ SOURCES += src/main.cpp \ src/CUcontent_DCs_engine.cpp \ src/CUcontent_DCs_twoMemories.cpp \ src/CUcontent_DCs_stopCodes.cpp \ + src/CUcontent_LocalIdentifiers.cpp \ src/CUcontent_MBsSWs.cpp \ src/CUcontent_MBsSWs_tableView.cpp \ src/CUcontent_Adjustments.cpp \ diff --git a/resources/FreeSSM.qrc b/resources/FreeSSM.qrc index 536125d..5b14a37 100644 --- a/resources/FreeSSM.qrc +++ b/resources/FreeSSM.qrc @@ -33,6 +33,7 @@ icons/freessm/64x64/AirCon.png icons/freessm/64x64/CruiseControl.png icons/freessm/64x64/Engine.png + icons/freessm/64x64/TirePressure.png icons/freessm/64x64/Transmission.png icons/oxygen/16x16/chronometer.png icons/oxygen/22x22/applications-utilities.png diff --git a/resources/changelog_en.txt b/resources/changelog_en.txt index a6738ec..289ba84 100644 --- a/resources/changelog_en.txt +++ b/resources/changelog_en.txt @@ -2,6 +2,9 @@ next release (current development snapshot): - Added experimental support for J2534 interfaces - Added experimental support for AT command controlled interfaces - Added experimental support for SSM2 over ISO-15765 (CAN) + - Added experimental support for TPMS control units + - Added TPMS diagnostic code reading and clear-memory support + - Added TPMS transmitter ID and live data displays - Added support for the old SSM1 communication protocol - Added basic support for additional control units: ABS/VDC, CC, A/C (SSM1 only, definitions incomplete) diff --git a/resources/icons/freessm/64x64/TirePressure.png b/resources/icons/freessm/64x64/TirePressure.png new file mode 100644 index 0000000000000000000000000000000000000000..336c91a964c1a182638270d14919a9e33dd6b001 GIT binary patch literal 2938 zcmV-=3x)KFP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGmbN~PnbOGLGA9w%&3lB*|K~#8N?V5XV zR979xzxQUdk8HAeKweP7yP>pVqy(e{Xh|)0gvz6J&}!AuaoUc5K%qcsRa#{zQXMU$ zV$pVN3k;03U>$8O^Z{5Y2&5Pup}Z0x;gOIBB%4jLd;Olf=O%Y|?`DB!B?*2eH#z6r zn|sgicYf!0e&?Y8(0JXnsPgYk%l{Q1|K7A*l@G|s$iT$RX0!&x<3ej1s{KjWb)s6& z-)O!#q%Zm=G$Eji10<>%c3gDg(xpp!zB6JfAR|2kHOu<}^#NHTaVwazx&iN(o|XkS zhDjs(;lm%M1C3!~q^juqbQNl9YGi>mF}uJ$xos5Q4>W~cR|3efx5%e%9Q~ZEAL|lP zzdAqe$>F^i#8g0f7F*vR*7_2EHyA)Esx^TCGIILMOmt!@U}SDGUuG?-BKzF+k&N#Y z=IED5UpLVjfps346Z^d}6>uBQ@VCWdih?%pWtq7)iU&EMt-2kr%udrUkuDzSkaw?* zfUi-nOC%~rXtDiMOa<6o)S_mgX1j(>$F9B7HdVpa#bbeLIwvpRD=wzDE*Xc!gqYQd zVAD~%UY7`H0SFP>6 zF>}1kUju;js(vc#jJc>P70xi+S{%Ol?>&}_KZ zaYAOUjVWs{=yeK#-^fosB{R|KQ~^b!h5^2?5x^0^FL$|d{&eh@TjA59f3mZCopG_U z0xNeq0se&G(=hS#!)3;rPQSQ$8sF%X8G-7@X@4H(Z`dmfx(^HgT!IEKeUiB=PyxCO zoe)(4Pk(7J`gj;fv>O0loSKfjA8nKQ?nml#|6x~1V@fK4p?gM3E1tP8x-YO)fHSQx zem30|^w0*WHhg9EF`4PEXt@8kWqMuPp$tEz6}U69WkD#G3b^#dK>jj?kq!+T_5*)A zQY#C(FK-{M$GW{7wag~taG}ZILJ80hree-(hl2SYz{6|H z;PrEuR%QRCEY8F$SbR@pXdI@1WGtV-hrGr=@^4l)oJ-ladKgJdOMyO_Oi5WN)AAX& zFyRU2B_Rq}Hk}VN)-fep-;;pZFCAyV(;UqAB>X~>CnP; zStYsxGP81!>TZyppI%?h#qPr=#jRe!o+GE=RdSi4L!^wJqa~VoMo^LnA`wtTR8Yk_iXY(StZFw8(K^V+iTw6gbfP z6abAfDZ=axXQ*KGpcJUXayTRytG+b%6mYV@}@+~Zp@J=GH@Xx0*sbO}enA=gsS0FJA{p($=y$QG&qO@lKfU1s9L zitX%&RvR{M-rE`9-R1&^h;Kqg4$UbxjA`5@Gx6c!jt;Sg=pEIK}Y&BG6$XAqq8x9X4dHkwvWf$NIcFQnl+fH`mZp`NMZ#78yE zB7x;15W2pN%I=L5t^^VO%3e>IPt`O+-F=F4Wpg)ZQ!s95$AUp`p>QxgZ)->Y7ry7? z@;0iY^%BEkv05sJCe8|{-_bXi?nONCxy+6kFT1)wA&=AIi$QyMv*a8#BDK@1;qii` zV7eFa=qM)@AT6D9o=qj9JID_4$3qMd5~Tt(1?iqfr082r@#DwE{ZaM&RQ(d^c#@ow zioWUe^753MF#nei2dzO@z`J{o0ZFDU>*fHSDvn=Nw)^oBcy_7>InBrQOQc0vywGK# zOgdt(BRv=I>@L%@(k1$_@e_J}5tInT!r>&bt7=k87coA+KMIGkB^p@~aZW&7OpCG! zw^?sreKu4qnMhfT<$hZFn|nk+WU>IkvUeDTxeS3>!RE_YI5|t^yN>ze7>pP@Pi9y) zuaNO@7xUyK%Fxotlr(>*f`vOfj`y`I;J}$W)YdT|GNz2p8dgjfC%BAVh4}N?PMuj{ z!_TMZc9=h9tF3q7SXswDXS)If(>7nBFEEN&8DAq-e(iRd?;3u+*Go&Y5R@&ms>FO6 ze`uy%!|H|*12vNXCr6*8VZ|f*+QLx}HZ`8f@>tV;ia_leXH{7C9!rFKx zDfr}!9UmOHzB58rxY9GRa3W3JSnp)(*I#yEN6Dwbyd*>cf}tk+y`wa_|*Y_JU@GsEa<*0cyJPm@=d}^8RootJeUZ>QURjrvwq*kzG*U!Mh%PZ^5I((#kyMe zW39cXs9{QX?0W`{!a)n zwDt7K#^k&vped}Li5gxw;Kq|1_sfDvI#s}sVZ(9!2NW>Uc?Q=Ij7^3cO@LPF4-;O% zp?1t~E?{qY^fS$!DnOw9VhqhHbTP4KK(W$Nq0HMO^VY;{!nOO@{Kiz-3Ma=}5yBgn z)oNNITgd#3*|{2sGV?QblkYKbggxW3c*ek{VEw+>=Nw{MK+(uN?0AH;DX)bRD17qk z1JG7o&fcKH%Yoye;WliX##b6nm%=}`D+{atRRxz_g{Em}R+6F3Wk_oDSqiVb=;rGh zpePEwtpR+0Y$n!Bpy{^AHlpxz{%*sDBQ0<-kPOi5)rr=4U=DQ!S>S5 z4|T`1fSrdbfE3QC#5_72n+=WShu}MZ0^X`)96C61)SRJzFuj&(Z_QbtCiqPAIgZCw zrTYK2BhqIN>i6{bRG)yari!&QMW0MJS5sJiLp-B@lix;yMT9Eq>dB5Nydb6m1phe9 zruDE@#iEJ0T>Lk&T)j%DLJ(IX|Hu3c z(@x`rhe0CWBf5pCi>Q-PKh||ynRsVxVs?QbHsswo2?cdK5lC>r<#HhgOgwV;9cc0ePnZee-`G=*ePyAo@xpiSMQvm70A{+|i3P8`$5cn93x?<6 zp>add)Dk?ioMgA*_3ejoxZ=E?7buP-JUgQR<&_ucryJn)dZGG#C`l_q#oq0F!gSs_ k3RkIs-pf^Wf!+)7U&&*j0Ln<++yDRo07*qoM6N<$g3^+oCIA2c literal 0 HcmV?d00001 diff --git a/src/CUcontent_DCs_abstract.cpp b/src/CUcontent_DCs_abstract.cpp index 6f37ea3..ae3c297 100644 --- a/src/CUcontent_DCs_abstract.cpp +++ b/src/CUcontent_DCs_abstract.cpp @@ -262,6 +262,9 @@ void CUcontent_DCs_abstract::printDCprotocol() case CUtype::AirCon: CU = tr("Air Conditioning"); break; + case CUtype::TPMS: + CU = tr("Tire Pressure Monitoring System"); + break; case CUtype::FourWheelSteering: CU = tr("4 Wheel Steering"); break; diff --git a/src/CUcontent_LocalIdentifiers.cpp b/src/CUcontent_LocalIdentifiers.cpp new file mode 100644 index 0000000..4ddae6f --- /dev/null +++ b/src/CUcontent_LocalIdentifiers.cpp @@ -0,0 +1,154 @@ +/* + * CUcontent_LocalIdentifiers.cpp - Widget for local identifier data + * + * Copyright (C) 2026 + * + * 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. + */ + +#include "CUcontent_LocalIdentifiers.h" + + +CUcontent_LocalIdentifiers::CUcontent_LocalIdentifiers(QWidget *parent) : QWidget(parent) +{ + _SSMPdev = NULL; + + QVBoxLayout *mainLayout = new QVBoxLayout(this); + mainLayout->setContentsMargins(0, 0, 0, 0); + mainLayout->setSpacing(6); + + _sectionsLayout = new QVBoxLayout(); + _sectionsLayout->setContentsMargins(0, 0, 0, 0); + _sectionsLayout->setSpacing(6); + mainLayout->addLayout(_sectionsLayout); + + QHBoxLayout *buttonLayout = new QHBoxLayout(); + buttonLayout->addStretch(); + _refreshButton = new QPushButton(tr("Refresh"), this); + _refreshButton->setMinimumSize(90, 34); + buttonLayout->addWidget(_refreshButton); + mainLayout->addLayout(buttonLayout); + + connect(_refreshButton, SIGNAL(released()), this, SLOT(refreshData())); +} + + +CUcontent_LocalIdentifiers::~CUcontent_LocalIdentifiers() +{ + disconnect(_refreshButton, SIGNAL(released()), this, SLOT(refreshData())); +} + + +bool CUcontent_LocalIdentifiers::setup(SSMprotocol *SSMPdev) +{ + _SSMPdev = SSMPdev; + if (_SSMPdev == NULL) + return false; + return readAndDisplayData(); +} + + +void CUcontent_LocalIdentifiers::refreshData() +{ + if (!readAndDisplayData()) + { + emit error(); + return; + } +} + + +bool CUcontent_LocalIdentifiers::readAndDisplayData() +{ + if (_SSMPdev == NULL) + return false; + + std::vector sections; + if (!_SSMPdev->readLocalIdentifierData(§ions)) + return false; + + clearSections(); + for (std::vector::const_iterator it = sections.begin(); it != sections.end(); ++it) + addSection(*it); + return true; +} + + +void CUcontent_LocalIdentifiers::clearSections() +{ + QLayoutItem *item = NULL; + while ((item = _sectionsLayout->takeAt(0)) != NULL) + { + if (item->widget() != NULL) + delete item->widget(); + delete item; + } +} + + +void CUcontent_LocalIdentifiers::addSection(const local_identifier_section_dt& section) +{ + QFont titleFont = font(); + titleFont.setUnderline(true); + + QLabel *titleLabel = new QLabel(section.title, this); + titleLabel->setFont(titleFont); + _sectionsLayout->addWidget(titleLabel); + + if (!section.rawValue.isEmpty()) + { + QLabel *rawLabel = new QLabel(tr("Raw: %1").arg(section.rawValue), this); + _sectionsLayout->addWidget(rawLabel); + } + + if (section.rows.empty()) + return; + + int columnCount = section.columnHeaders.size(); + if (columnCount == 0) + columnCount = section.rows.at(0).size(); + if (columnCount == 0) + return; + + QTableWidget *table = new QTableWidget(static_cast(section.rows.size()), columnCount, this); + setupTable(table); + if (section.columnHeaders.size() == columnCount) + table->setHorizontalHeaderLabels(section.columnHeaders); + for (std::size_t row = 0; row < section.rows.size(); row++) + { + const QStringList& values = section.rows.at(row); + for (int column = 0; column < columnCount; column++) + { + QTableWidgetItem *item = new QTableWidgetItem(); + if (column == 0) + item->setTextAlignment(Qt::AlignCenter); + item->setText((column < values.size()) ? values.at(column) : ""); + table->setItem(static_cast(row), column, item); + } + } + _sectionsLayout->addWidget(table); +} + + +void CUcontent_LocalIdentifiers::setupTable(QTableWidget *table) +{ + table->setEditTriggers(QAbstractItemView::NoEditTriggers); + table->setAlternatingRowColors(true); + table->setSelectionBehavior(QAbstractItemView::SelectRows); + table->verticalHeader()->hide(); + table->setColumnWidth(0, 70); +#if QT_VERSION < 0x050000 + table->horizontalHeader()->setResizeMode(0, QHeaderView::Interactive); + for (int column = 1; column < table->columnCount(); column++) + table->horizontalHeader()->setResizeMode(column, QHeaderView::Stretch); + table->verticalHeader()->setResizeMode(QHeaderView::Fixed); +#else + table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Interactive); + for (int column = 1; column < table->columnCount(); column++) + table->horizontalHeader()->setSectionResizeMode(column, QHeaderView::Stretch); + table->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); +#endif +} diff --git a/src/CUcontent_LocalIdentifiers.h b/src/CUcontent_LocalIdentifiers.h new file mode 100644 index 0000000..7436463 --- /dev/null +++ b/src/CUcontent_LocalIdentifiers.h @@ -0,0 +1,53 @@ +/* + * CUcontent_LocalIdentifiers.h - Widget for local identifier data + * + * Copyright (C) 2026 + * + * 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. + */ + +#ifndef CUCONTENT_LOCALIDENTIFIERS_H +#define CUCONTENT_LOCALIDENTIFIERS_H + + +#include +#if QT_VERSION < 0x050000 +#include +#else +#include +#endif +#include "LocalIdentifier.h" +#include "SSMprotocol.h" + + +class CUcontent_LocalIdentifiers : public QWidget +{ + Q_OBJECT + +public: + CUcontent_LocalIdentifiers(QWidget *parent = 0); + ~CUcontent_LocalIdentifiers(); + bool setup(SSMprotocol *SSMPdev); + +signals: + void error(); + +private slots: + void refreshData(); + +private: + SSMprotocol *_SSMPdev; + QVBoxLayout *_sectionsLayout; + QPushButton *_refreshButton; + + bool readAndDisplayData(); + void clearSections(); + void addSection(const local_identifier_section_dt& section); + void setupTable(QTableWidget *table); +}; + + +#endif diff --git a/src/ClearMemoryDlg.cpp b/src/ClearMemoryDlg.cpp index a563226..d2c6c52 100644 --- a/src/ClearMemoryDlg.cpp +++ b/src/ClearMemoryDlg.cpp @@ -20,6 +20,12 @@ #include "ClearMemoryDlg.h" +ClearMemoryDlg::StoppedOperation_dt::StoppedOperation_dt() +{ + state = SSMprotocol::state_normal; + DCgroups = 0; +} + ClearMemoryDlg::ClearMemoryDlg(QDialog *parent, SSMprotocol *SSMPdev, SSMprotocol::CMlevel_dt level) { @@ -31,23 +37,15 @@ ClearMemoryDlg::ClearMemoryDlg(QDialog *parent, SSMprotocol *SSMPdev, SSMprotoco ClearMemoryDlg::CMresult_dt ClearMemoryDlg::run() { - CMresult_dt result = CMresult_success; - bool ok = false; - bool CMsuccess = false; CUtype cu_old; - std::string SYS_ID_old; - std::string ROM_ID_old; - SSMprotocol::state_dt CUstate_old; - int oldDCgroups = 0; - std::vector oldMBSWmetaList; - std::vector oldAdjVal; - bool tm = false; - bool enginerunning = false; - std::vector supAdj; - QEventLoop el; + SSMprotocol::CMprocedure_dt procedure; + StoppedOperation_dt operation; + CMresult_dt result; if (!_SSMPdev->CUtype(&cu_old)) return ClearMemoryDlg::CMresult_communicationError; + if (!_SSMPdev->clearMemoryProcedure(&procedure)) + return ClearMemoryDlg::CMresult_communicationError; // Let the user confirm the Clear Memory procedure: if (!confirmClearMemory(cu_old)) return ClearMemoryDlg::CMresult_aborted; @@ -59,22 +57,89 @@ ClearMemoryDlg::CMresult_dt ClearMemoryDlg::run() FSSM_WaitMsgBox waitmsgbox(_parent, waitstr); waitmsgbox.show(); // Save CU-state, prepare for Clear Memory: - CUstate_old = _SSMPdev->state(); - if (CUstate_old == SSMprotocol::state_DCreading) + result = stopCurrentOperation(&operation); + if (result != ClearMemoryDlg::CMresult_success) + { + waitmsgbox.close(); + return result; + } + // NOTE: it's currently not possible to call this function while actuator-test is in progress, so we don't need to care about running actuator-tests + + if (procedure == SSMprotocol::CMprocedure_direct) + return runDirectClearMemory(operation, &waitmsgbox); + return runIgnitionCycleClearMemory(cu_old, operation, &waitmsgbox); +} + + +ClearMemoryDlg::CMresult_dt ClearMemoryDlg::stopCurrentOperation(StoppedOperation_dt *operation) +{ + if (operation == NULL) + return ClearMemoryDlg::CMresult_communicationError; + + operation->state = _SSMPdev->state(); + if (operation->state == SSMprotocol::state_DCreading) { - if (!_SSMPdev->getLastDCgroupsSelection(&oldDCgroups)) + if (!_SSMPdev->getLastDCgroupsSelection(&operation->DCgroups)) return ClearMemoryDlg::CMresult_communicationError; if (!_SSMPdev->stopDCreading()) return ClearMemoryDlg::CMresult_communicationError; } - else if (CUstate_old == SSMprotocol::state_MBSWreading) + else if (operation->state == SSMprotocol::state_MBSWreading) { - if (!_SSMPdev->getLastMBSWselection(&oldMBSWmetaList)) + if (!_SSMPdev->getLastMBSWselection(&operation->MBSWmetaList)) return ClearMemoryDlg::CMresult_communicationError; if (!_SSMPdev->stopMBSWreading()) return ClearMemoryDlg::CMresult_communicationError; } - // NOTE: it's currently not possible to call this function while actuator-test is in progress, so we don't need to care about running actuator-tests + + return ClearMemoryDlg::CMresult_success; +} + + +ClearMemoryDlg::CMresult_dt ClearMemoryDlg::restoreStoppedOperation(const StoppedOperation_dt& operation) +{ + if (operation.state == SSMprotocol::state_DCreading) + { + if (!_SSMPdev->startDCreading(operation.DCgroups)) + return ClearMemoryDlg::CMresult_communicationError; + } + else if (operation.state == SSMprotocol::state_MBSWreading) + { + if (!_SSMPdev->startMBSWreading(operation.MBSWmetaList)) + return ClearMemoryDlg::CMresult_communicationError; + } + + return ClearMemoryDlg::CMresult_success; +} + + +ClearMemoryDlg::CMresult_dt ClearMemoryDlg::runDirectClearMemory(const StoppedOperation_dt& operation, FSSM_WaitMsgBox *waitmsgbox) +{ + bool ok = false; + bool CMsuccess = false; + + ok = _SSMPdev->clearMemory(_level, &CMsuccess); + if (waitmsgbox != NULL) + waitmsgbox->close(); + if (!ok || !CMsuccess) + return ClearMemoryDlg::CMresult_communicationError; + return restoreStoppedOperation(operation); +} + + +ClearMemoryDlg::CMresult_dt ClearMemoryDlg::runIgnitionCycleClearMemory(CUtype cu_old, const StoppedOperation_dt& operation, FSSM_WaitMsgBox *waitmsgbox) +{ + CMresult_dt result = CMresult_success; + bool ok = false; + bool CMsuccess = false; + std::string SYS_ID_old; + std::string ROM_ID_old; + std::vector oldAdjVal; + bool tm = false; + bool enginerunning = false; + std::vector supAdj; + QEventLoop el; + SYS_ID_old = _SSMPdev->getSysID(); if (!SYS_ID_old.length()) return ClearMemoryDlg::CMresult_communicationError; @@ -95,13 +160,15 @@ ClearMemoryDlg::CMresult_dt ClearMemoryDlg::run() QTimer::singleShot(800, &el, SLOT( quit() )); el.exec(); // Request user to switch ignition off and wait for communication error: - waitmsgbox.setText(tr("Please switch ignition OFF and be patient...")); + if (waitmsgbox != NULL) + waitmsgbox->setText(tr("Please switch ignition OFF and be patient...")); ok = _SSMPdev->waitForIgnitionOff(); // Wait 5 seconds QTimer::singleShot(5000, &el, SLOT( quit() )); el.exec(); // Close wait-message box: - waitmsgbox.close(); + if (waitmsgbox != NULL) + waitmsgbox->close(); if (!ok) return ClearMemoryDlg::CMresult_communicationError; // Request user to switch ignition on and ensure that CU is still the same: @@ -162,16 +229,9 @@ ClearMemoryDlg::CMresult_dt ClearMemoryDlg::run() } } // Restore last CU-state: - if (CUstate_old == SSMprotocol::state_DCreading) - { - if (!_SSMPdev->startDCreading(oldDCgroups)) - return ClearMemoryDlg::CMresult_communicationError; - } - else if (CUstate_old == SSMprotocol::state_MBSWreading) - { - if (!_SSMPdev->startMBSWreading(oldMBSWmetaList)) - return ClearMemoryDlg::CMresult_communicationError; - } + result = restoreStoppedOperation(operation); + if (result != ClearMemoryDlg::CMresult_success) + return result; // Return result: return result; } @@ -180,14 +240,17 @@ ClearMemoryDlg::CMresult_dt ClearMemoryDlg::run() bool ClearMemoryDlg::confirmClearMemory(CUtype cu_type) { int uc = 0; + SSMprotocol::CMprocedure_dt procedure = SSMprotocol::CMprocedure_ignitionCycle; // Create dialog QString winTitle = tr("Clear Memory"); QString confirmStr = tr("The Clear Memory procedure"); if (_level == SSMprotocol::CMlevel_2) confirmStr.append( tr(" (level 2)") ); confirmStr.append( '\n' + tr(" - clears the Diagnostic Codes") ); - confirmStr.append( '\n' + tr(" - resets all non-permanent Adjustment Values") ); - if ( cu_type == CUtype::Engine || ((cu_type == CUtype::Transmission) && (_level == SSMprotocol::CMlevel_2)) ) + _SSMPdev->clearMemoryProcedure(&procedure); + if (procedure == SSMprotocol::CMprocedure_ignitionCycle) + confirmStr.append( '\n' + tr(" - resets all non-permanent Adjustment Values") ); + if ( (procedure == SSMprotocol::CMprocedure_ignitionCycle) && (cu_type == CUtype::Engine || ((cu_type == CUtype::Transmission) && (_level == SSMprotocol::CMlevel_2))) ) confirmStr.append( '\n' + tr(" - resets the Control Units' learning values") ); confirmStr.append( "\n\n" + tr("Do you really want to clear the Control Units' memory") ); if (_level == SSMprotocol::CMlevel_2) diff --git a/src/ClearMemoryDlg.h b/src/ClearMemoryDlg.h index 2d6cd57..4ec991d 100644 --- a/src/ClearMemoryDlg.h +++ b/src/ClearMemoryDlg.h @@ -43,8 +43,21 @@ class ClearMemoryDlg : public QObject SSMprotocol *_SSMPdev; SSMprotocol::CMlevel_dt _level; + class StoppedOperation_dt + { + public: + StoppedOperation_dt(); + SSMprotocol::state_dt state; + int DCgroups; + std::vector MBSWmetaList; + }; + bool confirmClearMemory(CUtype cu_type); bool confirmAdjustmentValuesRestoration(); + CMresult_dt stopCurrentOperation(StoppedOperation_dt *operation); + CMresult_dt restoreStoppedOperation(const StoppedOperation_dt& operation); + CMresult_dt runDirectClearMemory(const StoppedOperation_dt& operation, FSSM_WaitMsgBox *waitmsgbox); + CMresult_dt runIgnitionCycleClearMemory(CUtype cu_old, const StoppedOperation_dt& operation, FSSM_WaitMsgBox *waitmsgbox); CMresult_dt restoreAdjustmentValues(std::vector oldAdjVal); CMresult_dt reconnect(CUtype cu, std::string SYS_ID_old, std::string ROM_ID_old); diff --git a/src/CmdLine.cpp b/src/CmdLine.cpp index 9fe7898..914ca05 100644 --- a/src/CmdLine.cpp +++ b/src/CmdLine.cpp @@ -32,6 +32,7 @@ Options:\n\ Supported values for are:\n\ engine\n\ transmission\n\ + tpms\n\ absvdc\n\ cruisectrl\n\ aircon\n\ diff --git a/src/ControlUnitDialog.cpp b/src/ControlUnitDialog.cpp index 844f2bb..cd7d68f 100644 --- a/src/ControlUnitDialog.cpp +++ b/src/ControlUnitDialog.cpp @@ -36,6 +36,7 @@ ControlUnitDialog::ControlUnitDialog(QString title, AbstractDiagInterface *diagI _setup_done = false; _mode = Mode::None; _content_DCs = NULL; + _content_LocalIdentifiers = NULL; _content_MBsSWs = NULL; _content_Adjustments = NULL; _content_SysTests = NULL; @@ -111,6 +112,12 @@ void ControlUnitDialog::addContent(ContentSelection csel) icon = QIcon(QString::fromUtf8(":/icons/chrystal/22x22/messagebox_warning.png")); checkable = true; } + else if (csel == ContentSelection::LocalIdentifiersMode) + { + title = tr("&Live Data"); + icon = QIcon(QString::fromUtf8(":/icons/oxygen/22x22/applications-utilities.png")); + checkable = true; + } else if (csel == ContentSelection::MBsSWsMode) { title = tr("&Measuring Blocks"); @@ -180,6 +187,8 @@ void ControlUnitDialog::addContent(ContentSelection csel) // Connect buttons with slots: if (csel == ContentSelection::DCsMode) connect( button, SIGNAL( clicked() ), this, SLOT( switchToDCsMode() ) ); + else if (csel == ContentSelection::LocalIdentifiersMode) + connect( button, SIGNAL( clicked() ), this, SLOT( switchToLocalIdentifiersMode() ) ); else if (csel == ContentSelection::MBsSWsMode) connect( button, SIGNAL( clicked() ), this, SLOT( switchToMBsSWsMode() ) ); else if (csel == ContentSelection::AdjustmentsMode) @@ -315,6 +324,12 @@ bool ControlUnitDialog::setup(ContentSelection csel, QStringList cmdline_args) goto commError; setContentSelectionButtonEnabled(ContentSelection::ClearMemory2Fcn, supported); } + if (contentSupported(ContentSelection::LocalIdentifiersMode)) + { + if (!_SSMPdev->hasLocalIdentifierData(&supported)) + goto commError; + setContentSelectionButtonEnabled(ContentSelection::LocalIdentifiersMode, supported); + } // NOTE: enable modes unconditionally, UI contents are deactivated if unsupported by the CU setContentSelectionButtonEnabled(ContentSelection::DCsMode, true); setContentSelectionButtonEnabled(ContentSelection::MBsSWsMode, true); @@ -409,6 +424,13 @@ bool ControlUnitDialog::prepareContentWidget(Mode mode) setContentWidget(tr("Diagnostic Codes:"), _content_DCs); _content_DCs->show(); } + else if (mode == Mode::LocalIdentifiers) + { + setContentSelectionButtonChecked(ContentSelection::LocalIdentifiersMode, true); + _content_LocalIdentifiers = new CUcontent_LocalIdentifiers(); + setContentWidget(tr("Live Data:"), _content_LocalIdentifiers); + _content_LocalIdentifiers->show(); + } else if (mode == Mode::MBsSWs) { setContentSelectionButtonChecked(ContentSelection::MBsSWsMode, true); @@ -452,6 +474,11 @@ void ControlUnitDialog::deleteContentWidgets() delete(_content_DCs); _content_DCs = NULL; } + if (_content_LocalIdentifiers != NULL) + { + delete(_content_LocalIdentifiers); + _content_LocalIdentifiers = NULL; + } if (_content_MBsSWs != NULL) { delete(_content_MBsSWs); @@ -545,6 +572,8 @@ bool ControlUnitDialog::getModeForContentSelection(ContentSelection csel, Mode * { if ((csel == ContentSelection::DCsMode) || (csel == ContentSelection::ClearMemoryFcn) || (csel == ContentSelection::ClearMemory2Fcn)) *mode = Mode::DCs; + else if (csel == ContentSelection::LocalIdentifiersMode) + *mode = Mode::LocalIdentifiers; else if (csel == ContentSelection::MBsSWsMode) *mode = Mode::MBsSWs; else if (csel == ContentSelection::AdjustmentsMode) @@ -578,6 +607,24 @@ SSMprotocol::CUsetupResult_dt ControlUnitDialog::probeProtocol(CUtype CUtype) if receive buffer flushing doesn't work reliable with the used serial port driver ! */ SSMprotocol::CUsetupResult_dt result = SSMprotocol::result_commError; + if (CUtype == CUtype::TPMS) + { + if (_diagInterface->connect(AbstractDiagInterface::protocol_type::SSM3_ISO14230)) + { + _SSMPdev = new SSM3protocolTPMS(_diagInterface, _language); + result = _SSMPdev->setupCUdata(CUtype); + if (result == SSMprotocol::result_success) + { + connect(_SSMPdev, SIGNAL(commError()), this, SLOT(communicationError())); + } + else + { + delete _SSMPdev; + _SSMPdev = NULL; + _diagInterface->disconnect(); + } + } + } if ((CUtype == CUtype::Engine) || (CUtype == CUtype::Transmission)) { // Probe SSM2-protocol: @@ -612,7 +659,7 @@ SSMprotocol::CUsetupResult_dt ControlUnitDialog::probeProtocol(CUtype CUtype) _SSMPdev = NULL; } } - if (_SSMPdev == NULL) + if ((_SSMPdev == NULL) && (CUtype != CUtype::TPMS)) { // Probe SSM1-protocol: if (_diagInterface->connect(AbstractDiagInterface::protocol_type::SSM1)) @@ -735,6 +782,29 @@ void ControlUnitDialog::switchToDCsMode() } +void ControlUnitDialog::switchToLocalIdentifiersMode() +{ + bool com_err = false; + if (_mode == Mode::LocalIdentifiers) return; + // Show wait-message: + FSSM_WaitMsgBox waitmsgbox(this, tr("Switching to Live Data... Please wait !")); + waitmsgbox.show(); + // Save content settings: + saveContentSettings(); + // Delete current content widget: + deleteContentWidgets(); + // Create and insert new content widget: + if (prepareContentWidget(Mode::LocalIdentifiers)) + // Start Live Data mode: + com_err = !startLocalIdentifiersMode(); + // Close wait-message: + waitmsgbox.close(); + // Check for communication error: + if (com_err) + communicationError(); +} + + void ControlUnitDialog::switchToMBsSWsMode() { bool com_err = false; @@ -809,6 +879,8 @@ bool ControlUnitDialog::startMode(Mode mode) bool ok = true; if (mode == Mode::DCs) ok = startDCsMode(); + else if (mode == Mode::LocalIdentifiers) + ok = startLocalIdentifiersMode(); else if (mode == Mode::MBsSWs) ok = startMBsSWsMode(); else if (mode == Mode::Adjustments) @@ -841,6 +913,18 @@ bool ControlUnitDialog::startDCsMode() } +bool ControlUnitDialog::startLocalIdentifiersMode() +{ + if (_content_LocalIdentifiers == NULL) + return false; + if (!_content_LocalIdentifiers->setup(_SSMPdev)) + return false; + connect(_content_LocalIdentifiers, SIGNAL(error()), this, SLOT(close())); + _mode = Mode::LocalIdentifiers; + return true; +} + + bool ControlUnitDialog::startMBsSWsMode() { if (_content_MBsSWs == NULL) @@ -895,6 +979,7 @@ void ControlUnitDialog::runClearMemory(SSMprotocol::CMlevel_dt level) { bool ok = false; ClearMemoryDlg::CMresult_dt result; + // Create "Clear Memory"-dialog: ClearMemoryDlg cmdlg(this, _SSMPdev, level); // Temporary disconnect from "communication error"-signal: diff --git a/src/ControlUnitDialog.h b/src/ControlUnitDialog.h index 103394e..9babc40 100644 --- a/src/ControlUnitDialog.h +++ b/src/ControlUnitDialog.h @@ -25,6 +25,7 @@ #include "ui_ControlUnitDialog.h" #include "CUinfo_abstract.h" #include "CUcontent_DCs_abstract.h" +#include "CUcontent_LocalIdentifiers.h" #include "CUcontent_MBsSWs.h" #include "CUcontent_Adjustments.h" #include "CUcontent_sysTests.h" @@ -35,20 +36,19 @@ #include "FSSMdialogs.h" - class ControlUnitDialog : public QDialog, private Ui::ControlUnit_Dialog { Q_OBJECT public: - enum class ContentSelection {DCsMode, MBsSWsMode, AdjustmentsMode, SysTestsMode, ClearMemoryFcn, ClearMemory2Fcn}; + enum class ContentSelection {DCsMode, LocalIdentifiersMode, MBsSWsMode, AdjustmentsMode, SysTestsMode, ClearMemoryFcn, ClearMemory2Fcn}; ControlUnitDialog(QString title, AbstractDiagInterface *diagInterface, QString language, bool preferSSM2protocolVariantISO14230 = false); ~ControlUnitDialog(); bool setup(ContentSelection csel, QStringList cmdline_args = QStringList()); protected: - enum class Mode {None, DCs, MBsSWs, Adjustments, SysTests}; + enum class Mode {None, DCs, LocalIdentifiers, MBsSWs, Adjustments, SysTests}; void addContent(ContentSelection csel); bool contentSupported(ContentSelection csel); @@ -62,6 +62,7 @@ class ControlUnitDialog : public QDialog, private Ui::ControlUnit_Dialog CUinfo_abstract *_infoWidget; QWidget *_contentWidget; CUcontent_DCs_abstract *_content_DCs; + CUcontent_LocalIdentifiers *_content_LocalIdentifiers; CUcontent_MBsSWs *_content_MBsSWs; CUcontent_Adjustments *_content_Adjustments; CUcontent_sysTests *_content_SysTests; @@ -92,6 +93,7 @@ class ControlUnitDialog : public QDialog, private Ui::ControlUnit_Dialog bool handleActuatorTests(FSSM_ProgressDialog *statusmsgbox); bool startMode(Mode mode); bool startDCsMode(); + bool startLocalIdentifiersMode(); bool startMBsSWsMode(); bool startAdjustmentsMode(); bool startSystemOperationTestsMode(); @@ -101,6 +103,7 @@ class ControlUnitDialog : public QDialog, private Ui::ControlUnit_Dialog private slots: void switchToDCsMode(); + void switchToLocalIdentifiersMode(); void switchToMBsSWsMode(); void switchToAdjustmentsMode(); void switchToSystemOperationTestsMode(); diff --git a/src/FreeSSM.cpp b/src/FreeSSM.cpp index b51ca18..1181957 100644 --- a/src/FreeSSM.cpp +++ b/src/FreeSSM.cpp @@ -223,6 +223,7 @@ FreeSSM::FreeSSM(QApplication *app) // CONNECT SIGNALS/SLOTS: connect( engine_pushButton, SIGNAL( released() ), this, SLOT( engine() ) ); connect( transmission_pushButton, SIGNAL( released() ), this, SLOT( transmission() ) ); + connect( tpms_pushButton, SIGNAL( released() ), this, SLOT( tpms() ) ); connect( absvdc_pushButton, SIGNAL( released() ), this, SLOT( abs() ) ); connect( cruisecontrol_pushButton, SIGNAL( released() ), this, SLOT( cruisecontrol() ) ); connect( aircon_pushButton, SIGNAL( released() ), this, SLOT( aircon() ) ); @@ -240,6 +241,7 @@ FreeSSM::~FreeSSM() disconnect( _dump_action, SIGNAL( triggered() ), this, SLOT( dumpCUdata() ) ); disconnect( engine_pushButton, SIGNAL( released() ), this, SLOT( engine() ) ); disconnect( transmission_pushButton, SIGNAL( released() ), this, SLOT( transmission() ) ); + disconnect( tpms_pushButton, SIGNAL( released() ), this, SLOT( tpms() ) ); disconnect( absvdc_pushButton, SIGNAL( released() ), this, SLOT( abs() ) ); disconnect( cruisecontrol_pushButton, SIGNAL( released() ), this, SLOT( cruisecontrol() ) ); disconnect( aircon_pushButton, SIGNAL( released() ), this, SLOT( aircon() ) ); @@ -310,6 +312,29 @@ void FreeSSM::transmission(QStringList cmdline_args) } +void FreeSSM::tpms(QStringList cmdline_args) +{ + if (_dumping) return; + ControlUnitDialog::ContentSelection csel = ControlUnitDialog::ContentSelection::DCsMode; + if (!getContentSelectionFromCmdLine(&cmdline_args, &csel)) + exit(ERROR_BADCMDLINEARGS); + AbstractDiagInterface *diagInterface = initInterface(); + if (diagInterface) + { + TPMSdialog *tpmsdialog = new TPMSdialog(diagInterface, _language); +#ifdef SMALL_RESOLUTION + tpmsdialog->showFullScreen(); +#else + tpmsdialog->show(); +#endif + if (tpmsdialog->setup(csel, cmdline_args)) + tpmsdialog->exec(); + delete tpmsdialog; + delete diagInterface; + } +} + + void FreeSSM::abs(QStringList cmdline_args) { if (_dumping) return; @@ -710,6 +735,10 @@ bool FreeSSM::getContentSelectionFromCmdLine(QStringList *cmdline_args, ControlU { *csel = ControlUnitDialog::ContentSelection::MBsSWsMode; } + else if ((selstr == "localidentifiers") || (selstr == "livedata")) + { + *csel = ControlUnitDialog::ContentSelection::LocalIdentifiersMode; + } else if (selstr == "adjustments") { *csel = ControlUnitDialog::ContentSelection::AdjustmentsMode; diff --git a/src/FreeSSM.h b/src/FreeSSM.h index d99870b..e46305f 100644 --- a/src/FreeSSM.h +++ b/src/FreeSSM.h @@ -32,6 +32,7 @@ #include "SSMP2communication.h" #include "libFSSM.h" #include "EngineDialog.h" +#include "TPMSdialog.h" #include "TransmissionDialog.h" #include "ABSdialog.h" #include "CruiseControlDialog.h" @@ -71,6 +72,7 @@ class FreeSSM : public QMainWindow, private Ui::FreeSSM_MainWindow public slots: void engine(QStringList cmdline_args = QStringList()); void transmission(QStringList cmdline_args = QStringList()); + void tpms(QStringList cmdline_args = QStringList()); void abs(QStringList cmdline_args = QStringList()); void cruisecontrol(QStringList cmdline_args = QStringList()); void aircon(QStringList cmdline_args = QStringList()); diff --git a/src/TPMSdialog.cpp b/src/TPMSdialog.cpp new file mode 100644 index 0000000..84e3453 --- /dev/null +++ b/src/TPMSdialog.cpp @@ -0,0 +1,79 @@ +/* + * TPMSdialog.cpp - TPMS Control Unit dialog + * + * Copyright (C) 2012 L1800Turbo, 2008-2019 Comer352L, 2024 jimihimi + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "TPMSdialog.h" +#include "CUcontent_DCs_stopCodes.h" + + +TPMSdialog::TPMSdialog(AbstractDiagInterface *diagInterface, QString language) : ControlUnitDialog(controlUnitName(), diagInterface, language) +{ + // Add information widget: + setInfoWidget( new CUinfo_simple() ); + // Add content: + addContent(ContentSelection::DCsMode); + addContent(ContentSelection::LocalIdentifiersMode); + addContent(ContentSelection::ClearMemoryFcn); +} + + +QString TPMSdialog::systemName() +{ + return tr("TPMS"); +} + + +QString TPMSdialog::controlUnitName() +{ + return tr("TPMS Control Unit"); +} + + +CUtype TPMSdialog::controlUnitType() +{ + return CUtype::TPMS; +} + + +bool TPMSdialog::systemRequiresManualON() +{ + return false; +} + + +CUcontent_DCs_abstract * TPMSdialog::allocate_DCsContentWidget() +{ + return new CUcontent_DCs_stopCodes(); +} + + +bool TPMSdialog::displayExtendedCUinfo(SSMprotocol *SSMPdev, CUinfo_abstract *abstractInfoWidget, FSSM_ProgressDialog*) +{ + std::vector supportedMBs; + std::vector supportedSWs; + if (SSMPdev == NULL) + return false; + CUinfo_simple *infoWidget = dynamic_cast(abstractInfoWidget); + if (infoWidget == NULL) + return true; // NOTE: no communication error + // Number of supported MBs / SWs: + if ((!SSMPdev->getSupportedMBs(&supportedMBs)) || (!SSMPdev->getSupportedSWs(&supportedSWs))) + return false; // commError + infoWidget->setNrOfSupportedMBsSWs(supportedMBs.size(), supportedSWs.size()); + return true; +} diff --git a/src/TPMSdialog.h b/src/TPMSdialog.h new file mode 100644 index 0000000..576602f --- /dev/null +++ b/src/TPMSdialog.h @@ -0,0 +1,59 @@ +/* + * TPMSdialog.h - TPMS dialog + * + * Copyright (C) 2012 L1800Turbo, 2008-2019 Comer352L, 2024 jimihimi + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TPMSDIALOG_H +#define TPMSDIALOG_H + + +#ifdef __WIN32__ + #include "windows\serialCOM.h" +#elif defined __linux__ + #include "linux/serialCOM.h" +#else + #error "Operating system not supported !" +#endif +#include +#include "ControlUnitDialog.h" +#include "CUinfo_simple.h" +#include "AbstractDiagInterface.h" +#include "SSMCUdata.h" +#include "SSMprotocol.h" + + + +class TPMSdialog : public ControlUnitDialog +{ + Q_OBJECT + +public: + TPMSdialog(AbstractDiagInterface *diagInterface, QString language); + +private: + QString systemName(); + QString controlUnitName(); + CUtype controlUnitType(); + bool systemRequiresManualON(); + CUcontent_DCs_abstract * allocate_DCsContentWidget(); + bool displayExtendedCUinfo(SSMprotocol *SSMPdev, CUinfo_abstract *abstractInfoWidget, FSSM_ProgressDialog *initstatusmsgbox); + +}; + + + +#endif diff --git a/src/main.cpp b/src/main.cpp index dde16ef..547f8e2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -52,6 +52,8 @@ static bool applyCmdLineStartupOptions(FreeSSM *freessm_mainwindow, QStringList freessm_mainwindow->engine(cmdline_args); else if (cu_str == "transmission") freessm_mainwindow->transmission(cmdline_args); + else if (cu_str == "tpms") + freessm_mainwindow->tpms(cmdline_args); else if (cu_str == "absvdc") freessm_mainwindow->abs(cmdline_args); else if (cu_str == "cruisectrl") diff --git a/ui/About.ui b/ui/About.ui index 08fc812..c2c1f07 100644 --- a/ui/About.ui +++ b/ui/About.ui @@ -511,7 +511,7 @@ This program is NOT A PRODUCT OF FUJI HEAVY INDUSTRIES LTD. OR ANY SUBARU®-ASSO 170 - 320 + 330 330 20 @@ -530,7 +530,7 @@ This program is NOT A PRODUCT OF FUJI HEAVY INDUSTRIES LTD. OR ANY SUBARU®-ASSO 10 - 320 + 330 150 20 @@ -543,7 +543,7 @@ This program is NOT A PRODUCT OF FUJI HEAVY INDUSTRIES LTD. OR ANY SUBARU®-ASSO 10 - 170 + 190 511 20 @@ -559,7 +559,7 @@ This program is NOT A PRODUCT OF FUJI HEAVY INDUSTRIES LTD. OR ANY SUBARU®-ASSO 10 - 230 + 250 511 20 @@ -575,7 +575,7 @@ This program is NOT A PRODUCT OF FUJI HEAVY INDUSTRIES LTD. OR ANY SUBARU®-ASSO 10 - 260 + 280 511 20 @@ -592,7 +592,7 @@ This program is NOT A PRODUCT OF FUJI HEAVY INDUSTRIES LTD. OR ANY SUBARU®-ASSO 10 50 - 131 + 111 20 @@ -606,14 +606,19 @@ This program is NOT A PRODUCT OF FUJI HEAVY INDUSTRIES LTD. OR ANY SUBARU®-ASSO - 140 + 130 50 - 380 - 111 + 400 + 120 + + + 10 + + - <html><head/><body><p>L1800Turbo (SSM1 ECU definitions, testing)<br/>MartinX (SSM2 definitions, bugfix)<br/>Antoine Giniès (background picture, Copyright ©)<br/>Honza Šolc (SSM1 ECU investigations, testing)<br/>Nikolay Marinov (UI for small screen resolutions)<br/>madanadam (Turkish translation)</p></body></html> + <html><head/><body><p>L1800Turbo (SSM1 defs/testing)<br/>MartinX (SSM2 defs/bugfix)<br/>Antoine Giniès (background)<br/>Honza Šolc (SSM1 research/testing)<br/>Nikolay Marinov (small UI)<br/>James Hyatt (TPMS, SSM3)<br/>madanadam (Turkish)</p></body></html> Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop @@ -623,7 +628,7 @@ This program is NOT A PRODUCT OF FUJI HEAVY INDUSTRIES LTD. OR ANY SUBARU®-ASSO 10 - 200 + 220 511 20 diff --git a/ui/FreeSSM.ui b/ui/FreeSSM.ui index e1d8522..20db97a 100644 --- a/ui/FreeSSM.ui +++ b/ui/FreeSSM.ui @@ -51,7 +51,7 @@ - E&xit + E&xit @@ -93,7 +93,7 @@ - &Engine + &Engine @@ -116,7 +116,7 @@ - &Transmission + &Transmission @@ -139,7 +139,7 @@ - A&BS/VDC + A&BS/VDC @@ -165,7 +165,7 @@ - &Cruise Control + &Cruise Control @@ -201,6 +201,29 @@ + + + + 379 + 24 + 172 + 40 + + + + Ti&re Pressure + + + + :/icons/freessm/64x64/TirePressure.png:/icons/freessm/64x64/TirePressure.png + + + + 32 + 32 + + + @@ -231,7 +254,7 @@ - &Help + &Help @@ -254,7 +277,7 @@ - &About + &About @@ -277,7 +300,7 @@ - &Preferences + &Preferences @@ -313,6 +336,7 @@ engine_pushButton transmission_pushButton + tpms_pushButton absvdc_pushButton cruisecontrol_pushButton aircon_pushButton diff --git a/ui/small/About.ui b/ui/small/About.ui index 62d7671..ff3f3ac 100644 --- a/ui/small/About.ui +++ b/ui/small/About.ui @@ -669,7 +669,7 @@ This program is NOT A PRODUCT OF FUJI HEAVY INDUSTRIES LTD. OR ANY SUBARU®-ASSO - <html><head/><body><p>L1800Turbo (SSM1 ECU definitions, testing)<br/>MartinX (SSM2 definitions, bugfix)<br/>Antoine Giniès (background picture, Copyright ©)<br/>Honza Šolc (SSM1 ECU investigations, testing)<br/>Nikolay Marinov (UI for small screen resolutions)<br/>madanadam (Turkish translation)</p></body></html> + <html><head/><body><p>L1800Turbo (SSM1 defs/testing)<br/>MartinX (SSM2 defs/bugfix)<br/>Antoine Giniès (background)<br/>Honza Šolc (SSM1 research/testing)<br/>Nikolay Marinov (small UI)<br/>James Hyatt (TPMS, SSM3)<br/>madanadam (Turkish)</p></body></html> Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop diff --git a/ui/small/FreeSSM.ui b/ui/small/FreeSSM.ui index c493d49..8da5c92 100644 --- a/ui/small/FreeSSM.ui +++ b/ui/small/FreeSSM.ui @@ -230,6 +230,39 @@ + + + + 0 + 0 + + + + + 12 + 50 + false + + + + PointingHandCursor + + + Ti&re Pressure + + + + :/icons/freessm/64x64/TirePressure.png:/icons/freessm/64x64/TirePressure.png + + + + 32 + 32 + + + + + @@ -262,7 +295,7 @@ - + @@ -295,7 +328,7 @@ - + @@ -328,7 +361,7 @@ - +