diff --git a/FreeSSM.pro b/FreeSSM.pro
index 60516633..f2ed51cf 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 \
@@ -48,6 +49,8 @@ HEADERS += src/FreeSSM.h \
src/CUcontent_DCs_engine.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 \
@@ -69,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 \
@@ -89,6 +93,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 \
@@ -100,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 536125d3..5b14a373 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 a6738ec3..289ba84e 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 00000000..336c91a9
Binary files /dev/null and b/resources/icons/freessm/64x64/TirePressure.png differ
diff --git a/src/AbstractDiagInterface.cpp b/src/AbstractDiagInterface.cpp
index c047b064..44efa198 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 d656f654..762f769f 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/CUcontent_DCs_abstract.cpp b/src/CUcontent_DCs_abstract.cpp
index 6f37ea31..ae3c2974 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 00000000..4ddae6f8
--- /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 00000000..7436463c
--- /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 a5632266..d2c6c521 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 2d6cd57a..4ec991df 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 9fe7898b..914ca051 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 844f2bba..cd7d68f4 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 103394e4..9babc40f 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 b51ca189..11819577 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 d99870b0..e46305fd 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/J2534DiagInterface.cpp b/src/J2534DiagInterface.cpp
index 94a2b4c3..658f7ea3 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/LocalIdentifier.h b/src/LocalIdentifier.h
new file mode 100644
index 00000000..c260e647
--- /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 00000000..7f8be2fa
--- /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 9fb844b7..20ed9bd6 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 95cc224b..0bc79287 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 9e8b34b9..6483ec82 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
diff --git a/src/SerialPassThroughDiagInterface.cpp b/src/SerialPassThroughDiagInterface.cpp
index 001aa362..010286ce 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 ))
diff --git a/src/TPMSdialog.cpp b/src/TPMSdialog.cpp
new file mode 100644
index 00000000..84e3453b
--- /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 00000000..576602f1
--- /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 dde16ef1..547f8e2c 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 08fc8129..c2c1f072 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 e1d85222..20db97aa 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 62d76710..ff3f3ac2 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 c493d490..8da5c924 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 @@
- -
+
-