diff --git a/SavvyCAN.pro b/SavvyCAN.pro index 0ef31a1..1e02488 100644 --- a/SavvyCAN.pro +++ b/SavvyCAN.pro @@ -66,7 +66,8 @@ SOURCES += main.cpp\ frameplaybackobject.cpp \ helpwindow.cpp \ blfhandler.cpp \ - re/sniffer/SnifferDelegate.cpp + re/sniffer/SnifferDelegate.cpp \ + connections/newconnectiondialog.cpp HEADERS += mainwindow.h \ can_structs.h \ @@ -123,7 +124,8 @@ HEADERS += mainwindow.h \ frameplaybackobject.h \ helpwindow.h \ blfhandler.h \ - re/sniffer/SnifferDelegate.h + re/sniffer/SnifferDelegate.h \ + connections/newconnectiondialog.h FORMS += ui/candatagrid.ui \ ui/connectionwindow.ui \ @@ -150,7 +152,8 @@ FORMS += ui/candatagrid.ui \ ui/udsscanwindow.ui \ ui/bisectwindow.ui \ ui/signalviewerwindow.ui \ - helpwindow.ui + helpwindow.ui \ + ui/newconnectiondialog.ui DISTFILES += diff --git a/blfhandler.cpp b/blfhandler.cpp index 439c2ef..49e9694 100644 --- a/blfhandler.cpp +++ b/blfhandler.cpp @@ -94,7 +94,8 @@ bool BLFHandler::loadBLF(QString filename, QVector* frames) frame.remote = false; for (int i = 0; i < 8; i++) frame.data[i] = canObject.data[i]; } - frame.timestamp = obj.header.uncompSize / 1000000.0; //uncompsize field also used for timestamp oddly enough + //Should we divide by a thousand or a million? Unsure here. It appears some logs are stamped in microseconds and some in milliseconds? + frame.timestamp = obj.header.uncompSize / 1000.0; //uncompsize field also used for timestamp oddly enough frames->append(frame); } else diff --git a/candatagrid.cpp b/candatagrid.cpp index adbbd08..8327608 100644 --- a/candatagrid.cpp +++ b/candatagrid.cpp @@ -73,7 +73,7 @@ void CANDataGrid::paintEvent(QPaintEvent *event) //The left most column has "BYTES" written vertically down it //the next left most column has "0 1 2 3 4 5 6 7" written down along the grid - painter.setPen(QPen(Qt::black)); + painter.setPen(QPen(QApplication::palette().color(QPalette::Text))); QFont mainFont; mainFont.setPixelSize(qMin(xSector, ySector) - 10); painter.setFont(mainFont); diff --git a/canframemodel.cpp b/canframemodel.cpp index eea4ae0..199a196 100644 --- a/canframemodel.cpp +++ b/canframemodel.cpp @@ -134,25 +134,33 @@ void CANFrameModel::setTimeFormat(QString format) endResetModel(); } +/* + * Scan all frames for the smallest timestamp and offset all timestamps so that smallest one is at 0 +*/ void CANFrameModel::normalizeTiming() { mutex.lock(); if (frames.count() == 0) return; timeOffset = frames[0].timestamp; + + //find the absolute lowest timestamp in the whole time. Needed because maybe timestamp was reset in the middle. for (int j = 0; j < frames.count(); j++) { if (frames[j].timestamp < timeOffset) timeOffset = frames[j].timestamp; } + for (int i = 0; i < frames.count(); i++) { frames[i].timestamp -= timeOffset; } + this->beginResetModel(); for (int i = 0; i < filteredFrames.count(); i++) { filteredFrames[i].timestamp -= timeOffset; } this->endResetModel(); + mutex.unlock(); } @@ -227,6 +235,8 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const int dLen; QString tempString; CANFrame thisFrame; + static bool rowFlip = false; + QVariant ts; if (!index.isValid()) return QVariant(); @@ -246,8 +256,9 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const return msg->bgColor; } } - //return QApplication::palette().color(QPalette::Button); - return QColor(Qt::white); + rowFlip = (index.row() % 2); + if (rowFlip) return QApplication::palette().color(QPalette::Base); + else return QApplication::palette().color(QPalette::AlternateBase); } if (role == Qt::TextAlignmentRole) @@ -332,11 +343,17 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const for (int j = 0; j < msg->sigHandler->getCount(); j++) { QString sigString; - if (msg->sigHandler->findSignalByIdx(j)->processAsText(thisFrame, sigString)) + DBC_SIGNAL* sig = msg->sigHandler->findSignalByIdx(j); + if (sig->processAsText(thisFrame, sigString)) { tempString.append(sigString); tempString.append("\n"); } + else if (sig->isMultiplexed && overwriteDups) //wasn't in this exact frame but is in the message. Use cached value + { + tempString.append(sig->makePrettyOutput(sig->cachedValue.toDouble(), sig->cachedValue.toLongLong())); + tempString.append("\n"); + } } } } diff --git a/config.h b/config.h index 5febcc8..b072063 100644 --- a/config.h +++ b/config.h @@ -1,7 +1,7 @@ #ifndef CONFIG #define CONFIG -#define VERSION 190 +#define VERSION 196 //try to keep this in sync. //SavvyCAN will complain if you connect a GVRET board with a revision diff --git a/connections/canbus.cpp b/connections/canbus.cpp index 13aeb11..24238f7 100644 --- a/connections/canbus.cpp +++ b/connections/canbus.cpp @@ -40,7 +40,7 @@ void CANBus::setSingleWire(bool mode){ singleWire = mode; } -void CANBus::setEnabled(bool mode){ +void CANBus::setActive(bool mode){ //qDebug() << "CANBUS SetEnabled = " << mode; active = mode; } diff --git a/connections/canbus.h b/connections/canbus.h index 73f945f..fb2d382 100644 --- a/connections/canbus.h +++ b/connections/canbus.h @@ -20,7 +20,7 @@ public: void setSpeed(int); // new speed void setListenOnly(bool); //bool for whether to only listen void setSingleWire(bool); //bool for whether to use single wire mode - void setEnabled(bool); //whether this bus should be enabled or not. + void setActive(bool); //whether this bus should be enabled or not. int getSpeed(); bool isListenOnly(); bool isSingleWire(); diff --git a/connections/canconmanager.cpp b/connections/canconmanager.cpp index b3428a3..014248f 100644 --- a/connections/canconmanager.cpp +++ b/connections/canconmanager.cpp @@ -2,6 +2,7 @@ #include #include "canconmanager.h" +#include "canconfactory.h" CANConManager* CANConManager::mInstance = NULL; @@ -76,10 +77,33 @@ int CANConManager::getNumBuses() return buses; } +int CANConManager::getBusBase(CANConnection *which) +{ + int buses = 0; + foreach(CANConnection* conn_p, mConns) + { + if (conn_p != which) buses += conn_p->getNumBuses(); + else return buses; + } + return -1; +} + void CANConManager::refreshCanList() { QObject* sender_p = QObject::sender(); + if (mConns.count() == 0) + { + //TODO: Seems to crash under heavy load. Find out why. + if(buslessFrames.size()) { + tempFrames.clear(); + tempFrames.append(buslessFrames); //make a copy and pass that copy + buslessFrames.clear(); //delete all frames from the original + emit framesReceived(nullptr, tempFrames); + } + return; + } + if( sender_p != &mTimer) { /* if we are not the sender, the signal is coming from a connection */ @@ -176,6 +200,12 @@ bool CANConManager::sendFrame(const CANFrame& pFrame) CANFrame workingFrame = pFrame; CANFrame *txFrame; + if (mConns.count() == 0) + { + buslessFrames.append(pFrame); + return true; + } + foreach (CANConnection* conn, mConns) { //check if this CAN connection is supposed to handle the requested bus diff --git a/connections/canconmanager.h b/connections/canconmanager.h index 26c6c76..5a5f9dc 100644 --- a/connections/canconmanager.h +++ b/connections/canconmanager.h @@ -26,6 +26,7 @@ public: void resetTimeBasis(); int getNumBuses(); + int getBusBase(CANConnection *); /** * @brief sendFrame sends a single frame out the desired bus @@ -77,7 +78,9 @@ private: QElapsedTimer mElapsedTimer; uint64_t mTimestampBasis; uint32_t mNumActiveBuses; - bool useSystemTime; + bool useSystemTime; + QVector buslessFrames; + QVector tempFrames; }; #endif // CANCONNECTIONMODEL_H diff --git a/connections/canconnection.cpp b/connections/canconnection.cpp index ec99099..6a41758 100644 --- a/connections/canconnection.cpp +++ b/connections/canconnection.cpp @@ -210,7 +210,7 @@ void CANConnection::setConfigured(int pBusId, bool pConfigured) { bool CANConnection::getBusConfig(int pBusId, CANBus& pBus) { if( pBusId < 0 || pBusId >= getNumBuses() || !isConfigured(pBusId)) return false; - + qDebug() << "getBusConfig id: " << pBusId; pBus = mBusData[pBusId].mBus; return true; } diff --git a/connections/canconnectionmodel.cpp b/connections/canconnectionmodel.cpp index ac07450..12d4f25 100644 --- a/connections/canconnectionmodel.cpp +++ b/connections/canconnectionmodel.cpp @@ -12,14 +12,11 @@ CANConnectionModel::~CANConnectionModel() } enum class Column { - Bus = 0, ///< A sequential number describing the bus - Type = 1, ///< The CAN driver/backend type, e.g. GVRET, peakcan, or socketcan + Type = 0, ///< The CAN driver/backend type, e.g. GVRET, peakcan, or socketcan + Subtype = 1, ///< Mostly used by SerialBus devices to pick the sub type Port = 2, ///< The CAN hardware port, e.g. can0 for socketcan - Speed = 3, ///< The bus speed in bit/second - ListenOnly = 4, ///< True if the bus is in listen-only mode - SingleWire = 5, ///< True if the bus operates in single-wire mode - Active = 6, ///< True if the bus is activated for sending and receiving - Status = 7 ///< The bus status as text message + NumBuses = 3, ///< Number of buses exposed by this device. Usually non-GVRET devices will just have one + Status = 4 ///< The bus status as text message }; QVariant CANConnectionModel::headerData(int section, Qt::Orientation orientation, int role) const @@ -31,20 +28,14 @@ QVariant CANConnectionModel::headerData(int section, Qt::Orientation orientation { switch (Column(section)) { - case Column::Bus: - return QString(tr("Bus")); case Column::Type: return QString(tr("Type")); + case Column::Subtype: + return QString(tr("Subtype")); case Column::Port: return QString(tr("Port")); - case Column::Speed: - return QString(tr("Speed")); - case Column::ListenOnly: - return QString(tr("Listen Only")); - case Column::SingleWire: - return QString(tr("Single Wire")); - case Column::Active: - return QString(tr("Active")); + case Column::NumBuses: + return QString(tr("Buses")); case Column::Status: return QString(tr("Status")); } @@ -59,7 +50,7 @@ QVariant CANConnectionModel::headerData(int section, Qt::Orientation orientation int CANConnectionModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); - return 8; + return 5; } @@ -67,78 +58,9 @@ int CANConnectionModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); - int rows = 0; QList& conns = CANConManager::getInstance()->getConnections(); - foreach(const CANConnection* conn_p, conns) - rows += conn_p->getNumBuses(); - - //qDebug() << "Num Rows: " << rows; - - 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; - - //socketcan is limited for what you can set but the other serialbus - //devices should be able to set the stuff. For now let anyone try - //and the underlying drivers can do with them as they will - bool editParams = true; - //if (conn_p->getType() == CANCon::GVRET_SERIAL) editParams = true; - - switch (Column(index.column())) - { - case Column::Speed: - if (editParams) return Qt::ItemFlag::ItemIsEditable | Qt::ItemFlag::ItemIsEnabled; - return Qt::ItemFlag::NoItemFlags; - case Column::ListenOnly: - case Column::SingleWire: - if (editParams) return Qt::ItemFlag::ItemIsEditable | Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsUserCheckable; - return Qt::ItemFlag::NoItemFlags; - case Column::Active: - return Qt::ItemFlag::ItemIsEditable | Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsUserCheckable; - default: - return Qt::ItemFlag::ItemIsEnabled; - } -} - -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 (Column(index.column())) - { - case Column::Speed: - bus.speed = value.toInt(); - break; - case Column::ListenOnly: - bus.listenOnly = value.toBool(); - break; - case Column::SingleWire: - bus.singleWire = value.toBool(); - break; - case Column::Active: - bus.active = value.toBool(); - break; - default: {} - } - conn_p->setBusSettings(busId, bus); - return true; + return conns.count(); } QVariant CANConnectionModel::data(const QModelIndex &index, int role) const @@ -147,23 +69,16 @@ QVariant CANConnectionModel::data(const QModelIndex &index, int role) const return QVariant(); //qDebug() << "Row: " << index.row(); - int busId; - CANConnection *conn_p = getAtIdx(index.row(), busId); - CANBus bus; + CANConnection *conn_p = getAtIdx(index.row()); bool ret; if (!conn_p) return QVariant(); - ret = conn_p->getBusSettings(busId, bus); - bool isSocketCAN = (conn_p->getType() == CANCon::SERIALBUS) ? true: false; - //qDebug() << "ConnP: " << conn_p << " ret " << ret; + bool isSocketCAN = (conn_p->getType() == CANCon::SERIALBUS) ? true: false; if (role == Qt::DisplayRole) { switch (Column(index.column())) { - case Column::Bus: - //return QString::number(busId); - return QString::number(index.row()); case Column::Type: if (conn_p) switch (conn_p->getType()) { @@ -178,34 +93,16 @@ QVariant CANConnectionModel::data(const QModelIndex &index, int role) const if (conn_p) return conn_p->getPort(); else qDebug() << "Tried to show connection port but connection was NULL"; break; - case Column::Speed: - if(!ret) return QVariant(); - if (!isSocketCAN) return QString::number(bus.speed); - else return QString("N/A"); - case Column::ListenOnly: - return QVariant(); - case Column::SingleWire: - return QVariant(); - case Column::Active: - return QVariant(); + case Column::Subtype: + return conn_p->getDriver(); + break; + case Column::NumBuses: + return conn_p->getNumBuses(); + break; case Column::Status: return (conn_p->getStatus()==CANCon::CONNECTED) ? "Connected" : "Not Connected"; } } - if (role == Qt::CheckStateRole) - { - switch (Column(index.column())) - { - case Column::ListenOnly: - return (bus.listenOnly) ? Qt::Checked : Qt::Unchecked; - case Column::SingleWire: - return (bus.singleWire) ? Qt::Checked : Qt::Unchecked; - case Column::Active: - return (bus.active) ? Qt::Checked : Qt::Unchecked; - default: {} - } - } - return QVariant(); } @@ -230,25 +127,14 @@ void CANConnectionModel::remove(CANConnection* pConn_p) } -CANConnection* CANConnectionModel::getAtIdx(int pIdx, int& pBusId) const +CANConnection* CANConnectionModel::getAtIdx(int pIdx) const { if (pIdx < 0) return NULL; - int i=0; QList& conns = CANConManager::getInstance()->getConnections(); - foreach(CANConnection* conn_p, conns) - { - if( i <= pIdx && pIdx < i+conn_p->getNumBuses() ) { - pBusId = pIdx - i; - return conn_p; - } - - i+= conn_p->getNumBuses(); - } - - return NULL; + return conns.at(pIdx); } void CANConnectionModel::refresh(int pIndex) diff --git a/connections/canconnectionmodel.h b/connections/canconnectionmodel.h index f4a0094..8ea3ed3 100644 --- a/connections/canconnectionmodel.h +++ b/connections/canconnectionmodel.h @@ -21,15 +21,12 @@ public: 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); void remove(CANConnection* pConn_p); - CANConnection* getAtIdx(int, int&) const; + CANConnection* getAtIdx(int) const; void refresh(int pIndex=-1); }; diff --git a/connections/connectionwindow.cpp b/connections/connectionwindow.cpp index b1512ba..5155e5f 100644 --- a/connections/connectionwindow.cpp +++ b/connections/connectionwindow.cpp @@ -1,4 +1,5 @@ #include +#include #include #include "connectionwindow.h" @@ -8,6 +9,8 @@ #include "connections/canconfactory.h" #include "connections/canconmanager.h" #include "canbus.h" +#include +#include ConnectionWindow::ConnectionWindow(QWidget *parent) : QDialog(parent), @@ -22,16 +25,15 @@ ConnectionWindow::ConnectionWindow(QWidget *parent) : qRegisterMetaType("const CANFrame *"); qRegisterMetaType *>("const QList *"); + + //List of devices with details. None of it can be edited. connection type, serialbus type, port name, number of buses, status connModel = new CANConnectionModel(this); ui->tableConnections->setModel(connModel); - ui->tableConnections->setColumnWidth(0, 40); - ui->tableConnections->setColumnWidth(1, 70); - ui->tableConnections->setColumnWidth(2, 70); + ui->tableConnections->setColumnWidth(0, 100); + ui->tableConnections->setColumnWidth(1, 100); + ui->tableConnections->setColumnWidth(2, 130); 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); + ui->tableConnections->setColumnWidth(4, 200); QHeaderView *HorzHdr = ui->tableConnections->horizontalHeader(); HorzHdr->setStretchLastSection(true); //causes the data column to automatically fill the tableview @@ -41,30 +43,51 @@ ConnectionWindow::ConnectionWindow(QWidget *parent) : ui->btnSendText->setEnabled(false); ui->lineSend->setEnabled(false); - /* load connection configuration */ - loadConnections(); + if (settings.value("Main/SaveRestoreConnections", false).toBool()) + { + /* load connection configuration */ + loadConnections(); + } - ui->rbSocketCAN->setEnabled(isSerialBusAvailable()); - - connect(ui->btnOK, &QAbstractButton::clicked, this, &ConnectionWindow::handleOKButton); - connect(ui->rbGVRET, &QAbstractButton::clicked, this, &ConnectionWindow::handleConnTypeChanged); - connect(ui->rbSocketCAN, &QAbstractButton::clicked, this, &ConnectionWindow::handleConnTypeChanged); - connect(ui->rbRemote, &QAbstractButton::clicked, this, &ConnectionWindow::handleConnTypeChanged); - connect(ui->cbDeviceType, QOverload::of(&QComboBox::currentIndexChanged), this, &ConnectionWindow::handleDeviceTypeChanged); - connect(ui->tableConnections->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &ConnectionWindow::currentRowChanged); - connect(ui->btnActivateAll, &QPushButton::clicked, this, &ConnectionWindow::handleEnableAll); - connect(ui->btnDeactivateAll, &QPushButton::clicked, this, &ConnectionWindow::handleDisableAll); - connect(ui->btnReconnect, &QPushButton::clicked, this, &ConnectionWindow::handleReconnect); - connect(ui->btnRemoveBus, &QPushButton::clicked, this, &ConnectionWindow::handleRemoveConn); - connect(ui->btnClearDebug, &QPushButton::clicked, this, &ConnectionWindow::handleClearDebugText); + connect(ui->btnDisconnect, &QPushButton::clicked, this, &ConnectionWindow::handleRemoveConn); connect(ui->btnSendHex, &QPushButton::clicked, this, &ConnectionWindow::handleSendHex); connect(ui->btnSendText, &QPushButton::clicked, this, &ConnectionWindow::handleSendText); connect(ui->ckEnableConsole, &QCheckBox::toggled, this, &ConnectionWindow::consoleEnableChanged); + connect(ui->btnClearDebug, &QPushButton::clicked, this, &ConnectionWindow::handleClearDebugText); + connect(ui->btnNewConnection, &QPushButton::clicked, this, &ConnectionWindow::handleNewConn); + connect(ui->tableConnections->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &ConnectionWindow::currentRowChanged); + connect(ui->tabBuses, &QTabBar::currentChanged, this, &ConnectionWindow::currentTabChanged); + connect(ui->btnSaveBus, &QPushButton::clicked, this, &ConnectionWindow::saveBusSettings); + + ui->cbBusSpeed->addItem("50000"); + ui->cbBusSpeed->addItem("100000"); + ui->cbBusSpeed->addItem("125000"); + ui->cbBusSpeed->addItem("250000"); + ui->cbBusSpeed->addItem("500000"); + ui->cbBusSpeed->addItem("1000000"); + + rxBroadcast = new QUdpSocket(this); + //Need to make sure it tries to share the address in case there are + //multiple instances of SavvyCAN running. + rxBroadcast->bind(QHostAddress::AnyIPv4, 17222, QAbstractSocket::ShareAddress); + + connect(rxBroadcast, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams())); - ui->lblDeviceType->setHidden(true); - ui->cbDeviceType->setHidden(true); } + +void ConnectionWindow::readPendingDatagrams() +{ + //qDebug() << "Got a UDP frame!"; + while (rxBroadcast->hasPendingDatagrams()) { + QNetworkDatagram datagram = rxBroadcast->receiveDatagram(); + if (!remoteDeviceIP.contains(datagram.senderAddress().toString())) + { + remoteDeviceIP.append(datagram.senderAddress().toString()); + //qDebug() << "Add new remote IP " << datagram.senderAddress().toString(); + } + } +} ConnectionWindow::~ConnectionWindow() { QList& conns = CANConManager::getInstance()->getConnections(); @@ -93,7 +116,6 @@ void ConnectionWindow::showEvent(QShowEvent* event) readSettings(); ui->tableConnections->selectRow(0); currentRowChanged(ui->tableConnections->currentIndex(), ui->tableConnections->currentIndex()); - handleConnTypeChanged(); } void ConnectionWindow::closeEvent(QCloseEvent *event) @@ -142,48 +164,6 @@ void ConnectionWindow::writeSettings() } } -void ConnectionWindow::setSuspendAll(bool pSuspend) -{ - QList& conns = CANConManager::getInstance()->getConnections(); - - foreach(CANConnection* conn_p, conns) - conn_p->suspend(pSuspend); - - connModel->refresh(); -} - - -void ConnectionWindow::setActiveAll(bool pActive) -{ - CANBus bus; - QList& conns = CANConManager::getInstance()->getConnections(); - - foreach(CANConnection* conn_p, conns) - { - for(int i=0 ; igetNumBuses() ; i++) { - if( conn_p->getBusSettings(i, bus) ) { - bus.active = pActive; - conn_p->setBusSettings(i, bus); - } - } - } - - connModel->refresh(); -} - -void ConnectionWindow::handleReconnect() -{ - int selIdx = ui->tableConnections->selectionModel()->currentIndex().row(); - if (selIdx <0) return; - - int busId; - CANConnection* conn_p = connModel->getAtIdx(selIdx, busId); - if(!conn_p) return; - - conn_p->stop(); - conn_p->start(); -} - void ConnectionWindow::consoleEnableChanged(bool checked) { ui->textConsole->setEnabled(checked); ui->btnClearDebug->setEnabled(checked); @@ -191,52 +171,40 @@ void ConnectionWindow::consoleEnableChanged(bool checked) { ui->btnSendText->setEnabled(checked); ui->lineSend->setEnabled(checked); - QList& conns = CANConManager::getInstance()->getConnections(); + int selIdx = ui->tableConnections->currentIndex().row(); - foreach(CANConnection* conn_p, conns) - { - if (checked) { //enable console - connect(conn_p, SIGNAL(debugOutput(QString)), this, SLOT(getDebugText(QString))); - connect(this, SIGNAL(sendDebugData(QByteArray)), conn_p, SLOT(debugInput(QByteArray))); - } - else { //turn it off - disconnect(conn_p, SIGNAL(debugOutput(QString)), nullptr, nullptr); - disconnect(this, SIGNAL(sendDebugData(QByteArray)), conn_p, SLOT(debugInput(QByteArray))); - } + if (selIdx == -1) + return; + + CANConnection* conn_p = connModel->getAtIdx(selIdx); + + if (checked) { //enable console + connect(conn_p, SIGNAL(debugOutput(QString)), this, SLOT(getDebugText(QString))); + connect(this, SIGNAL(sendDebugData(QByteArray)), conn_p, SLOT(debugInput(QByteArray))); + } + else { //turn it off + disconnect(conn_p, SIGNAL(debugOutput(QString)), nullptr, nullptr); + disconnect(this, SIGNAL(sendDebugData(QByteArray)), conn_p, SLOT(debugInput(QByteArray))); } } void ConnectionWindow::handleNewConn() { - ui->tableConnections->setCurrentIndex(QModelIndex()); - currentRowChanged(ui->tableConnections->currentIndex(), ui->tableConnections->currentIndex()); -} + NewConnectionDialog *thisDialog = new NewConnectionDialog(&remoteDeviceIP); + CANCon::type newType; + QString newPort; + QString newDriver; + CANConnection *conn; - -void ConnectionWindow::handleEnableAll() -{ - setActiveAll(true); -} - -void ConnectionWindow::handleDisableAll() -{ - setActiveAll(false); -} - -void ConnectionWindow::handleConnTypeChanged() -{ - if (ui->rbGVRET->isChecked()) selectSerial(); - if (ui->rbSocketCAN->isChecked()) selectSocketCan(); - if (ui->rbRemote->isChecked()) selectRemote(); -} - -void ConnectionWindow::handleDeviceTypeChanged() -{ - ui->cbPort->clear(); - canDevices = QCanBus::instance()->availableDevices(ui->cbDeviceType->currentText()); - - for (int i = 0; i < canDevices.count(); i++) - ui->cbPort->addItem(canDevices[i].name()); + if (thisDialog->exec() == QDialog::Accepted) + { + newType = thisDialog->getConnectionType(); + newPort = thisDialog->getPortName(); + newDriver = thisDialog->getDriverName(); + conn = create(newType, newPort, newDriver); + if (conn) connModel->add(conn); + } + delete thisDialog; } /* status */ @@ -248,21 +216,89 @@ void ConnectionWindow::connectionStatus(CANConStatus pStatus) connModel->refresh(); } - -void ConnectionWindow::handleOKButton() +void ConnectionWindow::setSuspendAll(bool pSuspend) { - CANConnection* conn_p = nullptr; + QList& conns = CANConManager::getInstance()->getConnections(); - if( ! CANConManager::getInstance()->getByName(getPortName()) ) - { - /* create connection */ - conn_p = create(getConnectionType(), getPortName(), getDriverName()); - if(!conn_p) - return; - /* add connection to model */ - connModel->add(conn_p); - consoleEnableChanged(ui->ckEnableConsole->isChecked()); + foreach(CANConnection* conn_p, conns) + conn_p->suspend(pSuspend); + + connModel->refresh(); +} + +void ConnectionWindow::saveBusSettings() +{ + int selIdx = ui->tableConnections->currentIndex().row(); + int offset = ui->tabBuses->currentIndex(); + + /* set parameters */ + if (selIdx == -1) { + return; } + else + { + CANConnection* conn_p = connModel->getAtIdx(selIdx); + CANBus bus; + if(!conn_p) return; + + if (!conn_p->getBusSettings(offset, bus)) + { + qDebug() << "Could not retrieve bus settings!"; + return; + } + + bus.setSpeed(ui->cbBusSpeed->currentText().toInt()); + bus.setActive(ui->ckEnable->isChecked()); + bus.setListenOnly(ui->ckListenOnly->isChecked()); + conn_p->setBusSettings(offset, bus); + } +} + +void ConnectionWindow::populateBusDetails(int offset) +{ + int selIdx = ui->tableConnections->currentIndex().row(); + + /* set parameters */ + if (selIdx == -1) { + return; + } + else + { + bool ret; + int numBuses; + + CANConnection* conn_p = connModel->getAtIdx(selIdx); + CANBus bus; + if(!conn_p) return; + + if (!conn_p->getBusSettings(offset, bus)) + { + qDebug() << "Could not retrieve bus settings!"; + return; + } + + int busBase = CANConManager::getInstance()->getBusBase(conn_p); + ui->lblBusNum->setText(QString::number(busBase + offset)); + ui->ckListenOnly->setChecked(bus.isListenOnly()); + ui->ckEnable->setChecked(bus.isActive()); + + bool found = false; + for (int i = 0; i < ui->cbBusSpeed->count(); i++) + { + if (bus.getSpeed() == ui->cbBusSpeed->itemText(i).toInt()) + { + found = true; + ui->cbBusSpeed->setCurrentIndex(i); + break; + } + } + if (!found) ui->cbBusSpeed->addItem(QString::number(bus.getSpeed())); + } +} + +void ConnectionWindow::currentTabChanged(int newIdx) +{ + populateBusDetails(newIdx); } void ConnectionWindow::currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous) @@ -271,43 +307,35 @@ void ConnectionWindow::currentRowChanged(const QModelIndex ¤t, const QMode int selIdx = current.row(); - int busId; - - 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); - ui->gbType->setEnabled(selIdx==-1); - ui->lPort->setEnabled(selIdx==-1); + disconnect(connModel->getAtIdx(previous.row()), SIGNAL(debugOutput(QString)), 0, 0); + disconnect(this, SIGNAL(sendDebugData(QByteArray)), connModel->getAtIdx(previous.row()), SLOT(debugInput(QByteArray))); /* set parameters */ - if (selIdx == -1) - { - ui->btnOK->setText(tr("Create New Connection")); - ui->rbGVRET->setChecked(true); - setSpeed(0); - setPortName(CANCon::GVRET_SERIAL, "", ""); + if (selIdx == -1) { + ui->groupBus->setEnabled(false); + return; } else { bool ret; - CANBus bus; - CANConnection* conn_p = connModel->getAtIdx(selIdx, busId); + ui->groupBus->setEnabled(true); + int numBuses; + + CANConnection* conn_p = connModel->getAtIdx(selIdx); if(!conn_p) return; - if (ui->ckEnableConsole->isChecked()) { //only connect if console is actually enabled + numBuses = conn_p->getNumBuses(); + int numB = ui->tabBuses->count(); + for (int i = 0; i < numB; i++) ui->tabBuses->removeTab(0); + + if (numBuses > 1) for (int i = 0; i < numBuses; i++) ui->tabBuses->addTab(QString::number(i+1)); + + populateBusDetails(0); + if (ui->ckEnableConsole->isChecked()) + { connect(conn_p, SIGNAL(debugOutput(QString)), this, SLOT(getDebugText(QString))); connect(this, SIGNAL(sendDebugData(QByteArray)), conn_p, SLOT(debugInput(QByteArray))); } - - ret = conn_p->getBusSettings(busId, bus); - if(!ret) return; - - ui->btnOK->setText(tr("Update Connection Settings")); - setSpeed(bus.getSpeed()); - setPortName(conn_p->getType(), conn_p->getPort(), conn_p->getDriver()); } } @@ -335,146 +363,6 @@ void ConnectionWindow::handleSendText() { emit sendDebugData(bytes); } -void ConnectionWindow::selectSerial() -{ - ui->lPort->setText("Port:"); - /* set combobox page visible */ - ui->stPort->setCurrentWidget(ui->cbPage); - ui->lblDeviceType->setHidden(true); - ui->cbDeviceType->setHidden(true); - - ui->cbPort->clear(); - ports = QSerialPortInfo::availablePorts(); - - for (int i = 0; i < ports.count(); i++) - ui->cbPort->addItem(ports[i].portName()); -} - -void ConnectionWindow::selectSocketCan() -{ - ui->lPort->setText("Port:"); - /* set edit text page visible */ - ui->stPort->setCurrentWidget(ui->cbPage); - ui->lblDeviceType->setHidden(false); - ui->cbDeviceType->setHidden(false); - - ui->cbDeviceType->clear(); - QStringList plugins; - plugins = QCanBus::instance()->plugins(); - for (int i = 0; i < plugins.count(); i++) - ui->cbDeviceType->addItem(plugins[i]); -} - -void ConnectionWindow::selectRemote() -{ - ui->lPort->setText("IP Address:"); - ui->stPort->setCurrentWidget(ui->etPage); - ui->lblDeviceType->setHidden(true); - ui->cbDeviceType->setHidden(true); -} - -void ConnectionWindow::setSpeed(int speed0) -{ - Q_UNUSED(speed0); -} - -void ConnectionWindow::setPortName(CANCon::type pType, QString pPortName, QString pDriver) -{ - switch(pType) - { - case CANCon::GVRET_SERIAL: - ui->rbGVRET->setChecked(true); - break; - case CANCon::SERIALBUS: - ui->rbSocketCAN->setChecked(true); - //you can't configure any of the below three with socketcan so dim them out - break; - default: {} - } - - /* refresh names whenever needed */ - handleConnTypeChanged(); - - switch(pType) - { - case CANCon::GVRET_SERIAL: - { - int idx = ui->cbPort->findText(pPortName); - if( idx<0 ) idx=0; - ui->cbPort->setCurrentIndex(idx); - break; - } - case CANCon::SERIALBUS: - { - int idx = ui->cbDeviceType->findText(pDriver); - if (idx < 0) idx = 0; - ui->cbDeviceType->setCurrentIndex(idx); - idx = ui->cbPort->findText(pPortName); - if( idx < 0 ) idx = 0; - ui->cbPort->setCurrentIndex(idx); - break; - } - case CANCon::REMOTE: - { - ui->lePort->setText(pPortName); - break; - } - default: {} - } -} - - -//-1 means leave it at whatever it booted up to. 0 means disable. Otherwise the actual rate we want. -int ConnectionWindow::getSpeed() -{ - return -1; -} - -QString ConnectionWindow::getPortName() -{ - switch( getConnectionType() ) { - case CANCon::GVRET_SERIAL: - case CANCon::SERIALBUS: - return ui->cbPort->currentText(); - case CANCon::REMOTE: - return ui->lePort->text(); - default: - qDebug() << "getPortName: can't get port"; - } - - return ""; -} - -QString ConnectionWindow::getDriverName() -{ - if (getConnectionType() == CANCon::SERIALBUS) - { - return ui->cbDeviceType->currentText(); - } - - return ""; -} - -CANCon::type ConnectionWindow::getConnectionType() -{ - if (ui->rbGVRET->isChecked()) return CANCon::GVRET_SERIAL; - if (ui->rbSocketCAN->isChecked()) return CANCon::SERIALBUS; - if (ui->rbRemote->isChecked()) return CANCon::REMOTE; - qDebug() << "getConnectionType: error"; - return CANCon::NONE; -} - - -void ConnectionWindow::setSWMode(bool mode) -{ - Q_UNUSED(mode); -} - -bool ConnectionWindow::getSWMode() -{ - return false; -} - void ConnectionWindow::handleRemoveConn() { int selIdx = ui->tableConnections->selectionModel()->currentIndex().row(); @@ -482,8 +370,7 @@ void ConnectionWindow::handleRemoveConn() qDebug() << "remove connection at index: " << selIdx; - int busId; - CANConnection* conn_p = connModel->getAtIdx(selIdx, busId); + CANConnection* conn_p = connModel->getAtIdx(selIdx); if(!conn_p) return; /* remove connection from model & manager */ @@ -497,19 +384,6 @@ void ConnectionWindow::handleRemoveConn() ui->tableConnections->selectRow(0); } -void ConnectionWindow::handleRevert() -{ - -} - - -bool ConnectionWindow::isSerialBusAvailable() -{ - if (QCanBus::instance()->plugins().count() > 0) return true; - return false; -} - - CANConnection* ConnectionWindow::create(CANCon::type pTye, QString pPortName, QString pDriver) { CANConnection* conn_p; diff --git a/connections/connectionwindow.h b/connections/connectionwindow.h index 7b44a1d..1af482f 100644 --- a/connections/connectionwindow.h +++ b/connections/connectionwindow.h @@ -3,13 +3,14 @@ -#include #include +#include #include #include #include #include #include +#include #include "canconnectionmodel.h" #include "connections/canconnection.h" @@ -29,58 +30,38 @@ public: explicit ConnectionWindow(QWidget *parent = 0); ~ConnectionWindow(); - CANCon::type getConnectionType(); - bool getSWMode(); - signals: void updateBusSettings(CANBus *bus); void updatePortName(QString port); void sendDebugData(QByteArray bytes); public slots: - void setSpeed(int speed0); - void setSWMode(bool mode); - + void getDebugText(QString debugText); void setSuspendAll(bool pSuspend); - void getDebugText(QString debugText); private slots: - void handleOKButton(); - void handleConnTypeChanged(); - void handleDeviceTypeChanged(); void currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous); + void currentTabChanged(int newIdx); void consoleEnableChanged(bool checked); void handleRemoveConn(); - void handleEnableAll(); - void handleDisableAll(); - void handleReconnect(); - void handleRevert(); void handleNewConn(); void handleClearDebugText(); void handleSendHex(); void handleSendText(); + void saveBusSettings(); void connectionStatus(CANConStatus); + void readPendingDatagrams(); private: - Ui::ConnectionWindow *ui; - QList ports; - QList canDevices; + Ui::ConnectionWindow *ui; QSettings *settings; CANConnectionModel *connModel; + QUdpSocket *rxBroadcast; + QVector remoteDeviceIP; - void selectSerial(); - void selectKvaser(); - void selectSocketCan(); - void selectRemote(); - bool isSerialBusAvailable(); - int getSpeed(); - QString getPortName(); - QString getDriverName(); - void setPortName(CANCon::type pType, QString pPortName, QString pDriver); - - void setActiveAll(bool pActive); CANConnection* create(CANCon::type pTye, QString pPortName, QString pDriver); + void populateBusDetails(int offset); void loadConnections(); void saveConnections(); void showEvent(QShowEvent *); diff --git a/connections/gvretserial.cpp b/connections/gvretserial.cpp index 86d1b0f..0d42518 100644 --- a/connections/gvretserial.cpp +++ b/connections/gvretserial.cpp @@ -819,8 +819,8 @@ 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].mBus.setActive(can0Enabled); + mBusData[1].mBus.setActive(can1Enabled); mBusData[0].mConfigured = true; mBusData[1].mConfigured = true; @@ -962,7 +962,7 @@ void GVRetSerial::procRXChar(unsigned char c) if (getNumBuses() > 2) { mBusData[2].mBus.setSpeed(swcanBaud); - mBusData[2].mBus.setEnabled(swcanEnabled); + mBusData[2].mBus.setActive(swcanEnabled); } setStatus(CANCon::CONNECTED); diff --git a/connections/newconnectiondialog.cpp b/connections/newconnectiondialog.cpp new file mode 100644 index 0000000..92ee31b --- /dev/null +++ b/connections/newconnectiondialog.cpp @@ -0,0 +1,179 @@ +#include +#include "newconnectiondialog.h" +#include "ui_newconnectiondialog.h" + +NewConnectionDialog::NewConnectionDialog(QVector* ips, QWidget *parent) : + QDialog(parent), + ui(new Ui::NewConnectionDialog), + remoteDeviceIP(ips) +{ + ui->setupUi(this); + + ui->rbSocketCAN->setEnabled(isSerialBusAvailable()); + + connect(ui->rbGVRET, &QAbstractButton::clicked, this, &NewConnectionDialog::handleConnTypeChanged); + connect(ui->rbSocketCAN, &QAbstractButton::clicked, this, &NewConnectionDialog::handleConnTypeChanged); + connect(ui->rbRemote, &QAbstractButton::clicked, this, &NewConnectionDialog::handleConnTypeChanged); + connect(ui->cbDeviceType, QOverload::of(&QComboBox::currentIndexChanged), this, &NewConnectionDialog::handleDeviceTypeChanged); + connect(ui->btnOK, &QPushButton::clicked, this, &NewConnectionDialog::handleCreateButton); + + ui->lblDeviceType->setHidden(true); + ui->cbDeviceType->setHidden(true); + selectSerial(); + + qDebug() << "Was passed " << remoteDeviceIP->count() << " remote IPs"; +} + +NewConnectionDialog::~NewConnectionDialog() +{ + delete ui; +} + +void NewConnectionDialog::handleCreateButton() +{ + accept(); +} + +void NewConnectionDialog::handleConnTypeChanged() +{ + if (ui->rbGVRET->isChecked()) selectSerial(); + if (ui->rbSocketCAN->isChecked()) selectSocketCan(); + if (ui->rbRemote->isChecked()) selectRemote(); +} + +void NewConnectionDialog::handleDeviceTypeChanged() +{ + + ui->cbPort->clear(); + canDevices = QCanBus::instance()->availableDevices(ui->cbDeviceType->currentText()); + + for (int i = 0; i < canDevices.count(); i++) + ui->cbPort->addItem(canDevices[i].name()); +} + +void NewConnectionDialog::selectSerial() +{ + ui->lPort->setText("Serial Port:"); + + ui->lblDeviceType->setHidden(true); + ui->cbDeviceType->setHidden(true); + + ui->cbPort->clear(); + ports = QSerialPortInfo::availablePorts(); + + for (int i = 0; i < ports.count(); i++) + ui->cbPort->addItem(ports[i].portName()); +} + +void NewConnectionDialog::selectSocketCan() +{ + ui->lPort->setText("Port:"); + ui->lblDeviceType->setHidden(false); + ui->cbDeviceType->setHidden(false); + + ui->cbDeviceType->clear(); + QStringList plugins; + plugins = QCanBus::instance()->plugins(); + for (int i = 0; i < plugins.count(); i++) + ui->cbDeviceType->addItem(plugins[i]); + +} + +void NewConnectionDialog::selectRemote() +{ + ui->lPort->setText("IP Address:"); + ui->lblDeviceType->setHidden(true); + ui->cbDeviceType->setHidden(true); + ui->cbPort->clear(); + foreach(QString pName, *remoteDeviceIP) + { + ui->cbPort->addItem(pName); + } +} + +void NewConnectionDialog::setPortName(CANCon::type pType, QString pPortName, QString pDriver) +{ + + switch(pType) + { + case CANCon::GVRET_SERIAL: + ui->rbGVRET->setChecked(true); + break; + case CANCon::SERIALBUS: + ui->rbSocketCAN->setChecked(true); + //you can't configure any of the below three with socketcan so dim them out + break; + default: {} + } + + /* refresh names whenever needed */ + //handleConnTypeChanged(); + + switch(pType) + { + case CANCon::GVRET_SERIAL: + { + int idx = ui->cbPort->findText(pPortName); + if( idx<0 ) idx=0; + ui->cbPort->setCurrentIndex(idx); + break; + } + case CANCon::SERIALBUS: + { + int idx = ui->cbDeviceType->findText(pDriver); + if (idx < 0) idx = 0; + ui->cbDeviceType->setCurrentIndex(idx); + idx = ui->cbPort->findText(pPortName); + if( idx < 0 ) idx = 0; + ui->cbPort->setCurrentIndex(idx); + break; + } + case CANCon::REMOTE: + { + int idx = ui->cbPort->findText(pPortName); + if (idx > -1) ui->cbPort->setCurrentIndex(idx); + else ui->cbPort->addItem(pPortName); + break; + } + default: {} + } +} + +QString NewConnectionDialog::getPortName() +{ + switch( getConnectionType() ) { + case CANCon::GVRET_SERIAL: + case CANCon::SERIALBUS: + case CANCon::REMOTE: + return ui->cbPort->currentText(); + default: + qDebug() << "getPortName: can't get port"; + } + + return ""; +} + +QString NewConnectionDialog::getDriverName() +{ + if (getConnectionType() == CANCon::SERIALBUS) + { + return ui->cbDeviceType->currentText(); + } + return "N/A"; +} + +CANCon::type NewConnectionDialog::getConnectionType() +{ + if (ui->rbGVRET->isChecked()) return CANCon::GVRET_SERIAL; + if (ui->rbSocketCAN->isChecked()) return CANCon::SERIALBUS; + if (ui->rbRemote->isChecked()) return CANCon::REMOTE; + qDebug() << "getConnectionType: error"; + + return CANCon::NONE; +} + +bool NewConnectionDialog::isSerialBusAvailable() +{ + if (QCanBus::instance()->plugins().count() > 0) return true; + return false; +} diff --git a/connections/newconnectiondialog.h b/connections/newconnectiondialog.h new file mode 100644 index 0000000..f826b70 --- /dev/null +++ b/connections/newconnectiondialog.h @@ -0,0 +1,47 @@ +#ifndef NEWCONNECTIONDIALOG_H +#define NEWCONNECTIONDIALOG_H + +#include +#include +#include +#include +#include +#include "canconnectionmodel.h" +#include "connections/canconnection.h" + +namespace Ui { +class NewConnectionDialog; +} + +class NewConnectionDialog : public QDialog +{ + Q_OBJECT + +public: + explicit NewConnectionDialog(QVector* ips, QWidget *parent = nullptr); + ~NewConnectionDialog(); + + CANCon::type getConnectionType(); + QString getPortName(); + QString getDriverName(); + +public slots: + void handleConnTypeChanged(); + void handleDeviceTypeChanged(); + void handleCreateButton(); + +private: + Ui::NewConnectionDialog *ui; + QList ports; + QList canDevices; + QVector* remoteDeviceIP; + + void selectSerial(); + void selectKvaser(); + void selectSocketCan(); + void selectRemote(); + bool isSerialBusAvailable(); + void setPortName(CANCon::type pType, QString pPortName, QString pDriver); +}; + +#endif // NEWCONNECTIONDIALOG_H diff --git a/connections/serialbusconnection.cpp b/connections/serialbusconnection.cpp index af67b9e..03891ff 100644 --- a/connections/serialbusconnection.cpp +++ b/connections/serialbusconnection.cpp @@ -46,7 +46,7 @@ void SerialBusConnection::piStarted() mTimer.setInterval(1000); mTimer.setSingleShot(false); //keep ticking mTimer.start(); - mBusData[0].mBus.setEnabled(true); + mBusData[0].mBus.setActive(true); mBusData[0].mConfigured = true; } @@ -281,7 +281,7 @@ void SerialBusConnection::testConnection() { CANBus bus; if(getBusConfig(0, bus)) { - bus.setEnabled(true); + bus.setActive(true); setBusSettings(0, bus); } diff --git a/dbc/dbc_classes.cpp b/dbc/dbc_classes.cpp index 7d8f013..f9106e1 100644 --- a/dbc/dbc_classes.cpp +++ b/dbc/dbc_classes.cpp @@ -49,6 +49,7 @@ bool DBC_SIGNAL::processAsText(const CANFrame &frame, QString &outString) int bytes = signalSize / 8; for (int x = 0; x < bytes; x++) buildString.append(frame.data[startByte + x]); outString = buildString; + cachedValue = outString; return true; } @@ -69,7 +70,7 @@ bool DBC_SIGNAL::processAsText(const CANFrame &frame, QString &outString) { result = Utility::processIntegerSignal(frame.data, startBit, signalSize, intelByteOrder, isSigned); endResult = ((double)result * factor) + bias; - result = (int64_t)endResult; + result = (int64_t)endResult; } else if (valType == SP_FLOAT) { @@ -94,6 +95,13 @@ bool DBC_SIGNAL::processAsText(const CANFrame &frame, QString &outString) endResult = (*((double *)(&result)) * factor) + bias; } + outString = makePrettyOutput(endResult, result); + cachedValue = endResult; + return true; +} + +QString DBC_SIGNAL::makePrettyOutput(double floatVal, int64_t intVal) +{ QString outputString; outputString = name + ": "; @@ -103,22 +111,20 @@ bool DBC_SIGNAL::processAsText(const CANFrame &frame, QString &outString) bool foundVal = false; for (int x = 0; x < valList.count(); x++) { - if (valList.at(x).value == result) + if (valList.at(x).value == intVal) { outputString += valList.at(x).descript; foundVal = true; break; } } - if (!foundVal) outputString += QString::number(endResult) + unitName; + if (!foundVal) outputString += QString::number(intVal) + unitName; } else //otherwise display the actual number and unit (if it exists) { - outputString += QString::number(endResult) + unitName; + outputString += QString::number(floatVal) + unitName; } - - outString = outputString; - return true; + return outputString; } //Works quite a bit like the above version but this one is cut down and only will return int32_t which is perfect for @@ -158,7 +164,7 @@ bool DBC_SIGNAL::processAsInt(const CANFrame &frame, int32_t &outValue) double endResult = ((double)result * factor) + bias; result = (int32_t)endResult; - + cachedValue = result; outValue = result; return true; } @@ -230,7 +236,7 @@ bool DBC_SIGNAL::processAsDouble(const CANFrame &frame, double &outValue) result = Utility::processIntegerSignal(frame.data, 0, 64, false, false); endResult = (*((double *)(&result)) * factor) + bias; } - + cachedValue = endResult; outValue = endResult; return true; } diff --git a/dbc/dbc_classes.h b/dbc/dbc_classes.h index d71544b..76fe85b 100644 --- a/dbc/dbc_classes.h +++ b/dbc/dbc_classes.h @@ -97,12 +97,14 @@ public: //TODO: this is sloppy. It shouldn't all be public! DBC_MESSAGE *parentMessage; QString unitName; QString comment; + QVariant cachedValue; QList attributes; QList valList; bool processAsText(const CANFrame &frame, QString &outString); bool processAsInt(const CANFrame &frame, int32_t &outValue); bool processAsDouble(const CANFrame &frame, double &outValue); + QString makePrettyOutput(double floatVal, int64_t intVal); DBC_ATTRIBUTE_VALUE *findAttrValByName(QString name); DBC_ATTRIBUTE_VALUE *findAttrValByIdx(int idx); }; diff --git a/dbc/dbchandler.cpp b/dbc/dbchandler.cpp index dbd33ac..b1353c2 100644 --- a/dbc/dbchandler.cpp +++ b/dbc/dbchandler.cpp @@ -809,7 +809,7 @@ void DBCFile::loadFile(QString fileName) if (parseAttribute(line.right(line.length() - 12), attr)) { - qDebug() << "Success"; + //qDebug() << "Success"; attr.attrType = SIG; dbc_attributes.append(attr); } @@ -831,7 +831,7 @@ void DBCFile::loadFile(QString fileName) if (parseAttribute(line.right(line.length() - 12), attr)) { - qDebug() << "Success"; + //qDebug() << "Success"; attr.attrType = NODE; dbc_attributes.append(attr); } @@ -855,7 +855,7 @@ void DBCFile::loadFile(QString fileName) if (!bgAttr) { attr.attrType = MESSAGE; - attr.defaultValue = QColor(Qt::white).name(); + attr.defaultValue = QApplication::palette().color(QPalette::Base).name(); attr.enumVals.clear(); attr.lower = 0; attr.upper = 0; @@ -1366,7 +1366,7 @@ int DBCHandler::createBlankFile() //add our custom attributes to the new file so that we know they're already there. attr.attrType = MESSAGE; - attr.defaultValue = QColor(Qt::white).name(); + attr.defaultValue = QApplication::palette().color(QPalette::Base).name(); attr.enumVals.clear(); attr.lower = 0; attr.upper = 0; diff --git a/dbc/dbcsignaleditor.cpp b/dbc/dbcsignaleditor.cpp index 5e47d0a..d86353d 100644 --- a/dbc/dbcsignaleditor.cpp +++ b/dbc/dbcsignaleditor.cpp @@ -232,6 +232,9 @@ bool DBCSignalEditor::eventFilter(QObject *obj, QEvent *event) case Qt::Key_F1: HelpWindow::getRef()->showHelp("signaleditor.html"); break; + case Qt::Key_F2: + cloneSignal(); + break; } return true; } else { @@ -324,7 +327,11 @@ void DBCSignalEditor::onCustomMenuSignals(QPoint point) menu->setAttribute(Qt::WA_DeleteOnClose); menu->addAction(tr("Add a new signal"), this, SLOT(addNewSignal())); - menu->addAction(tr("Delete currently selected signal"), this, SLOT(deleteCurrentSignal())); + if (ui->signalsList->currentRow() != -1) + { + menu->addAction(tr("Clone currently selected signal"), this, SLOT(cloneSignal())); + menu->addAction(tr("Delete currently selected signal"), this, SLOT(deleteCurrentSignal())); + } menu->popup(ui->signalsList->mapToGlobal(point)); } @@ -365,7 +372,43 @@ void DBCSignalEditor::addNewSignal() /* this will call clickSignalList */ ui->signalsList->addItem(newName); ui->signalsList->setCurrentRow(ui->signalsList->count()-1); +} +void DBCSignalEditor::cloneSignal() +{ + int num = qrand() % 100; + + int idx = ui->signalsList->currentRow(); + if (idx < 0) return; + + DBC_SIGNAL *oldSig = dbcMessage->sigHandler->findSignalByIdx(idx); + if (!oldSig) return; + + QString newName = oldSig->name + QString::number(num); + DBC_SIGNAL newSig; + newSig.name = newName; + newSig.bias = oldSig->bias; + newSig.factor = oldSig->factor; + newSig.intelByteOrder = oldSig->intelByteOrder; + newSig.max = oldSig->max; + newSig.min = oldSig->min; + newSig.receiver = oldSig->receiver; + newSig.signalSize = oldSig->signalSize; + newSig.startBit = oldSig->startBit; + newSig.valType = oldSig->valType; + newSig.valList.append(oldSig->valList); + newSig.isMultiplexed = oldSig->isMultiplexed; + newSig.isMultiplexor = oldSig->isMultiplexor; //maybe should force this false since you can't have two or more! + newSig.multiplexValue = oldSig->multiplexValue; + newSig.parentMessage = dbcMessage; + + dbcMessage->sigHandler->addSignal(newSig); + + /* add item at the end of the list */ + ui->signalsList->addItem(newName); + + //unlike adding a signal we don't want to select the new signal here. + //ui->signalsList->setCurrentRow(ui->signalsList->count()-1); } void DBCSignalEditor::deleteCurrentSignal() diff --git a/dbc/dbcsignaleditor.h b/dbc/dbcsignaleditor.h index 97b883f..e807f58 100644 --- a/dbc/dbcsignaleditor.h +++ b/dbc/dbcsignaleditor.h @@ -27,6 +27,7 @@ private slots: void onCustomMenuSignals(QPoint); void onCustomMenuValues(QPoint); void addNewSignal(); + void cloneSignal(); void deleteCurrentSignal(); void deleteCurrentValue(); diff --git a/framefileio.cpp b/framefileio.cpp index 713aecd..fd6d01b 100644 --- a/framefileio.cpp +++ b/framefileio.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -32,6 +33,7 @@ bool FrameFileIO::saveFrameFile(QString &fileName, const QVector* fram filters.append(QString(tr("Vehicle Spy (*.csv *.CSV)"))); filters.append(QString(tr("Candump/Kayak(*.log)"))); filters.append(QString(tr("Cabana Log(*.csv *.CSV)"))); + filters.append(QString(tr("CANalyzer Ascii Log (*.asc *.ASC)"))); dialog.setFileMode(QFileDialog::AnyFile); dialog.setNameFilters(filters); @@ -111,6 +113,12 @@ bool FrameFileIO::saveFrameFile(QString &fileName, const QVector* fram if (!filename.contains('.')) filename += ".csv"; result = saveCabanaFile(filename, frameCache); } + if (dialog.selectedNameFilter() == filters[11]) + { + if (!filename.contains('.')) filename += ".asc"; + result = saveCanalyzerASC(filename, frameCache); + } + progress.cancel(); if (result) @@ -148,6 +156,7 @@ bool FrameFileIO::loadFrameFile(QString &fileName, QVector* frameCache filters.append(QString(tr("CANalyzer Binary Log Files (*.blf *.BLF)"))); filters.append(QString(tr("CANHacker Trace Files (*.trc *.TRC)"))); filters.append(QString(tr("Cabana Log (*.csv *.CSV)"))); + filters.append(QString(tr("CANOpen Magic (*.csv *.CSV)"))); dialog.setFileMode(QFileDialog::ExistingFile); dialog.setNameFilters(filters); @@ -184,6 +193,7 @@ bool FrameFileIO::loadFrameFile(QString &fileName, QVector* frameCache if (dialog.selectedNameFilter() == filters[14]) result = loadCanalyzerBLF(filename, frameCache); if (dialog.selectedNameFilter() == filters[15]) result = loadCANHackerFile(filename, frameCache); if (dialog.selectedNameFilter() == filters[16]) result = loadCabanaFile(filename, frameCache); + if (dialog.selectedNameFilter() == filters[17]) result = loadCANOpenFile(filename, frameCache); progress.cancel(); @@ -449,6 +459,70 @@ bool FrameFileIO::loadCANHackerFile(QString filename, QVector* frames) return !foundErrors; } + +//"Message Number","Time (ms)","Time","Excel Time","Count","ID","Flags","Message Type","Node","Details","Process Data","Data (Hex)","Data (Text)","Data (Decimal)","Length","Raw Message" +//"0","0.000","8:09:42:48.7953090'",43447.7100146116,"","0x2E1","","Default: PDO","","Default: TPDO 2 of Node 0x61 (97)","","10 21 04 00 00 00 00 00 ",". ! . . . . . . ","U:0 S:0","8","10 21 04 00 00 00 00 00" +bool FrameFileIO::loadCANOpenFile(QString filename, QVector* frames) +{ + QFile *inFile = new QFile(filename); + CANFrame thisFrame; + QByteArray line; + int lineCounter = 0; + bool foundErrors = false; + + if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text)) + { + delete inFile; + qDebug() << "Could not open the file!"; + return false; + } + + line = inFile->readLine(); //read out the header first and discard it. + line = inFile->readLine(); + line = inFile->readLine(); + line = inFile->readLine(); + line = inFile->readLine(); + + while (!inFile->atEnd()) { + lineCounter++; + if (lineCounter > 100) + { + qApp->processEvents(); + lineCounter = 0; + } + + line = inFile->readLine().replace('\"', ' ').simplified(); + if (line.length() > 2) + { + QList tokens = line.split(','); + if (tokens.length() > 11) + { + thisFrame.timestamp = (int64_t)(tokens[1].simplified().toDouble() * 1000.0); + thisFrame.ID = Utility::ParseStringToNum(tokens[5].simplified()); + thisFrame.extended = (thisFrame.ID > 0x7FF); + thisFrame.isReceived = true; + thisFrame.remote = false; + thisFrame.bus = 0; + QList dataTok = tokens[11].simplified().split(' '); + thisFrame.len = dataTok.length(); + for (unsigned int d = 0; d < thisFrame.len; d++) + { + if (dataTok[d] != "") + { + thisFrame.data[d] = dataTok[d].simplified().toInt(NULL, 16); + } + else thisFrame.data[d] = 0; + } + frames->append(thisFrame); + } + else foundErrors = true; + } + } + inFile->close(); + delete inFile; + return !foundErrors; +} + bool FrameFileIO::saveCRTDFile(QString filename, const QVector* frames) { QFile *outFile = new QFile(filename); @@ -555,7 +629,7 @@ bool FrameFileIO::loadPCANFile(QString filename, QVector* frames) { if (fileVersion == 1) { - thisFrame.timestamp = (uint32_t)(line.mid(10, 8).simplified().toFloat() * 1000.0); + thisFrame.timestamp = (uint64_t)(line.mid(10, 8).simplified().toDouble() * 1000.0); thisFrame.ID = line.mid(28, 8).simplified().toUInt(NULL, 16); if (thisFrame.ID < 0x1FFFFFFF) { @@ -587,7 +661,7 @@ bool FrameFileIO::loadPCANFile(QString filename, QVector* frames) } else if (fileVersion == 2) { - thisFrame.timestamp = (uint32_t)(line.mid(8, 13).simplified().toFloat() * 1000.0); + thisFrame.timestamp = (uint64_t)(line.mid(8, 13).simplified().toDouble() * 1000.0); thisFrame.ID = line.mid(25, 8).simplified().toUInt(NULL, 16); if (thisFrame.ID < 0x1FFFFFFF) { @@ -641,6 +715,7 @@ bool FrameFileIO::loadCanalyzerASC(QString filename, QVector* frames) bool foundErrors = false; bool inHeader = true; thisFrame.remote = false; + QList tokens; if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text)) { @@ -656,18 +731,21 @@ bool FrameFileIO::loadCanalyzerASC(QString filename, QVector* frames) lineCounter = 0; } line = inFile->readLine(); - if (line.startsWith("//")) + if (inHeader) { - inHeader = false; - continue; + if (line.startsWith("//") || lineCounter > 4) + { + inHeader = false; + continue; + } } if (inHeader) continue; if (line.length() > 2) { - QList tokens = line.simplified().split(' '); - if (tokens.length() > 4) + tokens = line.simplified().split(' '); + if (tokens.length() > 5) { - thisFrame.timestamp = (uint32_t)(tokens[0].toFloat() * 1000000.0); + thisFrame.timestamp = (uint64_t)(tokens[0].toDouble() * (double)1000000.0); thisFrame.ID = tokens[2].toUInt(NULL, 16); thisFrame.len = tokens[5].toUInt(); thisFrame.isReceived = tokens[3].toUpper().contains("RX"); @@ -696,6 +774,83 @@ bool FrameFileIO::loadCanalyzerASC(QString filename, QVector* frames) return !foundErrors; } +bool FrameFileIO::saveCanalyzerASC(QString filename, const QVector* frames) +{ + QFile *outFile = new QFile(filename); + int lineCounter = 0; + uint64_t offsetTime = frames->at(0).timestamp; + for (int c = 0; c < frames->count(); c++) + { + if (frames->at(c).timestamp < offsetTime) offsetTime = frames->at(c).timestamp; + } + + if (!outFile->open(QIODevice::WriteOnly | QIODevice::Text)) + { + delete outFile; + return false; + } + + QDateTime now; + now = QDateTime::currentDateTime(); + if (offsetTime > 10000000000) //chances are the input file had times as system time so load it + { + now.setMSecsSinceEpoch(offsetTime / 1000); //offsetTime was in microseconds + } + outFile->write("date " + now.toString("ddd MMM dd h:mm:ss.zzz a yyyy").toUtf8()); + + outFile->write("\nbase hex timestamps absolute\n"); + outFile->write("no internal event logging\n"); + outFile->write("// version 11.0.0\n"); + + for (int c = 0; c < frames->count(); c++) + { + lineCounter++; + if (lineCounter > 100) + { + qApp->processEvents(); + lineCounter = 0; + } + + uint64_t timeStamp = (frames->at(c).timestamp - offsetTime) / 1000000ull; + int tsLen = QString::number(timeStamp).length(); + int precision = 6; + //vector seems to keep 10 bytes at the start of the line for the timestamp. It should never exceed this + //and there should never be a precision over 6 digits after the decimal + if (tsLen > 3) precision = 9 - tsLen; + outFile->write(QString::number((frames->at(c).timestamp - offsetTime) / 1000000.0, 'f', precision).rightJustified(10, ' ').toUtf8()); + outFile->putChar(' '); + outFile->write(QString::number(frames->at(c).bus + 1).toUtf8()); + outFile->write(" "); + if (frames->at(c).extended) + outFile->write(QString::number(frames->at(c).ID, 16).toUpper().rightJustified(8, '0').toUtf8()); + else + { + outFile->write(QString::number(frames->at(c).ID, 16).toUpper().rightJustified(3, '0').toUtf8()); + outFile->write(" "); + } + outFile->write(" "); + + if (frames->at(c).isReceived) outFile->write("Rx D "); + else outFile->write("Tx D "); + + outFile->write(QString::number(frames->at(c).len).toUtf8()); + outFile->write(" "); + + for (unsigned int temp = 0; temp < frames->at(c).len; temp++) + { + outFile->write(QString::number(frames->at(c).data[temp], 16).toUpper().rightJustified(2, '0').toUtf8()); + outFile->write(" "); + } + + outFile->write("\n"); + } + outFile->close(); + delete outFile; + + return true; +} + +//this one is pretty complicated and handled by it's own class bool FrameFileIO::loadCanalyzerBLF(QString filename, QVector *frames) { BLFHandler blf; @@ -703,6 +858,8 @@ bool FrameFileIO::loadCanalyzerBLF(QString filename, QVector *frames) } //The "native" file format for this program +//Time Stamp,ID,Extended,Dir,Bus,LEN,D1,D2,D3,D4,D5,D6,D7,D8 +//39747828,000005EB,false,Rx,0,8,E8,45,85,4B,4A,28,36,69, bool FrameFileIO::loadNativeCSVFile(QString filename, QVector* frames) { QFile *inFile = new QFile(filename); @@ -759,7 +916,9 @@ bool FrameFileIO::loadNativeCSVFile(QString filename, QVector* frames) thisFrame.isReceived = true; thisFrame.bus = tokens[3].toInt(); thisFrame.len = tokens[4].toUInt(); + if (thisFrame.len > 8) thisFrame.len = 8; for (int c = 0; c < 8; c++) thisFrame.data[c] = 0; + if (thisFrame.len + 5 > (unsigned int) tokens.length()) thisFrame.len = tokens.length() - 5; for (unsigned int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = tokens[5 + d].toInt(NULL, 16); } @@ -769,6 +928,7 @@ bool FrameFileIO::loadNativeCSVFile(QString filename, QVector* frames) else thisFrame.isReceived = false; thisFrame.bus = tokens[4].toInt(); thisFrame.len = tokens[5].toUInt(); + if (thisFrame.len > 8) thisFrame.len = 8; if (thisFrame.len + 6 > (unsigned int) tokens.length()) thisFrame.len = tokens.length() - 6; for (int c = 0; c < 8; c++) thisFrame.data[c] = 0; for (unsigned int d = 0; d < thisFrame.len; d++) @@ -1819,12 +1979,21 @@ bool FrameFileIO::saveCanDumpFile(QString filename, const QVector * fr delete outFile; return true; } -/* (0.003800) vcan0 164#0000c01aa8000013 */ + +/* + (0.003800) vcan0 164#0000c01aa8000013 + or + (1551774790.942758) can1 7A8 [8] F4 DC D1 83 0E 02 00 00 +*/ bool FrameFileIO::loadCanDumpFile(QString filename, QVector* frames) { QFile *inFile = new QFile(filename); CANFrame thisFrame; QByteArray line; + QList tokens; + QRegExp timeExp("^\\((\\S+)\\)$"); + QRegExp IdValExp("^(\\S+)#(\\S+)$"); + QRegExp valExp("(\\S{2})"); int lineCounter = 0; int pos = 0; bool ret; @@ -1847,50 +2016,68 @@ bool FrameFileIO::loadCanDumpFile(QString filename, QVector* frames) if (line.length() > 1) { /* tokenize */ - QList tokens = line.split(' '); + tokens.clear(); + tokens = line.simplified().split(' '); if(tokens.count()<3) continue; /* timestamp */ - QRegExp timeExp("^\\((\\S+)\\)$"); ret = timeExp.exactMatch(tokens[0]); if(!ret) continue; - thisFrame.timestamp = timeExp.cap(1).toDouble(&ret) * 1000000; + thisFrame.timestamp = (uint64_t)(timeExp.cap(1).toDouble(&ret) * (double)1000000.0); if(!ret) continue; - /* ID & value */ - QRegExp IdValExp("^(\\S+)#(\\S+)\n$"); - qDebug() << tokens[2]; - ret = IdValExp.exactMatch(tokens[2]); - if(!ret) continue; - - /* ID */ - thisFrame.ID = IdValExp.cap(1).toInt(&ret, 16); - if (IdValExp.cap(1).length() > 3) { - thisFrame.extended = true; - } else { - thisFrame.extended = false; - } - if(!ret) continue; - - QString val= IdValExp.cap(2); - QRegExp valExp("(\\S{2})"); - - pos = 0; - thisFrame.len = 0; - if (val.startsWith("R") && val.at(1).isDigit()) { - thisFrame.len = val.at(1).toLatin1() - '0'; - thisFrame.remote = true; - } else { + if (line.contains('[')) //the expanded format (second one from the above list) + { + //(1551774790.942758) can1 7A8 [8] F4 DC D1 83 0E 02 00 00 + // 0 1 2 3 4 5 6 7 8 9 10 11 + thisFrame.ID = tokens[2].toULong(nullptr, 16); + if (thisFrame.ID > 0x7FF) thisFrame.extended = true; + else thisFrame.extended = false; thisFrame.remote = false; - /* val byte per byte */ - while ((pos = valExp.indexIn(val, pos)) != -1) + thisFrame.len = tokens[3].at(1) - '0'; + for (int c = 0; c < thisFrame.len; c++) { - thisFrame.data[thisFrame.len] = valExp.cap(1).toInt(&ret, 16); - if(!ret) continue; + thisFrame.data[c] = tokens[4 + c].toInt(nullptr, 16); + } + } + else //the more concise format (first one from list above) + { + /* ID & value */ + //qDebug() << tokens[2]; + ret = IdValExp.exactMatch(tokens[2]); + if(!ret) + { + qDebug() << "ID regex didn't match!"; + continue; + } - thisFrame.len++; - pos += valExp.matchedLength(); + /* ID */ + thisFrame.ID = IdValExp.cap(1).toInt(&ret, 16); + if (IdValExp.cap(1).length() > 3) { + thisFrame.extended = true; + } else { + thisFrame.extended = false; + } + + QString val= IdValExp.cap(2); + + pos = 0; + thisFrame.len = 0; + if (val.startsWith("R") && val.at(1).isDigit()) { + thisFrame.len = val.at(1).toLatin1() - '0'; + thisFrame.remote = true; + } else { + thisFrame.remote = false; + /* val byte per byte */ + while ((pos = valExp.indexIn(val, pos)) != -1) + { + thisFrame.data[thisFrame.len] = valExp.cap(1).toInt(&ret, 16); + if(!ret) continue; + + thisFrame.len++; + pos += valExp.matchedLength(); + } } } diff --git a/framefileio.h b/framefileio.h index c60e1c7..820426c 100644 --- a/framefileio.h +++ b/framefileio.h @@ -46,6 +46,7 @@ public: static bool loadCanalyzerBLF(QString, QVector*); static bool loadCANHackerFile(QString filename, QVector* frames); static bool loadCabanaFile(QString filename, QVector* frames); + static bool loadCANOpenFile(QString filename, QVector* frames); static bool saveCRTDFile(QString, const QVector*); static bool saveNativeCSVFile(QString, const QVector*); static bool saveGenericCSVFile(QString, const QVector*); @@ -57,6 +58,7 @@ public: static bool saveVehicleSpyFile(QString, const QVector*); static bool saveCanDumpFile(QString filename, const QVector * frames); static bool saveCabanaFile(QString filename, const QVector* frames); + static bool saveCanalyzerASC(QString filename, const QVector* frames); static bool openContinuousNative(); static bool closeContinuousNative(); static bool writeContinuousNative(const QVector*, int); diff --git a/mainsettingsdialog.cpp b/mainsettingsdialog.cpp index 2dd0a38..1a503d5 100644 --- a/mainsettingsdialog.cpp +++ b/mainsettingsdialog.cpp @@ -31,6 +31,7 @@ MainSettingsDialog::MainSettingsDialog(QWidget *parent) : ui->lineRemoteHost->setText(settings->value("Remote/Host", "api.savvycan.com").toString()); ui->lineRemotePort->setText(settings->value("Remote/Port", "21315").toString()); // = 0x5343 = SC. Yep, really creative port number ui->cbAutoStartRemote->setChecked(settings->value("Remote/AutoStart", false).toBool()); + ui->cbLoadConnections->setChecked(settings->value("Main/SaveRestoreConnections", false).toBool()); ui->spinFontSize->setValue(settings->value("Main/FontSize", ui->cbDisplayHex->font().pointSize()).toUInt()); @@ -82,6 +83,7 @@ MainSettingsDialog::MainSettingsDialog(QWidget *parent) : connect(ui->cbAutoStartRemote, SIGNAL(toggled(bool)), this, SLOT(updateSettings())); connect(ui->lineRemoteHost, SIGNAL(editingFinished()), this, SLOT(updateSettings())); connect(ui->lineRemotePort, SIGNAL(editingFinished()), this, SLOT(updateSettings())); + connect(ui->cbLoadConnections, SIGNAL(toggled(bool)), this, SLOT(updateSettings())); installEventFilter(this); } @@ -127,6 +129,7 @@ void MainSettingsDialog::updateSettings() settings->setValue("Main/AutoScroll", ui->cbMainAutoScroll->isChecked()); settings->setValue("Playback/AutoLoop", ui->cbPlaybackLoop->isChecked()); settings->setValue("Main/SaveRestorePositions", ui->cbRestorePositions->isChecked()); + settings->setValue("Main/SaveRestoreConnections", ui->cbLoadConnections->isChecked()); settings->setValue("Main/ValidateComm", ui->cbValidate->isChecked()); settings->setValue("Playback/DefSpeed", ui->spinPlaybackSpeed->value()); settings->setValue("Main/TimeSeconds", ui->rbSeconds->isChecked()); diff --git a/re/filecomparatorwindow.cpp b/re/filecomparatorwindow.cpp index a2e8d5b..3102142 100644 --- a/re/filecomparatorwindow.cpp +++ b/re/filecomparatorwindow.cpp @@ -16,7 +16,7 @@ FileComparatorWindow::FileComparatorWindow(QWidget *parent) : connect(ui->btnClear, SIGNAL(clicked(bool)), this, SLOT(clearReference())); ui->lblFirstFile->setText(""); - ui->lblRefFrames->setText("0"); + ui->lblRefFrames->setText("Loaded frames: 0"); installEventFilter(this); } @@ -81,21 +81,28 @@ void FileComparatorWindow::loadInterestedFile() { interestedFrames.clear(); QString resultingFileName; + + qApp->processEvents(); + if (FrameFileIO::loadFrameFile(resultingFileName, &interestedFrames)) { ui->lblFirstFile->setText(resultingFileName); interestedFilename = resultingFileName; if (interestedFrames.count() > 0 && referenceFrames.count() > 0) calculateDetails(); } + } void FileComparatorWindow::loadReferenceFile() { //secondFileFrames.clear(); QString resultingFileName; + + qApp->processEvents(); + if (FrameFileIO::loadFrameFile(resultingFileName, &referenceFrames)) { - ui->lblRefFrames->setText(QString::number(referenceFrames.length())); + ui->lblRefFrames->setText("Loaded frames: " + QString::number(referenceFrames.length())); if (interestedFrames.count() > 0 && referenceFrames.count() > 0) calculateDetails(); } } @@ -104,6 +111,7 @@ void FileComparatorWindow::clearReference() { referenceFrames.clear(); ui->treeDetails->clear(); + ui->lblRefFrames->setText("Loaded frames: " + QString::number(referenceFrames.length())); } void FileComparatorWindow::calculateDetails() @@ -116,6 +124,16 @@ void FileComparatorWindow::calculateDetails() bool uniqueInterested = ui->ckUniqueToInterested->isChecked(); + QProgressDialog progress(this); + progress.setWindowModality(Qt::WindowModal); + progress.setLabelText("Calculating differences"); + progress.setCancelButton(0); + progress.setRange(0,0); + progress.setMinimumDuration(0); + progress.show(); + + qApp->processEvents(); + ui->treeDetails->clear(); interestedOnlyBase = new QTreeWidgetItem(); @@ -123,10 +141,10 @@ void FileComparatorWindow::calculateDetails() if (!uniqueInterested) { referenceOnlyBase = new QTreeWidgetItem(); - referenceOnlyBase->setText(0, "IDs found only in reference frames"); + referenceOnlyBase->setText(0, "IDs found only in Side 2 - Reference frames"); } sharedBase = new QTreeWidgetItem(); - sharedBase->setText(0,"IDs found in both places"); + sharedBase->setText(0,"IDs found on both sides"); //first we have to fill out the data structures to get ready to do the report for (int x = 0; x < interestedFrames.count(); x++) @@ -171,6 +189,8 @@ void FileComparatorWindow::calculateDetails() } } + qApp->processEvents(); + for (int x = 0; x < referenceFrames.count(); x++) { CANFrame frame = referenceFrames.at(x); @@ -211,17 +231,27 @@ void FileComparatorWindow::calculateDetails() } } + qApp->processEvents(); + //now we iterate through the IDs within both files and see which are unique to one file and which //are shared bool interestedHadUnique = false; QMap::iterator i; + int framesCounter = 0; for (i = interestedIDs.begin(); i != interestedIDs.end(); ++i) { + framesCounter++; + if (framesCounter > 10000) + { + framesCounter = 0; + qApp->processEvents(); + } + int keyone = i.key(); if (!referenceIDs.contains(keyone)) { valuesBase = new QTreeWidgetItem(); - valuesBase->setText(0, QString::number(keyone, 16)); + valuesBase->setText(0, Utility::formatHexNum(keyone)); interestedOnlyBase->addChild(valuesBase); } else //ID was in both files @@ -240,7 +270,7 @@ void FileComparatorWindow::calculateDetails() if (!uniqueInterested) { bitmapBaseReference = new QTreeWidgetItem(); - bitmapBaseReference->setText(0, "Bits set only in reference frames"); + bitmapBaseReference->setText(0, "Bits set only in Side 2 - Reference frames"); } sharedItem->addChild(bitmapBaseInterested); if (!uniqueInterested) sharedItem->addChild(bitmapBaseReference); @@ -277,7 +307,7 @@ void FileComparatorWindow::calculateDetails() if (!uniqueInterested) { valuesReference = new QTreeWidgetItem(); - valuesReference->setText(0, "Values found only in reference frames"); + valuesReference->setText(0, "Values found only in Side 2 - Reference frames"); } valuesBase->addChild(valuesInterested); if (!uniqueInterested) valuesBase->addChild(valuesReference); @@ -300,6 +330,8 @@ void FileComparatorWindow::calculateDetails() } } + qApp->processEvents(); + if (!uniqueInterested) { QMap::iterator itwo; @@ -327,6 +359,8 @@ void FileComparatorWindow::calculateDetails() { ui->treeDetails->expandAll(); } + + progress.cancel(); } void FileComparatorWindow::saveDetails() diff --git a/re/flowviewwindow.cpp b/re/flowviewwindow.cpp index 0587b7c..5092bd6 100644 --- a/re/flowviewwindow.cpp +++ b/re/flowviewwindow.cpp @@ -56,7 +56,8 @@ FlowViewWindow::FlowViewWindow(const QVector *frames, QWidget *parent) //ui->graphView->xAxis->setAutoSubTicks(false); //ui->graphView->xAxis->setAutoTicks(false); QCPAxisTicker *xTicker = new QCPAxisTicker(); - xTicker->setTickCount(10); + xTicker->setTickCount(5); + xTicker->setTickStepStrategy(QCPAxisTicker::tssReadability); ui->graphView->xAxis->setTicker(QSharedPointer(xTicker)); //ui->graphView->xAxis->setAutoTickStep(false); //ui->graphView->xAxis->setAutoSubTicks(false); @@ -444,7 +445,8 @@ void FlowViewWindow::updatedFrames(int numFrames) { for (int k = 0; k < 8; k++) { - graphRef[k]->addData(newX[k], newY[k]); + if (graphRef[k] && graphRef[k]->data()) + graphRef[k]->addData(newX[k], newY[k]); } ui->graphView->replot(); updateDataView(); @@ -465,6 +467,8 @@ void FlowViewWindow::createGraph(int byteNum) int tempVal; float minval=1000000, maxval = -100000; + qDebug() << "Create Graph " << byteNum; + bool graphByTime = ui->cbTimeGraph->isChecked(); int numEntries = frameCache.count(); @@ -533,6 +537,7 @@ void FlowViewWindow::updateFrameLabel() void FlowViewWindow::changeID(QString newID) { + qDebug() << "change id " << newID; //parse the ID and then load up the frame cache with just messages with that ID. uint32_t id = (uint32_t)Utility::ParseStringToNum(newID); frameCache.clear(); @@ -555,7 +560,8 @@ void FlowViewWindow::changeID(QString newID) if (frameCache.count() == 0) return; removeAllGraphs(); - for (uint32_t c = 0; c < frameCache.at(0).len; c++) + //for (uint32_t c = 0; c < frameCache.at(0).len; c++) + for (uint32_t c = 0; c < 8; c++) { createGraph(c); } diff --git a/re/graphingwindow.cpp b/re/graphingwindow.cpp index 0cc5121..b311623 100644 --- a/re/graphingwindow.cpp +++ b/re/graphingwindow.cpp @@ -458,7 +458,7 @@ bool GraphingWindow::eventFilter(QObject *obj, QEvent *event) void GraphingWindow::resetView() { double yminval=10000000.0, ymaxval = -1000000.0; - double xminval=10000000000.0, xmaxval = -10000000000.0; + double xminval=100000000000, xmaxval = -10000000000.0; for (int i = 0; i < graphParams.count(); i++) { for (int j = 0; j < graphParams[i].x.count(); j++) @@ -1076,8 +1076,8 @@ void GraphingWindow::appendToGraph(GraphParams ¶ms, CANFrame &frame, QVector void GraphingWindow::createGraph(GraphParams ¶ms, bool createGraphParam) { int64_t tempVal; //64 bit temp value. - float yminval=10000000.0, ymaxval = -1000000.0; - float xminval=10000000000.0, xmaxval = -10000000000.0; + double yminval=10000000.0, ymaxval = -1000000.0; + double xminval=10000000000.0, xmaxval = -10000000000.0; GraphParams *refParam = ¶ms; int sBit, bits; bool intelFormat, isSigned; diff --git a/re/sniffer/SnifferDelegate.cpp b/re/sniffer/SnifferDelegate.cpp index 82b2fdd..543d0e8 100644 --- a/re/sniffer/SnifferDelegate.cpp +++ b/re/sniffer/SnifferDelegate.cpp @@ -1,19 +1,32 @@ #include "SnifferDelegate.h" #include +#include #include #include "utility.h" #include "re/sniffer/snifferitem.h" SnifferDelegate::SnifferDelegate(QWidget *parent) : QItemDelegate(parent) { + QColor TextColor = QApplication::palette().color(QPalette::Text); + if (TextColor.red() + TextColor.green() + TextColor.blue() < 200) + { + mDarkMode = false; + redBrush = QBrush(Qt::red); + greenBrush = QBrush(Qt::green); + } + else + { + mDarkMode = true; + redBrush = QBrush(QColor(128,0,0)); + greenBrush = QBrush(QColor(0,128,0)); + } blackBrush = QBrush(Qt::black); whiteBrush = QBrush(Qt::white); - redBrush = QBrush(Qt::red); - greenBrush = QBrush(Qt::green); grayBrush = QBrush(QColor(230,230,230)); mainFont.setPointSize(10); mainFontInfo = new QFontInfo(mainFont); mFadeInactive = false; + } bool SnifferDelegate::getFadeInactive() @@ -101,7 +114,7 @@ void SnifferDelegate::paint(QPainter *painter, const QStyleOptionViewItem &optio //painter->setPen(QPen(QColor(v,v,v,255))); painter->setOpacity(1.0); - painter->setPen(Qt::black); + painter->setPen(QApplication::palette().color(QPalette::Text)); painter->setFont(mainFont); painter->drawText(QRect(viewport.left(), viewport.top() + xSector + yOffset, xSpan, mainFontInfo->pixelSize()), Qt::AlignCenter, Utility::formatNumber(val)); } diff --git a/re/sniffer/SnifferDelegate.h b/re/sniffer/SnifferDelegate.h index 693c259..9c98ed5 100644 --- a/re/sniffer/SnifferDelegate.h +++ b/re/sniffer/SnifferDelegate.h @@ -21,7 +21,8 @@ private: QBrush blackBrush, whiteBrush, redBrush, greenBrush, grayBrush; QFont mainFont; QFontInfo* mainFontInfo; - bool mFadeInactive; + bool mFadeInactive; + bool mDarkMode; }; #endif diff --git a/re/sniffer/sniffermodel.cpp b/re/sniffer/sniffermodel.cpp index c55163c..2fb0b77 100644 --- a/re/sniffer/sniffermodel.cpp +++ b/re/sniffer/sniffermodel.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include "sniffermodel.h" #include "snifferwindow.h" #include "SnifferDelegate.h" @@ -11,6 +13,12 @@ SnifferModel::SnifferModel(QObject *parent) mMuteNotched(false), mTimeSequence(0) { + QColor TextColor = QApplication::palette().color(QPalette::Text); + if (TextColor.red() + TextColor.green() + TextColor.blue() < 200) + { + mDarkMode = false; + } + else mDarkMode = true; } SnifferModel::~SnifferModel() @@ -69,13 +77,20 @@ QVariant SnifferModel::data(const QModelIndex &index, int role) const } case Qt::ForegroundRole: { - if (!mFadeInactive || col < 2) return QBrush(Qt::black); + if (!mFadeInactive || col < 2) return QApplication::palette().brush(QPalette::Text); int v = item->getSeqInterval(col - 2) * 10; //qDebug() << "mTS: " << mTimeSequence << " gDT(" << (col - 2) << ") " << item->getDataTimestamp(col - 2); if (v > 225) v = 225; if (v < 0) v = 0; - return QBrush(QColor(v,v,v,255)); - break; + + if (!mDarkMode) //text defaults to being dark + { + return QBrush(QColor(v,v,v,255)); + } + else //text defaults to being light + { + return QBrush(QColor(255-v,255-v,255-v,255)); + } } case Qt::BackgroundRole: @@ -83,7 +98,10 @@ QVariant SnifferModel::data(const QModelIndex &index, int role) const if(tc::ID==col) { if(item->elapsed() > 4000) - return QBrush(Qt::red); + { + if (!mDarkMode) return QBrush(Qt::red); + return QBrush(QColor(128,0,0)); + } } else if(tc::DATA_0<=col && col<=tc::DATA_7) { @@ -91,11 +109,13 @@ QVariant SnifferModel::data(const QModelIndex &index, int role) const switch(change) { case dc::INC: - return QBrush(Qt::green); + if (!mDarkMode) return QBrush(Qt::green); + return QBrush(QColor(0,128,0)); case dc::DEINC: - return QBrush(Qt::red); + if (!mDarkMode) return QBrush(Qt::red); + return QBrush(QColor(128,0,0)); default: - break; + return QApplication::palette().brush(QPalette::Base); } } break; diff --git a/re/sniffer/sniffermodel.h b/re/sniffer/sniffermodel.h index 4945cd2..04ee5f8 100644 --- a/re/sniffer/sniffermodel.h +++ b/re/sniffer/sniffermodel.h @@ -63,6 +63,7 @@ private: bool mNeverExpire; bool mFadeInactive; bool mMuteNotched; + bool mDarkMode; quint32 mTimeSequence; }; diff --git a/ui/connectionwindow.ui b/ui/connectionwindow.ui index b679a1b..d132606 100644 --- a/ui/connectionwindow.ui +++ b/ui/connectionwindow.ui @@ -19,7 +19,7 @@ - Connections: + Connected Devices: @@ -37,192 +37,104 @@ - - - - - Reconnect - - - - - - - Remove Selected Connection - - - - - - - Activate All Connections - - - - - - - Deactivate All Connections - - - - + + + Add New Device Connection + + + + + + + Disconnect Selected Device + + + + + + + false + + + Bus Details: + + + Qt::AlignCenter + + + + + + + + + + + CAN Bus Number: + + + + + + + + + + + + + + Speed: + + + + + + + + + + Listen Only: + + + + + + + + + + + + + + Enable Bus: + + + + + + + + + + + + + + Save Bus Settings + + + + + + + - - - - Connection Type - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - GVRET Serial - - - true - - - - - - - false - - - QT SerialBus Devices (SocketCAN, PeakCAN, etc) - - - - - - - Remote Host - - - - - - - - - - Device Type: - - - - - - - - - - - 0 - 0 - - - - Port: - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - Qt::LeftToRight - - - 0 - - - - - 0 - 0 - - - - Qt::LeftToRight - - - - - - - 0 - 0 - - - - - 341 - 16777215 - - - - - - - - - - - - - 0 - 0 - - - - - - - - - - - - - - Create New Connection - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - @@ -296,6 +208,13 @@ + + + QTabBar + QWidget +
qtabbar.h
+
+
diff --git a/ui/filecomparatorwindow.ui b/ui/filecomparatorwindow.ui index 0711cca..94e6685 100644 --- a/ui/filecomparatorwindow.ui +++ b/ui/filecomparatorwindow.ui @@ -15,13 +15,31 @@ - + + + + + + 16 + + + + SIDE 1 + + + Qt::AlignCenter + + + - File of interest: + Single file to compare to side 2: + + + Qt::AlignCenter @@ -41,12 +59,40 @@ + + + + Qt::Vertical + + + + + + + + 16 + + + + Side 2 + + + Qt::AlignCenter + + + - <html><head/><body><p>Loaded reference frames:</p></body></html> + One or more files to compare with the single file on side1: + + + Qt::AlignCenter + + + true @@ -79,10 +125,20 @@
+ + + + Qt::Horizontal + + + + + true + - Show only unique data for interested file + Show only data unique to Side 1 diff --git a/ui/mainsettingsdialog.ui b/ui/mainsettingsdialog.ui index 1b790dd..05de6aa 100644 --- a/ui/mainsettingsdialog.ui +++ b/ui/mainsettingsdialog.ui @@ -45,6 +45,13 @@ + + + + Save/Restore CAN bus connections + + + @@ -337,20 +344,27 @@ + cbMainAutoScroll cbRestorePositions + cbLoadConnections cbDisplayHex cbValidate + cbUseFiltered + cbUseOpenGL rbSeconds rbMicros rbSysClock lineClockFormat - cbMainAutoScroll + spinFontSize cbFlowUseTimestamp cbFlowAutoRef cbPlaybackLoop spinPlaybackSpeed comboSendingBus cbInfoAutoExpand + lineRemoteHost + lineRemotePort + cbAutoStartRemote diff --git a/ui/newconnectiondialog.ui b/ui/newconnectiondialog.ui new file mode 100644 index 0000000..de55127 --- /dev/null +++ b/ui/newconnectiondialog.ui @@ -0,0 +1,109 @@ + + + NewConnectionDialog + + + + 0 + 0 + 356 + 282 + + + + New Connection + + + + + + Connection Type + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + Serial Connection + + + true + + + + + + + false + + + QT SerialBus Devices (SocketCAN, PeakCAN, etc) + + + + + + + Network connection + + + + + + + + + + SerialBus Device Type: + + + + + + + + + + + 0 + 0 + + + + Serial Port: + + + + + + + + 0 + 0 + + + + + 341 + 16777215 + + + + true + + + + + + + Create New Connection + + + + + + + +