From 98b0b1d1c92392cda4894ccd89ab560673c89a99 Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Thu, 12 Oct 2017 21:47:27 -0400 Subject: [PATCH 01/11] More implementation in the ISOTP/UDS decoder (well, all UDS decoding changes in this commit) --- bus_protocols/uds_handler.cpp | 105 +++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 2 deletions(-) diff --git a/bus_protocols/uds_handler.cpp b/bus_protocols/uds_handler.cpp index 86f7551..3c3884b 100644 --- a/bus_protocols/uds_handler.cpp +++ b/bus_protocols/uds_handler.cpp @@ -23,6 +23,8 @@ QVector UDS_COMM_CTRL_SUB = { {0,"COMM_NORMAL", "Enable both Rx and Tx of normal messages"}, {1,"COMM_DIS_TX", "Enable reception of normal messages but don't Tx them"}, {3,"COMM_DIS_ALL", "Disable both Rx and Tx of non-diagnostics messages"}, + {4,"COMM_DIS_TX_ENH", "Addressed bus master should turn off TX on related sub-bus"}, + {5,"COMM_ENHANC", "Addressed bus master should set related sub-bus to app scheduling mode"}, }; QVector UDS_ROUTINE_SUB = { @@ -319,6 +321,8 @@ QString UDS_HANDLER::getDetailedMessageAnalysis(const UDS_MESSAGE &msg) { QString buildString; bool isResponse = true; + int dataSize; + int addrSize; if (msg.isErrorReply) { @@ -384,8 +388,15 @@ QString UDS_HANDLER::getDetailedMessageAnalysis(const UDS_MESSAGE &msg) else buildString.append("\nNo powerdown time returned"); break; case UDS_SERVICES::COMM_CTRL: - //Comm control has two parameters, sub funct and the next byte should be 1. But it's always one so ignore for now - buildString.append("Comm type: " + getLongDesc(UDS_COMM_CTRL_SUB, msg.subFunc)); + //Comm control has potentially a lot of parameters. control type, comm type, nodeID + buildString.append("Control type: " + getLongDesc(UDS_COMM_CTRL_SUB, msg.subFunc)); + if (msg.data.length() > 1) + buildString.append("\nComm Type: " + QString::number(msg.data[1])); //TODO: no attempt to interpret yet + if (msg.data.length() > 3) + { + int nodeID = (msg.data[2] * 256 + msg.data[3]); + buildString.append("\nNode ID: " + Utility::formatHexNum(nodeID)); + } break; case UDS_SERVICES::SECURITY_ACCESS: if ((msg.subFunc % 2) == 1) @@ -423,6 +434,96 @@ QString UDS_HANDLER::getDetailedMessageAnalysis(const UDS_MESSAGE &msg) buildString.append("\nECU is now unlocked"); } break; + case UDS_SERVICES::READ_BY_ID: + //parameter is groups of two bytes, each of which specify an ID to read + if (msg.data.length() > 2) + { + uint32_t id; + for (int i = 1; i < msg.data.length(); i = i + 2) + { + id = (msg.data[i] * 256) + msg.data[i+1]; + buildString.append("\nID to read: " + Utility::formatHexNum(id)); + } + } + break; + case UDS_SERVICES::READ_BY_ID + 0x40: //reply + buildString.append("Reply is non-standard and so no decoding is done. The format is (ID) followed by how ever much data that ID returns, followed by more ID/data pairs if applicable.\nPayload: "); + for (int i = 1; i < msg.data.length(); i++) + { + buildString.append(Utility::formatHexNum(msg.data[i]) + " "); + } + break; + case UDS_SERVICES::READ_BY_ADDR: + //subfunc byte specifies address and length format, then address, then size + dataSize = msg.subFunc >> 4; + addrSize = msg.subFunc & 0xF; + if (msg.data.length() > (dataSize + addrSize)) + { + buildString.append("Address: 0x"); + for (int i = 0; i < addrSize; i++) buildString.append(QString::number(msg.data[1+i], 16).toUpper().rightJustified(2,'0')); + buildString.append("\nSize: 0x"); + for (int i = 0; i < dataSize; i++) buildString.append(QString::number(msg.data[1+i+addrSize], 16).toUpper().rightJustified(2,'0')); + } + else + { + buildString.append("Message has insufficient bytes to properly decode address and size!"); + } + break; + case UDS_SERVICES::READ_BY_ADDR + 0x40: + buildString.append("Reply is a raw packet of data of the size requested.\nPayload: "); + for (int i = 1; i < msg.data.length(); i++) + { + buildString.append(Utility::formatHexNum(msg.data[i]) + " "); + } + break; + case UDS_SERVICES::WRITE_BY_ID: + break; + case UDS_SERVICES::ROUTINE_CTRL: + buildString.append("Routine Control: " + getLongDesc(UDS_ROUTINE_SUB, msg.subFunc)); + if (msg.data.length() > 2) + { + int routineID; + routineID = (msg.data[1] * 256 + msg.data[2]); + buildString.append("\nRoutine ID: " + Utility::formatHexNum(routineID)); + } + if (msg.data.length() > 3) + { + buildString.append("\nParameter bytes to routine: "); + for (int i = 4; i < msg.data.length(); i++) + { + buildString.append(Utility::formatHexNum(msg.data[i]) + " "); + } + } + break; + case UDS_SERVICES::ROUTINE_CTRL + 0x40: + buildString.append("Routine Control: " + getLongDesc(UDS_ROUTINE_SUB, msg.subFunc)); + if (msg.data.length() > 2) + { + int routineID; + routineID = (msg.data[1] * 256 + msg.data[2]); + buildString.append("\nRoutine ID: " + Utility::formatHexNum(routineID)); + } + if (msg.data.length() > 3) + { + buildString.append("\nBytes returned by routine: "); + for (int i = 4; i < msg.data.length(); i++) + { + buildString.append(Utility::formatHexNum(msg.data[i]) + " "); + } + } + break; + case UDS_SERVICES::REQUEST_DOWNLOAD: + break; + case UDS_SERVICES::REQUEST_UPLOAD: + break; + case UDS_SERVICES::TRANSFER_DATA: + break; + case UDS_SERVICES::REQ_TRANS_EXIT: + break; + case UDS_SERVICES::REQ_FILE_TRANS: + break; + case UDS_SERVICES::WRITE_BY_ADDR: + break; } } From bb3fee1a121c01c263aff6da714fac4311f211ae Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Wed, 18 Oct 2017 21:47:47 -0400 Subject: [PATCH 02/11] Slight change to description of P2 in UDS decoder. --- bus_protocols/uds_handler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bus_protocols/uds_handler.cpp b/bus_protocols/uds_handler.cpp index 3c3884b..e9e0ed0 100644 --- a/bus_protocols/uds_handler.cpp +++ b/bus_protocols/uds_handler.cpp @@ -365,9 +365,9 @@ QString UDS_HANDLER::getDetailedMessageAnalysis(const UDS_MESSAGE &msg) else { int p2 = msg.data[1] * 256 + msg.data[2]; - buildString.append("\nP2MAX: " + QString::number(p2) + "ms"); + buildString.append("\nP2MAX (Max Wait / Resp Time): " + QString::number(p2) + "ms"); p2 = (msg.data[3] * 256 + msg.data[4]) * 10; - buildString.append("\nP2*MAX: " + QString::number(p2) + "ms"); + buildString.append("\nP2 Ext MAX: " + QString::number(p2) + "ms"); } break; case UDS_SERVICES::ECU_RESET: From 383ee8fe19f2e6d0233f4594df5849c45ff758a8 Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Wed, 18 Oct 2017 21:48:13 -0400 Subject: [PATCH 03/11] Big changes to connection window to make it more intuitive. Also brings window closer to supporting M2RET devices better. --- connections/canconnectionmodel.cpp | 109 +++++++++++++++++++++++++---- connections/canconnectionmodel.h | 4 ++ connections/connectionwindow.cpp | 81 +++++---------------- ui/connectionwindow.ui | 86 +++++------------------ 4 files changed, 131 insertions(+), 149 deletions(-) diff --git a/connections/canconnectionmodel.cpp b/connections/canconnectionmodel.cpp index 726c334..dd88ad9 100644 --- a/connections/canconnectionmodel.cpp +++ b/connections/canconnectionmodel.cpp @@ -40,10 +40,10 @@ QVariant CANConnectionModel::headerData(int section, Qt::Orientation orientation return QString(tr("Single Wire")); break; case 6: - return QString(tr("Status")); + return QString(tr("Active")); break; case 7: - return QString(tr("Active")); + return QString(tr("Status")); break; } } @@ -54,11 +54,10 @@ QVariant CANConnectionModel::headerData(int section, Qt::Orientation orientation return QVariant(); } - int CANConnectionModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); - return 7; + return 8; } @@ -75,22 +74,87 @@ int CANConnectionModel::rowCount(const QModelIndex &parent) const return rows; } +Qt::ItemFlags CANConnectionModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return Qt::ItemFlag::NoItemFlags; + + int busId; + CANConnection *conn_p = getAtIdx(index.row(), busId); + if (!conn_p) return Qt::ItemFlag::NoItemFlags; + + //you can't set speed, single wire, or listen only on socketcan devices so + //detect if we're using GVRET where you can and turn that functionality on + bool editParams = false; + if (conn_p->getType() == CANCon::GVRET_SERIAL) editParams = true; + + switch (index.column()) + { + case 3: //speed + if (editParams) return Qt::ItemFlag::ItemIsEditable | Qt::ItemFlag::ItemIsEnabled; + else return Qt::ItemFlag::NoItemFlags; + break; + case 4: //listen only + case 5: //single wire + if (editParams) return Qt::ItemFlag::ItemIsEditable | Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsUserCheckable; + else return Qt::ItemFlag::NoItemFlags; + break; + case 6: //enabled + return Qt::ItemFlag::ItemIsEditable | Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsUserCheckable; + break; + default: + return Qt::ItemFlag::ItemIsEnabled; + break; + } +} + +bool CANConnectionModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + qDebug() << "setData: " << index.row() << ":" << index.column() << " role: " << role << " Val: " << value; + + int busId; + CANConnection *conn_p = getAtIdx(index.row(), busId); + if (!conn_p) return false; + CANBus bus; + bool ret; + ret = conn_p->getBusSettings(busId, bus); + if (!ret) return false; + + switch (index.column()) + { + case 3: //speed + bus.speed = value.toInt(); + break; + case 4: //listen only + bus.listenOnly = value.toBool(); + break; + case 5: //single wire + bus.singleWire = value.toBool(); + break; + case 6: //active + bus.active = value.toBool(); + break; + } + conn_p->setBusSettings(busId, bus); + return true; +} QVariant CANConnectionModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); + int busId; + CANConnection *conn_p = getAtIdx(index.row(), busId); + CANBus bus; + bool ret; + ret = conn_p->getBusSettings(busId, bus); + bool isSocketCAN = (conn_p->getType() == CANCon::SOCKETCAN) ? true: false; if (role == Qt::DisplayRole) { - int busId; - CANConnection *conn_p = getAtIdx(index.row(), busId); if(!conn_p) return QVariant(); - CANBus bus; - bool ret; - ret = conn_p->getBusSettings(busId, bus); if(!ret) return QVariant(); switch (index.column()) @@ -114,18 +178,34 @@ QVariant CANConnectionModel::data(const QModelIndex &index, int role) const else qDebug() << "Tried to show connection port but connection was NULL"; break; case 3: //speed - return QString::number(bus.speed); + if (!isSocketCAN) return QString::number(bus.speed); + else return QString("N/A"); case 4: //Listen Only - return (bus.listenOnly) ? "True" : "False"; + return QVariant(); case 5: //Single Wire - return (bus.singleWire) ? "True" : "False"; + return QVariant(); case 6: //Status - return (conn_p->getStatus()==CANCon::CONNECTED) ? "Connected" : "Not Connected"; + return QVariant(); case 7: //Active - return (bus.active) ? "True" : "False"; + return (conn_p->getStatus()==CANCon::CONNECTED) ? "Connected" : "Not Connected"; default: {} } } + if (role == Qt::CheckStateRole) + { + switch (index.column()) + { + case 4: + return (bus.listenOnly) ? Qt::Checked : Qt::Unchecked; + break; + case 5: + return (bus.singleWire) ? Qt::Checked : Qt::Unchecked; + break; + case 6: + return (bus.active) ? Qt::Checked : Qt::Unchecked; + break; + } + } return QVariant(); } @@ -172,7 +252,6 @@ CANConnection* CANConnectionModel::getAtIdx(int pIdx, int& pBusId) const return NULL; } - void CANConnectionModel::refresh(int pIndex) { QModelIndex begin; diff --git a/connections/canconnectionmodel.h b/connections/canconnectionmodel.h index 68a8d45..190dd27 100644 --- a/connections/canconnectionmodel.h +++ b/connections/canconnectionmodel.h @@ -21,6 +21,10 @@ public: QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + Qt::ItemFlags flags(const QModelIndex &index) const override; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; void add(CANConnection* pConn_p); diff --git a/connections/connectionwindow.cpp b/connections/connectionwindow.cpp index ccaeaab..b28bb93 100644 --- a/connections/connectionwindow.cpp +++ b/connections/connectionwindow.cpp @@ -24,25 +24,17 @@ ConnectionWindow::ConnectionWindow(QWidget *parent) : connModel = new CANConnectionModel(this); ui->tableConnections->setModel(connModel); - ui->tableConnections->setColumnWidth(0, 50); - ui->tableConnections->setColumnWidth(1, 110); - ui->tableConnections->setColumnWidth(2, 110); - ui->tableConnections->setColumnWidth(3, 110); - ui->tableConnections->setColumnWidth(4, 75); - ui->tableConnections->setColumnWidth(5, 75); - ui->tableConnections->setColumnWidth(6, 75); - ui->tableConnections->setColumnWidth(7, 75); + ui->tableConnections->setColumnWidth(0, 40); + ui->tableConnections->setColumnWidth(1, 70); + ui->tableConnections->setColumnWidth(2, 70); + ui->tableConnections->setColumnWidth(3, 70); + ui->tableConnections->setColumnWidth(4, 70); + ui->tableConnections->setColumnWidth(5, 70); + ui->tableConnections->setColumnWidth(6, 70); + ui->tableConnections->setColumnWidth(7, 90); QHeaderView *HorzHdr = ui->tableConnections->horizontalHeader(); HorzHdr->setStretchLastSection(true); //causes the data column to automatically fill the tableview - ui->ckSingleWire->setChecked(settings.value("Main/SingleWireMode", false).toBool()); - - ui->cbSpeed->addItem(tr("125000")); - ui->cbSpeed->addItem(tr("250000")); - ui->cbSpeed->addItem(tr("500000")); - ui->cbSpeed->addItem(tr("1000000")); - ui->cbSpeed->addItem(tr("33333")); - ui->textConsole->setEnabled(false); ui->btnClearDebug->setEnabled(false); ui->btnSendHex->setEnabled(false); @@ -61,9 +53,7 @@ ConnectionWindow::ConnectionWindow(QWidget *parent) : connect(ui->rbGVRET, &QAbstractButton::clicked, this, &ConnectionWindow::handleConnTypeChanged); connect(ui->rbKvaser, &QAbstractButton::clicked, this, &ConnectionWindow::handleConnTypeChanged); connect(ui->rbSocketCAN, &QAbstractButton::clicked, this, &ConnectionWindow::handleConnTypeChanged); - connect(ui->btnRevert, &QPushButton::clicked, this, &ConnectionWindow::handleRevert); connect(ui->tableConnections->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &ConnectionWindow::currentRowChanged); - connect(ui->btnNewConn, &QPushButton::clicked, this, &ConnectionWindow::handleNewConn); connect(ui->btnActivateAll, &QPushButton::clicked, this, &ConnectionWindow::handleEnableAll); connect(ui->btnDeactivateAll, &QPushButton::clicked, this, &ConnectionWindow::handleDisableAll); connect(ui->btnRemoveBus, &QPushButton::clicked, this, &ConnectionWindow::handleRemoveConn); @@ -236,10 +226,10 @@ void ConnectionWindow::handleOKButton() if(!ret) return; - bus.setListenOnly(ui->ckListenOnly->isChecked()); - bus.setSingleWire(ui->ckSingleWire->isChecked()); - bus.setEnabled(ui->ckEnabled->isChecked()); - bus.setSpeed(ui->cbSpeed->currentText().toInt()); + //bus.setListenOnly(ui->ckListenOnly->isChecked()); + //bus.setSingleWire(ui->ckSingleWire->isChecked()); + //bus.setEnabled(ui->ckEnabled->isChecked()); + //bus.setSpeed(ui->cbSpeed->currentText().toInt()); /* update bus settings */ conn_p->setBusSettings(busId, bus); @@ -255,11 +245,11 @@ void ConnectionWindow::handleOKButton() for (int i=0 ; igetNumBuses() ; i++) { /* set bus configuration */ CANBus bus; - bus.active = ui->ckEnabled->isChecked(); - bus.listenOnly = ui->ckListenOnly->isChecked(); - bus.singleWire = ui->ckSingleWire->isChecked(); + //bus.active = ui->ckEnabled->isChecked(); + //bus.listenOnly = ui->ckListenOnly->isChecked(); + //bus.singleWire = ui->ckSingleWire->isChecked(); - bus.speed = ui->cbSpeed->currentText().toInt(); + //bus.speed = ui->cbSpeed->currentText().toInt(); /* update bus settings */ conn_p->setBusSettings(i, bus); @@ -280,6 +270,7 @@ void ConnectionWindow::currentRowChanged(const QModelIndex ¤t, const QMode disconnect(connModel->getAtIdx(previous.row(), busId), SIGNAL(debugOutput(QString)), 0, 0); disconnect(this, SIGNAL(sendDebugData(QByteArray)), connModel->getAtIdx(previous.row(), busId), SLOT(debugInput(QByteArray))); +return; /* enable / diable connection type */ ui->stPort->setEnabled(selIdx==-1); @@ -291,9 +282,6 @@ void ConnectionWindow::currentRowChanged(const QModelIndex ¤t, const QMode { ui->btnOK->setText(tr("Create New Connection")); ui->rbGVRET->setChecked(true); - ui->ckListenOnly->setChecked(false); - ui->ckSingleWire->setChecked(false); - ui->ckEnabled->setChecked(false); setSpeed(0); setPortName(CANCon::GVRET_SERIAL, ""); } @@ -313,9 +301,6 @@ void ConnectionWindow::currentRowChanged(const QModelIndex ¤t, const QMode if(!ret) return; ui->btnOK->setText(tr("Update Connection Settings")); - ui->ckListenOnly->setChecked(bus.isListenOnly()); - ui->ckSingleWire->setChecked(bus.isSingleWire()); - ui->ckEnabled->setChecked(bus.isActive()); setSpeed(bus.getSpeed()); setPortName(conn_p->getType(), conn_p->getPort()); } @@ -349,7 +334,6 @@ void ConnectionWindow::selectSerial() { /* set combobox page visible */ ui->stPort->setCurrentWidget(ui->cbPage); - ui->cbSpeed->setEnabled(true); ui->cbPort->clear(); ports = QSerialPortInfo::availablePorts(); @@ -362,7 +346,6 @@ void ConnectionWindow::selectKvaser() { /* set combobox page visible */ ui->stPort->setCurrentWidget(ui->cbPage); - ui->cbSpeed->setEnabled(false); } void ConnectionWindow::selectSocketCan() @@ -373,18 +356,6 @@ void ConnectionWindow::selectSocketCan() void ConnectionWindow::setSpeed(int speed0) { - for (int i = 0; i < ui->cbSpeed->count(); i++) - { - if (ui->cbSpeed->itemText(i).toInt() == speed0) - { - ui->cbSpeed->setCurrentIndex(i); - return; - } - } - - /* add custom speed */ - ui->cbSpeed->addItem(QString::number(speed0)); - ui->cbSpeed->setCurrentIndex(ui->cbSpeed->count() - 1); } void ConnectionWindow::setPortName(CANCon::type pType, QString pPortName) @@ -393,9 +364,6 @@ void ConnectionWindow::setPortName(CANCon::type pType, QString pPortName) { case CANCon::GVRET_SERIAL: ui->rbGVRET->setChecked(true); - ui->cbSpeed->setEnabled(true); - ui->ckListenOnly->setEnabled(true); - ui->ckSingleWire->setEnabled(true); break; case CANCon::KVASER: ui->rbKvaser->setChecked(true); @@ -403,9 +371,6 @@ void ConnectionWindow::setPortName(CANCon::type pType, QString pPortName) case CANCon::SOCKETCAN: ui->rbSocketCAN->setChecked(true); //you can't configure any of the below three with socketcan so dim them out - ui->cbSpeed->setEnabled(false); - ui->ckListenOnly->setEnabled(false); - ui->ckSingleWire->setEnabled(false); break; default: {} } @@ -435,16 +400,6 @@ void ConnectionWindow::setPortName(CANCon::type pType, QString pPortName) //-1 means leave it at whatever it booted up to. 0 means disable. Otherwise the actual rate we want. int ConnectionWindow::getSpeed() { - switch (ui->cbSpeed->currentIndex()) - { - case -1: - case 0: - return -1; - case 1: - return 0; - default: - return (ui->cbSpeed->currentText().toInt()); - } } QString ConnectionWindow::getPortName() @@ -475,12 +430,10 @@ CANCon::type ConnectionWindow::getConnectionType() void ConnectionWindow::setSWMode(bool mode) { - ui->ckSingleWire->setChecked(mode); } bool ConnectionWindow::getSWMode() { - if (ui->ckSingleWire->checkState() == Qt::Checked) return true; return false; } diff --git a/ui/connectionwindow.ui b/ui/connectionwindow.ui index 634ba67..e2578af 100644 --- a/ui/connectionwindow.ui +++ b/ui/connectionwindow.ui @@ -25,6 +25,9 @@ + + true + QAbstractItemView::SingleSelection @@ -35,13 +38,6 @@ - - - - New Connection - - - @@ -49,10 +45,6 @@ - - - - @@ -193,45 +185,6 @@ - - - - Single Wire Mode - - - - - - - Listen Only Mode - - - - - - - Enabled - - - - - - - - - CAN Speed - - - - - - - true - - - - - @@ -241,15 +194,21 @@ - - - - Revert - - - + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -319,19 +278,6 @@ - - - - Qt::Vertical - - - - 20 - 40 - - - - From ac976643f4a46fe9db5a1301285c493b8a1b60f8 Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Sun, 22 Oct 2017 20:15:18 -0400 Subject: [PATCH 04/11] Further work to get more buses working on the GVRET/M2RET devices --- config.h | 2 +- connections/canbus.h | 7 ++ connections/canconconst.h | 7 ++ connections/canconnection.cpp | 43 ++++------- connections/canconnection.h | 6 +- connections/canconnectionmodel.cpp | 14 +++- connections/connectionwindow.cpp | 33 +-------- connections/connectionwindow.h | 2 +- connections/gvretserial.cpp | 113 +++++++++++++++++++++++++++-- connections/gvretserial.h | 12 +-- connections/socketcan.cpp | 9 ++- 11 files changed, 168 insertions(+), 80 deletions(-) diff --git a/config.h b/config.h index 94ffff0..eba6add 100644 --- a/config.h +++ b/config.h @@ -1,7 +1,7 @@ #ifndef CONFIG #define CONFIG -#define VERSION 178 +#define VERSION 179 //try to keep this in sync. //SavvyCAN will complain if you connect a GVRET board with a revision diff --git a/connections/canbus.h b/connections/canbus.h index 9b39358..73f945f 100644 --- a/connections/canbus.h +++ b/connections/canbus.h @@ -1,6 +1,7 @@ #ifndef CANBus_H #define CANBus_H #include +#include "can_structs.h" class CANBus { @@ -31,4 +32,10 @@ QDataStream & operator>>(QDataStream & pStream, CANBus& pCanBus); Q_DECLARE_METATYPE(CANBus); +struct BusData { + CANBus mBus; + bool mConfigured; + QVector mTargettedFrames; +}; + #endif // CANBus_H diff --git a/connections/canconconst.h b/connections/canconconst.h index 707355d..386407a 100644 --- a/connections/canconconst.h +++ b/connections/canconconst.h @@ -21,4 +21,11 @@ namespace CANCon { }; } +class CANConStatus +{ +public: + CANCon::status conStatus; + int numHardwareBuses; +}; + #endif // CANCONCONST_H diff --git a/connections/canconnection.cpp b/connections/canconnection.cpp index 0294795..8617ac9 100644 --- a/connections/canconnection.cpp +++ b/connections/canconnection.cpp @@ -2,14 +2,6 @@ #include #include "canconnection.h" - -struct BusData { - CANBus mBus; - bool mConfigured; - QVector mTargettedFrames; -}; - - CANConnection::CANConnection(QString pPort, CANCon::type pType, int pNumBuses, @@ -27,7 +19,7 @@ CANConnection::CANConnection(QString pPort, /* register types */ qRegisterMetaType("CANBus"); qRegisterMetaType("CANFrame"); - qRegisterMetaType("CANCon::status"); + qRegisterMetaType("CANConStatus"); qRegisterMetaType("CANFlt"); /* set queue size */ @@ -35,9 +27,9 @@ CANConnection::CANConnection(QString pPort, /* allocate buses */ /* TODO: change those tables for a vector */ - mBusData_p = new BusData[mNumBuses]; + mBusData.resize(mNumBuses); for(int i=0 ; i= getNumBuses()) return false; - return mBusData_p[pBusId].mConfigured; + return mBusData[pBusId].mConfigured; } void CANConnection::setConfigured(int pBusId, bool pConfigured) { if( pBusId < 0 || pBusId >= getNumBuses()) return; - mBusData_p[pBusId].mConfigured = pConfigured; + mBusData[pBusId].mConfigured = pConfigured; } @@ -220,7 +209,7 @@ bool CANConnection::getBusConfig(int pBusId, CANBus& pBus) { if( pBusId < 0 || pBusId >= getNumBuses() || !isConfigured(pBusId)) return false; - pBus = mBusData_p[pBusId].mBus; + pBus = mBusData[pBusId].mBus; return true; } @@ -229,8 +218,8 @@ void CANConnection::setBusConfig(int pBusId, CANBus& pBus) { if( pBusId < 0 || pBusId >= getNumBuses()) return; - mBusData_p[pBusId].mConfigured = true; - mBusData_p[pBusId].mBus = pBus; + mBusData[pBusId].mConfigured = true; + mBusData[pBusId].mBus = pBus; } @@ -293,7 +282,7 @@ bool CANConnection::addTargettedFrame(int pBusId, uint32_t ID, uint32_t mask, QO target.id = ID; target.mask = mask; target.observer = receiver; - mBusData_p[pBusId].mTargettedFrames.append(target); + mBusData[pBusId].mTargettedFrames.append(target); return true; } @@ -321,7 +310,7 @@ bool CANConnection::removeTargettedFrame(int pBusId, uint32_t ID, uint32_t mask, target.id = ID; target.mask = mask; target.observer = receiver; - mBusData_p[pBusId].mTargettedFrames.removeAll(target); + mBusData[pBusId].mTargettedFrames.removeAll(target); return true; } @@ -329,9 +318,9 @@ bool CANConnection::removeTargettedFrame(int pBusId, uint32_t ID, uint32_t mask, bool CANConnection::removeAllTargettedFrames(QObject *receiver) { for (int i = 0; i < getNumBuses(); i++) { - foreach (const CANFltObserver filt, mBusData_p[i].mTargettedFrames) + foreach (const CANFltObserver filt, mBusData[i].mTargettedFrames) { - if (filt.observer == receiver) mBusData_p[i].mTargettedFrames.removeOne(filt); + if (filt.observer == receiver) mBusData[i].mTargettedFrames.removeOne(filt); } } @@ -342,10 +331,10 @@ void CANConnection::checkTargettedFrame(CANFrame &frame) { unsigned int maskedID; //qDebug() << "Got frame with ID " << frame.ID << " on bus " << frame.bus; - if (mBusData_p == 0) return; + if (mBusData.count() == 0) return; - if (mBusData_p[frame.bus].mTargettedFrames.length() == 0) return; - foreach (const CANFltObserver filt, mBusData_p[frame.bus].mTargettedFrames) + if (mBusData[frame.bus].mTargettedFrames.length() == 0) return; + foreach (const CANFltObserver filt, mBusData[frame.bus].mTargettedFrames) { //qDebug() << "Checking filter with id " << filt.id << " mask " << filt.mask; maskedID = frame.ID & filt.mask; diff --git a/connections/canconnection.h b/connections/canconnection.h index c659cab..0966ea2 100644 --- a/connections/canconnection.h +++ b/connections/canconnection.h @@ -89,7 +89,7 @@ signals: * @brief event emitted when the CANCon::status of the connection changes (connected->not_connected or the other way round) * @param pStatus: the new status of the device */ - void status(CANCon::status pStatus); + void status(CANConStatus pStatus); /** * @brief Event sent when device has done something worthy of debugging output. @@ -183,7 +183,8 @@ public slots: void debugInput(QByteArray bytes); protected: - int mNumBuses; //protected to allow connected device to figure out how many buses are available + int mNumBuses; //protected to allow connected device to figure out how many buses are available + QVector mBusData; //determine if the passed frame is part of a filter or not. void checkTargettedFrame(CANFrame &frame); @@ -297,7 +298,6 @@ private: bool mIsCapSuspended; QAtomicInt mStatus; bool mStarted; - BusData* mBusData_p; QThread* mThread_p; }; diff --git a/connections/canconnectionmodel.cpp b/connections/canconnectionmodel.cpp index dd88ad9..4a94f0a 100644 --- a/connections/canconnectionmodel.cpp +++ b/connections/canconnectionmodel.cpp @@ -65,11 +65,13 @@ int CANConnectionModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); - int rows=0; + int rows = 0; QList& conns = CANConManager::getInstance()->getConnections(); foreach(const CANConnection* conn_p, conns) - rows+=conn_p->getNumBuses(); + rows += conn_p->getNumBuses(); + + qDebug() << "Num Rows: " << rows; return rows; } @@ -143,6 +145,7 @@ QVariant CANConnectionModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); + qDebug() << "Row: " << index.row(); int busId; CANConnection *conn_p = getAtIdx(index.row(), busId); @@ -151,6 +154,8 @@ QVariant CANConnectionModel::data(const QModelIndex &index, int role) const ret = conn_p->getBusSettings(busId, bus); bool isSocketCAN = (conn_p->getType() == CANCon::SOCKETCAN) ? true: false; + qDebug() << "ConnP: " << conn_p << " ret " << ret; + if (role == Qt::DisplayRole) { if(!conn_p) return QVariant(); @@ -254,6 +259,9 @@ CANConnection* CANConnectionModel::getAtIdx(int pIdx, int& pBusId) const void CANConnectionModel::refresh(int pIndex) { + beginResetModel(); + endResetModel(); + /* QModelIndex begin; QModelIndex end; @@ -265,5 +273,5 @@ void CANConnectionModel::refresh(int pIndex) begin = createIndex(0, 0); end = createIndex(rowCount()-1, columnCount()-1); } - dataChanged(begin, end, QVector(Qt::DisplayRole)); + dataChanged(begin, end, QVector(Qt::DisplayRole)); */ } diff --git a/connections/connectionwindow.cpp b/connections/connectionwindow.cpp index b28bb93..3289906 100644 --- a/connections/connectionwindow.cpp +++ b/connections/connectionwindow.cpp @@ -197,7 +197,7 @@ void ConnectionWindow::handleConnTypeChanged() /* status */ -void ConnectionWindow::connectionStatus(CANCon::status pStatus) +void ConnectionWindow::connectionStatus(CANConStatus pStatus) { Q_UNUSED(pStatus); @@ -208,34 +208,9 @@ void ConnectionWindow::connectionStatus(CANCon::status pStatus) void ConnectionWindow::handleOKButton() { - int whichRow = ui->tableConnections->selectionModel()->currentIndex().row(); - CANConnection* conn_p = NULL; - if (whichRow > -1) - { - /* set information for selected connection */ - int busId; - CANBus bus; - bool ret; - - conn_p = connModel->getAtIdx(whichRow, busId); - if(!conn_p) return; - - ret = conn_p->getBusSettings(busId, bus); - if(!ret) return; - - - //bus.setListenOnly(ui->ckListenOnly->isChecked()); - //bus.setSingleWire(ui->ckSingleWire->isChecked()); - //bus.setEnabled(ui->ckEnabled->isChecked()); - //bus.setSpeed(ui->cbSpeed->currentText().toInt()); - /* update bus settings */ - conn_p->setBusSettings(busId, bus); - - connModel->refresh(whichRow); - } - else if( ! CANConManager::getInstance()->getByName(getPortName()) ) + if( ! CANConManager::getInstance()->getByName(getPortName()) ) { /* create connection */ conn_p = create(getConnectionType(), getPortName()); @@ -483,8 +458,8 @@ CANConnection* ConnectionWindow::create(CANCon::type pTye, QString pPortName) if(conn_p) { /* connect signal */ - connect(conn_p, SIGNAL(status(CANCon::status)), - this, SLOT(connectionStatus(CANCon::status))); + connect(conn_p, SIGNAL(status(CANConStatus)), + this, SLOT(connectionStatus(CANConStatus))); /*TODO add return value and checks */ conn_p->start(); diff --git a/connections/connectionwindow.h b/connections/connectionwindow.h index 58e99b2..77a0d88 100644 --- a/connections/connectionwindow.h +++ b/connections/connectionwindow.h @@ -57,7 +57,7 @@ private slots: void handleClearDebugText(); void handleSendHex(); void handleSendText(); - void connectionStatus(CANCon::status); + void connectionStatus(CANConStatus); private: Ui::ConnectionWindow *ui; diff --git a/connections/gvretserial.cpp b/connections/gvretserial.cpp index b8f24c6..b336e87 100644 --- a/connections/gvretserial.cpp +++ b/connections/gvretserial.cpp @@ -232,6 +232,10 @@ void GVRetSerial::connectDevice() output.append((char)0xE7); //this puts the device into binary comm mode output.append((char)0xE7); + output.append((char)0xF1); + output.append((char)0x0C); //get number of actually implemented buses. Not implemented except on M2RET + mNumBuses = 2; //the proper number if C/12 is not implemented + output.append((char)0xF1); //signal we want to issue a command output.append((char)0x06); //request canbus stats from the board @@ -249,15 +253,11 @@ void GVRetSerial::connectDevice() output.append((char)0xFF); //signal we don't want single wire mode }*/ - output.append((char)0xF1); //yet another command - output.append((char)0x09); //comm validation command - output.append((char)0xF1); //and another command output.append((char)0x01); //Time Sync - Not implemented until 333 but we can try - output.append((char)0xF1); - output.append((char)0x12); //get number of actually implemented buses. Not implemented except on M2RET - mNumBuses = 2; //the proper number if 0x12 is not implemented + output.append((char)0xF1); //yet another command + output.append((char)0x09); //comm validation command continuousTimeSync = true; @@ -274,7 +274,10 @@ void GVRetSerial::connectDevice() } else { setStatus(CANCon::CONNECTED); - emit status(getStatus()); + CANConStatus stats; + stats.conStatus = getStatus(); + stats.numHardwareBuses = mNumBuses; + emit status(stats); } /* connect reading event */ @@ -336,6 +339,10 @@ void GVRetSerial::debugInput(QByteArray bytes) { void GVRetSerial::procRXChar(unsigned char c) { + CANConStatus stats; + int oldBuses; + QByteArray output; + switch (rx_state) { case IDLE: @@ -380,6 +387,12 @@ void GVRetSerial::procRXChar(unsigned char c) break; case 12: rx_state = GET_NUM_BUSES; + qDebug() << "Got num buses reply"; + rx_step = 0; + break; + case 13: + rx_state = GET_EXT_BUSES; + qDebug() << "Got extended buses info reply"; rx_step = 0; break; } @@ -545,6 +558,8 @@ void GVRetSerial::procRXChar(unsigned char c) rx_state = IDLE; qDebug() << "Baud 0 = " << can0Baud; qDebug() << "Baud 1 = " << can1Baud; + mBusData[0].mBus.setSpeed(can0Baud); + mBusData[1].mBus.setSpeed(can1Baud); can0Baud |= 0x80000000; if (can0Enabled) can0Baud |= 0x40000000; @@ -556,7 +571,9 @@ void GVRetSerial::procRXChar(unsigned char c) if (deviceSingleWireMode > 0) can1Baud |= 0x10000000; setStatus(CANCon::CONNECTED); - emit status(getStatus()); + stats.conStatus = getStatus(); + stats.numHardwareBuses = mNumBuses; + emit status(stats); int can0Status = 0x78; //updating everything we can update int can1Status = 0x78; @@ -606,8 +623,88 @@ void GVRetSerial::procRXChar(unsigned char c) rx_state = IDLE; break; case GET_NUM_BUSES: + oldBuses = mNumBuses; mNumBuses = c; rx_state = IDLE; + qDebug() << "Get number of buses = " << mNumBuses; + stats.conStatus = getStatus(); + stats.numHardwareBuses = mNumBuses; + mBusData.resize(mNumBuses); + if (mNumBuses > oldBuses) + { + for (int i = oldBuses; i < mNumBuses; i++) + { + mBusData[i].mConfigured = true; + mBusData[i].mBus = mBusData[0].mBus; + } + } + + output.append((char)0xF1); //start a new command + output.append((char)13); //get extended buses + serial->write(output); + + emit status(stats); + break; + case GET_EXT_BUSES: + switch (rx_step) + { + case 0: + swcanEnabled = (c & 0xF); + swcanListenOnly = (c >> 4); + break; + case 1: + swcanBaud = c; + break; + case 2: + swcanBaud |= c << 8; + break; + case 3: + swcanBaud |= c << 16; + break; + case 4: + swcanBaud |= c << 24; + break; + case 5: + lin1Enabled = (c & 0xF); + break; + case 6: + lin1Baud = c; + break; + case 7: + lin1Baud |= c << 8; + break; + case 8: + lin1Baud |= c << 16; + break; + case 9: + lin1Baud |= c << 24; + case 10: + lin2Enabled = (c & 0xF); + break; + case 11: + lin2Baud = c; + break; + case 12: + lin2Baud |= c << 8; + break; + case 13: + lin2Baud |= c << 16; + break; + case 14: + lin2Baud |= c << 24; + rx_state = IDLE; + qDebug() << "SWCAN Baud = " << swcanBaud; + qDebug() << "LIN1 Baud = " << lin1Baud; + qDebug() << "LIN2 Baud = " << lin2Baud; + mBusData[2].mBus.setSpeed(swcanBaud); + + setStatus(CANCon::CONNECTED); + stats.conStatus = getStatus(); + stats.numHardwareBuses = mNumBuses; + emit status(stats); + break; + } + rx_step++; break; } } diff --git a/connections/gvretserial.h b/connections/gvretserial.h index 6b8e5ac..a4a3963 100644 --- a/connections/gvretserial.h +++ b/connections/gvretserial.h @@ -16,7 +16,7 @@ namespace SERIALSTATE { -enum STATE //keep this enum synchronized with the Arduino firmware project +enum STATE { IDLE, GET_COMMAND, @@ -29,12 +29,12 @@ enum STATE //keep this enum synchronized with the Arduino firmware project GET_CANBUS_PARAMS, GET_DEVICE_INFO, SET_SINGLEWIRE_MODE, - GET_NUM_BUSES + GET_NUM_BUSES, + GET_EXT_BUSES }; } - using namespace SERIALSTATE; class GVRetSerial : public CANConnection { @@ -83,9 +83,9 @@ protected: STATE rx_state; uint32_t rx_step; CANFrame buildFrame; - int can0Baud, can1Baud; - bool can0Enabled, can1Enabled; - bool can0ListenOnly, can1ListenOnly; + int can0Baud, can1Baud, swcanBaud, lin1Baud, lin2Baud; + bool can0Enabled, can1Enabled, swcanEnabled, lin1Enabled, lin2Enabled; + bool can0ListenOnly, can1ListenOnly, swcanListenOnly; int deviceBuildNum; int deviceSingleWireMode; uint32_t buildTimeBasis; diff --git a/connections/socketcan.cpp b/connections/socketcan.cpp index 7eefe2f..6455d21 100644 --- a/connections/socketcan.cpp +++ b/connections/socketcan.cpp @@ -211,6 +211,7 @@ void SocketCan::framesReceived() void SocketCan::testConnection() { QCanBusDevice* dev_p = QCanBus::instance()->createDevice("socketcan", getPort()); + CANConStatus stats; switch(getStatus()) { @@ -220,7 +221,9 @@ void SocketCan::testConnection() { disconnectDevice(); setStatus(CANCon::NOT_CONNECTED); - emit status(getStatus()); + stats.conStatus = getStatus(); + stats.numHardwareBuses = mNumBuses; + emit status(stats); } break; case CANCon::NOT_CONNECTED: @@ -235,7 +238,9 @@ void SocketCan::testConnection() { dev_p->disconnectDevice(); setStatus(CANCon::CONNECTED); - emit status(getStatus()); + stats.conStatus = getStatus(); + stats.numHardwareBuses = mNumBuses; + emit status(stats); } break; default: {} From 0519e2d2c9af173e0856acd3e7c9f61770b22900 Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Sun, 22 Oct 2017 20:42:02 -0400 Subject: [PATCH 05/11] More work on supporting swcan - it's there now! Untested as of yet. --- connections/canconnectionmodel.cpp | 6 +-- connections/gvretserial.cpp | 82 +++++++++++++++++++++++------- connections/socketcan.cpp | 6 ++- 3 files changed, 72 insertions(+), 22 deletions(-) diff --git a/connections/canconnectionmodel.cpp b/connections/canconnectionmodel.cpp index 4a94f0a..f68b9d0 100644 --- a/connections/canconnectionmodel.cpp +++ b/connections/canconnectionmodel.cpp @@ -71,7 +71,7 @@ int CANConnectionModel::rowCount(const QModelIndex &parent) const foreach(const CANConnection* conn_p, conns) rows += conn_p->getNumBuses(); - qDebug() << "Num Rows: " << rows; + //qDebug() << "Num Rows: " << rows; return rows; } @@ -145,7 +145,7 @@ QVariant CANConnectionModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); - qDebug() << "Row: " << index.row(); + //qDebug() << "Row: " << index.row(); int busId; CANConnection *conn_p = getAtIdx(index.row(), busId); @@ -154,7 +154,7 @@ QVariant CANConnectionModel::data(const QModelIndex &index, int role) const ret = conn_p->getBusSettings(busId, bus); bool isSocketCAN = (conn_p->getType() == CANCon::SOCKETCAN) ? true: false; - qDebug() << "ConnP: " << conn_p << " ret " << ret; + //qDebug() << "ConnP: " << conn_p << " ret " << ret; if (role == Qt::DisplayRole) { if(!conn_p) diff --git a/connections/gvretserial.cpp b/connections/gvretserial.cpp index b336e87..62b6f78 100644 --- a/connections/gvretserial.cpp +++ b/connections/gvretserial.cpp @@ -125,25 +125,71 @@ void GVRetSerial::piSetBusSettings(int pBusIdx, CANBus bus) } else deviceSingleWireMode = 0; } + else if (pBusIdx == 2) + { + swcanBaud = bus.getSpeed(); + swcanBaud |= 0x80000000; + if (bus.isActive()) + { + swcanBaud |= 0x40000000; + swcanEnabled = true; + } + else swcanEnabled = false; - /* update baud rates */ - QByteArray buffer; - qDebug() << "Got signal to update bauds. 1: " << can0Baud <<" 2: " << can1Baud; - debugOutput("Got signal to update bauds. 1: " + QString::number(can0Baud) + " 2: " + QString::number(can1Baud)); - buffer[0] = (char)0xF1; //start of a command over serial - buffer[1] = 5; //setup canbus - buffer[2] = (unsigned char)(can0Baud & 0xFF); //four bytes of ID LSB first - buffer[3] = (unsigned char)(can0Baud >> 8); - buffer[4] = (unsigned char)(can0Baud >> 16); - buffer[5] = (unsigned char)(can0Baud >> 24); - buffer[6] = (unsigned char)(can1Baud & 0xFF); //four bytes of ID LSB first - buffer[7] = (unsigned char)(can1Baud >> 8); - buffer[8] = (unsigned char)(can1Baud >> 16); - buffer[9] = (unsigned char)(can1Baud >> 24); - buffer[10] = 0; - if (serial == NULL) return; - if (!serial->isOpen()) return; - serial->write(buffer); + if (bus.isListenOnly()) + { + swcanBaud |= 0x20000000; + swcanListenOnly = true; + } + else swcanListenOnly = false; + + } + + if (pBusIdx < 2) { + /* update baud rates */ + QByteArray buffer; + qDebug() << "Got signal to update bauds. 1: " << can0Baud <<" 2: " << can1Baud; + debugOutput("Got signal to update bauds. 1: " + QString::number(can0Baud) + " 2: " + QString::number(can1Baud)); + buffer[0] = (char)0xF1; //start of a command over serial + buffer[1] = 5; //setup canbus + buffer[2] = (unsigned char)(can0Baud & 0xFF); //four bytes of ID LSB first + buffer[3] = (unsigned char)(can0Baud >> 8); + buffer[4] = (unsigned char)(can0Baud >> 16); + buffer[5] = (unsigned char)(can0Baud >> 24); + buffer[6] = (unsigned char)(can1Baud & 0xFF); //four bytes of ID LSB first + buffer[7] = (unsigned char)(can1Baud >> 8); + buffer[8] = (unsigned char)(can1Baud >> 16); + buffer[9] = (unsigned char)(can1Baud >> 24); + buffer[10] = 0; + if (serial == NULL) return; + if (!serial->isOpen()) return; + serial->write(buffer); + } + else + { + /* update baud rates */ + QByteArray buffer; + qDebug() << "Got signal to update extended bus speeds SWCAN: " << swcanBaud <<" LIN1: " << lin1Baud << " LIN2: " << lin2Baud; + debugOutput("Got signal to update extended bus speeds SWCAN: " + QString::number(swcanBaud) + " LIN1: " + QString::number(lin1Baud) + " LIN2: " + QString::number(lin2Baud)); + buffer[0] = (char)0xF1; //start of a command over serial + buffer[1] = 14; //setup extended buses + buffer[2] = (unsigned char)(swcanBaud & 0xFF); //four bytes of ID LSB first + buffer[3] = (unsigned char)(swcanBaud >> 8); + buffer[4] = (unsigned char)(swcanBaud >> 16); + buffer[5] = (unsigned char)(swcanBaud >> 24); + buffer[6] = (unsigned char)(lin1Baud & 0xFF); //four bytes of ID LSB first + buffer[7] = (unsigned char)(lin1Baud >> 8); + buffer[8] = (unsigned char)(lin1Baud >> 16); + buffer[9] = (unsigned char)(lin1Baud >> 24); + buffer[10] = (unsigned char)(lin2Baud & 0xFF); //four bytes of ID LSB first + buffer[11] = (unsigned char)(lin2Baud >> 8); + buffer[12] = (unsigned char)(lin2Baud >> 16); + buffer[13] = (unsigned char)(lin2Baud >> 24); + buffer[14] = 0; + if (serial == NULL) return; + if (!serial->isOpen()) return; + serial->write(buffer); + } } diff --git a/connections/socketcan.cpp b/connections/socketcan.cpp index 6455d21..3fd9eeb 100644 --- a/connections/socketcan.cpp +++ b/connections/socketcan.cpp @@ -31,6 +31,7 @@ void SocketCan::piStarted() mTimer.setInterval(1000); mTimer.setSingleShot(false); //keep ticking mTimer.start(); + mBusData[0].mBus.setEnabled(true); } @@ -59,6 +60,7 @@ bool SocketCan::piGetBusSettings(int pBusIdx, CANBus& pBus) void SocketCan::piSetBusSettings(int pBusIdx, CANBus bus) { + CANConStatus stats; /* sanity checks */ if(0 != pBusIdx) return; @@ -109,7 +111,6 @@ bool SocketCan::piSendFrame(const CANFrame& pFrame) /* sanity checks */ if(0 != pFrame.bus || pFrame.len>8) return false; - if (!mDev_p) return false; /* fill frame */ @@ -232,7 +233,10 @@ void SocketCan::testConnection() { /* try to reconnect */ CANBus bus; if(getBusConfig(0, bus)) + { + bus.setEnabled(true); setBusSettings(0, bus); + } } /* disconnect test instance */ dev_p->disconnectDevice(); From bc4e823d3d244032098cc41861f98041e3b20b99 Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Mon, 23 Oct 2017 19:45:08 -0400 Subject: [PATCH 06/11] CAN Connection Window mostly done now. --- connections/canbus.cpp | 5 +++++ connections/connectionwindow.cpp | 30 ------------------------------ connections/gvretserial.cpp | 9 +++++++-- connections/socketcan.cpp | 1 + 4 files changed, 13 insertions(+), 32 deletions(-) diff --git a/connections/canbus.cpp b/connections/canbus.cpp index d0f4646..13aeb11 100644 --- a/connections/canbus.cpp +++ b/connections/canbus.cpp @@ -1,4 +1,5 @@ #include +#include #include "canbus.h" CANBus::CANBus() @@ -25,18 +26,22 @@ bool CANBus::operator==(const CANBus& bus) const{ } void CANBus::setSpeed(int newSpeed){ + //qDebug() << "CANBUS SetSpeed = " << newSpeed; speed = newSpeed; } void CANBus::setListenOnly(bool mode){ + //qDebug() << "CANBUS SetListenOnly = " << mode; listenOnly = mode; } void CANBus::setSingleWire(bool mode){ + //qDebug() << "CANBUS SetSingleWire = " << mode; singleWire = mode; } void CANBus::setEnabled(bool mode){ + //qDebug() << "CANBUS SetEnabled = " << mode; active = mode; } diff --git a/connections/connectionwindow.cpp b/connections/connectionwindow.cpp index 3289906..a326a9e 100644 --- a/connections/connectionwindow.cpp +++ b/connections/connectionwindow.cpp @@ -216,20 +216,6 @@ void ConnectionWindow::handleOKButton() conn_p = create(getConnectionType(), getPortName()); if(!conn_p) return; - - for (int i=0 ; igetNumBuses() ; i++) { - /* set bus configuration */ - CANBus bus; - //bus.active = ui->ckEnabled->isChecked(); - //bus.listenOnly = ui->ckListenOnly->isChecked(); - //bus.singleWire = ui->ckSingleWire->isChecked(); - - //bus.speed = ui->cbSpeed->currentText().toInt(); - - /* update bus settings */ - conn_p->setBusSettings(i, bus); - } - /* add connection to model */ connModel->add(conn_p); } @@ -480,17 +466,10 @@ void ConnectionWindow::loadConnections() /* fill connection list */ QVector portNames = settings.value("connections/portNames").value>(); QVector devTypes = settings.value("connections/types").value>(); - QList busses = settings.value("connections/busses").value>(); - for(int i=0 ; igetNumBuses() ; j++) - conn_p->setBusSettings(j, busses.takeFirst()); - } /* add connection to model */ connModel->add(conn_p); } @@ -507,23 +486,14 @@ void ConnectionWindow::saveConnections() QSettings settings; QVector portNames; QVector devTypes; - QList busses; /* save connections */ foreach(CANConnection* conn_p, conns) { portNames.append(conn_p->getPort()); devTypes.append(conn_p->getType()); - - for(int i=0 ; igetNumBuses() ; i++) - { - CANBus bus; - conn_p->getBusSettings(i, bus); - busses.append(bus); - } } settings.setValue("connections/portNames", QVariant::fromValue(portNames)); settings.setValue("connections/types", QVariant::fromValue(devTypes)); - settings.setValue("connections/busses", QVariant::fromValue(busses)); } diff --git a/connections/gvretserial.cpp b/connections/gvretserial.cpp index 62b6f78..0e38871 100644 --- a/connections/gvretserial.cpp +++ b/connections/gvretserial.cpp @@ -148,8 +148,8 @@ void GVRetSerial::piSetBusSettings(int pBusIdx, CANBus bus) if (pBusIdx < 2) { /* update baud rates */ QByteArray buffer; - qDebug() << "Got signal to update bauds. 1: " << can0Baud <<" 2: " << can1Baud; - debugOutput("Got signal to update bauds. 1: " + QString::number(can0Baud) + " 2: " + QString::number(can1Baud)); + qDebug() << "Got signal to update bauds. 1: " << (can0Baud & 0xFFFFFFF) <<" 2: " << (can1Baud & 0xFFFFFFF); + debugOutput("Got signal to update bauds. 1: " + QString::number((can0Baud & 0xFFFFFFF)) + " 2: " + QString::number((can1Baud & 0xFFFFFFF))); buffer[0] = (char)0xF1; //start of a command over serial buffer[1] = 5; //setup canbus buffer[2] = (unsigned char)(can0Baud & 0xFF); //four bytes of ID LSB first @@ -606,6 +606,10 @@ void GVRetSerial::procRXChar(unsigned char c) qDebug() << "Baud 1 = " << can1Baud; mBusData[0].mBus.setSpeed(can0Baud); mBusData[1].mBus.setSpeed(can1Baud); + mBusData[0].mBus.setEnabled(can0Enabled); + mBusData[1].mBus.setEnabled(can1Enabled); + mBusData[0].mConfigured = true; + mBusData[1].mConfigured = true; can0Baud |= 0x80000000; if (can0Enabled) can0Baud |= 0x40000000; @@ -743,6 +747,7 @@ void GVRetSerial::procRXChar(unsigned char c) qDebug() << "LIN1 Baud = " << lin1Baud; qDebug() << "LIN2 Baud = " << lin2Baud; mBusData[2].mBus.setSpeed(swcanBaud); + mBusData[2].mBus.setEnabled(swcanEnabled); setStatus(CANCon::CONNECTED); stats.conStatus = getStatus(); diff --git a/connections/socketcan.cpp b/connections/socketcan.cpp index 3fd9eeb..d370784 100644 --- a/connections/socketcan.cpp +++ b/connections/socketcan.cpp @@ -32,6 +32,7 @@ void SocketCan::piStarted() mTimer.setSingleShot(false); //keep ticking mTimer.start(); mBusData[0].mBus.setEnabled(true); + mBusData[0].mConfigured = true; } From 9c9ab1933b99cf6c70cf4b4e245977b4d9e61bf5 Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Tue, 24 Oct 2017 21:27:55 -0400 Subject: [PATCH 07/11] Add mode to playback window to it to approximate the original frame timings from the file/capture. --- can_structs.h | 5 ++ frameplaybackwindow.cpp | 150 +++++++++++++++++++++++++++++++------- frameplaybackwindow.h | 9 ++- ui/frameplaybackwindow.ui | 7 ++ 4 files changed, 143 insertions(+), 28 deletions(-) diff --git a/can_structs.h b/can_structs.h index 42c5c2e..b19e901 100644 --- a/can_structs.h +++ b/can_structs.h @@ -15,6 +15,11 @@ public: uint32_t len; unsigned char data[8]; uint64_t timestamp; + + friend bool operator<(const CANFrame& l, const CANFrame& r) + { + return l.timestamp < r.timestamp; + } }; class CANFltObserver diff --git a/frameplaybackwindow.cpp b/frameplaybackwindow.cpp index 70f929d..b0f0eaa 100644 --- a/frameplaybackwindow.cpp +++ b/frameplaybackwindow.cpp @@ -48,26 +48,27 @@ FramePlaybackWindow::FramePlaybackWindow(const QVector *frames, QWidge updateFrameLabel(); - connect(ui->btnStepBack, SIGNAL(clicked(bool)), this, SLOT(btnBackOneClick())); - connect(ui->btnPause, SIGNAL(clicked(bool)), this, SLOT(btnPauseClick())); - connect(ui->btnPlayReverse, SIGNAL(clicked(bool)), this, SLOT(btnReverseClick())); - connect(ui->btnStop, SIGNAL(clicked(bool)), this, SLOT(btnStopClick())); - connect(ui->btnPlay, SIGNAL(clicked(bool)), this, SLOT(btnPlayClick())); - connect(ui->btnStepForward, SIGNAL(clicked(bool)), this, SLOT(btnFwdOneClick())); - connect(ui->btnSelectAll, SIGNAL(clicked(bool)), this, SLOT(btnSelectAllClick())); - connect(ui->btnSelectNone, SIGNAL(clicked(bool)), this, SLOT(btnSelectNoneClick())); - connect(ui->btnDelete, SIGNAL(clicked(bool)), this, SLOT(btnDeleteCurrSeq())); + connect(ui->btnStepBack, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnBackOneClick); + connect(ui->btnPause, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnPauseClick); + connect(ui->btnPlayReverse, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnReverseClick); + connect(ui->btnStop, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnStopClick); + connect(ui->btnPlay, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnPlayClick); + connect(ui->btnStepForward, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnFwdOneClick); + connect(ui->btnSelectAll, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnSelectAllClick); + connect(ui->btnSelectNone, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnSelectNoneClick); + connect(ui->btnDelete, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnDeleteCurrSeq); connect(ui->spinPlaySpeed, SIGNAL(valueChanged(int)), this, SLOT(changePlaybackSpeed(int))); //connect(ui->cbLoop, SIGNAL(clicked(bool)), this, SLOT(changeLooping(bool))); connect(ui->comboCANBus, SIGNAL(currentIndexChanged(int)), this, SLOT(changeSendingBus(int))); - connect(ui->listID, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(changeIDFiltering(QListWidgetItem*))); - connect(playbackTimer, SIGNAL(timeout()), this, SLOT(timerTriggered())); - connect(ui->btnLoadFile, SIGNAL(clicked(bool)), this, SLOT(btnLoadFile())); - connect(ui->btnLoadLive, SIGNAL(clicked(bool)), this, SLOT(btnLoadLive())); - connect(ui->tblSequence, SIGNAL(cellPressed(int,int)), this, SLOT(seqTableCellClicked(int,int))); - connect(ui->tblSequence, SIGNAL(cellChanged(int,int)), this, SLOT(seqTableCellChanged(int,int))); - connect(ui->btnLoadFilters, SIGNAL(clicked(bool)), this, SLOT(loadFilters())); - connect(ui->btnSaveFilters, SIGNAL(clicked(bool)), this, SLOT(saveFilters())); + connect(ui->listID, &QListWidget::itemClicked, this, &FramePlaybackWindow::changeIDFiltering); + connect(playbackTimer, &QTimer::timeout, this, &FramePlaybackWindow::timerTriggered); + connect(ui->btnLoadFile, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnLoadFile); + connect(ui->btnLoadLive, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnLoadLive); + connect(ui->tblSequence, &QTableWidget::cellPressed, this, &FramePlaybackWindow::seqTableCellClicked); + connect(ui->tblSequence, &QTableWidget::cellChanged, this, &FramePlaybackWindow::seqTableCellChanged); + connect(ui->btnLoadFilters, &QAbstractButton::clicked, this, &FramePlaybackWindow::loadFilters); + connect(ui->btnSaveFilters, &QAbstractButton::clicked, this, &FramePlaybackWindow::saveFilters); + connect(ui->cbOriginalTiming, &QCheckBox::toggled, this, &FramePlaybackWindow::useOrigTimingClicked); ui->listID->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui->listID, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuFilters(QPoint))); @@ -313,6 +314,20 @@ void FramePlaybackWindow::fillIDHash(SequenceItem &item) } } +void FramePlaybackWindow::useOrigTimingClicked() +{ + if (ui->cbOriginalTiming->isChecked()) + { + ui->spinBurstSpeed->setEnabled(false); + ui->spinPlaySpeed->setEnabled(false); + } + else + { + ui->spinBurstSpeed->setEnabled(true); + ui->spinPlaySpeed->setEnabled(true); + } +} + void FramePlaybackWindow::btnDeleteCurrSeq() { if (currentSeqNum == -1) return; @@ -345,6 +360,7 @@ void FramePlaybackWindow::btnLoadFile() if (FrameFileIO::loadFrameFile(filename, &item.data)) { + qSort(item.data); //sort by timestamp to be sure it's in order QStringList fileList = filename.split('/'); item.filename = fileList[fileList.length() - 1]; item.currentLoopCount = 0; @@ -377,6 +393,7 @@ void FramePlaybackWindow::btnLoadLive() item.currentLoopCount = 0; item.maxLoops = 1; item.data = QVector(*modelFrames); //create a copy of the current frames from the main view + qSort(item.data); //be sure it's all in time based order fillIDHash(item); if (ui->tblSequence->currentRow() == -1) { @@ -417,6 +434,12 @@ void FramePlaybackWindow::btnReverseClick() { playbackActive = true; playbackForward = false; + if (ui->cbOriginalTiming->isChecked()) + { + playbackElapsed.start(); + playbackTimer->setInterval(1); + playbackLastTimeStamp = currentSeqItem->data[currentPosition].timestamp + 2000; + } playbackTimer->start(); } @@ -446,6 +469,14 @@ void FramePlaybackWindow::btnPlayClick() { playbackActive = true; playbackForward = true; + if (ui->cbOriginalTiming->isChecked()) + { + playbackTimer->setInterval(1); + playbackElapsed.start(); + if (currentSeqItem->data[currentPosition].timestamp > 1000) + playbackLastTimeStamp = currentSeqItem->data[currentPosition].timestamp - 2000; + else playbackLastTimeStamp = 0; + } playbackTimer->start(); } @@ -503,26 +534,68 @@ void FramePlaybackWindow::btnSelectNoneClick() void FramePlaybackWindow::timerTriggered() { sendingBuffer.clear(); - for (int count = 0; count < ui->spinBurstSpeed->value(); count++) + + if (ui->cbOriginalTiming->isChecked()) { - if (!playbackActive) - { - playbackTimer->stop(); - return; - } + //get elapsed microseconds since last tick (in case timer skips or is otherwise inaccurate, though there are no guarantees about elapsed timer either) + quint64 elapsed = playbackElapsed.nsecsElapsed() / 1000; + playbackElapsed.start(); if (playbackForward) { - updatePosition(true); + playbackLastTimeStamp += elapsed; + //qDebug() << playbackLastTimeStamp; + while (peekPosition(true) <= playbackLastTimeStamp) + { + updatePosition(true); + } + if (peekPosition(true) == 0xFFFFFFFFFFFFFFFFull) + { + updatePosition(true); //this'll go to the next log (if there is one) + if (currentSeqItem->data[currentPosition].timestamp > 1000) + playbackLastTimeStamp = currentSeqItem->data[currentPosition].timestamp - 1000; + else playbackLastTimeStamp = 0; + } } else { - updatePosition(false); + if (playbackLastTimeStamp > elapsed) + playbackLastTimeStamp -= elapsed; + else playbackLastTimeStamp = 0; + while (peekPosition(false) >= playbackLastTimeStamp && peekPosition(false) != 0xFFFFFFFFFFFFFFFFull) + { + updatePosition(false); + } + if (peekPosition(false) == 0xFFFFFFFFFFFFFFFFull) + { + updatePosition(false); //this'll go to the next log (if there is one) + playbackLastTimeStamp = currentSeqItem->data[currentPosition].timestamp + 1000; + } } } + else + { + for (int count = 0; count < ui->spinBurstSpeed->value(); count++) + { + if (!playbackActive) + { + playbackTimer->stop(); + return; + } + if (playbackForward) + { + updatePosition(true); + } + else + { + updatePosition(false); + } + } + } + CANConManager::getInstance()->sendFrames(sendingBuffer); } -void FramePlaybackWindow::updatePosition(bool forward) +quint64 FramePlaybackWindow::updatePosition(bool forward) { //qDebug() << "updatePosition"; if (forward) @@ -613,4 +686,29 @@ void FramePlaybackWindow::updatePosition(bool forward) thisFrame->bus = originalBus; } + return thisFrame->timestamp; } + +quint64 FramePlaybackWindow::peekPosition(bool forward) +{ + int peekCurrentPosition = currentPosition; + if (forward) + { + if (peekCurrentPosition < (currentSeqItem->data.count() - 1)) peekCurrentPosition++; //still in same file so keep going + else //hit the end of the current file + { + return 0xFFFFFFFFFFFFFFFFull; + } + } + else + { + if (peekCurrentPosition > 0) peekCurrentPosition--; + else //hit the beginning of the current sequence + { + return 0xFFFFFFFFFFFFFFFFull; + } + } + CANFrame *thisFrame = ¤tSeqItem->data[peekCurrentPosition]; + return thisFrame->timestamp; +} + diff --git a/frameplaybackwindow.h b/frameplaybackwindow.h index a0a2026..7de1ac3 100644 --- a/frameplaybackwindow.h +++ b/frameplaybackwindow.h @@ -2,6 +2,7 @@ #define FRAMEPLAYBACKWINDOW_H #include +#include #include #include #include "can_structs.h" @@ -51,6 +52,7 @@ private slots: void contextMenuFilters(QPoint); void saveFilters(); void loadFilters(); + void useOrigTimingClicked(); private: Ui::FramePlaybackWindow *ui; @@ -60,6 +62,8 @@ private: const QVector *modelFrames; int currentPosition; QTimer *playbackTimer; + QElapsedTimer playbackElapsed; + quint64 playbackLastTimeStamp; bool playbackActive; bool playbackForward; int whichBusSend; @@ -69,8 +73,9 @@ private: void refreshIDList(); void updateFrameLabel(); - void updatePosition(bool forward); - void fillIDHash(SequenceItem &item); + quint64 updatePosition(bool forward); + quint64 peekPosition(bool forward); + void fillIDHash(SequenceItem &item); void showEvent(QShowEvent *); void closeEvent(QCloseEvent *event); void readSettings(); diff --git a/ui/frameplaybackwindow.ui b/ui/frameplaybackwindow.ui index 557cb94..b49c350 100644 --- a/ui/frameplaybackwindow.ui +++ b/ui/frameplaybackwindow.ui @@ -100,6 +100,13 @@ + + + + Use original frame timing from captured frames + + + From 3bf19fdbc492a5ab956bac36fb40c73b73a35b1c Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Wed, 8 Nov 2017 20:38:19 -0500 Subject: [PATCH 08/11] Moved a lot of the frame playback window functionality to a new class. This allows the functionality to be run on a separate thread. The performance is a lot better and "use original timing" is now reasonably accurate. --- SavvyCAN.pro | 6 +- connections/connectionwindow.cpp | 1 + frameplaybackobject.cpp | 456 +++++++++++++++++++++++++++++++ frameplaybackobject.h | 102 +++++++ frameplaybackwindow.cpp | 303 +++++--------------- frameplaybackwindow.h | 31 +-- 6 files changed, 635 insertions(+), 264 deletions(-) create mode 100644 frameplaybackobject.cpp create mode 100644 frameplaybackobject.h diff --git a/SavvyCAN.pro b/SavvyCAN.pro index 7f1d15e..39f0178 100644 --- a/SavvyCAN.pro +++ b/SavvyCAN.pro @@ -64,7 +64,8 @@ SOURCES += main.cpp\ bus_protocols/isotp_handler.cpp \ bus_protocols/j1939_handler.cpp \ bus_protocols/uds_handler.cpp \ - jsedit.cpp + jsedit.cpp \ + frameplaybackobject.cpp HEADERS += mainwindow.h \ can_structs.h \ @@ -117,7 +118,8 @@ HEADERS += mainwindow.h \ bus_protocols/j1939_handler.h \ bus_protocols/uds_handler.h \ bus_protocols/isotp_message.h \ - jsedit.h + jsedit.h \ + frameplaybackobject.h FORMS += ui/candatagrid.ui \ ui/connectionwindow.ui \ diff --git a/connections/connectionwindow.cpp b/connections/connectionwindow.cpp index a326a9e..99d084b 100644 --- a/connections/connectionwindow.cpp +++ b/connections/connectionwindow.cpp @@ -90,6 +90,7 @@ void ConnectionWindow::showEvent(QShowEvent* event) readSettings(); ui->tableConnections->selectRow(0); currentRowChanged(ui->tableConnections->currentIndex(), ui->tableConnections->currentIndex()); + handleConnTypeChanged(); } void ConnectionWindow::closeEvent(QCloseEvent *event) diff --git a/frameplaybackobject.cpp b/frameplaybackobject.cpp new file mode 100644 index 0000000..c58c048 --- /dev/null +++ b/frameplaybackobject.cpp @@ -0,0 +1,456 @@ +#include "frameplaybackobject.h" + +FramePlaybackObject::FramePlaybackObject() +{ + mThread_p = new QThread(); + + currentPosition = 0; + playbackInterval = 1; + playbackBurst = 1; + statusCounter = 0; + numBuses = 0; + playbackActive = false; + playbackForward = true; + useOrigTiming = false; + whichBusSend = -1; +} + +FramePlaybackObject::~FramePlaybackObject() +{ + mThread_p->quit(); + mThread_p->wait(); + delete mThread_p; +} + +quint64 FramePlaybackObject::updatePosition(bool forward) +{ + //qDebug() << "updatePosition"; + if (forward) + { + if (currentPosition < (currentSeqItem->data.count() - 1)) currentPosition++; //still in same file so keep going + else //hit the end of the current file + { + qDebug() << "hit end of current sequence"; + currentSeqItem->currentLoopCount++; + currentPosition = 0; + if (currentSeqItem->currentLoopCount == currentSeqItem->maxLoops) //have we looped enough times? + { + playbackActive = false; + playbackTimer->stop(); + emit EndOfFrameCache(); + /* + currentSeqNum++; //go forward in the sequence + if (currentSeqNum == seqItems.count()) //are we at the end of the sequence? + { + //reset the loop figures for each sequence entry + for (int i = 0; i < seqItems.count(); i++) seqItems[i].currentLoopCount = 0; + currentSeqNum = 0; + if (ui->cbLoop->isChecked()) //go back to beginning if we're looping the sequence + { + + } + else //not looping so stop playback entirely + { + playbackActive = false; + playbackTimer->stop(); + } + } + currentSeqItem = &seqItems[currentSeqNum]; + ui->tblSequence->setCurrentCell(currentSeqNum, 0); + */ + } + } + } + else + { + if (currentPosition > 0) currentPosition--; + else //hit the beginning of the current sequence + { + qDebug() << "hit start of current sequence"; + currentSeqItem->currentLoopCount++; + currentPosition = currentSeqItem->data.count() - 1; + if (currentSeqItem->currentLoopCount == currentSeqItem->maxLoops) //have we looped enough times? + { + playbackActive = false; + playbackTimer->stop(); + emit EndOfFrameCache(); + + /* + currentSeqNum--; //go backward in the sequence + if (currentSeqNum == -1) //are we trying to go past the beginning? + { + //reset the loop figures for each sequence entry + for (int i = 0; i < seqItems.count(); i++) seqItems[i].currentLoopCount = 0; + currentSeqNum = seqItems.count() - 1; + if (ui->cbLoop->isChecked()) //go back to the last sequence entry if we're looping + { + + } + else //not looping so stop playback entirely + { + playbackActive = false; + playbackTimer->stop(); + } + } + currentSeqItem = &seqItems[currentSeqNum]; + ui->tblSequence->setCurrentCell(currentSeqNum, 0); + */ + } + } + } + //updateFrameLabel(); + //only send frame out if its ID is checked in the list. Otherwise discard it. + CANFrame *thisFrame = ¤tSeqItem->data[currentPosition]; + uint32_t originalBus = thisFrame->bus; + if (currentSeqItem->idFilters.find(thisFrame->ID).value()) + { + if (whichBusSend > -1) + { + thisFrame->bus = whichBusSend; + sendingBuffer.append(*thisFrame); + } + else if (whichBusSend == -1) + { + for (int c = 0; c < numBuses; c++) + { + thisFrame->bus = c; + sendingBuffer.append(*thisFrame); + } + } + else //from file so retain original bus and send as-is + { + sendingBuffer.append(*thisFrame); + } + + thisFrame->bus = originalBus; + } + return thisFrame->timestamp; +} + +quint64 FramePlaybackObject::peekPosition(bool forward) +{ + int peekCurrentPosition = currentPosition; + if (forward) + { + if (peekCurrentPosition < (currentSeqItem->data.count() - 1)) peekCurrentPosition++; //still in same file so keep going + else //hit the end of the current file + { + return 0xFFFFFFFFFFFFFFFFull; + } + } + else + { + if (peekCurrentPosition > 0) peekCurrentPosition--; + else //hit the beginning of the current sequence + { + return 0xFFFFFFFFFFFFFFFFull; + } + } + CANFrame *thisFrame = ¤tSeqItem->data[peekCurrentPosition]; + return thisFrame->timestamp; +} + +void FramePlaybackObject::piStart() +{ + playbackTimer = new QTimer(); + playbackTimer->setTimerType(Qt::PreciseTimer); + playbackTimer->setInterval(1); + + currentPosition = 0; + playbackActive = false; + playbackForward = true; + whichBusSend = 0; + + connect(playbackTimer, &QTimer::timeout, this, &FramePlaybackObject::timerTriggered); +} + +void FramePlaybackObject::piStop() +{ + playbackTimer->stop(); + delete playbackTimer; +} + +void FramePlaybackObject::initialize() +{ + if( mThread_p && (mThread_p != QThread::currentThread()) ) + { + /* move ourself to the thread */ + moveToThread(mThread_p); /*TODO handle errors */ + /* connect started() */ + connect(mThread_p, SIGNAL(started()), this, SLOT(initialize())); + /* start the thread */ + mThread_p->start(QThread::HighPriority); + return; + } + + /* set started flag */ + //mStarted = true; + + /* in multithread case, this will be called before entering thread event loop */ + return piStart(); + +} + +void FramePlaybackObject::finalize() +{ + /* 1) execute in mThread_p context */ + if( mThread_p && (mThread_p != QThread::currentThread()) ) + { + /* if thread is finished, it means we call this function for the second time so we can leave */ + if( !mThread_p->isFinished() ) + { + /* we need to call piStop() */ + QMetaObject::invokeMethod(this, "finalize", + Qt::BlockingQueuedConnection); + /* 3) stop thread */ + mThread_p->quit(); + if(!mThread_p->wait()) { + qDebug() << "can't stop thread"; + } + } + return; + } + + /* 2) call piStop in mThread context */ + return piStop(); +} + +void FramePlaybackObject::startPlaybackForward() +{ + /* make sure we execute in mThread context */ + if( mThread_p && (mThread_p != QThread::currentThread()) ) { + QMetaObject::invokeMethod(this, "startPlaybackForward", + Qt::BlockingQueuedConnection); + return; + } + + playbackActive = true; + playbackForward = true; + + if (useOrigTiming) + { + playbackTimer->setInterval(1); + playbackElapsed.start(); + if (currentSeqItem->data[currentPosition].timestamp > 2000) + playbackLastTimeStamp = currentSeqItem->data[currentPosition].timestamp - 2000; + else playbackLastTimeStamp = 0; + } + playbackTimer->start(); +} + +void FramePlaybackObject::startPlaybackBackward() +{ + /* make sure we execute in mThread context */ + if( mThread_p && (mThread_p != QThread::currentThread()) ) { + QMetaObject::invokeMethod(this, "startPlaybackBackward", + Qt::BlockingQueuedConnection); + return; + } + + playbackActive = true; + playbackForward = false; + if (useOrigTiming) + { + playbackElapsed.start(); + playbackTimer->setInterval(1); + playbackLastTimeStamp = currentSeqItem->data[currentPosition].timestamp + 2000; + } + playbackTimer->start(); +} + +void FramePlaybackObject::stepPlaybackForward() +{ + /* make sure we execute in mThread context */ + if( mThread_p && (mThread_p != QThread::currentThread()) ) { + QMetaObject::invokeMethod(this, "stepPlaybackForward", + Qt::BlockingQueuedConnection); + return; + } + + sendingBuffer.clear(); + playbackTimer->stop(); + playbackActive = false; + updatePosition(true); + CANConManager::getInstance()->sendFrames(sendingBuffer); +} + +void FramePlaybackObject::stepPlaybackBackward() +{ + /* make sure we execute in mThread context */ + if( mThread_p && (mThread_p != QThread::currentThread()) ) { + QMetaObject::invokeMethod(this, "stepPlaybackBackward", + Qt::BlockingQueuedConnection); + return; + } + + sendingBuffer.clear(); + playbackTimer->stop(); //pushing this button halts automatic playback + playbackActive = false; + + updatePosition(false); + CANConManager::getInstance()->sendFrames(sendingBuffer); +} + +void FramePlaybackObject::stopPlayback() +{ + /* make sure we execute in mThread context */ + if( mThread_p && (mThread_p != QThread::currentThread()) ) { + QMetaObject::invokeMethod(this, "stopPlayback", + Qt::BlockingQueuedConnection); + return; + } + + playbackTimer->stop(); //pushing this button halts automatic playback + playbackActive = false; + currentPosition = 0; + /* + if (seqItems.count() > 0) + { + currentSeqNum = 0; + currentSeqItem = &seqItems[currentSeqNum]; + } + else { + currentSeqNum = -1; + currentSeqItem = NULL; + } + if (ui->tblSequence->rowCount() > 0) + { + ui->tblSequence->setCurrentCell(0, 0); + refreshIDList(); + } + updateFrameLabel(); */ +} + +void FramePlaybackObject::pausePlayback() +{ + /* make sure we execute in mThread context */ + if( mThread_p && (mThread_p != QThread::currentThread()) ) { + QMetaObject::invokeMethod(this, "pausePlayback", + Qt::BlockingQueuedConnection); + return; + } + + playbackActive = false; + playbackTimer->stop(); +} + +void FramePlaybackObject::setSequenceObject(SequenceItem *item) +{ + currentSeqItem = item; +} + +void FramePlaybackObject::setUseOriginalTiming(bool state) +{ + useOrigTiming = state; +} + +void FramePlaybackObject::setSendingBus(int bus) +{ + whichBusSend = bus; +} + +void FramePlaybackObject::setPlaybackBurst(int burst) +{ + playbackBurst = burst; +} + +void FramePlaybackObject::setNumBuses(int buses) +{ + numBuses = buses; +} + +//any time you touch objects that live in a potentially different thread you must switch into that thread. +//So this function is a bit different than the rest of the simple setters for that reason. +void FramePlaybackObject::setPlaybackInterval(int interval) +{ + /* make sure we execute in mThread context */ + if( mThread_p && (mThread_p != QThread::currentThread()) ) { + QMetaObject::invokeMethod(this, "setPlaybackInterval", + Qt::BlockingQueuedConnection, + Q_ARG(int , interval) ); + return; + } + playbackInterval = interval; + playbackTimer->setInterval(interval); +} + +void FramePlaybackObject::timerTriggered() +{ + sendingBuffer.clear(); + + if (useOrigTiming) + { + //get elapsed microseconds since last tick (in case timer skips or is otherwise inaccurate, though there are no guarantees about elapsed timer either) + quint64 elapsed = playbackElapsed.nsecsElapsed() / 1000; + playbackElapsed.start(); + if (playbackForward) + { + playbackLastTimeStamp += elapsed; + //qDebug() << playbackLastTimeStamp; + //qDebug() << "El: " << elapsed; + while (peekPosition(true) <= playbackLastTimeStamp) + { + updatePosition(true); + } + if (peekPosition(true) == 0xFFFFFFFFFFFFFFFFull) + { + updatePosition(true); //this'll go to the next log (if there is one) + if (currentSeqItem->data[currentPosition].timestamp > 1000) + playbackLastTimeStamp = currentSeqItem->data[currentPosition].timestamp - 1000; + else playbackLastTimeStamp = 0; + } + } + else + { + if (playbackLastTimeStamp > elapsed) + playbackLastTimeStamp -= elapsed; + else playbackLastTimeStamp = 0; + while (peekPosition(false) >= playbackLastTimeStamp && peekPosition(false) != 0xFFFFFFFFFFFFFFFFull) + { + updatePosition(false); + } + if (peekPosition(false) == 0xFFFFFFFFFFFFFFFFull) + { + updatePosition(false); //this'll go to the next log (if there is one) + playbackLastTimeStamp = currentSeqItem->data[currentPosition].timestamp + 1000; + } + } + statusCounter++; + } + else + { + for (int count = 0; count < playbackBurst; count++) + { + if (!playbackActive) + { + playbackTimer->stop(); + return; + } + if (playbackForward) + { + updatePosition(true); + } + else + { + updatePosition(false); + } + } + statusCounter += playbackInterval; + } + + if (statusCounter > 249) + { + statusCounter = 0; + emit statusUpdate(currentPosition); + } + + //qDebug() << "sb: " << sendingBuffer.count(); + if (sendingBuffer.count() > 0) CANConManager::getInstance()->sendFrames(sendingBuffer); +} + + + + + + + diff --git a/frameplaybackobject.h b/frameplaybackobject.h new file mode 100644 index 0000000..0935ffc --- /dev/null +++ b/frameplaybackobject.h @@ -0,0 +1,102 @@ +#ifndef FRAMEPLAYBACKOBJECT_H +#define FRAMEPLAYBACKOBJECT_H + +#include +#include +#include +#include +#include +#include "can_structs.h" +#include "connections/canconmanager.h" + +//one entry in the sequence of data to use +struct SequenceItem +{ + QString filename; + QVector data; + QHash idFilters; + int maxLoops; + int currentLoopCount; +}; + +/* + broken out functionality that used to be in frameplaybackwindow. That mixed code for Model/View/Controller into one giant + class. I wasn't too concerned about that but the problem is that all code within a GUI object runs in GUI context and that + is most certainly not a feature, especially if you have a multi-core CPU. This object lives in a separate thread from the GUI + and thus is better scheduled and doesn't block the GUI thread. Really all functionality in this program should be broken into + a separate thread from GUI if it is prone to running a long time and/or taking up a lot of CPU time (unless it really does + have to interface with the GUI in some way. All gui touching code must run on its thread). +*/ +class FramePlaybackObject : public QObject +{ + Q_OBJECT + +public: + FramePlaybackObject(); + ~FramePlaybackObject(); + +public slots: + /** + * @brief start the device. This calls piStarted + * @note starts the working thread if required (piStart is called in the working thread context) + */ + void initialize(); + + /** + * @brief stop the device. This calls piStop + * @note if a working thread is used, piStop is called before exiting the working thread + */ + void finalize(); + + void startPlaybackForward(); + void startPlaybackBackward(); + void stepPlaybackForward(); + void stepPlaybackBackward(); + void stopPlayback(); + void pausePlayback(); + + void setSequenceObject(SequenceItem *item); + void setUseOriginalTiming(bool state); + void setSendingBus(int bus); + void setPlaybackInterval(int interval); + void setPlaybackBurst(int burst); + void setNumBuses(int buses); + +signals: + void EndOfFrameCache(); //we hit the end/beginning of the frame cache (depending on direction of playback) + void statusUpdate(int frameNum); + +private slots: + void timerTriggered(); + +private: + QList sendingBuffer; + SequenceItem *currentSeqItem; + int currentPosition; + QTimer *playbackTimer; + QElapsedTimer playbackElapsed; + quint64 playbackLastTimeStamp; + int playbackInterval; + int playbackBurst; + int numBuses; + int statusCounter; + bool playbackActive; + bool playbackForward; + bool useOrigTiming; + int whichBusSend; + QThread* mThread_p; + + quint64 updatePosition(bool forward); + quint64 peekPosition(bool forward); + /** + * @brief starts the device + */ + void piStart(); + + /** + * @brief stops the device + */ + void piStop(); +}; + +#endif // FRAMEPLAYBACKOBJECT_H diff --git a/frameplaybackwindow.cpp b/frameplaybackwindow.cpp index b0f0eaa..87725ae 100644 --- a/frameplaybackwindow.cpp +++ b/frameplaybackwindow.cpp @@ -32,19 +32,17 @@ FramePlaybackWindow::FramePlaybackWindow(const QVector *frames, QWidge ui->comboCANBus->addItem(tr("From File")); ui->comboCANBus->setCurrentIndex(0); + playbackObject.initialize(); + playbackObject.setNumBuses(numBuses); + readSettings(); modelFrames = frames; - playbackTimer = new QTimer(); - playbackTimer->setTimerType(Qt::PreciseTimer); - - currentPosition = 0; - playbackActive = false; - playbackForward = true; - whichBusSend = 0; //0 = no bus, 1 = bus 0, 2 = bus 1, 4 = from file - Bitfield so you can 'or' them. currentSeqItem = NULL; currentSeqNum = -1; + currentPosition = 0; + forward = true; updateFrameLabel(); @@ -58,10 +56,10 @@ FramePlaybackWindow::FramePlaybackWindow(const QVector *frames, QWidge connect(ui->btnSelectNone, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnSelectNoneClick); connect(ui->btnDelete, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnDeleteCurrSeq); connect(ui->spinPlaySpeed, SIGNAL(valueChanged(int)), this, SLOT(changePlaybackSpeed(int))); + connect(ui->spinBurstSpeed, SIGNAL(valueChanged(int)), this, SLOT(changeBurstRate(int))); //connect(ui->cbLoop, SIGNAL(clicked(bool)), this, SLOT(changeLooping(bool))); connect(ui->comboCANBus, SIGNAL(currentIndexChanged(int)), this, SLOT(changeSendingBus(int))); connect(ui->listID, &QListWidget::itemClicked, this, &FramePlaybackWindow::changeIDFiltering); - connect(playbackTimer, &QTimer::timeout, this, &FramePlaybackWindow::timerTriggered); connect(ui->btnLoadFile, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnLoadFile); connect(ui->btnLoadLive, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnLoadLive); connect(ui->tblSequence, &QTableWidget::cellPressed, this, &FramePlaybackWindow::seqTableCellClicked); @@ -70,10 +68,13 @@ FramePlaybackWindow::FramePlaybackWindow(const QVector *frames, QWidge connect(ui->btnSaveFilters, &QAbstractButton::clicked, this, &FramePlaybackWindow::saveFilters); connect(ui->cbOriginalTiming, &QCheckBox::toggled, this, &FramePlaybackWindow::useOrigTimingClicked); + connect(&playbackObject, &FramePlaybackObject::EndOfFrameCache, this, &FramePlaybackWindow::EndOfFrameCache); + connect(&playbackObject, &FramePlaybackObject::statusUpdate, this, &FramePlaybackWindow::getStatusUpdate); + ui->listID->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui->listID, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuFilters(QPoint))); - playbackTimer->setInterval(ui->spinPlaySpeed->value()); //set the timer to the default value of the control + playbackObject.setPlaybackInterval(ui->spinPlaySpeed->value()); QStringList headers; headers << "Source" << "Loops"; @@ -86,9 +87,6 @@ FramePlaybackWindow::FramePlaybackWindow(const QVector *frames, QWidge FramePlaybackWindow::~FramePlaybackWindow() { delete ui; - - playbackTimer->stop(); - delete playbackTimer; } void FramePlaybackWindow::showEvent(QShowEvent *) @@ -116,7 +114,8 @@ void FramePlaybackWindow::readSettings() } ui->spinPlaySpeed->setValue(settings.value("Playback/DefSpeed", 5).toInt()); ui->comboCANBus->setCurrentIndex(settings.value("Playback/SendingBus", 0).toInt()); - whichBusSend = ui->comboCANBus->currentIndex(); + + calculateWhichBus(); } void FramePlaybackWindow::writeSettings() @@ -257,6 +256,35 @@ void FramePlaybackWindow::refreshIDList() ui->listID->sortItems(); } +void FramePlaybackWindow::calculateWhichBus() +{ + int idx = ui->comboCANBus->currentIndex(); + int maxIdx = ui->comboCANBus->count() - 1; + int out = idx; + if (idx == (maxIdx - 1) ) out = -1; + if (idx == maxIdx) out = -2; + + playbackObject.setSendingBus(out); +} + +void FramePlaybackWindow::EndOfFrameCache() +{ + if (forward) + { + + } + else + { + + } +} + +void FramePlaybackWindow::getStatusUpdate(int frameNum) +{ + currentPosition = frameNum; + updateFrameLabel(); +} + void FramePlaybackWindow::updateFrameLabel() { int row = currentSeqNum; @@ -320,11 +348,13 @@ void FramePlaybackWindow::useOrigTimingClicked() { ui->spinBurstSpeed->setEnabled(false); ui->spinPlaySpeed->setEnabled(false); + playbackObject.setUseOriginalTiming(true); } else { ui->spinBurstSpeed->setEnabled(true); ui->spinPlaySpeed->setEnabled(true); + playbackObject.setUseOriginalTiming(false); } } @@ -332,11 +362,7 @@ void FramePlaybackWindow::btnDeleteCurrSeq() { if (currentSeqNum == -1) return; - if (playbackActive) - { - playbackActive = false; - playbackTimer->stop(); - } + playbackObject.stopPlayback(); seqItems.removeAt(currentSeqNum); ui->tblSequence->removeRow(currentSeqNum); @@ -380,6 +406,7 @@ void FramePlaybackWindow::btnLoadFile() { currentSeqNum = 0; currentSeqItem = &seqItems[0]; + playbackObject.setSequenceObject(currentSeqItem); } refreshIDList(); updateFrameLabel(); @@ -408,6 +435,7 @@ void FramePlaybackWindow::btnLoadLive() { currentSeqNum = 0; currentSeqItem = &seqItems[0]; + playbackObject.setSequenceObject(currentSeqItem); } refreshIDList(); updateFrameLabel(); @@ -416,38 +444,24 @@ void FramePlaybackWindow::btnLoadLive() void FramePlaybackWindow::btnBackOneClick() { - sendingBuffer.clear(); - playbackTimer->stop(); //pushing this button halts automatic playback - playbackActive = false; - - updatePosition(false); - CANConManager::getInstance()->sendFrames(sendingBuffer); + forward = false; + playbackObject.stepPlaybackBackward(); } void FramePlaybackWindow::btnPauseClick() { - playbackActive = false; - playbackTimer->stop(); + playbackObject.pausePlayback(); } void FramePlaybackWindow::btnReverseClick() { - playbackActive = true; - playbackForward = false; - if (ui->cbOriginalTiming->isChecked()) - { - playbackElapsed.start(); - playbackTimer->setInterval(1); - playbackLastTimeStamp = currentSeqItem->data[currentPosition].timestamp + 2000; - } - playbackTimer->start(); + forward = false; + playbackObject.startPlaybackBackward(); } void FramePlaybackWindow::btnStopClick() { - playbackTimer->stop(); //pushing this button halts automatic playback - playbackActive = false; - currentPosition = 0; + playbackObject.stopPlayback(); if (seqItems.count() > 0) { currentSeqNum = 0; @@ -462,36 +476,29 @@ void FramePlaybackWindow::btnStopClick() ui->tblSequence->setCurrentCell(0, 0); refreshIDList(); } - updateFrameLabel(); + //updateFrameLabel(); } void FramePlaybackWindow::btnPlayClick() { - playbackActive = true; - playbackForward = true; - if (ui->cbOriginalTiming->isChecked()) - { - playbackTimer->setInterval(1); - playbackElapsed.start(); - if (currentSeqItem->data[currentPosition].timestamp > 1000) - playbackLastTimeStamp = currentSeqItem->data[currentPosition].timestamp - 2000; - else playbackLastTimeStamp = 0; - } - playbackTimer->start(); + forward = true; + playbackObject.startPlaybackForward(); } void FramePlaybackWindow::btnFwdOneClick() { - sendingBuffer.clear(); - playbackTimer->stop(); - playbackActive = false; - updatePosition(true); - CANConManager::getInstance()->sendFrames(sendingBuffer); + forward = true; + playbackObject.stepPlaybackForward(); } void FramePlaybackWindow::changePlaybackSpeed(int newSpeed) { - playbackTimer->setInterval(newSpeed); + playbackObject.setPlaybackInterval(newSpeed); +} + +void FramePlaybackWindow::changeBurstRate(int burst) +{ + playbackObject.setPlaybackBurst(burst); } void FramePlaybackWindow::changeLooping(bool check) @@ -501,7 +508,7 @@ void FramePlaybackWindow::changeLooping(bool check) void FramePlaybackWindow::changeSendingBus(int newIdx) { - whichBusSend = newIdx; + calculateWhichBus(); } void FramePlaybackWindow::changeIDFiltering(QListWidgetItem *item) @@ -530,185 +537,3 @@ void FramePlaybackWindow::btnSelectNoneClick() currentSeqItem->idFilters[Utility::ParseStringToNum(item->text())] = false; } } - -void FramePlaybackWindow::timerTriggered() -{ - sendingBuffer.clear(); - - if (ui->cbOriginalTiming->isChecked()) - { - //get elapsed microseconds since last tick (in case timer skips or is otherwise inaccurate, though there are no guarantees about elapsed timer either) - quint64 elapsed = playbackElapsed.nsecsElapsed() / 1000; - playbackElapsed.start(); - if (playbackForward) - { - playbackLastTimeStamp += elapsed; - //qDebug() << playbackLastTimeStamp; - while (peekPosition(true) <= playbackLastTimeStamp) - { - updatePosition(true); - } - if (peekPosition(true) == 0xFFFFFFFFFFFFFFFFull) - { - updatePosition(true); //this'll go to the next log (if there is one) - if (currentSeqItem->data[currentPosition].timestamp > 1000) - playbackLastTimeStamp = currentSeqItem->data[currentPosition].timestamp - 1000; - else playbackLastTimeStamp = 0; - } - } - else - { - if (playbackLastTimeStamp > elapsed) - playbackLastTimeStamp -= elapsed; - else playbackLastTimeStamp = 0; - while (peekPosition(false) >= playbackLastTimeStamp && peekPosition(false) != 0xFFFFFFFFFFFFFFFFull) - { - updatePosition(false); - } - if (peekPosition(false) == 0xFFFFFFFFFFFFFFFFull) - { - updatePosition(false); //this'll go to the next log (if there is one) - playbackLastTimeStamp = currentSeqItem->data[currentPosition].timestamp + 1000; - } - } - } - else - { - for (int count = 0; count < ui->spinBurstSpeed->value(); count++) - { - if (!playbackActive) - { - playbackTimer->stop(); - return; - } - if (playbackForward) - { - updatePosition(true); - } - else - { - updatePosition(false); - } - } - } - - CANConManager::getInstance()->sendFrames(sendingBuffer); -} - -quint64 FramePlaybackWindow::updatePosition(bool forward) -{ - //qDebug() << "updatePosition"; - if (forward) - { - if (currentPosition < (currentSeqItem->data.count() - 1)) currentPosition++; //still in same file so keep going - else //hit the end of the current file - { - qDebug() << "hit end of current sequence"; - currentSeqItem->currentLoopCount++; - currentPosition = 0; - if (currentSeqItem->currentLoopCount == currentSeqItem->maxLoops) //have we looped enough times? - { - currentSeqNum++; //go forward in the sequence - if (currentSeqNum == seqItems.count()) //are we at the end of the sequence? - { - //reset the loop figures for each sequence entry - for (int i = 0; i < seqItems.count(); i++) seqItems[i].currentLoopCount = 0; - currentSeqNum = 0; - if (ui->cbLoop->isChecked()) //go back to beginning if we're looping the sequence - { - - } - else //not looping so stop playback entirely - { - playbackActive = false; - playbackTimer->stop(); - } - } - currentSeqItem = &seqItems[currentSeqNum]; - ui->tblSequence->setCurrentCell(currentSeqNum, 0); - } - } - } - else - { - if (currentPosition > 0) currentPosition--; - else //hit the beginning of the current sequence - { - qDebug() << "hit start of current sequence"; - currentSeqItem->currentLoopCount++; - currentPosition = currentSeqItem->data.count() - 1; - if (currentSeqItem->currentLoopCount == currentSeqItem->maxLoops) //have we looped enough times? - { - currentSeqNum--; //go backward in the sequence - if (currentSeqNum == -1) //are we trying to go past the beginning? - { - //reset the loop figures for each sequence entry - for (int i = 0; i < seqItems.count(); i++) seqItems[i].currentLoopCount = 0; - currentSeqNum = seqItems.count() - 1; - if (ui->cbLoop->isChecked()) //go back to the last sequence entry if we're looping - { - - } - else //not looping so stop playback entirely - { - playbackActive = false; - playbackTimer->stop(); - } - } - currentSeqItem = &seqItems[currentSeqNum]; - ui->tblSequence->setCurrentCell(currentSeqNum, 0); - } - } - } - updateFrameLabel(); - //only send frame out if its ID is checked in the list. Otherwise discard it. - CANFrame *thisFrame = ¤tSeqItem->data[currentPosition]; - uint32_t originalBus = thisFrame->bus; - if (currentSeqItem->idFilters.find(thisFrame->ID).value()) - { - if (whichBusSend < ui->comboCANBus->count() - 2) - { - thisFrame->bus = whichBusSend; - sendingBuffer.append(*thisFrame); - } - else if (whichBusSend == (ui->comboCANBus->count() - 2)) //all - { - for (int c = 0; c < ui->comboCANBus->count() - 2; c++) - { - thisFrame->bus = c; - sendingBuffer.append(*thisFrame); - } - } - else //from file so retain original bus and send as-is - { - sendingBuffer.append(*thisFrame); - } - - thisFrame->bus = originalBus; - } - return thisFrame->timestamp; -} - -quint64 FramePlaybackWindow::peekPosition(bool forward) -{ - int peekCurrentPosition = currentPosition; - if (forward) - { - if (peekCurrentPosition < (currentSeqItem->data.count() - 1)) peekCurrentPosition++; //still in same file so keep going - else //hit the end of the current file - { - return 0xFFFFFFFFFFFFFFFFull; - } - } - else - { - if (peekCurrentPosition > 0) peekCurrentPosition--; - else //hit the beginning of the current sequence - { - return 0xFFFFFFFFFFFFFFFFull; - } - } - CANFrame *thisFrame = ¤tSeqItem->data[peekCurrentPosition]; - return thisFrame->timestamp; -} - diff --git a/frameplaybackwindow.h b/frameplaybackwindow.h index 7de1ac3..f9e163d 100644 --- a/frameplaybackwindow.h +++ b/frameplaybackwindow.h @@ -2,26 +2,15 @@ #define FRAMEPLAYBACKWINDOW_H #include -#include #include -#include #include "can_structs.h" #include "framefileio.h" +#include "frameplaybackobject.h" namespace Ui { class FramePlaybackWindow; } -//one entry in the sequence of data to use -struct SequenceItem -{ - QString filename; - QVector data; - QHash idFilters; - int maxLoops; - int currentLoopCount; -}; - class FramePlaybackWindow : public QDialog { Q_OBJECT @@ -39,12 +28,12 @@ private slots: void btnFwdOneClick(); void btnDeleteCurrSeq(); void changePlaybackSpeed(int newSpeed); + void changeBurstRate(int burst); void changeLooping(bool check); void changeSendingBus(int newIdx); void changeIDFiltering(QListWidgetItem *item); void btnSelectAllClick(); void btnSelectNoneClick(); - void timerTriggered(); void btnLoadFile(); void btnLoadLive(); void seqTableCellClicked(int row, int col); @@ -53,33 +42,29 @@ private slots: void saveFilters(); void loadFilters(); void useOrigTimingClicked(); + void getStatusUpdate(int frameNum); + void EndOfFrameCache(); private: Ui::FramePlaybackWindow *ui; QList foundID; QList frameCache; - QList sendingBuffer; const QVector *modelFrames; - int currentPosition; - QTimer *playbackTimer; - QElapsedTimer playbackElapsed; - quint64 playbackLastTimeStamp; - bool playbackActive; - bool playbackForward; - int whichBusSend; QList seqItems; SequenceItem *currentSeqItem; int currentSeqNum; + FramePlaybackObject playbackObject; + bool forward; + int currentPosition; void refreshIDList(); void updateFrameLabel(); - quint64 updatePosition(bool forward); - quint64 peekPosition(bool forward); void fillIDHash(SequenceItem &item); void showEvent(QShowEvent *); void closeEvent(QCloseEvent *event); void readSettings(); void writeSettings(); + void calculateWhichBus(); }; #endif // FRAMEPLAYBACKWINDOW_H From ed2cd7bd8cf3d9e35127bb59360de35758c08cba Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Wed, 8 Nov 2017 21:09:20 -0500 Subject: [PATCH 09/11] Reimplemented the ability to chain multiple log files and run them in sequences. --- frameplaybackobject.cpp | 59 +---------------------------------------- frameplaybackwindow.cpp | 49 ++++++++++++++++++++++++++++++++-- frameplaybackwindow.h | 1 + 3 files changed, 49 insertions(+), 60 deletions(-) diff --git a/frameplaybackobject.cpp b/frameplaybackobject.cpp index c58c048..5d41774 100644 --- a/frameplaybackobject.cpp +++ b/frameplaybackobject.cpp @@ -38,26 +38,6 @@ quint64 FramePlaybackObject::updatePosition(bool forward) playbackActive = false; playbackTimer->stop(); emit EndOfFrameCache(); - /* - currentSeqNum++; //go forward in the sequence - if (currentSeqNum == seqItems.count()) //are we at the end of the sequence? - { - //reset the loop figures for each sequence entry - for (int i = 0; i < seqItems.count(); i++) seqItems[i].currentLoopCount = 0; - currentSeqNum = 0; - if (ui->cbLoop->isChecked()) //go back to beginning if we're looping the sequence - { - - } - else //not looping so stop playback entirely - { - playbackActive = false; - playbackTimer->stop(); - } - } - currentSeqItem = &seqItems[currentSeqNum]; - ui->tblSequence->setCurrentCell(currentSeqNum, 0); - */ } } } @@ -74,31 +54,10 @@ quint64 FramePlaybackObject::updatePosition(bool forward) playbackActive = false; playbackTimer->stop(); emit EndOfFrameCache(); - - /* - currentSeqNum--; //go backward in the sequence - if (currentSeqNum == -1) //are we trying to go past the beginning? - { - //reset the loop figures for each sequence entry - for (int i = 0; i < seqItems.count(); i++) seqItems[i].currentLoopCount = 0; - currentSeqNum = seqItems.count() - 1; - if (ui->cbLoop->isChecked()) //go back to the last sequence entry if we're looping - { - - } - else //not looping so stop playback entirely - { - playbackActive = false; - playbackTimer->stop(); - } - } - currentSeqItem = &seqItems[currentSeqNum]; - ui->tblSequence->setCurrentCell(currentSeqNum, 0); - */ } } } - //updateFrameLabel(); + //only send frame out if its ID is checked in the list. Otherwise discard it. CANFrame *thisFrame = ¤tSeqItem->data[currentPosition]; uint32_t originalBus = thisFrame->bus; @@ -303,22 +262,6 @@ void FramePlaybackObject::stopPlayback() playbackTimer->stop(); //pushing this button halts automatic playback playbackActive = false; currentPosition = 0; - /* - if (seqItems.count() > 0) - { - currentSeqNum = 0; - currentSeqItem = &seqItems[currentSeqNum]; - } - else { - currentSeqNum = -1; - currentSeqItem = NULL; - } - if (ui->tblSequence->rowCount() > 0) - { - ui->tblSequence->setCurrentCell(0, 0); - refreshIDList(); - } - updateFrameLabel(); */ } void FramePlaybackObject::pausePlayback() diff --git a/frameplaybackwindow.cpp b/frameplaybackwindow.cpp index 87725ae..d8460cb 100644 --- a/frameplaybackwindow.cpp +++ b/frameplaybackwindow.cpp @@ -43,6 +43,7 @@ FramePlaybackWindow::FramePlaybackWindow(const QVector *frames, QWidge currentSeqNum = -1; currentPosition = 0; forward = true; + isPlaying = false; updateFrameLabel(); @@ -271,11 +272,49 @@ void FramePlaybackWindow::EndOfFrameCache() { if (forward) { + currentSeqNum++; //go forward in the sequence + if (currentSeqNum == seqItems.count()) //are we at the end of the sequence? + { + //reset the loop figures for each sequence entry + for (int i = 0; i < seqItems.count(); i++) seqItems[i].currentLoopCount = 0; + currentSeqNum = 0; + if (ui->cbLoop->isChecked()) //go back to beginning if we're looping the sequence + { + } + else //not looping so stop playback entirely + { + isPlaying = false; + playbackObject.stopPlayback(); + } + } + currentSeqItem = &seqItems[currentSeqNum]; + playbackObject.setSequenceObject(currentSeqItem); + if (isPlaying) playbackObject.startPlaybackForward(); + ui->tblSequence->setCurrentCell(currentSeqNum, 0); } else { + currentSeqNum--; //go backward in the sequence + if (currentSeqNum == -1) //are we trying to go past the beginning? + { + //reset the loop figures for each sequence entry + for (int i = 0; i < seqItems.count(); i++) seqItems[i].currentLoopCount = 0; + currentSeqNum = seqItems.count() - 1; + if (ui->cbLoop->isChecked()) //go back to the last sequence entry if we're looping + { + } + else //not looping so stop playback entirely + { + isPlaying = false; + playbackObject.stopPlayback(); + } + } + currentSeqItem = &seqItems[currentSeqNum]; + playbackObject.setSequenceObject(currentSeqItem); + if (isPlaying) playbackObject.startPlaybackBackward(); + ui->tblSequence->setCurrentCell(currentSeqNum, 0); } } @@ -445,22 +484,26 @@ void FramePlaybackWindow::btnLoadLive() void FramePlaybackWindow::btnBackOneClick() { forward = false; + isPlaying = false; playbackObject.stepPlaybackBackward(); } void FramePlaybackWindow::btnPauseClick() { + isPlaying = false; playbackObject.pausePlayback(); } void FramePlaybackWindow::btnReverseClick() { forward = false; + isPlaying = true; playbackObject.startPlaybackBackward(); } void FramePlaybackWindow::btnStopClick() { + isPlaying = false; playbackObject.stopPlayback(); if (seqItems.count() > 0) { @@ -475,19 +518,21 @@ void FramePlaybackWindow::btnStopClick() { ui->tblSequence->setCurrentCell(0, 0); refreshIDList(); - } - //updateFrameLabel(); + } + updateFrameLabel(); } void FramePlaybackWindow::btnPlayClick() { forward = true; + isPlaying = true; playbackObject.startPlaybackForward(); } void FramePlaybackWindow::btnFwdOneClick() { forward = true; + isPlaying = false; playbackObject.stepPlaybackForward(); } diff --git a/frameplaybackwindow.h b/frameplaybackwindow.h index f9e163d..996ac55 100644 --- a/frameplaybackwindow.h +++ b/frameplaybackwindow.h @@ -55,6 +55,7 @@ private: int currentSeqNum; FramePlaybackObject playbackObject; bool forward; + bool isPlaying; int currentPosition; void refreshIDList(); From 545f258b8ee9ab61920370d09f8464398a0a3349 Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Wed, 8 Nov 2017 21:20:17 -0500 Subject: [PATCH 10/11] Make sent frames have a timestamp resolution of microseconds just like incoming frames. Previously sent frame time stamps were rounded to the nearest millisecond. Note, however, that this time stamp is when we first tried to send the frame to hardware, not when the hardware sent the frame. That will probably be later on but there's no way to know for sure if/when it will send the frame. --- connections/canconmanager.cpp | 12 ++++++++++-- connections/canconmanager.h | 2 ++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/connections/canconmanager.cpp b/connections/canconmanager.cpp index e9c3736..b3428a3 100644 --- a/connections/canconmanager.cpp +++ b/connections/canconmanager.cpp @@ -36,6 +36,7 @@ CANConManager::CANConManager(QObject *parent): QObject(parent) void CANConManager::resetTimeBasis() { mTimestampBasis = QDateTime::currentMSecsSinceEpoch() * 1000; + mElapsedTimer.restart(); } CANConManager::~CANConManager() @@ -182,8 +183,15 @@ bool CANConManager::sendFrame(const CANFrame& pFrame) { workingFrame.bus -= busBase; workingFrame.isReceived = false; - workingFrame.timestamp = (QDateTime::currentMSecsSinceEpoch() * 1000); - if (!useSystemTime) workingFrame.timestamp -= mTimestampBasis; + if (useSystemTime) + { + workingFrame.timestamp = (QDateTime::currentMSecsSinceEpoch() * 1000); + } + else + { + workingFrame.timestamp = mElapsedTimer.nsecsElapsed() / 1000; + //workingFrame.timestamp -= mTimestampBasis; + } txFrame = conn->getQueue().get(); *txFrame = workingFrame; conn->getQueue().queue(); diff --git a/connections/canconmanager.h b/connections/canconmanager.h index 7d82bb2..26c6c76 100644 --- a/connections/canconmanager.h +++ b/connections/canconmanager.h @@ -3,6 +3,7 @@ #include #include +#include #include "canconnection.h" @@ -73,6 +74,7 @@ private: static CANConManager* mInstance; QList mConns; QTimer mTimer; + QElapsedTimer mElapsedTimer; uint64_t mTimestampBasis; uint32_t mNumActiveBuses; bool useSystemTime; From c398856806a9c1287abb46299e6f8aef9a6ec6d9 Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Thu, 9 Nov 2017 20:07:00 -0500 Subject: [PATCH 11/11] Small fix to make unconnected devices still show up properly in the connection window --- connections/canconnectionmodel.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/connections/canconnectionmodel.cpp b/connections/canconnectionmodel.cpp index f68b9d0..a63c508 100644 --- a/connections/canconnectionmodel.cpp +++ b/connections/canconnectionmodel.cpp @@ -151,16 +151,13 @@ QVariant CANConnectionModel::data(const QModelIndex &index, int role) const CANConnection *conn_p = getAtIdx(index.row(), busId); CANBus bus; bool ret; + if (!conn_p) return QVariant(); ret = conn_p->getBusSettings(busId, bus); bool isSocketCAN = (conn_p->getType() == CANCon::SOCKETCAN) ? true: false; //qDebug() << "ConnP: " << conn_p << " ret " << ret; - if (role == Qt::DisplayRole) { - if(!conn_p) - return QVariant(); - - if(!ret) return QVariant(); + if (role == Qt::DisplayRole) { switch (index.column()) { @@ -183,6 +180,7 @@ QVariant CANConnectionModel::data(const QModelIndex &index, int role) const else qDebug() << "Tried to show connection port but connection was NULL"; break; case 3: //speed + if(!ret) return QVariant(); if (!isSocketCAN) return QString::number(bus.speed); else return QString("N/A"); case 4: //Listen Only