Merge pull request #105 from collin80/WIP

Merge Wip Changes into Master
This commit is contained in:
Collin Kidder
2017-11-09 20:12:25 -05:00
committed by GitHub
24 changed files with 1161 additions and 476 deletions
+4 -2
View File
@@ -64,7 +64,8 @@ SOURCES += main.cpp\
bus_protocols/isotp_handler.cpp \ bus_protocols/isotp_handler.cpp \
bus_protocols/j1939_handler.cpp \ bus_protocols/j1939_handler.cpp \
bus_protocols/uds_handler.cpp \ bus_protocols/uds_handler.cpp \
jsedit.cpp jsedit.cpp \
frameplaybackobject.cpp
HEADERS += mainwindow.h \ HEADERS += mainwindow.h \
can_structs.h \ can_structs.h \
@@ -117,7 +118,8 @@ HEADERS += mainwindow.h \
bus_protocols/j1939_handler.h \ bus_protocols/j1939_handler.h \
bus_protocols/uds_handler.h \ bus_protocols/uds_handler.h \
bus_protocols/isotp_message.h \ bus_protocols/isotp_message.h \
jsedit.h jsedit.h \
frameplaybackobject.h
FORMS += ui/candatagrid.ui \ FORMS += ui/candatagrid.ui \
ui/connectionwindow.ui \ ui/connectionwindow.ui \
+105 -4
View File
@@ -23,6 +23,8 @@ QVector<CODE_STRUCT> UDS_COMM_CTRL_SUB = {
{0,"COMM_NORMAL", "Enable both Rx and Tx of normal messages"}, {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"}, {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"}, {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<CODE_STRUCT> UDS_ROUTINE_SUB = { QVector<CODE_STRUCT> UDS_ROUTINE_SUB = {
@@ -319,6 +321,8 @@ QString UDS_HANDLER::getDetailedMessageAnalysis(const UDS_MESSAGE &msg)
{ {
QString buildString; QString buildString;
bool isResponse = true; bool isResponse = true;
int dataSize;
int addrSize;
if (msg.isErrorReply) if (msg.isErrorReply)
{ {
@@ -361,9 +365,9 @@ QString UDS_HANDLER::getDetailedMessageAnalysis(const UDS_MESSAGE &msg)
else else
{ {
int p2 = msg.data[1] * 256 + msg.data[2]; 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; 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; break;
case UDS_SERVICES::ECU_RESET: case UDS_SERVICES::ECU_RESET:
@@ -384,8 +388,15 @@ QString UDS_HANDLER::getDetailedMessageAnalysis(const UDS_MESSAGE &msg)
else buildString.append("\nNo powerdown time returned"); else buildString.append("\nNo powerdown time returned");
break; break;
case UDS_SERVICES::COMM_CTRL: 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 //Comm control has potentially a lot of parameters. control type, comm type, nodeID
buildString.append("Comm type: " + getLongDesc(UDS_COMM_CTRL_SUB, msg.subFunc)); 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; break;
case UDS_SERVICES::SECURITY_ACCESS: case UDS_SERVICES::SECURITY_ACCESS:
if ((msg.subFunc % 2) == 1) if ((msg.subFunc % 2) == 1)
@@ -423,6 +434,96 @@ QString UDS_HANDLER::getDetailedMessageAnalysis(const UDS_MESSAGE &msg)
buildString.append("\nECU is now unlocked"); buildString.append("\nECU is now unlocked");
} }
break; 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;
} }
} }
+5
View File
@@ -15,6 +15,11 @@ public:
uint32_t len; uint32_t len;
unsigned char data[8]; unsigned char data[8];
uint64_t timestamp; uint64_t timestamp;
friend bool operator<(const CANFrame& l, const CANFrame& r)
{
return l.timestamp < r.timestamp;
}
}; };
class CANFltObserver class CANFltObserver
+1 -1
View File
@@ -1,7 +1,7 @@
#ifndef CONFIG #ifndef CONFIG
#define CONFIG #define CONFIG
#define VERSION 178 #define VERSION 179
//try to keep this in sync. //try to keep this in sync.
//SavvyCAN will complain if you connect a GVRET board with a revision //SavvyCAN will complain if you connect a GVRET board with a revision
+5
View File
@@ -1,4 +1,5 @@
#include <QObject> #include <QObject>
#include <QDebug>
#include "canbus.h" #include "canbus.h"
CANBus::CANBus() CANBus::CANBus()
@@ -25,18 +26,22 @@ bool CANBus::operator==(const CANBus& bus) const{
} }
void CANBus::setSpeed(int newSpeed){ void CANBus::setSpeed(int newSpeed){
//qDebug() << "CANBUS SetSpeed = " << newSpeed;
speed = newSpeed; speed = newSpeed;
} }
void CANBus::setListenOnly(bool mode){ void CANBus::setListenOnly(bool mode){
//qDebug() << "CANBUS SetListenOnly = " << mode;
listenOnly = mode; listenOnly = mode;
} }
void CANBus::setSingleWire(bool mode){ void CANBus::setSingleWire(bool mode){
//qDebug() << "CANBUS SetSingleWire = " << mode;
singleWire = mode; singleWire = mode;
} }
void CANBus::setEnabled(bool mode){ void CANBus::setEnabled(bool mode){
//qDebug() << "CANBUS SetEnabled = " << mode;
active = mode; active = mode;
} }
+7
View File
@@ -1,6 +1,7 @@
#ifndef CANBus_H #ifndef CANBus_H
#define CANBus_H #define CANBus_H
#include <QDataStream> #include <QDataStream>
#include "can_structs.h"
class CANBus class CANBus
{ {
@@ -31,4 +32,10 @@ QDataStream & operator>>(QDataStream & pStream, CANBus& pCanBus);
Q_DECLARE_METATYPE(CANBus); Q_DECLARE_METATYPE(CANBus);
struct BusData {
CANBus mBus;
bool mConfigured;
QVector<CANFltObserver> mTargettedFrames;
};
#endif // CANBus_H #endif // CANBus_H
+7
View File
@@ -21,4 +21,11 @@ namespace CANCon {
}; };
} }
class CANConStatus
{
public:
CANCon::status conStatus;
int numHardwareBuses;
};
#endif // CANCONCONST_H #endif // CANCONCONST_H
+10 -2
View File
@@ -36,6 +36,7 @@ CANConManager::CANConManager(QObject *parent): QObject(parent)
void CANConManager::resetTimeBasis() void CANConManager::resetTimeBasis()
{ {
mTimestampBasis = QDateTime::currentMSecsSinceEpoch() * 1000; mTimestampBasis = QDateTime::currentMSecsSinceEpoch() * 1000;
mElapsedTimer.restart();
} }
CANConManager::~CANConManager() CANConManager::~CANConManager()
@@ -182,8 +183,15 @@ bool CANConManager::sendFrame(const CANFrame& pFrame)
{ {
workingFrame.bus -= busBase; workingFrame.bus -= busBase;
workingFrame.isReceived = false; workingFrame.isReceived = false;
workingFrame.timestamp = (QDateTime::currentMSecsSinceEpoch() * 1000); if (useSystemTime)
if (!useSystemTime) workingFrame.timestamp -= mTimestampBasis; {
workingFrame.timestamp = (QDateTime::currentMSecsSinceEpoch() * 1000);
}
else
{
workingFrame.timestamp = mElapsedTimer.nsecsElapsed() / 1000;
//workingFrame.timestamp -= mTimestampBasis;
}
txFrame = conn->getQueue().get(); txFrame = conn->getQueue().get();
*txFrame = workingFrame; *txFrame = workingFrame;
conn->getQueue().queue(); conn->getQueue().queue();
+2
View File
@@ -3,6 +3,7 @@
#include <QObject> #include <QObject>
#include <QTimer> #include <QTimer>
#include <QElapsedTimer>
#include "canconnection.h" #include "canconnection.h"
@@ -73,6 +74,7 @@ private:
static CANConManager* mInstance; static CANConManager* mInstance;
QList<CANConnection*> mConns; QList<CANConnection*> mConns;
QTimer mTimer; QTimer mTimer;
QElapsedTimer mElapsedTimer;
uint64_t mTimestampBasis; uint64_t mTimestampBasis;
uint32_t mNumActiveBuses; uint32_t mNumActiveBuses;
bool useSystemTime; bool useSystemTime;
+16 -27
View File
@@ -2,14 +2,6 @@
#include <QThread> #include <QThread>
#include "canconnection.h" #include "canconnection.h"
struct BusData {
CANBus mBus;
bool mConfigured;
QVector<CANFltObserver> mTargettedFrames;
};
CANConnection::CANConnection(QString pPort, CANConnection::CANConnection(QString pPort,
CANCon::type pType, CANCon::type pType,
int pNumBuses, int pNumBuses,
@@ -27,7 +19,7 @@ CANConnection::CANConnection(QString pPort,
/* register types */ /* register types */
qRegisterMetaType<CANBus>("CANBus"); qRegisterMetaType<CANBus>("CANBus");
qRegisterMetaType<CANFrame>("CANFrame"); qRegisterMetaType<CANFrame>("CANFrame");
qRegisterMetaType<CANCon::status>("CANCon::status"); qRegisterMetaType<CANConStatus>("CANConStatus");
qRegisterMetaType<CANFltObserver>("CANFlt"); qRegisterMetaType<CANFltObserver>("CANFlt");
/* set queue size */ /* set queue size */
@@ -35,9 +27,9 @@ CANConnection::CANConnection(QString pPort,
/* allocate buses */ /* allocate buses */
/* TODO: change those tables for a vector */ /* TODO: change those tables for a vector */
mBusData_p = new BusData[mNumBuses]; mBusData.resize(mNumBuses);
for(int i=0 ; i<mNumBuses ; i++) { for(int i=0 ; i<mNumBuses ; i++) {
mBusData_p[i].mConfigured = false; mBusData[i].mConfigured = false;
} }
/* if needed, create a thread and move ourself into it */ /* if needed, create a thread and move ourself into it */
@@ -57,10 +49,7 @@ CANConnection::~CANConnection()
mThread_p = NULL; mThread_p = NULL;
} }
if(mBusData_p) { mBusData.clear();
delete[] mBusData_p;
mBusData_p = NULL;
}
} }
@@ -206,13 +195,13 @@ int CANConnection::getNumBuses() const{
bool CANConnection::isConfigured(int pBusId) { bool CANConnection::isConfigured(int pBusId) {
if( pBusId < 0 || pBusId >= getNumBuses()) if( pBusId < 0 || pBusId >= getNumBuses())
return false; return false;
return mBusData_p[pBusId].mConfigured; return mBusData[pBusId].mConfigured;
} }
void CANConnection::setConfigured(int pBusId, bool pConfigured) { void CANConnection::setConfigured(int pBusId, bool pConfigured) {
if( pBusId < 0 || pBusId >= getNumBuses()) if( pBusId < 0 || pBusId >= getNumBuses())
return; 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)) if( pBusId < 0 || pBusId >= getNumBuses() || !isConfigured(pBusId))
return false; return false;
pBus = mBusData_p[pBusId].mBus; pBus = mBusData[pBusId].mBus;
return true; return true;
} }
@@ -229,8 +218,8 @@ void CANConnection::setBusConfig(int pBusId, CANBus& pBus) {
if( pBusId < 0 || pBusId >= getNumBuses()) if( pBusId < 0 || pBusId >= getNumBuses())
return; return;
mBusData_p[pBusId].mConfigured = true; mBusData[pBusId].mConfigured = true;
mBusData_p[pBusId].mBus = pBus; mBusData[pBusId].mBus = pBus;
} }
@@ -293,7 +282,7 @@ bool CANConnection::addTargettedFrame(int pBusId, uint32_t ID, uint32_t mask, QO
target.id = ID; target.id = ID;
target.mask = mask; target.mask = mask;
target.observer = receiver; target.observer = receiver;
mBusData_p[pBusId].mTargettedFrames.append(target); mBusData[pBusId].mTargettedFrames.append(target);
return true; return true;
} }
@@ -321,7 +310,7 @@ bool CANConnection::removeTargettedFrame(int pBusId, uint32_t ID, uint32_t mask,
target.id = ID; target.id = ID;
target.mask = mask; target.mask = mask;
target.observer = receiver; target.observer = receiver;
mBusData_p[pBusId].mTargettedFrames.removeAll(target); mBusData[pBusId].mTargettedFrames.removeAll(target);
return true; return true;
} }
@@ -329,9 +318,9 @@ bool CANConnection::removeTargettedFrame(int pBusId, uint32_t ID, uint32_t mask,
bool CANConnection::removeAllTargettedFrames(QObject *receiver) bool CANConnection::removeAllTargettedFrames(QObject *receiver)
{ {
for (int i = 0; i < getNumBuses(); i++) { 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; unsigned int maskedID;
//qDebug() << "Got frame with ID " << frame.ID << " on bus " << frame.bus; //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; if (mBusData[frame.bus].mTargettedFrames.length() == 0) return;
foreach (const CANFltObserver filt, mBusData_p[frame.bus].mTargettedFrames) foreach (const CANFltObserver filt, mBusData[frame.bus].mTargettedFrames)
{ {
//qDebug() << "Checking filter with id " << filt.id << " mask " << filt.mask; //qDebug() << "Checking filter with id " << filt.id << " mask " << filt.mask;
maskedID = frame.ID & filt.mask; maskedID = frame.ID & filt.mask;
+3 -3
View File
@@ -89,7 +89,7 @@ signals:
* @brief event emitted when the CANCon::status of the connection changes (connected->not_connected or the other way round) * @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 * @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. * @brief Event sent when device has done something worthy of debugging output.
@@ -183,7 +183,8 @@ public slots:
void debugInput(QByteArray bytes); void debugInput(QByteArray bytes);
protected: 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<BusData> mBusData;
//determine if the passed frame is part of a filter or not. //determine if the passed frame is part of a filter or not.
void checkTargettedFrame(CANFrame &frame); void checkTargettedFrame(CANFrame &frame);
@@ -297,7 +298,6 @@ private:
bool mIsCapSuspended; bool mIsCapSuspended;
QAtomicInt mStatus; QAtomicInt mStatus;
bool mStarted; bool mStarted;
BusData* mBusData_p;
QThread* mThread_p; QThread* mThread_p;
}; };
+107 -22
View File
@@ -40,10 +40,10 @@ QVariant CANConnectionModel::headerData(int section, Qt::Orientation orientation
return QString(tr("Single Wire")); return QString(tr("Single Wire"));
break; break;
case 6: case 6:
return QString(tr("Status")); return QString(tr("Active"));
break; break;
case 7: case 7:
return QString(tr("Active")); return QString(tr("Status"));
break; break;
} }
} }
@@ -54,11 +54,10 @@ QVariant CANConnectionModel::headerData(int section, Qt::Orientation orientation
return QVariant(); return QVariant();
} }
int CANConnectionModel::columnCount(const QModelIndex &parent) const int CANConnectionModel::columnCount(const QModelIndex &parent) const
{ {
Q_UNUSED(parent); Q_UNUSED(parent);
return 7; return 8;
} }
@@ -66,32 +65,99 @@ int CANConnectionModel::rowCount(const QModelIndex &parent) const
{ {
Q_UNUSED(parent); Q_UNUSED(parent);
int rows=0; int rows = 0;
QList<CANConnection*>& conns = CANConManager::getInstance()->getConnections(); QList<CANConnection*>& conns = CANConManager::getInstance()->getConnections();
foreach(const CANConnection* conn_p, conns) foreach(const CANConnection* conn_p, conns)
rows+=conn_p->getNumBuses(); rows += conn_p->getNumBuses();
//qDebug() << "Num Rows: " << rows;
return 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;
//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 QVariant CANConnectionModel::data(const QModelIndex &index, int role) const
{ {
if (!index.isValid()) if (!index.isValid())
return QVariant(); return QVariant();
//qDebug() << "Row: " << index.row();
int busId;
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;
if (role == Qt::DisplayRole) { //qDebug() << "ConnP: " << conn_p << " ret " << ret;
int busId;
CANConnection *conn_p = getAtIdx(index.row(), busId);
if(!conn_p)
return QVariant();
CANBus bus; if (role == Qt::DisplayRole) {
bool ret;
ret = conn_p->getBusSettings(busId, bus);
if(!ret) return QVariant();
switch (index.column()) switch (index.column())
{ {
@@ -114,18 +180,35 @@ QVariant CANConnectionModel::data(const QModelIndex &index, int role) const
else qDebug() << "Tried to show connection port but connection was NULL"; else qDebug() << "Tried to show connection port but connection was NULL";
break; break;
case 3: //speed case 3: //speed
return QString::number(bus.speed); if(!ret) return QVariant();
if (!isSocketCAN) return QString::number(bus.speed);
else return QString("N/A");
case 4: //Listen Only case 4: //Listen Only
return (bus.listenOnly) ? "True" : "False"; return QVariant();
case 5: //Single Wire case 5: //Single Wire
return (bus.singleWire) ? "True" : "False"; return QVariant();
case 6: //Status case 6: //Status
return (conn_p->getStatus()==CANCon::CONNECTED) ? "Connected" : "Not Connected"; return QVariant();
case 7: //Active case 7: //Active
return (bus.active) ? "True" : "False"; return (conn_p->getStatus()==CANCon::CONNECTED) ? "Connected" : "Not Connected";
default: {} 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(); return QVariant();
} }
@@ -172,9 +255,11 @@ CANConnection* CANConnectionModel::getAtIdx(int pIdx, int& pBusId) const
return NULL; return NULL;
} }
void CANConnectionModel::refresh(int pIndex) void CANConnectionModel::refresh(int pIndex)
{ {
beginResetModel();
endResetModel();
/*
QModelIndex begin; QModelIndex begin;
QModelIndex end; QModelIndex end;
@@ -186,5 +271,5 @@ void CANConnectionModel::refresh(int pIndex)
begin = createIndex(0, 0); begin = createIndex(0, 0);
end = createIndex(rowCount()-1, columnCount()-1); end = createIndex(rowCount()-1, columnCount()-1);
} }
dataChanged(begin, end, QVector<int>(Qt::DisplayRole)); dataChanged(begin, end, QVector<int>(Qt::DisplayRole)); */
} }
+4
View File
@@ -21,6 +21,10 @@ public:
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) 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; int rowCount(const QModelIndex &parent = QModelIndex()) const override;
void add(CANConnection* pConn_p); void add(CANConnection* pConn_p);
+14 -115
View File
@@ -24,25 +24,17 @@ ConnectionWindow::ConnectionWindow(QWidget *parent) :
connModel = new CANConnectionModel(this); connModel = new CANConnectionModel(this);
ui->tableConnections->setModel(connModel); ui->tableConnections->setModel(connModel);
ui->tableConnections->setColumnWidth(0, 50); ui->tableConnections->setColumnWidth(0, 40);
ui->tableConnections->setColumnWidth(1, 110); ui->tableConnections->setColumnWidth(1, 70);
ui->tableConnections->setColumnWidth(2, 110); ui->tableConnections->setColumnWidth(2, 70);
ui->tableConnections->setColumnWidth(3, 110); ui->tableConnections->setColumnWidth(3, 70);
ui->tableConnections->setColumnWidth(4, 75); ui->tableConnections->setColumnWidth(4, 70);
ui->tableConnections->setColumnWidth(5, 75); ui->tableConnections->setColumnWidth(5, 70);
ui->tableConnections->setColumnWidth(6, 75); ui->tableConnections->setColumnWidth(6, 70);
ui->tableConnections->setColumnWidth(7, 75); ui->tableConnections->setColumnWidth(7, 90);
QHeaderView *HorzHdr = ui->tableConnections->horizontalHeader(); QHeaderView *HorzHdr = ui->tableConnections->horizontalHeader();
HorzHdr->setStretchLastSection(true); //causes the data column to automatically fill the tableview 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->textConsole->setEnabled(false);
ui->btnClearDebug->setEnabled(false); ui->btnClearDebug->setEnabled(false);
ui->btnSendHex->setEnabled(false); ui->btnSendHex->setEnabled(false);
@@ -61,9 +53,7 @@ ConnectionWindow::ConnectionWindow(QWidget *parent) :
connect(ui->rbGVRET, &QAbstractButton::clicked, this, &ConnectionWindow::handleConnTypeChanged); connect(ui->rbGVRET, &QAbstractButton::clicked, this, &ConnectionWindow::handleConnTypeChanged);
connect(ui->rbKvaser, &QAbstractButton::clicked, this, &ConnectionWindow::handleConnTypeChanged); connect(ui->rbKvaser, &QAbstractButton::clicked, this, &ConnectionWindow::handleConnTypeChanged);
connect(ui->rbSocketCAN, &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->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->btnActivateAll, &QPushButton::clicked, this, &ConnectionWindow::handleEnableAll);
connect(ui->btnDeactivateAll, &QPushButton::clicked, this, &ConnectionWindow::handleDisableAll); connect(ui->btnDeactivateAll, &QPushButton::clicked, this, &ConnectionWindow::handleDisableAll);
connect(ui->btnRemoveBus, &QPushButton::clicked, this, &ConnectionWindow::handleRemoveConn); connect(ui->btnRemoveBus, &QPushButton::clicked, this, &ConnectionWindow::handleRemoveConn);
@@ -100,6 +90,7 @@ void ConnectionWindow::showEvent(QShowEvent* event)
readSettings(); readSettings();
ui->tableConnections->selectRow(0); ui->tableConnections->selectRow(0);
currentRowChanged(ui->tableConnections->currentIndex(), ui->tableConnections->currentIndex()); currentRowChanged(ui->tableConnections->currentIndex(), ui->tableConnections->currentIndex());
handleConnTypeChanged();
} }
void ConnectionWindow::closeEvent(QCloseEvent *event) void ConnectionWindow::closeEvent(QCloseEvent *event)
@@ -207,7 +198,7 @@ void ConnectionWindow::handleConnTypeChanged()
/* status */ /* status */
void ConnectionWindow::connectionStatus(CANCon::status pStatus) void ConnectionWindow::connectionStatus(CANConStatus pStatus)
{ {
Q_UNUSED(pStatus); Q_UNUSED(pStatus);
@@ -218,53 +209,14 @@ void ConnectionWindow::connectionStatus(CANCon::status pStatus)
void ConnectionWindow::handleOKButton() void ConnectionWindow::handleOKButton()
{ {
int whichRow = ui->tableConnections->selectionModel()->currentIndex().row();
CANConnection* conn_p = NULL; CANConnection* conn_p = NULL;
if (whichRow > -1) if( ! CANConManager::getInstance()->getByName(getPortName()) )
{
/* 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()) )
{ {
/* create connection */ /* create connection */
conn_p = create(getConnectionType(), getPortName()); conn_p = create(getConnectionType(), getPortName());
if(!conn_p) if(!conn_p)
return; return;
for (int i=0 ; i<conn_p->getNumBuses() ; 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 */ /* add connection to model */
connModel->add(conn_p); connModel->add(conn_p);
} }
@@ -280,6 +232,7 @@ void ConnectionWindow::currentRowChanged(const QModelIndex &current, const QMode
disconnect(connModel->getAtIdx(previous.row(), busId), SIGNAL(debugOutput(QString)), 0, 0); disconnect(connModel->getAtIdx(previous.row(), busId), SIGNAL(debugOutput(QString)), 0, 0);
disconnect(this, SIGNAL(sendDebugData(QByteArray)), connModel->getAtIdx(previous.row(), busId), SLOT(debugInput(QByteArray))); disconnect(this, SIGNAL(sendDebugData(QByteArray)), connModel->getAtIdx(previous.row(), busId), SLOT(debugInput(QByteArray)));
return;
/* enable / diable connection type */ /* enable / diable connection type */
ui->stPort->setEnabled(selIdx==-1); ui->stPort->setEnabled(selIdx==-1);
@@ -291,9 +244,6 @@ void ConnectionWindow::currentRowChanged(const QModelIndex &current, const QMode
{ {
ui->btnOK->setText(tr("Create New Connection")); ui->btnOK->setText(tr("Create New Connection"));
ui->rbGVRET->setChecked(true); ui->rbGVRET->setChecked(true);
ui->ckListenOnly->setChecked(false);
ui->ckSingleWire->setChecked(false);
ui->ckEnabled->setChecked(false);
setSpeed(0); setSpeed(0);
setPortName(CANCon::GVRET_SERIAL, ""); setPortName(CANCon::GVRET_SERIAL, "");
} }
@@ -313,9 +263,6 @@ void ConnectionWindow::currentRowChanged(const QModelIndex &current, const QMode
if(!ret) return; if(!ret) return;
ui->btnOK->setText(tr("Update Connection Settings")); 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()); setSpeed(bus.getSpeed());
setPortName(conn_p->getType(), conn_p->getPort()); setPortName(conn_p->getType(), conn_p->getPort());
} }
@@ -349,7 +296,6 @@ void ConnectionWindow::selectSerial()
{ {
/* set combobox page visible */ /* set combobox page visible */
ui->stPort->setCurrentWidget(ui->cbPage); ui->stPort->setCurrentWidget(ui->cbPage);
ui->cbSpeed->setEnabled(true);
ui->cbPort->clear(); ui->cbPort->clear();
ports = QSerialPortInfo::availablePorts(); ports = QSerialPortInfo::availablePorts();
@@ -362,7 +308,6 @@ void ConnectionWindow::selectKvaser()
{ {
/* set combobox page visible */ /* set combobox page visible */
ui->stPort->setCurrentWidget(ui->cbPage); ui->stPort->setCurrentWidget(ui->cbPage);
ui->cbSpeed->setEnabled(false);
} }
void ConnectionWindow::selectSocketCan() void ConnectionWindow::selectSocketCan()
@@ -373,18 +318,6 @@ void ConnectionWindow::selectSocketCan()
void ConnectionWindow::setSpeed(int speed0) 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) void ConnectionWindow::setPortName(CANCon::type pType, QString pPortName)
@@ -393,9 +326,6 @@ void ConnectionWindow::setPortName(CANCon::type pType, QString pPortName)
{ {
case CANCon::GVRET_SERIAL: case CANCon::GVRET_SERIAL:
ui->rbGVRET->setChecked(true); ui->rbGVRET->setChecked(true);
ui->cbSpeed->setEnabled(true);
ui->ckListenOnly->setEnabled(true);
ui->ckSingleWire->setEnabled(true);
break; break;
case CANCon::KVASER: case CANCon::KVASER:
ui->rbKvaser->setChecked(true); ui->rbKvaser->setChecked(true);
@@ -403,9 +333,6 @@ void ConnectionWindow::setPortName(CANCon::type pType, QString pPortName)
case CANCon::SOCKETCAN: case CANCon::SOCKETCAN:
ui->rbSocketCAN->setChecked(true); ui->rbSocketCAN->setChecked(true);
//you can't configure any of the below three with socketcan so dim them out //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; break;
default: {} default: {}
} }
@@ -435,16 +362,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. //-1 means leave it at whatever it booted up to. 0 means disable. Otherwise the actual rate we want.
int ConnectionWindow::getSpeed() 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() QString ConnectionWindow::getPortName()
@@ -475,12 +392,10 @@ CANCon::type ConnectionWindow::getConnectionType()
void ConnectionWindow::setSWMode(bool mode) void ConnectionWindow::setSWMode(bool mode)
{ {
ui->ckSingleWire->setChecked(mode);
} }
bool ConnectionWindow::getSWMode() bool ConnectionWindow::getSWMode()
{ {
if (ui->ckSingleWire->checkState() == Qt::Checked) return true;
return false; return false;
} }
@@ -530,8 +445,8 @@ CANConnection* ConnectionWindow::create(CANCon::type pTye, QString pPortName)
if(conn_p) if(conn_p)
{ {
/* connect signal */ /* connect signal */
connect(conn_p, SIGNAL(status(CANCon::status)), connect(conn_p, SIGNAL(status(CANConStatus)),
this, SLOT(connectionStatus(CANCon::status))); this, SLOT(connectionStatus(CANConStatus)));
/*TODO add return value and checks */ /*TODO add return value and checks */
conn_p->start(); conn_p->start();
@@ -552,17 +467,10 @@ void ConnectionWindow::loadConnections()
/* fill connection list */ /* fill connection list */
QVector<QString> portNames = settings.value("connections/portNames").value<QVector<QString>>(); QVector<QString> portNames = settings.value("connections/portNames").value<QVector<QString>>();
QVector<int> devTypes = settings.value("connections/types").value<QVector<int>>(); QVector<int> devTypes = settings.value("connections/types").value<QVector<int>>();
QList<CANBus> busses = settings.value("connections/busses").value<QList<CANBus>>();
for(int i=0 ; i<portNames.count() ; i++) for(int i=0 ; i<portNames.count() ; i++)
{ {
CANConnection* conn_p = create((CANCon::type)devTypes[i], portNames[i]); CANConnection* conn_p = create((CANCon::type)devTypes[i], portNames[i]);
if(conn_p)
{
for(int j=0 ; j<conn_p->getNumBuses() ; j++)
conn_p->setBusSettings(j, busses.takeFirst());
}
/* add connection to model */ /* add connection to model */
connModel->add(conn_p); connModel->add(conn_p);
} }
@@ -579,23 +487,14 @@ void ConnectionWindow::saveConnections()
QSettings settings; QSettings settings;
QVector<QString> portNames; QVector<QString> portNames;
QVector<int> devTypes; QVector<int> devTypes;
QList<CANBus> busses;
/* save connections */ /* save connections */
foreach(CANConnection* conn_p, conns) foreach(CANConnection* conn_p, conns)
{ {
portNames.append(conn_p->getPort()); portNames.append(conn_p->getPort());
devTypes.append(conn_p->getType()); devTypes.append(conn_p->getType());
for(int i=0 ; i<conn_p->getNumBuses() ; i++)
{
CANBus bus;
conn_p->getBusSettings(i, bus);
busses.append(bus);
}
} }
settings.setValue("connections/portNames", QVariant::fromValue(portNames)); settings.setValue("connections/portNames", QVariant::fromValue(portNames));
settings.setValue("connections/types", QVariant::fromValue(devTypes)); settings.setValue("connections/types", QVariant::fromValue(devTypes));
settings.setValue("connections/busses", QVariant::fromValue(busses));
} }
+1 -1
View File
@@ -57,7 +57,7 @@ private slots:
void handleClearDebugText(); void handleClearDebugText();
void handleSendHex(); void handleSendHex();
void handleSendText(); void handleSendText();
void connectionStatus(CANCon::status); void connectionStatus(CANConStatus);
private: private:
Ui::ConnectionWindow *ui; Ui::ConnectionWindow *ui;
+174 -26
View File
@@ -125,25 +125,71 @@ void GVRetSerial::piSetBusSettings(int pBusIdx, CANBus bus)
} }
else deviceSingleWireMode = 0; 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 */ if (bus.isListenOnly())
QByteArray buffer; {
qDebug() << "Got signal to update bauds. 1: " << can0Baud <<" 2: " << can1Baud; swcanBaud |= 0x20000000;
debugOutput("Got signal to update bauds. 1: " + QString::number(can0Baud) + " 2: " + QString::number(can1Baud)); swcanListenOnly = true;
buffer[0] = (char)0xF1; //start of a command over serial }
buffer[1] = 5; //setup canbus else swcanListenOnly = false;
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); if (pBusIdx < 2) {
buffer[6] = (unsigned char)(can1Baud & 0xFF); //four bytes of ID LSB first /* update baud rates */
buffer[7] = (unsigned char)(can1Baud >> 8); QByteArray buffer;
buffer[8] = (unsigned char)(can1Baud >> 16); qDebug() << "Got signal to update bauds. 1: " << (can0Baud & 0xFFFFFFF) <<" 2: " << (can1Baud & 0xFFFFFFF);
buffer[9] = (unsigned char)(can1Baud >> 24); debugOutput("Got signal to update bauds. 1: " + QString::number((can0Baud & 0xFFFFFFF)) + " 2: " + QString::number((can1Baud & 0xFFFFFFF)));
buffer[10] = 0; buffer[0] = (char)0xF1; //start of a command over serial
if (serial == NULL) return; buffer[1] = 5; //setup canbus
if (!serial->isOpen()) return; buffer[2] = (unsigned char)(can0Baud & 0xFF); //four bytes of ID LSB first
serial->write(buffer); 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);
}
} }
@@ -232,6 +278,10 @@ void GVRetSerial::connectDevice()
output.append((char)0xE7); //this puts the device into binary comm mode output.append((char)0xE7); //this puts the device into binary comm mode
output.append((char)0xE7); 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)0xF1); //signal we want to issue a command
output.append((char)0x06); //request canbus stats from the board output.append((char)0x06); //request canbus stats from the board
@@ -249,15 +299,11 @@ void GVRetSerial::connectDevice()
output.append((char)0xFF); //signal we don't want single wire mode 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)0xF1); //and another command
output.append((char)0x01); //Time Sync - Not implemented until 333 but we can try output.append((char)0x01); //Time Sync - Not implemented until 333 but we can try
output.append((char)0xF1); output.append((char)0xF1); //yet another command
output.append((char)0x12); //get number of actually implemented buses. Not implemented except on M2RET output.append((char)0x09); //comm validation command
mNumBuses = 2; //the proper number if 0x12 is not implemented
continuousTimeSync = true; continuousTimeSync = true;
@@ -274,7 +320,10 @@ void GVRetSerial::connectDevice()
} }
else { else {
setStatus(CANCon::CONNECTED); setStatus(CANCon::CONNECTED);
emit status(getStatus()); CANConStatus stats;
stats.conStatus = getStatus();
stats.numHardwareBuses = mNumBuses;
emit status(stats);
} }
/* connect reading event */ /* connect reading event */
@@ -336,6 +385,10 @@ void GVRetSerial::debugInput(QByteArray bytes) {
void GVRetSerial::procRXChar(unsigned char c) void GVRetSerial::procRXChar(unsigned char c)
{ {
CANConStatus stats;
int oldBuses;
QByteArray output;
switch (rx_state) switch (rx_state)
{ {
case IDLE: case IDLE:
@@ -380,6 +433,12 @@ void GVRetSerial::procRXChar(unsigned char c)
break; break;
case 12: case 12:
rx_state = GET_NUM_BUSES; 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; rx_step = 0;
break; break;
} }
@@ -545,6 +604,12 @@ void GVRetSerial::procRXChar(unsigned char c)
rx_state = IDLE; rx_state = IDLE;
qDebug() << "Baud 0 = " << can0Baud; qDebug() << "Baud 0 = " << can0Baud;
qDebug() << "Baud 1 = " << can1Baud; 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; can0Baud |= 0x80000000;
if (can0Enabled) can0Baud |= 0x40000000; if (can0Enabled) can0Baud |= 0x40000000;
@@ -556,7 +621,9 @@ void GVRetSerial::procRXChar(unsigned char c)
if (deviceSingleWireMode > 0) can1Baud |= 0x10000000; if (deviceSingleWireMode > 0) can1Baud |= 0x10000000;
setStatus(CANCon::CONNECTED); setStatus(CANCon::CONNECTED);
emit status(getStatus()); stats.conStatus = getStatus();
stats.numHardwareBuses = mNumBuses;
emit status(stats);
int can0Status = 0x78; //updating everything we can update int can0Status = 0x78; //updating everything we can update
int can1Status = 0x78; int can1Status = 0x78;
@@ -606,8 +673,89 @@ void GVRetSerial::procRXChar(unsigned char c)
rx_state = IDLE; rx_state = IDLE;
break; break;
case GET_NUM_BUSES: case GET_NUM_BUSES:
oldBuses = mNumBuses;
mNumBuses = c; mNumBuses = c;
rx_state = IDLE; 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);
mBusData[2].mBus.setEnabled(swcanEnabled);
setStatus(CANCon::CONNECTED);
stats.conStatus = getStatus();
stats.numHardwareBuses = mNumBuses;
emit status(stats);
break;
}
rx_step++;
break; break;
} }
} }
+6 -6
View File
@@ -16,7 +16,7 @@
namespace SERIALSTATE { namespace SERIALSTATE {
enum STATE //keep this enum synchronized with the Arduino firmware project enum STATE
{ {
IDLE, IDLE,
GET_COMMAND, GET_COMMAND,
@@ -29,12 +29,12 @@ enum STATE //keep this enum synchronized with the Arduino firmware project
GET_CANBUS_PARAMS, GET_CANBUS_PARAMS,
GET_DEVICE_INFO, GET_DEVICE_INFO,
SET_SINGLEWIRE_MODE, SET_SINGLEWIRE_MODE,
GET_NUM_BUSES GET_NUM_BUSES,
GET_EXT_BUSES
}; };
} }
using namespace SERIALSTATE; using namespace SERIALSTATE;
class GVRetSerial : public CANConnection class GVRetSerial : public CANConnection
{ {
@@ -83,9 +83,9 @@ protected:
STATE rx_state; STATE rx_state;
uint32_t rx_step; uint32_t rx_step;
CANFrame buildFrame; CANFrame buildFrame;
int can0Baud, can1Baud; int can0Baud, can1Baud, swcanBaud, lin1Baud, lin2Baud;
bool can0Enabled, can1Enabled; bool can0Enabled, can1Enabled, swcanEnabled, lin1Enabled, lin2Enabled;
bool can0ListenOnly, can1ListenOnly; bool can0ListenOnly, can1ListenOnly, swcanListenOnly;
int deviceBuildNum; int deviceBuildNum;
int deviceSingleWireMode; int deviceSingleWireMode;
uint32_t buildTimeBasis; uint32_t buildTimeBasis;
+13 -3
View File
@@ -31,6 +31,8 @@ void SocketCan::piStarted()
mTimer.setInterval(1000); mTimer.setInterval(1000);
mTimer.setSingleShot(false); //keep ticking mTimer.setSingleShot(false); //keep ticking
mTimer.start(); mTimer.start();
mBusData[0].mBus.setEnabled(true);
mBusData[0].mConfigured = true;
} }
@@ -59,6 +61,7 @@ bool SocketCan::piGetBusSettings(int pBusIdx, CANBus& pBus)
void SocketCan::piSetBusSettings(int pBusIdx, CANBus bus) void SocketCan::piSetBusSettings(int pBusIdx, CANBus bus)
{ {
CANConStatus stats;
/* sanity checks */ /* sanity checks */
if(0 != pBusIdx) if(0 != pBusIdx)
return; return;
@@ -109,7 +112,6 @@ bool SocketCan::piSendFrame(const CANFrame& pFrame)
/* sanity checks */ /* sanity checks */
if(0 != pFrame.bus || pFrame.len>8) if(0 != pFrame.bus || pFrame.len>8)
return false; return false;
if (!mDev_p) return false; if (!mDev_p) return false;
/* fill frame */ /* fill frame */
@@ -211,6 +213,7 @@ void SocketCan::framesReceived()
void SocketCan::testConnection() { void SocketCan::testConnection() {
QCanBusDevice* dev_p = QCanBus::instance()->createDevice("socketcan", getPort()); QCanBusDevice* dev_p = QCanBus::instance()->createDevice("socketcan", getPort());
CANConStatus stats;
switch(getStatus()) switch(getStatus())
{ {
@@ -220,7 +223,9 @@ void SocketCan::testConnection() {
disconnectDevice(); disconnectDevice();
setStatus(CANCon::NOT_CONNECTED); setStatus(CANCon::NOT_CONNECTED);
emit status(getStatus()); stats.conStatus = getStatus();
stats.numHardwareBuses = mNumBuses;
emit status(stats);
} }
break; break;
case CANCon::NOT_CONNECTED: case CANCon::NOT_CONNECTED:
@@ -229,13 +234,18 @@ void SocketCan::testConnection() {
/* try to reconnect */ /* try to reconnect */
CANBus bus; CANBus bus;
if(getBusConfig(0, bus)) if(getBusConfig(0, bus))
{
bus.setEnabled(true);
setBusSettings(0, bus); setBusSettings(0, bus);
}
} }
/* disconnect test instance */ /* disconnect test instance */
dev_p->disconnectDevice(); dev_p->disconnectDevice();
setStatus(CANCon::CONNECTED); setStatus(CANCon::CONNECTED);
emit status(getStatus()); stats.conStatus = getStatus();
stats.numHardwareBuses = mNumBuses;
emit status(stats);
} }
break; break;
default: {} default: {}
+399
View File
@@ -0,0 +1,399 @@
#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();
}
}
}
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();
}
}
}
//only send frame out if its ID is checked in the list. Otherwise discard it.
CANFrame *thisFrame = &currentSeqItem->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 = &currentSeqItem->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;
}
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);
}
+102
View File
@@ -0,0 +1,102 @@
#ifndef FRAMEPLAYBACKOBJECT_H
#define FRAMEPLAYBACKOBJECT_H
#include <QElapsedTimer>
#include <QTimer>
#include <QHash>
#include <QThread>
#include <QDebug>
#include "can_structs.h"
#include "connections/canconmanager.h"
//one entry in the sequence of data to use
struct SequenceItem
{
QString filename;
QVector<CANFrame> data;
QHash<int, bool> 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<CANFrame> 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
+142 -174
View File
@@ -32,47 +32,50 @@ FramePlaybackWindow::FramePlaybackWindow(const QVector<CANFrame> *frames, QWidge
ui->comboCANBus->addItem(tr("From File")); ui->comboCANBus->addItem(tr("From File"));
ui->comboCANBus->setCurrentIndex(0); ui->comboCANBus->setCurrentIndex(0);
playbackObject.initialize();
playbackObject.setNumBuses(numBuses);
readSettings(); readSettings();
modelFrames = frames; 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; currentSeqItem = NULL;
currentSeqNum = -1; currentSeqNum = -1;
currentPosition = 0;
forward = true;
isPlaying = false;
updateFrameLabel(); updateFrameLabel();
connect(ui->btnStepBack, SIGNAL(clicked(bool)), this, SLOT(btnBackOneClick())); connect(ui->btnStepBack, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnBackOneClick);
connect(ui->btnPause, SIGNAL(clicked(bool)), this, SLOT(btnPauseClick())); connect(ui->btnPause, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnPauseClick);
connect(ui->btnPlayReverse, SIGNAL(clicked(bool)), this, SLOT(btnReverseClick())); connect(ui->btnPlayReverse, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnReverseClick);
connect(ui->btnStop, SIGNAL(clicked(bool)), this, SLOT(btnStopClick())); connect(ui->btnStop, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnStopClick);
connect(ui->btnPlay, SIGNAL(clicked(bool)), this, SLOT(btnPlayClick())); connect(ui->btnPlay, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnPlayClick);
connect(ui->btnStepForward, SIGNAL(clicked(bool)), this, SLOT(btnFwdOneClick())); connect(ui->btnStepForward, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnFwdOneClick);
connect(ui->btnSelectAll, SIGNAL(clicked(bool)), this, SLOT(btnSelectAllClick())); connect(ui->btnSelectAll, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnSelectAllClick);
connect(ui->btnSelectNone, SIGNAL(clicked(bool)), this, SLOT(btnSelectNoneClick())); connect(ui->btnSelectNone, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnSelectNoneClick);
connect(ui->btnDelete, SIGNAL(clicked(bool)), this, SLOT(btnDeleteCurrSeq())); connect(ui->btnDelete, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnDeleteCurrSeq);
connect(ui->spinPlaySpeed, SIGNAL(valueChanged(int)), this, SLOT(changePlaybackSpeed(int))); 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->cbLoop, SIGNAL(clicked(bool)), this, SLOT(changeLooping(bool)));
connect(ui->comboCANBus, SIGNAL(currentIndexChanged(int)), this, SLOT(changeSendingBus(int))); connect(ui->comboCANBus, SIGNAL(currentIndexChanged(int)), this, SLOT(changeSendingBus(int)));
connect(ui->listID, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(changeIDFiltering(QListWidgetItem*))); connect(ui->listID, &QListWidget::itemClicked, this, &FramePlaybackWindow::changeIDFiltering);
connect(playbackTimer, SIGNAL(timeout()), this, SLOT(timerTriggered())); connect(ui->btnLoadFile, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnLoadFile);
connect(ui->btnLoadFile, SIGNAL(clicked(bool)), this, SLOT(btnLoadFile())); connect(ui->btnLoadLive, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnLoadLive);
connect(ui->btnLoadLive, SIGNAL(clicked(bool)), this, SLOT(btnLoadLive())); connect(ui->tblSequence, &QTableWidget::cellPressed, this, &FramePlaybackWindow::seqTableCellClicked);
connect(ui->tblSequence, SIGNAL(cellPressed(int,int)), this, SLOT(seqTableCellClicked(int,int))); connect(ui->tblSequence, &QTableWidget::cellChanged, this, &FramePlaybackWindow::seqTableCellChanged);
connect(ui->tblSequence, SIGNAL(cellChanged(int,int)), this, SLOT(seqTableCellChanged(int,int))); connect(ui->btnLoadFilters, &QAbstractButton::clicked, this, &FramePlaybackWindow::loadFilters);
connect(ui->btnLoadFilters, SIGNAL(clicked(bool)), this, SLOT(loadFilters())); connect(ui->btnSaveFilters, &QAbstractButton::clicked, this, &FramePlaybackWindow::saveFilters);
connect(ui->btnSaveFilters, SIGNAL(clicked(bool)), this, SLOT(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); ui->listID->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->listID, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuFilters(QPoint))); 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; QStringList headers;
headers << "Source" << "Loops"; headers << "Source" << "Loops";
@@ -85,9 +88,6 @@ FramePlaybackWindow::FramePlaybackWindow(const QVector<CANFrame> *frames, QWidge
FramePlaybackWindow::~FramePlaybackWindow() FramePlaybackWindow::~FramePlaybackWindow()
{ {
delete ui; delete ui;
playbackTimer->stop();
delete playbackTimer;
} }
void FramePlaybackWindow::showEvent(QShowEvent *) void FramePlaybackWindow::showEvent(QShowEvent *)
@@ -115,7 +115,8 @@ void FramePlaybackWindow::readSettings()
} }
ui->spinPlaySpeed->setValue(settings.value("Playback/DefSpeed", 5).toInt()); ui->spinPlaySpeed->setValue(settings.value("Playback/DefSpeed", 5).toInt());
ui->comboCANBus->setCurrentIndex(settings.value("Playback/SendingBus", 0).toInt()); ui->comboCANBus->setCurrentIndex(settings.value("Playback/SendingBus", 0).toInt());
whichBusSend = ui->comboCANBus->currentIndex();
calculateWhichBus();
} }
void FramePlaybackWindow::writeSettings() void FramePlaybackWindow::writeSettings()
@@ -256,6 +257,73 @@ void FramePlaybackWindow::refreshIDList()
ui->listID->sortItems(); 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)
{
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);
}
}
void FramePlaybackWindow::getStatusUpdate(int frameNum)
{
currentPosition = frameNum;
updateFrameLabel();
}
void FramePlaybackWindow::updateFrameLabel() void FramePlaybackWindow::updateFrameLabel()
{ {
int row = currentSeqNum; int row = currentSeqNum;
@@ -313,15 +381,27 @@ void FramePlaybackWindow::fillIDHash(SequenceItem &item)
} }
} }
void FramePlaybackWindow::useOrigTimingClicked()
{
if (ui->cbOriginalTiming->isChecked())
{
ui->spinBurstSpeed->setEnabled(false);
ui->spinPlaySpeed->setEnabled(false);
playbackObject.setUseOriginalTiming(true);
}
else
{
ui->spinBurstSpeed->setEnabled(true);
ui->spinPlaySpeed->setEnabled(true);
playbackObject.setUseOriginalTiming(false);
}
}
void FramePlaybackWindow::btnDeleteCurrSeq() void FramePlaybackWindow::btnDeleteCurrSeq()
{ {
if (currentSeqNum == -1) return; if (currentSeqNum == -1) return;
if (playbackActive) playbackObject.stopPlayback();
{
playbackActive = false;
playbackTimer->stop();
}
seqItems.removeAt(currentSeqNum); seqItems.removeAt(currentSeqNum);
ui->tblSequence->removeRow(currentSeqNum); ui->tblSequence->removeRow(currentSeqNum);
@@ -345,6 +425,7 @@ void FramePlaybackWindow::btnLoadFile()
if (FrameFileIO::loadFrameFile(filename, &item.data)) if (FrameFileIO::loadFrameFile(filename, &item.data))
{ {
qSort(item.data); //sort by timestamp to be sure it's in order
QStringList fileList = filename.split('/'); QStringList fileList = filename.split('/');
item.filename = fileList[fileList.length() - 1]; item.filename = fileList[fileList.length() - 1];
item.currentLoopCount = 0; item.currentLoopCount = 0;
@@ -364,6 +445,7 @@ void FramePlaybackWindow::btnLoadFile()
{ {
currentSeqNum = 0; currentSeqNum = 0;
currentSeqItem = &seqItems[0]; currentSeqItem = &seqItems[0];
playbackObject.setSequenceObject(currentSeqItem);
} }
refreshIDList(); refreshIDList();
updateFrameLabel(); updateFrameLabel();
@@ -377,6 +459,7 @@ void FramePlaybackWindow::btnLoadLive()
item.currentLoopCount = 0; item.currentLoopCount = 0;
item.maxLoops = 1; item.maxLoops = 1;
item.data = QVector<CANFrame>(*modelFrames); //create a copy of the current frames from the main view item.data = QVector<CANFrame>(*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); fillIDHash(item);
if (ui->tblSequence->currentRow() == -1) if (ui->tblSequence->currentRow() == -1)
{ {
@@ -391,6 +474,7 @@ void FramePlaybackWindow::btnLoadLive()
{ {
currentSeqNum = 0; currentSeqNum = 0;
currentSeqItem = &seqItems[0]; currentSeqItem = &seqItems[0];
playbackObject.setSequenceObject(currentSeqItem);
} }
refreshIDList(); refreshIDList();
updateFrameLabel(); updateFrameLabel();
@@ -399,32 +483,28 @@ void FramePlaybackWindow::btnLoadLive()
void FramePlaybackWindow::btnBackOneClick() void FramePlaybackWindow::btnBackOneClick()
{ {
sendingBuffer.clear(); forward = false;
playbackTimer->stop(); //pushing this button halts automatic playback isPlaying = false;
playbackActive = false; playbackObject.stepPlaybackBackward();
updatePosition(false);
CANConManager::getInstance()->sendFrames(sendingBuffer);
} }
void FramePlaybackWindow::btnPauseClick() void FramePlaybackWindow::btnPauseClick()
{ {
playbackActive = false; isPlaying = false;
playbackTimer->stop(); playbackObject.pausePlayback();
} }
void FramePlaybackWindow::btnReverseClick() void FramePlaybackWindow::btnReverseClick()
{ {
playbackActive = true; forward = false;
playbackForward = false; isPlaying = true;
playbackTimer->start(); playbackObject.startPlaybackBackward();
} }
void FramePlaybackWindow::btnStopClick() void FramePlaybackWindow::btnStopClick()
{ {
playbackTimer->stop(); //pushing this button halts automatic playback isPlaying = false;
playbackActive = false; playbackObject.stopPlayback();
currentPosition = 0;
if (seqItems.count() > 0) if (seqItems.count() > 0)
{ {
currentSeqNum = 0; currentSeqNum = 0;
@@ -438,29 +518,32 @@ void FramePlaybackWindow::btnStopClick()
{ {
ui->tblSequence->setCurrentCell(0, 0); ui->tblSequence->setCurrentCell(0, 0);
refreshIDList(); refreshIDList();
} }
updateFrameLabel(); updateFrameLabel();
} }
void FramePlaybackWindow::btnPlayClick() void FramePlaybackWindow::btnPlayClick()
{ {
playbackActive = true; forward = true;
playbackForward = true; isPlaying = true;
playbackTimer->start(); playbackObject.startPlaybackForward();
} }
void FramePlaybackWindow::btnFwdOneClick() void FramePlaybackWindow::btnFwdOneClick()
{ {
sendingBuffer.clear(); forward = true;
playbackTimer->stop(); isPlaying = false;
playbackActive = false; playbackObject.stepPlaybackForward();
updatePosition(true);
CANConManager::getInstance()->sendFrames(sendingBuffer);
} }
void FramePlaybackWindow::changePlaybackSpeed(int newSpeed) void FramePlaybackWindow::changePlaybackSpeed(int newSpeed)
{ {
playbackTimer->setInterval(newSpeed); playbackObject.setPlaybackInterval(newSpeed);
}
void FramePlaybackWindow::changeBurstRate(int burst)
{
playbackObject.setPlaybackBurst(burst);
} }
void FramePlaybackWindow::changeLooping(bool check) void FramePlaybackWindow::changeLooping(bool check)
@@ -470,7 +553,7 @@ void FramePlaybackWindow::changeLooping(bool check)
void FramePlaybackWindow::changeSendingBus(int newIdx) void FramePlaybackWindow::changeSendingBus(int newIdx)
{ {
whichBusSend = newIdx; calculateWhichBus();
} }
void FramePlaybackWindow::changeIDFiltering(QListWidgetItem *item) void FramePlaybackWindow::changeIDFiltering(QListWidgetItem *item)
@@ -499,118 +582,3 @@ void FramePlaybackWindow::btnSelectNoneClick()
currentSeqItem->idFilters[Utility::ParseStringToNum(item->text())] = false; currentSeqItem->idFilters[Utility::ParseStringToNum(item->text())] = false;
} }
} }
void FramePlaybackWindow::timerTriggered()
{
sendingBuffer.clear();
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)
{
//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 = &currentSeqItem->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;
}
}
+11 -20
View File
@@ -3,24 +3,14 @@
#include <QDialog> #include <QDialog>
#include <QListWidget> #include <QListWidget>
#include <QTimer>
#include "can_structs.h" #include "can_structs.h"
#include "framefileio.h" #include "framefileio.h"
#include "frameplaybackobject.h"
namespace Ui { namespace Ui {
class FramePlaybackWindow; class FramePlaybackWindow;
} }
//one entry in the sequence of data to use
struct SequenceItem
{
QString filename;
QVector<CANFrame> data;
QHash<int, bool> idFilters;
int maxLoops;
int currentLoopCount;
};
class FramePlaybackWindow : public QDialog class FramePlaybackWindow : public QDialog
{ {
Q_OBJECT Q_OBJECT
@@ -38,12 +28,12 @@ private slots:
void btnFwdOneClick(); void btnFwdOneClick();
void btnDeleteCurrSeq(); void btnDeleteCurrSeq();
void changePlaybackSpeed(int newSpeed); void changePlaybackSpeed(int newSpeed);
void changeBurstRate(int burst);
void changeLooping(bool check); void changeLooping(bool check);
void changeSendingBus(int newIdx); void changeSendingBus(int newIdx);
void changeIDFiltering(QListWidgetItem *item); void changeIDFiltering(QListWidgetItem *item);
void btnSelectAllClick(); void btnSelectAllClick();
void btnSelectNoneClick(); void btnSelectNoneClick();
void timerTriggered();
void btnLoadFile(); void btnLoadFile();
void btnLoadLive(); void btnLoadLive();
void seqTableCellClicked(int row, int col); void seqTableCellClicked(int row, int col);
@@ -51,30 +41,31 @@ private slots:
void contextMenuFilters(QPoint); void contextMenuFilters(QPoint);
void saveFilters(); void saveFilters();
void loadFilters(); void loadFilters();
void useOrigTimingClicked();
void getStatusUpdate(int frameNum);
void EndOfFrameCache();
private: private:
Ui::FramePlaybackWindow *ui; Ui::FramePlaybackWindow *ui;
QList<int> foundID; QList<int> foundID;
QList<CANFrame> frameCache; QList<CANFrame> frameCache;
QList<CANFrame> sendingBuffer;
const QVector<CANFrame> *modelFrames; const QVector<CANFrame> *modelFrames;
int currentPosition;
QTimer *playbackTimer;
bool playbackActive;
bool playbackForward;
int whichBusSend;
QList<SequenceItem> seqItems; QList<SequenceItem> seqItems;
SequenceItem *currentSeqItem; SequenceItem *currentSeqItem;
int currentSeqNum; int currentSeqNum;
FramePlaybackObject playbackObject;
bool forward;
bool isPlaying;
int currentPosition;
void refreshIDList(); void refreshIDList();
void updateFrameLabel(); void updateFrameLabel();
void updatePosition(bool forward); void fillIDHash(SequenceItem &item);
void fillIDHash(SequenceItem &item);
void showEvent(QShowEvent *); void showEvent(QShowEvent *);
void closeEvent(QCloseEvent *event); void closeEvent(QCloseEvent *event);
void readSettings(); void readSettings();
void writeSettings(); void writeSettings();
void calculateWhichBus();
}; };
#endif // FRAMEPLAYBACKWINDOW_H #endif // FRAMEPLAYBACKWINDOW_H
+16 -70
View File
@@ -25,6 +25,9 @@
</item> </item>
<item> <item>
<widget class="QTableView" name="tableConnections"> <widget class="QTableView" name="tableConnections">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode"> <property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum> <enum>QAbstractItemView::SingleSelection</enum>
</property> </property>
@@ -35,13 +38,6 @@
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_5"> <layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QPushButton" name="btnNewConn">
<property name="text">
<string>New Connection</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QPushButton" name="btnRemoveBus"> <widget class="QPushButton" name="btnRemoveBus">
<property name="text"> <property name="text">
@@ -49,10 +45,6 @@
</property> </property>
</widget> </widget>
</item> </item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item> <item>
<widget class="QPushButton" name="btnActivateAll"> <widget class="QPushButton" name="btnActivateAll">
<property name="text"> <property name="text">
@@ -193,45 +185,6 @@
</widget> </widget>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="ckSingleWire">
<property name="text">
<string>Single Wire Mode</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ckListenOnly">
<property name="text">
<string>Listen Only Mode</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ckEnabled">
<property name="text">
<string>Enabled</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3" stretch="1,2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>CAN Speed</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbSpeed">
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_4"> <layout class="QHBoxLayout" name="horizontalLayout_4">
<item> <item>
@@ -241,15 +194,21 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QPushButton" name="btnRevert">
<property name="text">
<string>Revert</string>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item alignment="Qt::AlignHCenter"> <item alignment="Qt::AlignHCenter">
<widget class="QCheckBox" name="ckEnableConsole"> <widget class="QCheckBox" name="ckEnableConsole">
<property name="text"> <property name="text">
@@ -319,19 +278,6 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout> </layout>
</item> </item>
</layout> </layout>
+7
View File
@@ -100,6 +100,13 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item>
<widget class="QCheckBox" name="cbOriginalTiming">
<property name="text">
<string>Use original frame timing from captured frames</string>
</property>
</widget>
</item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_4"> <layout class="QHBoxLayout" name="horizontalLayout_4">
<item> <item>