Merge pull request #105 from collin80/WIP
Merge Wip Changes into Master
This commit is contained in:
+4
-2
@@ -64,7 +64,8 @@ SOURCES += main.cpp\
|
||||
bus_protocols/isotp_handler.cpp \
|
||||
bus_protocols/j1939_handler.cpp \
|
||||
bus_protocols/uds_handler.cpp \
|
||||
jsedit.cpp
|
||||
jsedit.cpp \
|
||||
frameplaybackobject.cpp
|
||||
|
||||
HEADERS += mainwindow.h \
|
||||
can_structs.h \
|
||||
@@ -117,7 +118,8 @@ HEADERS += mainwindow.h \
|
||||
bus_protocols/j1939_handler.h \
|
||||
bus_protocols/uds_handler.h \
|
||||
bus_protocols/isotp_message.h \
|
||||
jsedit.h
|
||||
jsedit.h \
|
||||
frameplaybackobject.h
|
||||
|
||||
FORMS += ui/candatagrid.ui \
|
||||
ui/connectionwindow.ui \
|
||||
|
||||
@@ -23,6 +23,8 @@ QVector<CODE_STRUCT> UDS_COMM_CTRL_SUB = {
|
||||
{0,"COMM_NORMAL", "Enable both Rx and Tx of normal messages"},
|
||||
{1,"COMM_DIS_TX", "Enable reception of normal messages but don't Tx them"},
|
||||
{3,"COMM_DIS_ALL", "Disable both Rx and Tx of non-diagnostics messages"},
|
||||
{4,"COMM_DIS_TX_ENH", "Addressed bus master should turn off TX on related sub-bus"},
|
||||
{5,"COMM_ENHANC", "Addressed bus master should set related sub-bus to app scheduling mode"},
|
||||
};
|
||||
|
||||
QVector<CODE_STRUCT> UDS_ROUTINE_SUB = {
|
||||
@@ -319,6 +321,8 @@ QString UDS_HANDLER::getDetailedMessageAnalysis(const UDS_MESSAGE &msg)
|
||||
{
|
||||
QString buildString;
|
||||
bool isResponse = true;
|
||||
int dataSize;
|
||||
int addrSize;
|
||||
|
||||
if (msg.isErrorReply)
|
||||
{
|
||||
@@ -361,9 +365,9 @@ QString UDS_HANDLER::getDetailedMessageAnalysis(const UDS_MESSAGE &msg)
|
||||
else
|
||||
{
|
||||
int p2 = msg.data[1] * 256 + msg.data[2];
|
||||
buildString.append("\nP2MAX: " + QString::number(p2) + "ms");
|
||||
buildString.append("\nP2MAX (Max Wait / Resp Time): " + QString::number(p2) + "ms");
|
||||
p2 = (msg.data[3] * 256 + msg.data[4]) * 10;
|
||||
buildString.append("\nP2*MAX: " + QString::number(p2) + "ms");
|
||||
buildString.append("\nP2 Ext MAX: " + QString::number(p2) + "ms");
|
||||
}
|
||||
break;
|
||||
case UDS_SERVICES::ECU_RESET:
|
||||
@@ -384,8 +388,15 @@ QString UDS_HANDLER::getDetailedMessageAnalysis(const UDS_MESSAGE &msg)
|
||||
else buildString.append("\nNo powerdown time returned");
|
||||
break;
|
||||
case UDS_SERVICES::COMM_CTRL:
|
||||
//Comm control has two parameters, sub funct and the next byte should be 1. But it's always one so ignore for now
|
||||
buildString.append("Comm type: " + getLongDesc(UDS_COMM_CTRL_SUB, msg.subFunc));
|
||||
//Comm control has potentially a lot of parameters. control type, comm type, nodeID
|
||||
buildString.append("Control type: " + getLongDesc(UDS_COMM_CTRL_SUB, msg.subFunc));
|
||||
if (msg.data.length() > 1)
|
||||
buildString.append("\nComm Type: " + QString::number(msg.data[1])); //TODO: no attempt to interpret yet
|
||||
if (msg.data.length() > 3)
|
||||
{
|
||||
int nodeID = (msg.data[2] * 256 + msg.data[3]);
|
||||
buildString.append("\nNode ID: " + Utility::formatHexNum(nodeID));
|
||||
}
|
||||
break;
|
||||
case UDS_SERVICES::SECURITY_ACCESS:
|
||||
if ((msg.subFunc % 2) == 1)
|
||||
@@ -423,6 +434,96 @@ QString UDS_HANDLER::getDetailedMessageAnalysis(const UDS_MESSAGE &msg)
|
||||
buildString.append("\nECU is now unlocked");
|
||||
}
|
||||
break;
|
||||
case UDS_SERVICES::READ_BY_ID:
|
||||
//parameter is groups of two bytes, each of which specify an ID to read
|
||||
if (msg.data.length() > 2)
|
||||
{
|
||||
uint32_t id;
|
||||
for (int i = 1; i < msg.data.length(); i = i + 2)
|
||||
{
|
||||
id = (msg.data[i] * 256) + msg.data[i+1];
|
||||
buildString.append("\nID to read: " + Utility::formatHexNum(id));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case UDS_SERVICES::READ_BY_ID + 0x40: //reply
|
||||
buildString.append("Reply is non-standard and so no decoding is done. The format is (ID) followed by how ever much data that ID returns, followed by more ID/data pairs if applicable.\nPayload: ");
|
||||
for (int i = 1; i < msg.data.length(); i++)
|
||||
{
|
||||
buildString.append(Utility::formatHexNum(msg.data[i]) + " ");
|
||||
}
|
||||
break;
|
||||
case UDS_SERVICES::READ_BY_ADDR:
|
||||
//subfunc byte specifies address and length format, then address, then size
|
||||
dataSize = msg.subFunc >> 4;
|
||||
addrSize = msg.subFunc & 0xF;
|
||||
if (msg.data.length() > (dataSize + addrSize))
|
||||
{
|
||||
buildString.append("Address: 0x");
|
||||
for (int i = 0; i < addrSize; i++) buildString.append(QString::number(msg.data[1+i], 16).toUpper().rightJustified(2,'0'));
|
||||
buildString.append("\nSize: 0x");
|
||||
for (int i = 0; i < dataSize; i++) buildString.append(QString::number(msg.data[1+i+addrSize], 16).toUpper().rightJustified(2,'0'));
|
||||
}
|
||||
else
|
||||
{
|
||||
buildString.append("Message has insufficient bytes to properly decode address and size!");
|
||||
}
|
||||
break;
|
||||
case UDS_SERVICES::READ_BY_ADDR + 0x40:
|
||||
buildString.append("Reply is a raw packet of data of the size requested.\nPayload: ");
|
||||
for (int i = 1; i < msg.data.length(); i++)
|
||||
{
|
||||
buildString.append(Utility::formatHexNum(msg.data[i]) + " ");
|
||||
}
|
||||
break;
|
||||
case UDS_SERVICES::WRITE_BY_ID:
|
||||
break;
|
||||
case UDS_SERVICES::ROUTINE_CTRL:
|
||||
buildString.append("Routine Control: " + getLongDesc(UDS_ROUTINE_SUB, msg.subFunc));
|
||||
if (msg.data.length() > 2)
|
||||
{
|
||||
int routineID;
|
||||
routineID = (msg.data[1] * 256 + msg.data[2]);
|
||||
buildString.append("\nRoutine ID: " + Utility::formatHexNum(routineID));
|
||||
}
|
||||
if (msg.data.length() > 3)
|
||||
{
|
||||
buildString.append("\nParameter bytes to routine: ");
|
||||
for (int i = 4; i < msg.data.length(); i++)
|
||||
{
|
||||
buildString.append(Utility::formatHexNum(msg.data[i]) + " ");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case UDS_SERVICES::ROUTINE_CTRL + 0x40:
|
||||
buildString.append("Routine Control: " + getLongDesc(UDS_ROUTINE_SUB, msg.subFunc));
|
||||
if (msg.data.length() > 2)
|
||||
{
|
||||
int routineID;
|
||||
routineID = (msg.data[1] * 256 + msg.data[2]);
|
||||
buildString.append("\nRoutine ID: " + Utility::formatHexNum(routineID));
|
||||
}
|
||||
if (msg.data.length() > 3)
|
||||
{
|
||||
buildString.append("\nBytes returned by routine: ");
|
||||
for (int i = 4; i < msg.data.length(); i++)
|
||||
{
|
||||
buildString.append(Utility::formatHexNum(msg.data[i]) + " ");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case UDS_SERVICES::REQUEST_DOWNLOAD:
|
||||
break;
|
||||
case UDS_SERVICES::REQUEST_UPLOAD:
|
||||
break;
|
||||
case UDS_SERVICES::TRANSFER_DATA:
|
||||
break;
|
||||
case UDS_SERVICES::REQ_TRANS_EXIT:
|
||||
break;
|
||||
case UDS_SERVICES::REQ_FILE_TRANS:
|
||||
break;
|
||||
case UDS_SERVICES::WRITE_BY_ADDR:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,11 @@ public:
|
||||
uint32_t len;
|
||||
unsigned char data[8];
|
||||
uint64_t timestamp;
|
||||
|
||||
friend bool operator<(const CANFrame& l, const CANFrame& r)
|
||||
{
|
||||
return l.timestamp < r.timestamp;
|
||||
}
|
||||
};
|
||||
|
||||
class CANFltObserver
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef CONFIG
|
||||
#define CONFIG
|
||||
|
||||
#define VERSION 178
|
||||
#define VERSION 179
|
||||
|
||||
//try to keep this in sync.
|
||||
//SavvyCAN will complain if you connect a GVRET board with a revision
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <QObject>
|
||||
#include <QDebug>
|
||||
#include "canbus.h"
|
||||
|
||||
CANBus::CANBus()
|
||||
@@ -25,18 +26,22 @@ bool CANBus::operator==(const CANBus& bus) const{
|
||||
}
|
||||
|
||||
void CANBus::setSpeed(int newSpeed){
|
||||
//qDebug() << "CANBUS SetSpeed = " << newSpeed;
|
||||
speed = newSpeed;
|
||||
}
|
||||
|
||||
void CANBus::setListenOnly(bool mode){
|
||||
//qDebug() << "CANBUS SetListenOnly = " << mode;
|
||||
listenOnly = mode;
|
||||
}
|
||||
|
||||
void CANBus::setSingleWire(bool mode){
|
||||
//qDebug() << "CANBUS SetSingleWire = " << mode;
|
||||
singleWire = mode;
|
||||
}
|
||||
|
||||
void CANBus::setEnabled(bool mode){
|
||||
//qDebug() << "CANBUS SetEnabled = " << mode;
|
||||
active = mode;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef CANBus_H
|
||||
#define CANBus_H
|
||||
#include <QDataStream>
|
||||
#include "can_structs.h"
|
||||
|
||||
class CANBus
|
||||
{
|
||||
@@ -31,4 +32,10 @@ QDataStream & operator>>(QDataStream & pStream, CANBus& pCanBus);
|
||||
|
||||
Q_DECLARE_METATYPE(CANBus);
|
||||
|
||||
struct BusData {
|
||||
CANBus mBus;
|
||||
bool mConfigured;
|
||||
QVector<CANFltObserver> mTargettedFrames;
|
||||
};
|
||||
|
||||
#endif // CANBus_H
|
||||
|
||||
@@ -21,4 +21,11 @@ namespace CANCon {
|
||||
};
|
||||
}
|
||||
|
||||
class CANConStatus
|
||||
{
|
||||
public:
|
||||
CANCon::status conStatus;
|
||||
int numHardwareBuses;
|
||||
};
|
||||
|
||||
#endif // CANCONCONST_H
|
||||
|
||||
@@ -36,6 +36,7 @@ CANConManager::CANConManager(QObject *parent): QObject(parent)
|
||||
void CANConManager::resetTimeBasis()
|
||||
{
|
||||
mTimestampBasis = QDateTime::currentMSecsSinceEpoch() * 1000;
|
||||
mElapsedTimer.restart();
|
||||
}
|
||||
|
||||
CANConManager::~CANConManager()
|
||||
@@ -182,8 +183,15 @@ bool CANConManager::sendFrame(const CANFrame& pFrame)
|
||||
{
|
||||
workingFrame.bus -= busBase;
|
||||
workingFrame.isReceived = false;
|
||||
workingFrame.timestamp = (QDateTime::currentMSecsSinceEpoch() * 1000);
|
||||
if (!useSystemTime) workingFrame.timestamp -= mTimestampBasis;
|
||||
if (useSystemTime)
|
||||
{
|
||||
workingFrame.timestamp = (QDateTime::currentMSecsSinceEpoch() * 1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
workingFrame.timestamp = mElapsedTimer.nsecsElapsed() / 1000;
|
||||
//workingFrame.timestamp -= mTimestampBasis;
|
||||
}
|
||||
txFrame = conn->getQueue().get();
|
||||
*txFrame = workingFrame;
|
||||
conn->getQueue().queue();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
#include "canconnection.h"
|
||||
|
||||
@@ -73,6 +74,7 @@ private:
|
||||
static CANConManager* mInstance;
|
||||
QList<CANConnection*> mConns;
|
||||
QTimer mTimer;
|
||||
QElapsedTimer mElapsedTimer;
|
||||
uint64_t mTimestampBasis;
|
||||
uint32_t mNumActiveBuses;
|
||||
bool useSystemTime;
|
||||
|
||||
@@ -2,14 +2,6 @@
|
||||
#include <QThread>
|
||||
#include "canconnection.h"
|
||||
|
||||
|
||||
struct BusData {
|
||||
CANBus mBus;
|
||||
bool mConfigured;
|
||||
QVector<CANFltObserver> mTargettedFrames;
|
||||
};
|
||||
|
||||
|
||||
CANConnection::CANConnection(QString pPort,
|
||||
CANCon::type pType,
|
||||
int pNumBuses,
|
||||
@@ -27,7 +19,7 @@ CANConnection::CANConnection(QString pPort,
|
||||
/* register types */
|
||||
qRegisterMetaType<CANBus>("CANBus");
|
||||
qRegisterMetaType<CANFrame>("CANFrame");
|
||||
qRegisterMetaType<CANCon::status>("CANCon::status");
|
||||
qRegisterMetaType<CANConStatus>("CANConStatus");
|
||||
qRegisterMetaType<CANFltObserver>("CANFlt");
|
||||
|
||||
/* set queue size */
|
||||
@@ -35,9 +27,9 @@ CANConnection::CANConnection(QString pPort,
|
||||
|
||||
/* allocate buses */
|
||||
/* TODO: change those tables for a vector */
|
||||
mBusData_p = new BusData[mNumBuses];
|
||||
mBusData.resize(mNumBuses);
|
||||
for(int i=0 ; i<mNumBuses ; i++) {
|
||||
mBusData_p[i].mConfigured = false;
|
||||
mBusData[i].mConfigured = false;
|
||||
}
|
||||
|
||||
/* if needed, create a thread and move ourself into it */
|
||||
@@ -57,10 +49,7 @@ CANConnection::~CANConnection()
|
||||
mThread_p = NULL;
|
||||
}
|
||||
|
||||
if(mBusData_p) {
|
||||
delete[] mBusData_p;
|
||||
mBusData_p = NULL;
|
||||
}
|
||||
mBusData.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -206,13 +195,13 @@ int CANConnection::getNumBuses() const{
|
||||
bool CANConnection::isConfigured(int pBusId) {
|
||||
if( pBusId < 0 || pBusId >= getNumBuses())
|
||||
return false;
|
||||
return mBusData_p[pBusId].mConfigured;
|
||||
return mBusData[pBusId].mConfigured;
|
||||
}
|
||||
|
||||
void CANConnection::setConfigured(int pBusId, bool pConfigured) {
|
||||
if( pBusId < 0 || pBusId >= getNumBuses())
|
||||
return;
|
||||
mBusData_p[pBusId].mConfigured = pConfigured;
|
||||
mBusData[pBusId].mConfigured = pConfigured;
|
||||
}
|
||||
|
||||
|
||||
@@ -220,7 +209,7 @@ bool CANConnection::getBusConfig(int pBusId, CANBus& pBus) {
|
||||
if( pBusId < 0 || pBusId >= getNumBuses() || !isConfigured(pBusId))
|
||||
return false;
|
||||
|
||||
pBus = mBusData_p[pBusId].mBus;
|
||||
pBus = mBusData[pBusId].mBus;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -229,8 +218,8 @@ void CANConnection::setBusConfig(int pBusId, CANBus& pBus) {
|
||||
if( pBusId < 0 || pBusId >= getNumBuses())
|
||||
return;
|
||||
|
||||
mBusData_p[pBusId].mConfigured = true;
|
||||
mBusData_p[pBusId].mBus = pBus;
|
||||
mBusData[pBusId].mConfigured = true;
|
||||
mBusData[pBusId].mBus = pBus;
|
||||
}
|
||||
|
||||
|
||||
@@ -293,7 +282,7 @@ bool CANConnection::addTargettedFrame(int pBusId, uint32_t ID, uint32_t mask, QO
|
||||
target.id = ID;
|
||||
target.mask = mask;
|
||||
target.observer = receiver;
|
||||
mBusData_p[pBusId].mTargettedFrames.append(target);
|
||||
mBusData[pBusId].mTargettedFrames.append(target);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -321,7 +310,7 @@ bool CANConnection::removeTargettedFrame(int pBusId, uint32_t ID, uint32_t mask,
|
||||
target.id = ID;
|
||||
target.mask = mask;
|
||||
target.observer = receiver;
|
||||
mBusData_p[pBusId].mTargettedFrames.removeAll(target);
|
||||
mBusData[pBusId].mTargettedFrames.removeAll(target);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -329,9 +318,9 @@ bool CANConnection::removeTargettedFrame(int pBusId, uint32_t ID, uint32_t mask,
|
||||
bool CANConnection::removeAllTargettedFrames(QObject *receiver)
|
||||
{
|
||||
for (int i = 0; i < getNumBuses(); i++) {
|
||||
foreach (const CANFltObserver filt, mBusData_p[i].mTargettedFrames)
|
||||
foreach (const CANFltObserver filt, mBusData[i].mTargettedFrames)
|
||||
{
|
||||
if (filt.observer == receiver) mBusData_p[i].mTargettedFrames.removeOne(filt);
|
||||
if (filt.observer == receiver) mBusData[i].mTargettedFrames.removeOne(filt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,10 +331,10 @@ void CANConnection::checkTargettedFrame(CANFrame &frame)
|
||||
{
|
||||
unsigned int maskedID;
|
||||
//qDebug() << "Got frame with ID " << frame.ID << " on bus " << frame.bus;
|
||||
if (mBusData_p == 0) return;
|
||||
if (mBusData.count() == 0) return;
|
||||
|
||||
if (mBusData_p[frame.bus].mTargettedFrames.length() == 0) return;
|
||||
foreach (const CANFltObserver filt, mBusData_p[frame.bus].mTargettedFrames)
|
||||
if (mBusData[frame.bus].mTargettedFrames.length() == 0) return;
|
||||
foreach (const CANFltObserver filt, mBusData[frame.bus].mTargettedFrames)
|
||||
{
|
||||
//qDebug() << "Checking filter with id " << filt.id << " mask " << filt.mask;
|
||||
maskedID = frame.ID & filt.mask;
|
||||
|
||||
@@ -89,7 +89,7 @@ signals:
|
||||
* @brief event emitted when the CANCon::status of the connection changes (connected->not_connected or the other way round)
|
||||
* @param pStatus: the new status of the device
|
||||
*/
|
||||
void status(CANCon::status pStatus);
|
||||
void status(CANConStatus pStatus);
|
||||
|
||||
/**
|
||||
* @brief Event sent when device has done something worthy of debugging output.
|
||||
@@ -183,7 +183,8 @@ public slots:
|
||||
void debugInput(QByteArray bytes);
|
||||
|
||||
protected:
|
||||
int mNumBuses; //protected to allow connected device to figure out how many buses are available
|
||||
int mNumBuses; //protected to allow connected device to figure out how many buses are available
|
||||
QVector<BusData> mBusData;
|
||||
|
||||
//determine if the passed frame is part of a filter or not.
|
||||
void checkTargettedFrame(CANFrame &frame);
|
||||
@@ -297,7 +298,6 @@ private:
|
||||
bool mIsCapSuspended;
|
||||
QAtomicInt mStatus;
|
||||
bool mStarted;
|
||||
BusData* mBusData_p;
|
||||
QThread* mThread_p;
|
||||
};
|
||||
|
||||
|
||||
@@ -40,10 +40,10 @@ QVariant CANConnectionModel::headerData(int section, Qt::Orientation orientation
|
||||
return QString(tr("Single Wire"));
|
||||
break;
|
||||
case 6:
|
||||
return QString(tr("Status"));
|
||||
return QString(tr("Active"));
|
||||
break;
|
||||
case 7:
|
||||
return QString(tr("Active"));
|
||||
return QString(tr("Status"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -54,11 +54,10 @@ QVariant CANConnectionModel::headerData(int section, Qt::Orientation orientation
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
|
||||
int CANConnectionModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
return 7;
|
||||
return 8;
|
||||
}
|
||||
|
||||
|
||||
@@ -66,32 +65,99 @@ int CANConnectionModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
|
||||
int rows=0;
|
||||
int rows = 0;
|
||||
QList<CANConnection*>& conns = CANConManager::getInstance()->getConnections();
|
||||
|
||||
foreach(const CANConnection* conn_p, conns)
|
||||
rows+=conn_p->getNumBuses();
|
||||
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;
|
||||
|
||||
//you can't set speed, single wire, or listen only on socketcan devices so
|
||||
//detect if we're using GVRET where you can and turn that functionality on
|
||||
bool editParams = false;
|
||||
if (conn_p->getType() == CANCon::GVRET_SERIAL) editParams = true;
|
||||
|
||||
switch (index.column())
|
||||
{
|
||||
case 3: //speed
|
||||
if (editParams) return Qt::ItemFlag::ItemIsEditable | Qt::ItemFlag::ItemIsEnabled;
|
||||
else return Qt::ItemFlag::NoItemFlags;
|
||||
break;
|
||||
case 4: //listen only
|
||||
case 5: //single wire
|
||||
if (editParams) return Qt::ItemFlag::ItemIsEditable | Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsUserCheckable;
|
||||
else return Qt::ItemFlag::NoItemFlags;
|
||||
break;
|
||||
case 6: //enabled
|
||||
return Qt::ItemFlag::ItemIsEditable | Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsUserCheckable;
|
||||
break;
|
||||
default:
|
||||
return Qt::ItemFlag::ItemIsEnabled;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool CANConnectionModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
qDebug() << "setData: " << index.row() << ":" << index.column() << " role: " << role << " Val: " << value;
|
||||
|
||||
int busId;
|
||||
CANConnection *conn_p = getAtIdx(index.row(), busId);
|
||||
if (!conn_p) return false;
|
||||
CANBus bus;
|
||||
bool ret;
|
||||
ret = conn_p->getBusSettings(busId, bus);
|
||||
if (!ret) return false;
|
||||
|
||||
switch (index.column())
|
||||
{
|
||||
case 3: //speed
|
||||
bus.speed = value.toInt();
|
||||
break;
|
||||
case 4: //listen only
|
||||
bus.listenOnly = value.toBool();
|
||||
break;
|
||||
case 5: //single wire
|
||||
bus.singleWire = value.toBool();
|
||||
break;
|
||||
case 6: //active
|
||||
bus.active = value.toBool();
|
||||
break;
|
||||
}
|
||||
conn_p->setBusSettings(busId, bus);
|
||||
return true;
|
||||
}
|
||||
|
||||
QVariant CANConnectionModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
//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;
|
||||
|
||||
//qDebug() << "ConnP: " << conn_p << " ret " << ret;
|
||||
|
||||
if (role == Qt::DisplayRole) {
|
||||
int busId;
|
||||
CANConnection *conn_p = getAtIdx(index.row(), busId);
|
||||
if(!conn_p)
|
||||
return QVariant();
|
||||
|
||||
CANBus bus;
|
||||
bool ret;
|
||||
ret = conn_p->getBusSettings(busId, bus);
|
||||
if(!ret) return QVariant();
|
||||
|
||||
switch (index.column())
|
||||
{
|
||||
@@ -114,18 +180,35 @@ QVariant CANConnectionModel::data(const QModelIndex &index, int role) const
|
||||
else qDebug() << "Tried to show connection port but connection was NULL";
|
||||
break;
|
||||
case 3: //speed
|
||||
return QString::number(bus.speed);
|
||||
if(!ret) return QVariant();
|
||||
if (!isSocketCAN) return QString::number(bus.speed);
|
||||
else return QString("N/A");
|
||||
case 4: //Listen Only
|
||||
return (bus.listenOnly) ? "True" : "False";
|
||||
return QVariant();
|
||||
case 5: //Single Wire
|
||||
return (bus.singleWire) ? "True" : "False";
|
||||
return QVariant();
|
||||
case 6: //Status
|
||||
return (conn_p->getStatus()==CANCon::CONNECTED) ? "Connected" : "Not Connected";
|
||||
return QVariant();
|
||||
case 7: //Active
|
||||
return (bus.active) ? "True" : "False";
|
||||
return (conn_p->getStatus()==CANCon::CONNECTED) ? "Connected" : "Not Connected";
|
||||
default: {}
|
||||
}
|
||||
}
|
||||
if (role == Qt::CheckStateRole)
|
||||
{
|
||||
switch (index.column())
|
||||
{
|
||||
case 4:
|
||||
return (bus.listenOnly) ? Qt::Checked : Qt::Unchecked;
|
||||
break;
|
||||
case 5:
|
||||
return (bus.singleWire) ? Qt::Checked : Qt::Unchecked;
|
||||
break;
|
||||
case 6:
|
||||
return (bus.active) ? Qt::Checked : Qt::Unchecked;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
@@ -172,9 +255,11 @@ CANConnection* CANConnectionModel::getAtIdx(int pIdx, int& pBusId) const
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void CANConnectionModel::refresh(int pIndex)
|
||||
{
|
||||
beginResetModel();
|
||||
endResetModel();
|
||||
/*
|
||||
QModelIndex begin;
|
||||
QModelIndex end;
|
||||
|
||||
@@ -186,5 +271,5 @@ void CANConnectionModel::refresh(int pIndex)
|
||||
begin = createIndex(0, 0);
|
||||
end = createIndex(rowCount()-1, columnCount()-1);
|
||||
}
|
||||
dataChanged(begin, end, QVector<int>(Qt::DisplayRole));
|
||||
dataChanged(begin, end, QVector<int>(Qt::DisplayRole)); */
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@ public:
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
void add(CANConnection* pConn_p);
|
||||
|
||||
@@ -24,25 +24,17 @@ ConnectionWindow::ConnectionWindow(QWidget *parent) :
|
||||
|
||||
connModel = new CANConnectionModel(this);
|
||||
ui->tableConnections->setModel(connModel);
|
||||
ui->tableConnections->setColumnWidth(0, 50);
|
||||
ui->tableConnections->setColumnWidth(1, 110);
|
||||
ui->tableConnections->setColumnWidth(2, 110);
|
||||
ui->tableConnections->setColumnWidth(3, 110);
|
||||
ui->tableConnections->setColumnWidth(4, 75);
|
||||
ui->tableConnections->setColumnWidth(5, 75);
|
||||
ui->tableConnections->setColumnWidth(6, 75);
|
||||
ui->tableConnections->setColumnWidth(7, 75);
|
||||
ui->tableConnections->setColumnWidth(0, 40);
|
||||
ui->tableConnections->setColumnWidth(1, 70);
|
||||
ui->tableConnections->setColumnWidth(2, 70);
|
||||
ui->tableConnections->setColumnWidth(3, 70);
|
||||
ui->tableConnections->setColumnWidth(4, 70);
|
||||
ui->tableConnections->setColumnWidth(5, 70);
|
||||
ui->tableConnections->setColumnWidth(6, 70);
|
||||
ui->tableConnections->setColumnWidth(7, 90);
|
||||
QHeaderView *HorzHdr = ui->tableConnections->horizontalHeader();
|
||||
HorzHdr->setStretchLastSection(true); //causes the data column to automatically fill the tableview
|
||||
|
||||
ui->ckSingleWire->setChecked(settings.value("Main/SingleWireMode", false).toBool());
|
||||
|
||||
ui->cbSpeed->addItem(tr("125000"));
|
||||
ui->cbSpeed->addItem(tr("250000"));
|
||||
ui->cbSpeed->addItem(tr("500000"));
|
||||
ui->cbSpeed->addItem(tr("1000000"));
|
||||
ui->cbSpeed->addItem(tr("33333"));
|
||||
|
||||
ui->textConsole->setEnabled(false);
|
||||
ui->btnClearDebug->setEnabled(false);
|
||||
ui->btnSendHex->setEnabled(false);
|
||||
@@ -61,9 +53,7 @@ ConnectionWindow::ConnectionWindow(QWidget *parent) :
|
||||
connect(ui->rbGVRET, &QAbstractButton::clicked, this, &ConnectionWindow::handleConnTypeChanged);
|
||||
connect(ui->rbKvaser, &QAbstractButton::clicked, this, &ConnectionWindow::handleConnTypeChanged);
|
||||
connect(ui->rbSocketCAN, &QAbstractButton::clicked, this, &ConnectionWindow::handleConnTypeChanged);
|
||||
connect(ui->btnRevert, &QPushButton::clicked, this, &ConnectionWindow::handleRevert);
|
||||
connect(ui->tableConnections->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &ConnectionWindow::currentRowChanged);
|
||||
connect(ui->btnNewConn, &QPushButton::clicked, this, &ConnectionWindow::handleNewConn);
|
||||
connect(ui->btnActivateAll, &QPushButton::clicked, this, &ConnectionWindow::handleEnableAll);
|
||||
connect(ui->btnDeactivateAll, &QPushButton::clicked, this, &ConnectionWindow::handleDisableAll);
|
||||
connect(ui->btnRemoveBus, &QPushButton::clicked, this, &ConnectionWindow::handleRemoveConn);
|
||||
@@ -100,6 +90,7 @@ void ConnectionWindow::showEvent(QShowEvent* event)
|
||||
readSettings();
|
||||
ui->tableConnections->selectRow(0);
|
||||
currentRowChanged(ui->tableConnections->currentIndex(), ui->tableConnections->currentIndex());
|
||||
handleConnTypeChanged();
|
||||
}
|
||||
|
||||
void ConnectionWindow::closeEvent(QCloseEvent *event)
|
||||
@@ -207,7 +198,7 @@ void ConnectionWindow::handleConnTypeChanged()
|
||||
|
||||
|
||||
/* status */
|
||||
void ConnectionWindow::connectionStatus(CANCon::status pStatus)
|
||||
void ConnectionWindow::connectionStatus(CANConStatus pStatus)
|
||||
{
|
||||
Q_UNUSED(pStatus);
|
||||
|
||||
@@ -218,53 +209,14 @@ void ConnectionWindow::connectionStatus(CANCon::status pStatus)
|
||||
|
||||
void ConnectionWindow::handleOKButton()
|
||||
{
|
||||
int whichRow = ui->tableConnections->selectionModel()->currentIndex().row();
|
||||
|
||||
CANConnection* conn_p = NULL;
|
||||
|
||||
if (whichRow > -1)
|
||||
{
|
||||
/* set information for selected connection */
|
||||
int busId;
|
||||
CANBus bus;
|
||||
bool ret;
|
||||
|
||||
conn_p = connModel->getAtIdx(whichRow, busId);
|
||||
if(!conn_p) return;
|
||||
|
||||
ret = conn_p->getBusSettings(busId, bus);
|
||||
if(!ret) return;
|
||||
|
||||
|
||||
bus.setListenOnly(ui->ckListenOnly->isChecked());
|
||||
bus.setSingleWire(ui->ckSingleWire->isChecked());
|
||||
bus.setEnabled(ui->ckEnabled->isChecked());
|
||||
bus.setSpeed(ui->cbSpeed->currentText().toInt());
|
||||
/* update bus settings */
|
||||
conn_p->setBusSettings(busId, bus);
|
||||
|
||||
connModel->refresh(whichRow);
|
||||
}
|
||||
else if( ! CANConManager::getInstance()->getByName(getPortName()) )
|
||||
if( ! CANConManager::getInstance()->getByName(getPortName()) )
|
||||
{
|
||||
/* create connection */
|
||||
conn_p = create(getConnectionType(), getPortName());
|
||||
if(!conn_p)
|
||||
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 */
|
||||
connModel->add(conn_p);
|
||||
}
|
||||
@@ -280,6 +232,7 @@ void ConnectionWindow::currentRowChanged(const QModelIndex ¤t, const QMode
|
||||
|
||||
disconnect(connModel->getAtIdx(previous.row(), busId), SIGNAL(debugOutput(QString)), 0, 0);
|
||||
disconnect(this, SIGNAL(sendDebugData(QByteArray)), connModel->getAtIdx(previous.row(), busId), SLOT(debugInput(QByteArray)));
|
||||
return;
|
||||
|
||||
/* enable / diable connection type */
|
||||
ui->stPort->setEnabled(selIdx==-1);
|
||||
@@ -291,9 +244,6 @@ void ConnectionWindow::currentRowChanged(const QModelIndex ¤t, const QMode
|
||||
{
|
||||
ui->btnOK->setText(tr("Create New Connection"));
|
||||
ui->rbGVRET->setChecked(true);
|
||||
ui->ckListenOnly->setChecked(false);
|
||||
ui->ckSingleWire->setChecked(false);
|
||||
ui->ckEnabled->setChecked(false);
|
||||
setSpeed(0);
|
||||
setPortName(CANCon::GVRET_SERIAL, "");
|
||||
}
|
||||
@@ -313,9 +263,6 @@ void ConnectionWindow::currentRowChanged(const QModelIndex ¤t, const QMode
|
||||
if(!ret) return;
|
||||
|
||||
ui->btnOK->setText(tr("Update Connection Settings"));
|
||||
ui->ckListenOnly->setChecked(bus.isListenOnly());
|
||||
ui->ckSingleWire->setChecked(bus.isSingleWire());
|
||||
ui->ckEnabled->setChecked(bus.isActive());
|
||||
setSpeed(bus.getSpeed());
|
||||
setPortName(conn_p->getType(), conn_p->getPort());
|
||||
}
|
||||
@@ -349,7 +296,6 @@ void ConnectionWindow::selectSerial()
|
||||
{
|
||||
/* set combobox page visible */
|
||||
ui->stPort->setCurrentWidget(ui->cbPage);
|
||||
ui->cbSpeed->setEnabled(true);
|
||||
|
||||
ui->cbPort->clear();
|
||||
ports = QSerialPortInfo::availablePorts();
|
||||
@@ -362,7 +308,6 @@ void ConnectionWindow::selectKvaser()
|
||||
{
|
||||
/* set combobox page visible */
|
||||
ui->stPort->setCurrentWidget(ui->cbPage);
|
||||
ui->cbSpeed->setEnabled(false);
|
||||
}
|
||||
|
||||
void ConnectionWindow::selectSocketCan()
|
||||
@@ -373,18 +318,6 @@ void ConnectionWindow::selectSocketCan()
|
||||
|
||||
void ConnectionWindow::setSpeed(int speed0)
|
||||
{
|
||||
for (int i = 0; i < ui->cbSpeed->count(); i++)
|
||||
{
|
||||
if (ui->cbSpeed->itemText(i).toInt() == speed0)
|
||||
{
|
||||
ui->cbSpeed->setCurrentIndex(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* add custom speed */
|
||||
ui->cbSpeed->addItem(QString::number(speed0));
|
||||
ui->cbSpeed->setCurrentIndex(ui->cbSpeed->count() - 1);
|
||||
}
|
||||
|
||||
void ConnectionWindow::setPortName(CANCon::type pType, QString pPortName)
|
||||
@@ -393,9 +326,6 @@ void ConnectionWindow::setPortName(CANCon::type pType, QString pPortName)
|
||||
{
|
||||
case CANCon::GVRET_SERIAL:
|
||||
ui->rbGVRET->setChecked(true);
|
||||
ui->cbSpeed->setEnabled(true);
|
||||
ui->ckListenOnly->setEnabled(true);
|
||||
ui->ckSingleWire->setEnabled(true);
|
||||
break;
|
||||
case CANCon::KVASER:
|
||||
ui->rbKvaser->setChecked(true);
|
||||
@@ -403,9 +333,6 @@ void ConnectionWindow::setPortName(CANCon::type pType, QString pPortName)
|
||||
case CANCon::SOCKETCAN:
|
||||
ui->rbSocketCAN->setChecked(true);
|
||||
//you can't configure any of the below three with socketcan so dim them out
|
||||
ui->cbSpeed->setEnabled(false);
|
||||
ui->ckListenOnly->setEnabled(false);
|
||||
ui->ckSingleWire->setEnabled(false);
|
||||
break;
|
||||
default: {}
|
||||
}
|
||||
@@ -435,16 +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.
|
||||
int ConnectionWindow::getSpeed()
|
||||
{
|
||||
switch (ui->cbSpeed->currentIndex())
|
||||
{
|
||||
case -1:
|
||||
case 0:
|
||||
return -1;
|
||||
case 1:
|
||||
return 0;
|
||||
default:
|
||||
return (ui->cbSpeed->currentText().toInt());
|
||||
}
|
||||
}
|
||||
|
||||
QString ConnectionWindow::getPortName()
|
||||
@@ -475,12 +392,10 @@ CANCon::type ConnectionWindow::getConnectionType()
|
||||
|
||||
void ConnectionWindow::setSWMode(bool mode)
|
||||
{
|
||||
ui->ckSingleWire->setChecked(mode);
|
||||
}
|
||||
|
||||
bool ConnectionWindow::getSWMode()
|
||||
{
|
||||
if (ui->ckSingleWire->checkState() == Qt::Checked) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -530,8 +445,8 @@ CANConnection* ConnectionWindow::create(CANCon::type pTye, QString pPortName)
|
||||
if(conn_p)
|
||||
{
|
||||
/* connect signal */
|
||||
connect(conn_p, SIGNAL(status(CANCon::status)),
|
||||
this, SLOT(connectionStatus(CANCon::status)));
|
||||
connect(conn_p, SIGNAL(status(CANConStatus)),
|
||||
this, SLOT(connectionStatus(CANConStatus)));
|
||||
|
||||
/*TODO add return value and checks */
|
||||
conn_p->start();
|
||||
@@ -552,17 +467,10 @@ void ConnectionWindow::loadConnections()
|
||||
/* fill connection list */
|
||||
QVector<QString> portNames = settings.value("connections/portNames").value<QVector<QString>>();
|
||||
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++)
|
||||
{
|
||||
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 */
|
||||
connModel->add(conn_p);
|
||||
}
|
||||
@@ -579,23 +487,14 @@ void ConnectionWindow::saveConnections()
|
||||
QSettings settings;
|
||||
QVector<QString> portNames;
|
||||
QVector<int> devTypes;
|
||||
QList<CANBus> busses;
|
||||
|
||||
/* save connections */
|
||||
foreach(CANConnection* conn_p, conns)
|
||||
{
|
||||
portNames.append(conn_p->getPort());
|
||||
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/types", QVariant::fromValue(devTypes));
|
||||
settings.setValue("connections/busses", QVariant::fromValue(busses));
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ private slots:
|
||||
void handleClearDebugText();
|
||||
void handleSendHex();
|
||||
void handleSendText();
|
||||
void connectionStatus(CANCon::status);
|
||||
void connectionStatus(CANConStatus);
|
||||
|
||||
private:
|
||||
Ui::ConnectionWindow *ui;
|
||||
|
||||
+174
-26
@@ -125,25 +125,71 @@ void GVRetSerial::piSetBusSettings(int pBusIdx, CANBus bus)
|
||||
}
|
||||
else deviceSingleWireMode = 0;
|
||||
}
|
||||
else if (pBusIdx == 2)
|
||||
{
|
||||
swcanBaud = bus.getSpeed();
|
||||
swcanBaud |= 0x80000000;
|
||||
if (bus.isActive())
|
||||
{
|
||||
swcanBaud |= 0x40000000;
|
||||
swcanEnabled = true;
|
||||
}
|
||||
else swcanEnabled = false;
|
||||
|
||||
/* update baud rates */
|
||||
QByteArray buffer;
|
||||
qDebug() << "Got signal to update bauds. 1: " << can0Baud <<" 2: " << can1Baud;
|
||||
debugOutput("Got signal to update bauds. 1: " + QString::number(can0Baud) + " 2: " + QString::number(can1Baud));
|
||||
buffer[0] = (char)0xF1; //start of a command over serial
|
||||
buffer[1] = 5; //setup canbus
|
||||
buffer[2] = (unsigned char)(can0Baud & 0xFF); //four bytes of ID LSB first
|
||||
buffer[3] = (unsigned char)(can0Baud >> 8);
|
||||
buffer[4] = (unsigned char)(can0Baud >> 16);
|
||||
buffer[5] = (unsigned char)(can0Baud >> 24);
|
||||
buffer[6] = (unsigned char)(can1Baud & 0xFF); //four bytes of ID LSB first
|
||||
buffer[7] = (unsigned char)(can1Baud >> 8);
|
||||
buffer[8] = (unsigned char)(can1Baud >> 16);
|
||||
buffer[9] = (unsigned char)(can1Baud >> 24);
|
||||
buffer[10] = 0;
|
||||
if (serial == NULL) return;
|
||||
if (!serial->isOpen()) return;
|
||||
serial->write(buffer);
|
||||
if (bus.isListenOnly())
|
||||
{
|
||||
swcanBaud |= 0x20000000;
|
||||
swcanListenOnly = true;
|
||||
}
|
||||
else swcanListenOnly = false;
|
||||
|
||||
}
|
||||
|
||||
if (pBusIdx < 2) {
|
||||
/* update baud rates */
|
||||
QByteArray buffer;
|
||||
qDebug() << "Got signal to update bauds. 1: " << (can0Baud & 0xFFFFFFF) <<" 2: " << (can1Baud & 0xFFFFFFF);
|
||||
debugOutput("Got signal to update bauds. 1: " + QString::number((can0Baud & 0xFFFFFFF)) + " 2: " + QString::number((can1Baud & 0xFFFFFFF)));
|
||||
buffer[0] = (char)0xF1; //start of a command over serial
|
||||
buffer[1] = 5; //setup canbus
|
||||
buffer[2] = (unsigned char)(can0Baud & 0xFF); //four bytes of ID LSB first
|
||||
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);
|
||||
|
||||
output.append((char)0xF1);
|
||||
output.append((char)0x0C); //get number of actually implemented buses. Not implemented except on M2RET
|
||||
mNumBuses = 2; //the proper number if C/12 is not implemented
|
||||
|
||||
output.append((char)0xF1); //signal we want to issue a command
|
||||
output.append((char)0x06); //request canbus stats from the board
|
||||
|
||||
@@ -249,15 +299,11 @@ void GVRetSerial::connectDevice()
|
||||
output.append((char)0xFF); //signal we don't want single wire mode
|
||||
}*/
|
||||
|
||||
output.append((char)0xF1); //yet another command
|
||||
output.append((char)0x09); //comm validation command
|
||||
|
||||
output.append((char)0xF1); //and another command
|
||||
output.append((char)0x01); //Time Sync - Not implemented until 333 but we can try
|
||||
|
||||
output.append((char)0xF1);
|
||||
output.append((char)0x12); //get number of actually implemented buses. Not implemented except on M2RET
|
||||
mNumBuses = 2; //the proper number if 0x12 is not implemented
|
||||
output.append((char)0xF1); //yet another command
|
||||
output.append((char)0x09); //comm validation command
|
||||
|
||||
continuousTimeSync = true;
|
||||
|
||||
@@ -274,7 +320,10 @@ void GVRetSerial::connectDevice()
|
||||
}
|
||||
else {
|
||||
setStatus(CANCon::CONNECTED);
|
||||
emit status(getStatus());
|
||||
CANConStatus stats;
|
||||
stats.conStatus = getStatus();
|
||||
stats.numHardwareBuses = mNumBuses;
|
||||
emit status(stats);
|
||||
}
|
||||
|
||||
/* connect reading event */
|
||||
@@ -336,6 +385,10 @@ void GVRetSerial::debugInput(QByteArray bytes) {
|
||||
|
||||
void GVRetSerial::procRXChar(unsigned char c)
|
||||
{
|
||||
CANConStatus stats;
|
||||
int oldBuses;
|
||||
QByteArray output;
|
||||
|
||||
switch (rx_state)
|
||||
{
|
||||
case IDLE:
|
||||
@@ -380,6 +433,12 @@ void GVRetSerial::procRXChar(unsigned char c)
|
||||
break;
|
||||
case 12:
|
||||
rx_state = GET_NUM_BUSES;
|
||||
qDebug() << "Got num buses reply";
|
||||
rx_step = 0;
|
||||
break;
|
||||
case 13:
|
||||
rx_state = GET_EXT_BUSES;
|
||||
qDebug() << "Got extended buses info reply";
|
||||
rx_step = 0;
|
||||
break;
|
||||
}
|
||||
@@ -545,6 +604,12 @@ void GVRetSerial::procRXChar(unsigned char c)
|
||||
rx_state = IDLE;
|
||||
qDebug() << "Baud 0 = " << can0Baud;
|
||||
qDebug() << "Baud 1 = " << can1Baud;
|
||||
mBusData[0].mBus.setSpeed(can0Baud);
|
||||
mBusData[1].mBus.setSpeed(can1Baud);
|
||||
mBusData[0].mBus.setEnabled(can0Enabled);
|
||||
mBusData[1].mBus.setEnabled(can1Enabled);
|
||||
mBusData[0].mConfigured = true;
|
||||
mBusData[1].mConfigured = true;
|
||||
|
||||
can0Baud |= 0x80000000;
|
||||
if (can0Enabled) can0Baud |= 0x40000000;
|
||||
@@ -556,7 +621,9 @@ void GVRetSerial::procRXChar(unsigned char c)
|
||||
if (deviceSingleWireMode > 0) can1Baud |= 0x10000000;
|
||||
|
||||
setStatus(CANCon::CONNECTED);
|
||||
emit status(getStatus());
|
||||
stats.conStatus = getStatus();
|
||||
stats.numHardwareBuses = mNumBuses;
|
||||
emit status(stats);
|
||||
|
||||
int can0Status = 0x78; //updating everything we can update
|
||||
int can1Status = 0x78;
|
||||
@@ -606,8 +673,89 @@ void GVRetSerial::procRXChar(unsigned char c)
|
||||
rx_state = IDLE;
|
||||
break;
|
||||
case GET_NUM_BUSES:
|
||||
oldBuses = mNumBuses;
|
||||
mNumBuses = c;
|
||||
rx_state = IDLE;
|
||||
qDebug() << "Get number of buses = " << mNumBuses;
|
||||
stats.conStatus = getStatus();
|
||||
stats.numHardwareBuses = mNumBuses;
|
||||
mBusData.resize(mNumBuses);
|
||||
if (mNumBuses > oldBuses)
|
||||
{
|
||||
for (int i = oldBuses; i < mNumBuses; i++)
|
||||
{
|
||||
mBusData[i].mConfigured = true;
|
||||
mBusData[i].mBus = mBusData[0].mBus;
|
||||
}
|
||||
}
|
||||
|
||||
output.append((char)0xF1); //start a new command
|
||||
output.append((char)13); //get extended buses
|
||||
serial->write(output);
|
||||
|
||||
emit status(stats);
|
||||
break;
|
||||
case GET_EXT_BUSES:
|
||||
switch (rx_step)
|
||||
{
|
||||
case 0:
|
||||
swcanEnabled = (c & 0xF);
|
||||
swcanListenOnly = (c >> 4);
|
||||
break;
|
||||
case 1:
|
||||
swcanBaud = c;
|
||||
break;
|
||||
case 2:
|
||||
swcanBaud |= c << 8;
|
||||
break;
|
||||
case 3:
|
||||
swcanBaud |= c << 16;
|
||||
break;
|
||||
case 4:
|
||||
swcanBaud |= c << 24;
|
||||
break;
|
||||
case 5:
|
||||
lin1Enabled = (c & 0xF);
|
||||
break;
|
||||
case 6:
|
||||
lin1Baud = c;
|
||||
break;
|
||||
case 7:
|
||||
lin1Baud |= c << 8;
|
||||
break;
|
||||
case 8:
|
||||
lin1Baud |= c << 16;
|
||||
break;
|
||||
case 9:
|
||||
lin1Baud |= c << 24;
|
||||
case 10:
|
||||
lin2Enabled = (c & 0xF);
|
||||
break;
|
||||
case 11:
|
||||
lin2Baud = c;
|
||||
break;
|
||||
case 12:
|
||||
lin2Baud |= c << 8;
|
||||
break;
|
||||
case 13:
|
||||
lin2Baud |= c << 16;
|
||||
break;
|
||||
case 14:
|
||||
lin2Baud |= c << 24;
|
||||
rx_state = IDLE;
|
||||
qDebug() << "SWCAN Baud = " << swcanBaud;
|
||||
qDebug() << "LIN1 Baud = " << lin1Baud;
|
||||
qDebug() << "LIN2 Baud = " << lin2Baud;
|
||||
mBusData[2].mBus.setSpeed(swcanBaud);
|
||||
mBusData[2].mBus.setEnabled(swcanEnabled);
|
||||
|
||||
setStatus(CANCon::CONNECTED);
|
||||
stats.conStatus = getStatus();
|
||||
stats.numHardwareBuses = mNumBuses;
|
||||
emit status(stats);
|
||||
break;
|
||||
}
|
||||
rx_step++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
namespace SERIALSTATE {
|
||||
|
||||
enum STATE //keep this enum synchronized with the Arduino firmware project
|
||||
enum STATE
|
||||
{
|
||||
IDLE,
|
||||
GET_COMMAND,
|
||||
@@ -29,12 +29,12 @@ enum STATE //keep this enum synchronized with the Arduino firmware project
|
||||
GET_CANBUS_PARAMS,
|
||||
GET_DEVICE_INFO,
|
||||
SET_SINGLEWIRE_MODE,
|
||||
GET_NUM_BUSES
|
||||
GET_NUM_BUSES,
|
||||
GET_EXT_BUSES
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
using namespace SERIALSTATE;
|
||||
class GVRetSerial : public CANConnection
|
||||
{
|
||||
@@ -83,9 +83,9 @@ protected:
|
||||
STATE rx_state;
|
||||
uint32_t rx_step;
|
||||
CANFrame buildFrame;
|
||||
int can0Baud, can1Baud;
|
||||
bool can0Enabled, can1Enabled;
|
||||
bool can0ListenOnly, can1ListenOnly;
|
||||
int can0Baud, can1Baud, swcanBaud, lin1Baud, lin2Baud;
|
||||
bool can0Enabled, can1Enabled, swcanEnabled, lin1Enabled, lin2Enabled;
|
||||
bool can0ListenOnly, can1ListenOnly, swcanListenOnly;
|
||||
int deviceBuildNum;
|
||||
int deviceSingleWireMode;
|
||||
uint32_t buildTimeBasis;
|
||||
|
||||
@@ -31,6 +31,8 @@ void SocketCan::piStarted()
|
||||
mTimer.setInterval(1000);
|
||||
mTimer.setSingleShot(false); //keep ticking
|
||||
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)
|
||||
{
|
||||
CANConStatus stats;
|
||||
/* sanity checks */
|
||||
if(0 != pBusIdx)
|
||||
return;
|
||||
@@ -109,7 +112,6 @@ bool SocketCan::piSendFrame(const CANFrame& pFrame)
|
||||
/* sanity checks */
|
||||
if(0 != pFrame.bus || pFrame.len>8)
|
||||
return false;
|
||||
|
||||
if (!mDev_p) return false;
|
||||
|
||||
/* fill frame */
|
||||
@@ -211,6 +213,7 @@ void SocketCan::framesReceived()
|
||||
|
||||
void SocketCan::testConnection() {
|
||||
QCanBusDevice* dev_p = QCanBus::instance()->createDevice("socketcan", getPort());
|
||||
CANConStatus stats;
|
||||
|
||||
switch(getStatus())
|
||||
{
|
||||
@@ -220,7 +223,9 @@ void SocketCan::testConnection() {
|
||||
disconnectDevice();
|
||||
|
||||
setStatus(CANCon::NOT_CONNECTED);
|
||||
emit status(getStatus());
|
||||
stats.conStatus = getStatus();
|
||||
stats.numHardwareBuses = mNumBuses;
|
||||
emit status(stats);
|
||||
}
|
||||
break;
|
||||
case CANCon::NOT_CONNECTED:
|
||||
@@ -229,13 +234,18 @@ void SocketCan::testConnection() {
|
||||
/* try to reconnect */
|
||||
CANBus bus;
|
||||
if(getBusConfig(0, bus))
|
||||
{
|
||||
bus.setEnabled(true);
|
||||
setBusSettings(0, bus);
|
||||
}
|
||||
}
|
||||
/* disconnect test instance */
|
||||
dev_p->disconnectDevice();
|
||||
|
||||
setStatus(CANCon::CONNECTED);
|
||||
emit status(getStatus());
|
||||
stats.conStatus = getStatus();
|
||||
stats.numHardwareBuses = mNumBuses;
|
||||
emit status(stats);
|
||||
}
|
||||
break;
|
||||
default: {}
|
||||
|
||||
@@ -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 = ¤tSeqItem->data[currentPosition];
|
||||
uint32_t originalBus = thisFrame->bus;
|
||||
if (currentSeqItem->idFilters.find(thisFrame->ID).value())
|
||||
{
|
||||
if (whichBusSend > -1)
|
||||
{
|
||||
thisFrame->bus = whichBusSend;
|
||||
sendingBuffer.append(*thisFrame);
|
||||
}
|
||||
else if (whichBusSend == -1)
|
||||
{
|
||||
for (int c = 0; c < numBuses; c++)
|
||||
{
|
||||
thisFrame->bus = c;
|
||||
sendingBuffer.append(*thisFrame);
|
||||
}
|
||||
}
|
||||
else //from file so retain original bus and send as-is
|
||||
{
|
||||
sendingBuffer.append(*thisFrame);
|
||||
}
|
||||
|
||||
thisFrame->bus = originalBus;
|
||||
}
|
||||
return thisFrame->timestamp;
|
||||
}
|
||||
|
||||
quint64 FramePlaybackObject::peekPosition(bool forward)
|
||||
{
|
||||
int peekCurrentPosition = currentPosition;
|
||||
if (forward)
|
||||
{
|
||||
if (peekCurrentPosition < (currentSeqItem->data.count() - 1)) peekCurrentPosition++; //still in same file so keep going
|
||||
else //hit the end of the current file
|
||||
{
|
||||
return 0xFFFFFFFFFFFFFFFFull;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (peekCurrentPosition > 0) peekCurrentPosition--;
|
||||
else //hit the beginning of the current sequence
|
||||
{
|
||||
return 0xFFFFFFFFFFFFFFFFull;
|
||||
}
|
||||
}
|
||||
CANFrame *thisFrame = ¤tSeqItem->data[peekCurrentPosition];
|
||||
return thisFrame->timestamp;
|
||||
}
|
||||
|
||||
void FramePlaybackObject::piStart()
|
||||
{
|
||||
playbackTimer = new QTimer();
|
||||
playbackTimer->setTimerType(Qt::PreciseTimer);
|
||||
playbackTimer->setInterval(1);
|
||||
|
||||
currentPosition = 0;
|
||||
playbackActive = false;
|
||||
playbackForward = true;
|
||||
whichBusSend = 0;
|
||||
|
||||
connect(playbackTimer, &QTimer::timeout, this, &FramePlaybackObject::timerTriggered);
|
||||
}
|
||||
|
||||
void FramePlaybackObject::piStop()
|
||||
{
|
||||
playbackTimer->stop();
|
||||
delete playbackTimer;
|
||||
}
|
||||
|
||||
void FramePlaybackObject::initialize()
|
||||
{
|
||||
if( mThread_p && (mThread_p != QThread::currentThread()) )
|
||||
{
|
||||
/* move ourself to the thread */
|
||||
moveToThread(mThread_p); /*TODO handle errors */
|
||||
/* connect started() */
|
||||
connect(mThread_p, SIGNAL(started()), this, SLOT(initialize()));
|
||||
/* start the thread */
|
||||
mThread_p->start(QThread::HighPriority);
|
||||
return;
|
||||
}
|
||||
|
||||
/* set started flag */
|
||||
//mStarted = true;
|
||||
|
||||
/* in multithread case, this will be called before entering thread event loop */
|
||||
return piStart();
|
||||
|
||||
}
|
||||
|
||||
void FramePlaybackObject::finalize()
|
||||
{
|
||||
/* 1) execute in mThread_p context */
|
||||
if( mThread_p && (mThread_p != QThread::currentThread()) )
|
||||
{
|
||||
/* if thread is finished, it means we call this function for the second time so we can leave */
|
||||
if( !mThread_p->isFinished() )
|
||||
{
|
||||
/* we need to call piStop() */
|
||||
QMetaObject::invokeMethod(this, "finalize",
|
||||
Qt::BlockingQueuedConnection);
|
||||
/* 3) stop thread */
|
||||
mThread_p->quit();
|
||||
if(!mThread_p->wait()) {
|
||||
qDebug() << "can't stop thread";
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* 2) call piStop in mThread context */
|
||||
return piStop();
|
||||
}
|
||||
|
||||
void FramePlaybackObject::startPlaybackForward()
|
||||
{
|
||||
/* make sure we execute in mThread context */
|
||||
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
|
||||
QMetaObject::invokeMethod(this, "startPlaybackForward",
|
||||
Qt::BlockingQueuedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
playbackActive = true;
|
||||
playbackForward = true;
|
||||
|
||||
if (useOrigTiming)
|
||||
{
|
||||
playbackTimer->setInterval(1);
|
||||
playbackElapsed.start();
|
||||
if (currentSeqItem->data[currentPosition].timestamp > 2000)
|
||||
playbackLastTimeStamp = currentSeqItem->data[currentPosition].timestamp - 2000;
|
||||
else playbackLastTimeStamp = 0;
|
||||
}
|
||||
playbackTimer->start();
|
||||
}
|
||||
|
||||
void FramePlaybackObject::startPlaybackBackward()
|
||||
{
|
||||
/* make sure we execute in mThread context */
|
||||
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
|
||||
QMetaObject::invokeMethod(this, "startPlaybackBackward",
|
||||
Qt::BlockingQueuedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
playbackActive = true;
|
||||
playbackForward = false;
|
||||
if (useOrigTiming)
|
||||
{
|
||||
playbackElapsed.start();
|
||||
playbackTimer->setInterval(1);
|
||||
playbackLastTimeStamp = currentSeqItem->data[currentPosition].timestamp + 2000;
|
||||
}
|
||||
playbackTimer->start();
|
||||
}
|
||||
|
||||
void FramePlaybackObject::stepPlaybackForward()
|
||||
{
|
||||
/* make sure we execute in mThread context */
|
||||
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
|
||||
QMetaObject::invokeMethod(this, "stepPlaybackForward",
|
||||
Qt::BlockingQueuedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
sendingBuffer.clear();
|
||||
playbackTimer->stop();
|
||||
playbackActive = false;
|
||||
updatePosition(true);
|
||||
CANConManager::getInstance()->sendFrames(sendingBuffer);
|
||||
}
|
||||
|
||||
void FramePlaybackObject::stepPlaybackBackward()
|
||||
{
|
||||
/* make sure we execute in mThread context */
|
||||
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
|
||||
QMetaObject::invokeMethod(this, "stepPlaybackBackward",
|
||||
Qt::BlockingQueuedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
sendingBuffer.clear();
|
||||
playbackTimer->stop(); //pushing this button halts automatic playback
|
||||
playbackActive = false;
|
||||
|
||||
updatePosition(false);
|
||||
CANConManager::getInstance()->sendFrames(sendingBuffer);
|
||||
}
|
||||
|
||||
void FramePlaybackObject::stopPlayback()
|
||||
{
|
||||
/* make sure we execute in mThread context */
|
||||
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
|
||||
QMetaObject::invokeMethod(this, "stopPlayback",
|
||||
Qt::BlockingQueuedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
playbackTimer->stop(); //pushing this button halts automatic playback
|
||||
playbackActive = false;
|
||||
currentPosition = 0;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
+141
-173
@@ -32,47 +32,50 @@ FramePlaybackWindow::FramePlaybackWindow(const QVector<CANFrame> *frames, QWidge
|
||||
ui->comboCANBus->addItem(tr("From File"));
|
||||
ui->comboCANBus->setCurrentIndex(0);
|
||||
|
||||
playbackObject.initialize();
|
||||
playbackObject.setNumBuses(numBuses);
|
||||
|
||||
readSettings();
|
||||
|
||||
modelFrames = frames;
|
||||
|
||||
playbackTimer = new QTimer();
|
||||
playbackTimer->setTimerType(Qt::PreciseTimer);
|
||||
|
||||
currentPosition = 0;
|
||||
playbackActive = false;
|
||||
playbackForward = true;
|
||||
whichBusSend = 0; //0 = no bus, 1 = bus 0, 2 = bus 1, 4 = from file - Bitfield so you can 'or' them.
|
||||
currentSeqItem = NULL;
|
||||
currentSeqNum = -1;
|
||||
currentPosition = 0;
|
||||
forward = true;
|
||||
isPlaying = false;
|
||||
|
||||
updateFrameLabel();
|
||||
|
||||
connect(ui->btnStepBack, SIGNAL(clicked(bool)), this, SLOT(btnBackOneClick()));
|
||||
connect(ui->btnPause, SIGNAL(clicked(bool)), this, SLOT(btnPauseClick()));
|
||||
connect(ui->btnPlayReverse, SIGNAL(clicked(bool)), this, SLOT(btnReverseClick()));
|
||||
connect(ui->btnStop, SIGNAL(clicked(bool)), this, SLOT(btnStopClick()));
|
||||
connect(ui->btnPlay, SIGNAL(clicked(bool)), this, SLOT(btnPlayClick()));
|
||||
connect(ui->btnStepForward, SIGNAL(clicked(bool)), this, SLOT(btnFwdOneClick()));
|
||||
connect(ui->btnSelectAll, SIGNAL(clicked(bool)), this, SLOT(btnSelectAllClick()));
|
||||
connect(ui->btnSelectNone, SIGNAL(clicked(bool)), this, SLOT(btnSelectNoneClick()));
|
||||
connect(ui->btnDelete, SIGNAL(clicked(bool)), this, SLOT(btnDeleteCurrSeq()));
|
||||
connect(ui->btnStepBack, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnBackOneClick);
|
||||
connect(ui->btnPause, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnPauseClick);
|
||||
connect(ui->btnPlayReverse, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnReverseClick);
|
||||
connect(ui->btnStop, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnStopClick);
|
||||
connect(ui->btnPlay, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnPlayClick);
|
||||
connect(ui->btnStepForward, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnFwdOneClick);
|
||||
connect(ui->btnSelectAll, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnSelectAllClick);
|
||||
connect(ui->btnSelectNone, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnSelectNoneClick);
|
||||
connect(ui->btnDelete, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnDeleteCurrSeq);
|
||||
connect(ui->spinPlaySpeed, SIGNAL(valueChanged(int)), this, SLOT(changePlaybackSpeed(int)));
|
||||
connect(ui->spinBurstSpeed, SIGNAL(valueChanged(int)), this, SLOT(changeBurstRate(int)));
|
||||
//connect(ui->cbLoop, SIGNAL(clicked(bool)), this, SLOT(changeLooping(bool)));
|
||||
connect(ui->comboCANBus, SIGNAL(currentIndexChanged(int)), this, SLOT(changeSendingBus(int)));
|
||||
connect(ui->listID, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(changeIDFiltering(QListWidgetItem*)));
|
||||
connect(playbackTimer, SIGNAL(timeout()), this, SLOT(timerTriggered()));
|
||||
connect(ui->btnLoadFile, SIGNAL(clicked(bool)), this, SLOT(btnLoadFile()));
|
||||
connect(ui->btnLoadLive, SIGNAL(clicked(bool)), this, SLOT(btnLoadLive()));
|
||||
connect(ui->tblSequence, SIGNAL(cellPressed(int,int)), this, SLOT(seqTableCellClicked(int,int)));
|
||||
connect(ui->tblSequence, SIGNAL(cellChanged(int,int)), this, SLOT(seqTableCellChanged(int,int)));
|
||||
connect(ui->btnLoadFilters, SIGNAL(clicked(bool)), this, SLOT(loadFilters()));
|
||||
connect(ui->btnSaveFilters, SIGNAL(clicked(bool)), this, SLOT(saveFilters()));
|
||||
connect(ui->listID, &QListWidget::itemClicked, this, &FramePlaybackWindow::changeIDFiltering);
|
||||
connect(ui->btnLoadFile, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnLoadFile);
|
||||
connect(ui->btnLoadLive, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnLoadLive);
|
||||
connect(ui->tblSequence, &QTableWidget::cellPressed, this, &FramePlaybackWindow::seqTableCellClicked);
|
||||
connect(ui->tblSequence, &QTableWidget::cellChanged, this, &FramePlaybackWindow::seqTableCellChanged);
|
||||
connect(ui->btnLoadFilters, &QAbstractButton::clicked, this, &FramePlaybackWindow::loadFilters);
|
||||
connect(ui->btnSaveFilters, &QAbstractButton::clicked, this, &FramePlaybackWindow::saveFilters);
|
||||
connect(ui->cbOriginalTiming, &QCheckBox::toggled, this, &FramePlaybackWindow::useOrigTimingClicked);
|
||||
|
||||
connect(&playbackObject, &FramePlaybackObject::EndOfFrameCache, this, &FramePlaybackWindow::EndOfFrameCache);
|
||||
connect(&playbackObject, &FramePlaybackObject::statusUpdate, this, &FramePlaybackWindow::getStatusUpdate);
|
||||
|
||||
ui->listID->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(ui->listID, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuFilters(QPoint)));
|
||||
|
||||
playbackTimer->setInterval(ui->spinPlaySpeed->value()); //set the timer to the default value of the control
|
||||
playbackObject.setPlaybackInterval(ui->spinPlaySpeed->value());
|
||||
|
||||
QStringList headers;
|
||||
headers << "Source" << "Loops";
|
||||
@@ -85,9 +88,6 @@ FramePlaybackWindow::FramePlaybackWindow(const QVector<CANFrame> *frames, QWidge
|
||||
FramePlaybackWindow::~FramePlaybackWindow()
|
||||
{
|
||||
delete ui;
|
||||
|
||||
playbackTimer->stop();
|
||||
delete playbackTimer;
|
||||
}
|
||||
|
||||
void FramePlaybackWindow::showEvent(QShowEvent *)
|
||||
@@ -115,7 +115,8 @@ void FramePlaybackWindow::readSettings()
|
||||
}
|
||||
ui->spinPlaySpeed->setValue(settings.value("Playback/DefSpeed", 5).toInt());
|
||||
ui->comboCANBus->setCurrentIndex(settings.value("Playback/SendingBus", 0).toInt());
|
||||
whichBusSend = ui->comboCANBus->currentIndex();
|
||||
|
||||
calculateWhichBus();
|
||||
}
|
||||
|
||||
void FramePlaybackWindow::writeSettings()
|
||||
@@ -256,6 +257,73 @@ void FramePlaybackWindow::refreshIDList()
|
||||
ui->listID->sortItems();
|
||||
}
|
||||
|
||||
void FramePlaybackWindow::calculateWhichBus()
|
||||
{
|
||||
int idx = ui->comboCANBus->currentIndex();
|
||||
int maxIdx = ui->comboCANBus->count() - 1;
|
||||
int out = idx;
|
||||
if (idx == (maxIdx - 1) ) out = -1;
|
||||
if (idx == maxIdx) out = -2;
|
||||
|
||||
playbackObject.setSendingBus(out);
|
||||
}
|
||||
|
||||
void FramePlaybackWindow::EndOfFrameCache()
|
||||
{
|
||||
if (forward)
|
||||
{
|
||||
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()
|
||||
{
|
||||
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()
|
||||
{
|
||||
if (currentSeqNum == -1) return;
|
||||
|
||||
if (playbackActive)
|
||||
{
|
||||
playbackActive = false;
|
||||
playbackTimer->stop();
|
||||
}
|
||||
playbackObject.stopPlayback();
|
||||
|
||||
seqItems.removeAt(currentSeqNum);
|
||||
ui->tblSequence->removeRow(currentSeqNum);
|
||||
@@ -345,6 +425,7 @@ void FramePlaybackWindow::btnLoadFile()
|
||||
|
||||
if (FrameFileIO::loadFrameFile(filename, &item.data))
|
||||
{
|
||||
qSort(item.data); //sort by timestamp to be sure it's in order
|
||||
QStringList fileList = filename.split('/');
|
||||
item.filename = fileList[fileList.length() - 1];
|
||||
item.currentLoopCount = 0;
|
||||
@@ -364,6 +445,7 @@ void FramePlaybackWindow::btnLoadFile()
|
||||
{
|
||||
currentSeqNum = 0;
|
||||
currentSeqItem = &seqItems[0];
|
||||
playbackObject.setSequenceObject(currentSeqItem);
|
||||
}
|
||||
refreshIDList();
|
||||
updateFrameLabel();
|
||||
@@ -377,6 +459,7 @@ void FramePlaybackWindow::btnLoadLive()
|
||||
item.currentLoopCount = 0;
|
||||
item.maxLoops = 1;
|
||||
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);
|
||||
if (ui->tblSequence->currentRow() == -1)
|
||||
{
|
||||
@@ -391,6 +474,7 @@ void FramePlaybackWindow::btnLoadLive()
|
||||
{
|
||||
currentSeqNum = 0;
|
||||
currentSeqItem = &seqItems[0];
|
||||
playbackObject.setSequenceObject(currentSeqItem);
|
||||
}
|
||||
refreshIDList();
|
||||
updateFrameLabel();
|
||||
@@ -399,32 +483,28 @@ void FramePlaybackWindow::btnLoadLive()
|
||||
|
||||
void FramePlaybackWindow::btnBackOneClick()
|
||||
{
|
||||
sendingBuffer.clear();
|
||||
playbackTimer->stop(); //pushing this button halts automatic playback
|
||||
playbackActive = false;
|
||||
|
||||
updatePosition(false);
|
||||
CANConManager::getInstance()->sendFrames(sendingBuffer);
|
||||
forward = false;
|
||||
isPlaying = false;
|
||||
playbackObject.stepPlaybackBackward();
|
||||
}
|
||||
|
||||
void FramePlaybackWindow::btnPauseClick()
|
||||
{
|
||||
playbackActive = false;
|
||||
playbackTimer->stop();
|
||||
isPlaying = false;
|
||||
playbackObject.pausePlayback();
|
||||
}
|
||||
|
||||
void FramePlaybackWindow::btnReverseClick()
|
||||
{
|
||||
playbackActive = true;
|
||||
playbackForward = false;
|
||||
playbackTimer->start();
|
||||
forward = false;
|
||||
isPlaying = true;
|
||||
playbackObject.startPlaybackBackward();
|
||||
}
|
||||
|
||||
void FramePlaybackWindow::btnStopClick()
|
||||
{
|
||||
playbackTimer->stop(); //pushing this button halts automatic playback
|
||||
playbackActive = false;
|
||||
currentPosition = 0;
|
||||
isPlaying = false;
|
||||
playbackObject.stopPlayback();
|
||||
if (seqItems.count() > 0)
|
||||
{
|
||||
currentSeqNum = 0;
|
||||
@@ -444,23 +524,26 @@ void FramePlaybackWindow::btnStopClick()
|
||||
|
||||
void FramePlaybackWindow::btnPlayClick()
|
||||
{
|
||||
playbackActive = true;
|
||||
playbackForward = true;
|
||||
playbackTimer->start();
|
||||
forward = true;
|
||||
isPlaying = true;
|
||||
playbackObject.startPlaybackForward();
|
||||
}
|
||||
|
||||
void FramePlaybackWindow::btnFwdOneClick()
|
||||
{
|
||||
sendingBuffer.clear();
|
||||
playbackTimer->stop();
|
||||
playbackActive = false;
|
||||
updatePosition(true);
|
||||
CANConManager::getInstance()->sendFrames(sendingBuffer);
|
||||
forward = true;
|
||||
isPlaying = false;
|
||||
playbackObject.stepPlaybackForward();
|
||||
}
|
||||
|
||||
void FramePlaybackWindow::changePlaybackSpeed(int newSpeed)
|
||||
{
|
||||
playbackTimer->setInterval(newSpeed);
|
||||
playbackObject.setPlaybackInterval(newSpeed);
|
||||
}
|
||||
|
||||
void FramePlaybackWindow::changeBurstRate(int burst)
|
||||
{
|
||||
playbackObject.setPlaybackBurst(burst);
|
||||
}
|
||||
|
||||
void FramePlaybackWindow::changeLooping(bool check)
|
||||
@@ -470,7 +553,7 @@ void FramePlaybackWindow::changeLooping(bool check)
|
||||
|
||||
void FramePlaybackWindow::changeSendingBus(int newIdx)
|
||||
{
|
||||
whichBusSend = newIdx;
|
||||
calculateWhichBus();
|
||||
}
|
||||
|
||||
void FramePlaybackWindow::changeIDFiltering(QListWidgetItem *item)
|
||||
@@ -499,118 +582,3 @@ void FramePlaybackWindow::btnSelectNoneClick()
|
||||
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 = ¤tSeqItem->data[currentPosition];
|
||||
uint32_t originalBus = thisFrame->bus;
|
||||
if (currentSeqItem->idFilters.find(thisFrame->ID).value())
|
||||
{
|
||||
if (whichBusSend < ui->comboCANBus->count() - 2)
|
||||
{
|
||||
thisFrame->bus = whichBusSend;
|
||||
sendingBuffer.append(*thisFrame);
|
||||
}
|
||||
else if (whichBusSend == (ui->comboCANBus->count() - 2)) //all
|
||||
{
|
||||
for (int c = 0; c < ui->comboCANBus->count() - 2; c++)
|
||||
{
|
||||
thisFrame->bus = c;
|
||||
sendingBuffer.append(*thisFrame);
|
||||
}
|
||||
}
|
||||
else //from file so retain original bus and send as-is
|
||||
{
|
||||
sendingBuffer.append(*thisFrame);
|
||||
}
|
||||
|
||||
thisFrame->bus = originalBus;
|
||||
}
|
||||
}
|
||||
|
||||
+10
-19
@@ -3,24 +3,14 @@
|
||||
|
||||
#include <QDialog>
|
||||
#include <QListWidget>
|
||||
#include <QTimer>
|
||||
#include "can_structs.h"
|
||||
#include "framefileio.h"
|
||||
#include "frameplaybackobject.h"
|
||||
|
||||
namespace Ui {
|
||||
class FramePlaybackWindow;
|
||||
}
|
||||
|
||||
//one entry in the sequence of data to use
|
||||
struct SequenceItem
|
||||
{
|
||||
QString filename;
|
||||
QVector<CANFrame> data;
|
||||
QHash<int, bool> idFilters;
|
||||
int maxLoops;
|
||||
int currentLoopCount;
|
||||
};
|
||||
|
||||
class FramePlaybackWindow : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -38,12 +28,12 @@ private slots:
|
||||
void btnFwdOneClick();
|
||||
void btnDeleteCurrSeq();
|
||||
void changePlaybackSpeed(int newSpeed);
|
||||
void changeBurstRate(int burst);
|
||||
void changeLooping(bool check);
|
||||
void changeSendingBus(int newIdx);
|
||||
void changeIDFiltering(QListWidgetItem *item);
|
||||
void btnSelectAllClick();
|
||||
void btnSelectNoneClick();
|
||||
void timerTriggered();
|
||||
void btnLoadFile();
|
||||
void btnLoadLive();
|
||||
void seqTableCellClicked(int row, int col);
|
||||
@@ -51,30 +41,31 @@ private slots:
|
||||
void contextMenuFilters(QPoint);
|
||||
void saveFilters();
|
||||
void loadFilters();
|
||||
void useOrigTimingClicked();
|
||||
void getStatusUpdate(int frameNum);
|
||||
void EndOfFrameCache();
|
||||
|
||||
private:
|
||||
Ui::FramePlaybackWindow *ui;
|
||||
QList<int> foundID;
|
||||
QList<CANFrame> frameCache;
|
||||
QList<CANFrame> sendingBuffer;
|
||||
const QVector<CANFrame> *modelFrames;
|
||||
int currentPosition;
|
||||
QTimer *playbackTimer;
|
||||
bool playbackActive;
|
||||
bool playbackForward;
|
||||
int whichBusSend;
|
||||
QList<SequenceItem> seqItems;
|
||||
SequenceItem *currentSeqItem;
|
||||
int currentSeqNum;
|
||||
FramePlaybackObject playbackObject;
|
||||
bool forward;
|
||||
bool isPlaying;
|
||||
int currentPosition;
|
||||
|
||||
void refreshIDList();
|
||||
void updateFrameLabel();
|
||||
void updatePosition(bool forward);
|
||||
void fillIDHash(SequenceItem &item);
|
||||
void showEvent(QShowEvent *);
|
||||
void closeEvent(QCloseEvent *event);
|
||||
void readSettings();
|
||||
void writeSettings();
|
||||
void calculateWhichBus();
|
||||
};
|
||||
|
||||
#endif // FRAMEPLAYBACKWINDOW_H
|
||||
|
||||
+16
-70
@@ -25,6 +25,9 @@
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableView" name="tableConnections">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
@@ -35,13 +38,6 @@
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnNewConn">
|
||||
<property name="text">
|
||||
<string>New Connection</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnRemoveBus">
|
||||
<property name="text">
|
||||
@@ -49,10 +45,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnActivateAll">
|
||||
<property name="text">
|
||||
@@ -193,45 +185,6 @@
|
||||
</widget>
|
||||
</widget>
|
||||
</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>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
@@ -241,15 +194,21 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnRevert">
|
||||
<property name="text">
|
||||
<string>Revert</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</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">
|
||||
<widget class="QCheckBox" name="ckEnableConsole">
|
||||
<property name="text">
|
||||
@@ -319,19 +278,6 @@
|
||||
</item>
|
||||
</layout>
|
||||
</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>
|
||||
</item>
|
||||
</layout>
|
||||
|
||||
@@ -100,6 +100,13 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbOriginalTiming">
|
||||
<property name="text">
|
||||
<string>Use original frame timing from captured frames</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
|
||||
Reference in New Issue
Block a user