Much work on custom frame sender window. It is reasonably functional now and tested for timed sending
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
#ifndef CONFIG
|
#ifndef CONFIG
|
||||||
#define CONFIG
|
#define CONFIG
|
||||||
|
|
||||||
#define VERSION 132
|
#define VERSION 133
|
||||||
|
|
||||||
//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
|
||||||
//less than this number.
|
//less than this number.
|
||||||
#define CURRENT_GVRET_VER 322
|
#define CURRENT_GVRET_VER 323
|
||||||
|
|
||||||
#endif // CONFIG
|
#endif // CONFIG
|
||||||
|
|
||||||
|
|||||||
+351
-265
@@ -2,6 +2,17 @@
|
|||||||
#include "ui_framesenderwindow.h"
|
#include "ui_framesenderwindow.h"
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
|
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QDebug>
|
||||||
|
#include "mainwindow.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* notes: need to ensure that you grab pointers when modifying data structures and dont
|
||||||
|
* make copies. Also, check # of ms elapsed since last tick since they don't tend to come in at 1ms
|
||||||
|
* intervals like we asked.
|
||||||
|
* Also, rows default to enabled which is odd because the button state does not reflect that.
|
||||||
|
*/
|
||||||
|
|
||||||
FrameSenderWindow::FrameSenderWindow(const QVector<CANFrame> *frames, QWidget *parent) :
|
FrameSenderWindow::FrameSenderWindow(const QVector<CANFrame> *frames, QWidget *parent) :
|
||||||
QDialog(parent),
|
QDialog(parent),
|
||||||
ui(new Ui::FrameSenderWindow)
|
ui(new Ui::FrameSenderWindow)
|
||||||
@@ -16,19 +27,28 @@ FrameSenderWindow::FrameSenderWindow(const QVector<CANFrame> *frames, QWidget *p
|
|||||||
QStringList headers;
|
QStringList headers;
|
||||||
headers << "En" << "Bus" << "ID" << "Len" << "Data" << "Trigger" << "Modifications" << "Count";
|
headers << "En" << "Bus" << "ID" << "Len" << "Data" << "Trigger" << "Modifications" << "Count";
|
||||||
ui->tableSender->setColumnCount(8);
|
ui->tableSender->setColumnCount(8);
|
||||||
ui->tableSender->setColumnWidth(0, 40);
|
ui->tableSender->setColumnWidth(0, 50);
|
||||||
ui->tableSender->setColumnWidth(1, 40);
|
ui->tableSender->setColumnWidth(1, 50);
|
||||||
ui->tableSender->setColumnWidth(2, 40);
|
ui->tableSender->setColumnWidth(2, 50);
|
||||||
ui->tableSender->setColumnWidth(3, 40);
|
ui->tableSender->setColumnWidth(3, 50);
|
||||||
ui->tableSender->setColumnWidth(4, 200);
|
ui->tableSender->setColumnWidth(4, 220);
|
||||||
ui->tableSender->setColumnWidth(5, 200);
|
ui->tableSender->setColumnWidth(5, 220);
|
||||||
ui->tableSender->setColumnWidth(6, 200);
|
ui->tableSender->setColumnWidth(6, 220);
|
||||||
ui->tableSender->setColumnWidth(7, 80);
|
ui->tableSender->setColumnWidth(7, 80);
|
||||||
ui->tableSender->setHorizontalHeaderLabels(headers);
|
ui->tableSender->setHorizontalHeaderLabels(headers);
|
||||||
ui->tableSender->insertRow(0);
|
createBlankRow();
|
||||||
|
|
||||||
connect(ui->tableSender, SIGNAL(cellChanged(int,int)), this, SLOT(onCellChanged(int,int)));
|
connect(ui->tableSender, SIGNAL(cellChanged(int,int)), this, SLOT(onCellChanged(int,int)));
|
||||||
|
connect(intervalTimer, SIGNAL(timeout()), this, SLOT(handleTick()));
|
||||||
|
connect(ui->btnClearGrid, SIGNAL(clicked(bool)), this, SLOT(clearGrid()));
|
||||||
|
connect(ui->btnDisableAll, SIGNAL(clicked(bool)), this, SLOT(disableAll()));
|
||||||
|
connect(ui->btnEnableAll, SIGNAL(clicked(bool)), this, SLOT(enableAll()));
|
||||||
|
connect(ui->btnLoadGrid, SIGNAL(clicked(bool)), this, SLOT(loadGrid()));
|
||||||
|
connect(ui->btnSaveGrid, SIGNAL(clicked(bool)), this, SLOT(saveGrid()));
|
||||||
|
connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int)));
|
||||||
|
|
||||||
|
intervalTimer->start();
|
||||||
|
elapsedTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameSenderWindow::~FrameSenderWindow()
|
FrameSenderWindow::~FrameSenderWindow()
|
||||||
@@ -39,12 +59,263 @@ FrameSenderWindow::~FrameSenderWindow()
|
|||||||
delete intervalTimer;
|
delete intervalTimer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FrameSenderWindow::createBlankRow()
|
||||||
|
{
|
||||||
|
int row = ui->tableSender->rowCount();
|
||||||
|
ui->tableSender->insertRow(row);
|
||||||
|
|
||||||
|
QTableWidgetItem *item = new QTableWidgetItem();
|
||||||
|
item->setFlags(item->flags() |Qt::ItemIsUserCheckable);
|
||||||
|
item->setCheckState(Qt::Unchecked);
|
||||||
|
inhibitChanged = true;
|
||||||
|
ui->tableSender->setItem(row, 0, item);
|
||||||
|
|
||||||
|
for (int i = 1; i < 8; i++)
|
||||||
|
{
|
||||||
|
item = new QTableWidgetItem("");
|
||||||
|
ui->tableSender->setItem(row, i, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
inhibitChanged = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameSenderWindow::buildFrameCache()
|
||||||
|
{
|
||||||
|
CANFrame thisFrame;
|
||||||
|
frameCache.clear();
|
||||||
|
for (int i = 0; i < modelFrames->count(); i++)
|
||||||
|
{
|
||||||
|
thisFrame = modelFrames->at(i);
|
||||||
|
if (!frameCache.contains(thisFrame.ID))
|
||||||
|
{
|
||||||
|
frameCache.insert(thisFrame.ID, thisFrame);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
frameCache[thisFrame.ID] = thisFrame;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//remember, negative numbers are special -1 = all frames deleted, -2 = totally new set of frames.
|
||||||
|
void FrameSenderWindow::updatedFrames(int numFrames)
|
||||||
|
{
|
||||||
|
CANFrame thisFrame;
|
||||||
|
if (numFrames == -1) //all frames deleted.
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else if (numFrames == -2) //all new set of frames.
|
||||||
|
{
|
||||||
|
buildFrameCache();
|
||||||
|
}
|
||||||
|
else //just got some new frames. See if they are relevant.
|
||||||
|
{
|
||||||
|
qDebug() << "New frames in sender window";
|
||||||
|
//run through the supposedly new frames in order
|
||||||
|
for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++)
|
||||||
|
{
|
||||||
|
if (!frameCache.contains(thisFrame.ID))
|
||||||
|
{
|
||||||
|
frameCache.insert(thisFrame.ID, thisFrame);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
frameCache[thisFrame.ID] = thisFrame;
|
||||||
|
}
|
||||||
|
processIncomingFrame(&thisFrame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameSenderWindow::processIncomingFrame(CANFrame *frame)
|
||||||
|
{
|
||||||
|
for (int sd = 0; sd < sendingData.count(); sd++)
|
||||||
|
{
|
||||||
|
if (sendingData[sd].triggers.count() == 0) continue;
|
||||||
|
for (int trig = 0; trig < sendingData[sd].triggers.count(); trig++)
|
||||||
|
{
|
||||||
|
Trigger thisTrigger = sendingData[sd].triggers[trig];
|
||||||
|
if (thisTrigger.ID > 0 && thisTrigger.ID == frame->ID)
|
||||||
|
{
|
||||||
|
if (thisTrigger.bus == frame->bus || thisTrigger.bus == -1)
|
||||||
|
{
|
||||||
|
if (thisTrigger.currCount < thisTrigger.maxCount)
|
||||||
|
{
|
||||||
|
if (thisTrigger.milliseconds == 0) //immediate reply
|
||||||
|
{
|
||||||
|
thisTrigger.currCount++;
|
||||||
|
sendingData[sd].count++;
|
||||||
|
doModifiers(sd);
|
||||||
|
updateGridRow(sd);
|
||||||
|
sendCANFrame(&sendingData[sd], sendingData[sd].bus);
|
||||||
|
}
|
||||||
|
else //delayed sending frame
|
||||||
|
{
|
||||||
|
thisTrigger.readyCount = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameSenderWindow::enableAll()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < ui->tableSender->rowCount() - 1; i++)
|
||||||
|
{
|
||||||
|
ui->tableSender->item(i, 0)->setCheckState(Qt::Checked);
|
||||||
|
sendingData[i].enabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameSenderWindow::disableAll()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < ui->tableSender->rowCount() - 1; i++)
|
||||||
|
{
|
||||||
|
ui->tableSender->item(i, 0)->setCheckState(Qt::Unchecked);
|
||||||
|
sendingData[i].enabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameSenderWindow::clearGrid()
|
||||||
|
{
|
||||||
|
if (ui->tableSender->rowCount() == 1) return;
|
||||||
|
for (int i = ui->tableSender->rowCount() - 2; i >= 0; i--)
|
||||||
|
{
|
||||||
|
sendingData[i].enabled = false;
|
||||||
|
sendingData.removeAt(i);
|
||||||
|
ui->tableSender->removeRow(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameSenderWindow::saveGrid()
|
||||||
|
{
|
||||||
|
QString filename;
|
||||||
|
QFileDialog dialog(this);
|
||||||
|
|
||||||
|
QStringList filters;
|
||||||
|
filters.append(QString(tr("Frame Sender Definition (*.fsd)")));
|
||||||
|
|
||||||
|
dialog.setFileMode(QFileDialog::AnyFile);
|
||||||
|
dialog.setNameFilters(filters);
|
||||||
|
dialog.setViewMode(QFileDialog::Detail);
|
||||||
|
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||||
|
|
||||||
|
if (dialog.exec() == QDialog::Accepted)
|
||||||
|
{
|
||||||
|
filename = dialog.selectedFiles()[0];
|
||||||
|
|
||||||
|
if (dialog.selectedNameFilter() == filters[0])
|
||||||
|
{
|
||||||
|
if (!filename.contains('.')) filename += ".fsd";
|
||||||
|
saveSenderFile(filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameSenderWindow::loadGrid()
|
||||||
|
{
|
||||||
|
QString filename;
|
||||||
|
QFileDialog dialog(this);
|
||||||
|
|
||||||
|
QStringList filters;
|
||||||
|
filters.append(QString(tr("Frame Sender Definition (*.fsd)")));
|
||||||
|
|
||||||
|
dialog.setFileMode(QFileDialog::ExistingFile);
|
||||||
|
dialog.setNameFilters(filters);
|
||||||
|
dialog.setViewMode(QFileDialog::Detail);
|
||||||
|
|
||||||
|
if (dialog.exec() == QDialog::Accepted)
|
||||||
|
{
|
||||||
|
filename = dialog.selectedFiles()[0];
|
||||||
|
|
||||||
|
if (dialog.selectedNameFilter() == filters[0])
|
||||||
|
{
|
||||||
|
loadSenderFile(filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameSenderWindow::saveSenderFile(QString filename)
|
||||||
|
{
|
||||||
|
QFile *outFile = new QFile(filename);
|
||||||
|
QString outString;
|
||||||
|
|
||||||
|
if (!outFile->open(QIODevice::WriteOnly | QIODevice::Text))
|
||||||
|
{
|
||||||
|
delete outFile;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int c = 0; c < sendingData.count(); c++)
|
||||||
|
{
|
||||||
|
outString.clear();
|
||||||
|
if (ui->tableSender->item(c, 0)->checkState() == Qt::Checked)
|
||||||
|
{
|
||||||
|
outString = "T#";
|
||||||
|
}
|
||||||
|
else outString = "F#";
|
||||||
|
for (int i = 1; i < 7; i++)
|
||||||
|
{
|
||||||
|
outString.append(ui->tableSender->item(c, i)->text());
|
||||||
|
outString.append("#");
|
||||||
|
}
|
||||||
|
outString.append("\n");
|
||||||
|
outFile->write(outString.toUtf8());
|
||||||
|
}
|
||||||
|
|
||||||
|
outFile->close();
|
||||||
|
delete outFile;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameSenderWindow::loadSenderFile(QString filename)
|
||||||
|
{
|
||||||
|
QFile *inFile = new QFile(filename);
|
||||||
|
QByteArray line;
|
||||||
|
|
||||||
|
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
||||||
|
{
|
||||||
|
delete inFile;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->tableSender->clear();
|
||||||
|
sendingData.clear();
|
||||||
|
|
||||||
|
while (!inFile->atEnd()) {
|
||||||
|
line = inFile->readLine().simplified();
|
||||||
|
if (line.length() > 2)
|
||||||
|
{
|
||||||
|
QList<QByteArray> tokens = line.split('#');
|
||||||
|
int row = ui->tableSender->rowCount();
|
||||||
|
ui->tableSender->insertRow(row);
|
||||||
|
ui->tableSender->item(row, 0)->setFlags(Qt::ItemIsUserCheckable);
|
||||||
|
if (tokens[0] == "T")
|
||||||
|
{
|
||||||
|
ui->tableSender->item(row, 0)->setCheckState(Qt::Checked);
|
||||||
|
}
|
||||||
|
else ui->tableSender->item(row, 0)->setCheckState(Qt::Unchecked);
|
||||||
|
for (int i = 0; i < 7; i++) ui->tableSender->item(row, i)->setText(tokens[i]);
|
||||||
|
for (int k = 0; k < 7; k++) processCellChange(row, k);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inFile->close();
|
||||||
|
delete inFile;
|
||||||
|
}
|
||||||
|
|
||||||
void FrameSenderWindow::onCellChanged(int row, int col)
|
void FrameSenderWindow::onCellChanged(int row, int col)
|
||||||
{
|
{
|
||||||
|
if (inhibitChanged) return;
|
||||||
|
qDebug() << "onCellChanged";
|
||||||
if (row == ui->tableSender->rowCount() - 1)
|
if (row == ui->tableSender->rowCount() - 1)
|
||||||
{
|
{
|
||||||
ui->tableSender->insertRow(ui->tableSender->rowCount());
|
createBlankRow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
processCellChange(row, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -54,29 +325,33 @@ void FrameSenderWindow::onCellChanged(int row, int col)
|
|||||||
/// <param name="timerEventArgs"></param>
|
/// <param name="timerEventArgs"></param>
|
||||||
void FrameSenderWindow::handleTick()
|
void FrameSenderWindow::handleTick()
|
||||||
{
|
{
|
||||||
FrameSendData sendData;
|
FrameSendData *sendData;
|
||||||
Trigger trigger;
|
Trigger *trigger;
|
||||||
Modifier modifier;
|
int elapsed = elapsedTimer.restart();
|
||||||
|
if (elapsed == 0) elapsed = 1;
|
||||||
|
//Modifier modifier;
|
||||||
for (int i = 0; i < sendingData.count(); i++)
|
for (int i = 0; i < sendingData.count(); i++)
|
||||||
{
|
{
|
||||||
sendData = sendingData.at(i);
|
sendData = &sendingData[i];
|
||||||
if (!sendData.enabled) continue; //abort any processing on this if it is not enabled.
|
if (!sendData->enabled) continue; //abort any processing on this if it is not enabled.
|
||||||
if (sendData.triggers.count() == 0) return;
|
if (sendData->triggers.count() == 0) return;
|
||||||
for (int j = 0; j < sendData.triggers.count(); j++)
|
for (int j = 0; j < sendData->triggers.count(); j++)
|
||||||
{
|
{
|
||||||
trigger = sendData.triggers.at(j);
|
trigger = &sendData->triggers[j];
|
||||||
if (trigger.currCount >= trigger.maxCount) continue; //don't process if we've sent max frames we were supposed to
|
if (trigger->currCount >= trigger->maxCount) continue; //don't process if we've sent max frames we were supposed to
|
||||||
if (!trigger.readyCount) continue; //don't tick if not ready to tick
|
if (!trigger->readyCount) continue; //don't tick if not ready to tick
|
||||||
//is it time to fire?
|
//is it time to fire?
|
||||||
if (++trigger.msCounter >= trigger.milliseconds)
|
trigger->msCounter += elapsed; //gives proper tracking even if timer doesn't fire as fast as it should
|
||||||
|
if (trigger->msCounter >= trigger->milliseconds)
|
||||||
{
|
{
|
||||||
trigger.msCounter = 0;
|
trigger->msCounter = 0;
|
||||||
sendData.count++;
|
sendData->count++;
|
||||||
trigger.currCount++;
|
trigger->currCount++;
|
||||||
doModifiers(i);
|
doModifiers(i);
|
||||||
//updateGridRow(i);
|
updateGridRow(i);
|
||||||
//parent.SendCANFrame(sendingData[i], sendingData[i].bus);
|
qDebug() << "About to try to send a frame";
|
||||||
if (trigger.ID > 0) trigger.readyCount = false; //reset flag if this is a timed ID trigger
|
emit sendCANFrame(&sendingData[i], sendingData[i].bus);
|
||||||
|
if (trigger->ID > 0) trigger->readyCount = false; //reset flag if this is a timed ID trigger
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -91,18 +366,20 @@ void FrameSenderWindow::doModifiers(int idx)
|
|||||||
int shadowReg = 0; //shadow register we use to accumulate results
|
int shadowReg = 0; //shadow register we use to accumulate results
|
||||||
int first=0, second=0;
|
int first=0, second=0;
|
||||||
|
|
||||||
FrameSendData sendData = sendingData.at(idx);
|
FrameSendData *sendData = &sendingData[idx];
|
||||||
Modifier mod;
|
Modifier *mod;
|
||||||
ModifierOp op;
|
ModifierOp op;
|
||||||
|
|
||||||
if (sendData.modifiers.count() == 0) return; //if no modifiers just leave right now
|
if (sendData->modifiers.count() == 0) return; //if no modifiers just leave right now
|
||||||
|
|
||||||
for (int i = 0; i < sendData.modifiers.count(); i++)
|
qDebug() << "Doin' dem mods son";
|
||||||
|
|
||||||
|
for (int i = 0; i < sendData->modifiers.count(); i++)
|
||||||
{
|
{
|
||||||
mod = sendData.modifiers.at(i);
|
mod = &sendData->modifiers[i];
|
||||||
for (int j = 0; j < mod.operations.count(); j++)
|
for (int j = 0; j < mod->operations.count(); j++)
|
||||||
{
|
{
|
||||||
op = mod.operations.at(j);
|
op = mod->operations.at(j);
|
||||||
if (op.first.ID == -1)
|
if (op.first.ID == -1)
|
||||||
{
|
{
|
||||||
first = shadowReg;
|
first = shadowReg;
|
||||||
@@ -135,7 +412,7 @@ void FrameSenderWindow::doModifiers(int idx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Finally, drop the result into the proper data byte
|
//Finally, drop the result into the proper data byte
|
||||||
mod.destByte = (unsigned char) shadowReg;
|
sendData->data[mod->destByte] = (unsigned char) shadowReg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,15 +446,10 @@ int FrameSenderWindow::fetchOperand(int idx, ModifierOperand op)
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
CANFrame* FrameSenderWindow::lookupFrame(int ID, int bus)
|
CANFrame* FrameSenderWindow::lookupFrame(int ID, int bus)
|
||||||
{
|
{
|
||||||
CANFrame frame;
|
if (!frameCache.contains(ID)) return NULL;
|
||||||
for (int a = 0; a < frameCache.count(); a++)
|
|
||||||
{
|
if (bus == -1 || frameCache[ID].bus == bus) return &frameCache[ID];
|
||||||
frame = frameCache.at(a);
|
|
||||||
if ((ID == frame.ID) && ((bus == frame.bus) || bus == -1))
|
|
||||||
{
|
|
||||||
return &frame;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,6 +460,7 @@ CANFrame* FrameSenderWindow::lookupFrame(int ID, int bus)
|
|||||||
/// <param name="line"></param>
|
/// <param name="line"></param>
|
||||||
void FrameSenderWindow::processModifierText(int line)
|
void FrameSenderWindow::processModifierText(int line)
|
||||||
{
|
{
|
||||||
|
qDebug() << "processModifierText";
|
||||||
QString modString;
|
QString modString;
|
||||||
int numOps;
|
int numOps;
|
||||||
|
|
||||||
@@ -266,6 +539,7 @@ void FrameSenderWindow::processModifierText(int line)
|
|||||||
|
|
||||||
void FrameSenderWindow::processTriggerText(int line)
|
void FrameSenderWindow::processTriggerText(int line)
|
||||||
{
|
{
|
||||||
|
qDebug() << "processTriggerText";
|
||||||
QString trigger;
|
QString trigger;
|
||||||
|
|
||||||
//Example line:
|
//Example line:
|
||||||
@@ -340,6 +614,7 @@ void FrameSenderWindow::processTriggerText(int line)
|
|||||||
//Turn a set of tokens into an operand
|
//Turn a set of tokens into an operand
|
||||||
void FrameSenderWindow::parseOperandString(QStringList tokens, ModifierOperand &operand)
|
void FrameSenderWindow::parseOperandString(QStringList tokens, ModifierOperand &operand)
|
||||||
{
|
{
|
||||||
|
qDebug() << "parseOperandString";
|
||||||
//example string -> bus:0:id:200:d3
|
//example string -> bus:0:id:200:d3
|
||||||
|
|
||||||
operand.bus = -1;
|
operand.bus = -1;
|
||||||
@@ -370,6 +645,7 @@ void FrameSenderWindow::parseOperandString(QStringList tokens, ModifierOperand &
|
|||||||
|
|
||||||
ModifierOperationType FrameSenderWindow::parseOperation(QString op)
|
ModifierOperationType FrameSenderWindow::parseOperation(QString op)
|
||||||
{
|
{
|
||||||
|
qDebug() << "parseOperation";
|
||||||
if (op == "+") return ADDITION;
|
if (op == "+") return ADDITION;
|
||||||
if (op == "-") return SUBTRACTION;
|
if (op == "-") return SUBTRACTION;
|
||||||
if (op == "*") return MULTIPLICATION;
|
if (op == "*") return MULTIPLICATION;
|
||||||
@@ -382,113 +658,43 @@ ModifierOperationType FrameSenderWindow::parseOperation(QString op)
|
|||||||
if (op == "XOR") return XOR;
|
if (op == "XOR") return XOR;
|
||||||
return ADDITION;
|
return ADDITION;
|
||||||
}
|
}
|
||||||
//The below is c# code from the old project. It won't run as-is and must be ported to C++/Qt
|
|
||||||
|
|
||||||
/*
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updaet the DataGridView with the newest info from sendingData
|
/// Update the DataGridView with the newest info from sendingData
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="idx"></param>
|
/// <param name="idx"></param>
|
||||||
private void updateGridRow(int idx)
|
void FrameSenderWindow::updateGridRow(int idx)
|
||||||
{
|
{
|
||||||
FrameSendData temp = sendingData[idx];
|
qDebug() << "updateGridRow";
|
||||||
|
inhibitChanged = true;
|
||||||
|
FrameSendData *temp = &sendingData[idx];
|
||||||
int gridLine = idx;
|
int gridLine = idx;
|
||||||
StringBuilder dataString = new StringBuilder();
|
QString dataString;
|
||||||
dataGridView1.Rows[gridLine].Cells[7].Value = temp.count.ToString();
|
QTableWidgetItem *item = ui->tableSender->item(gridLine, 7);
|
||||||
for (int i = 0; i < temp.len; i++)
|
if (item == NULL) item = new QTableWidgetItem();
|
||||||
|
item->setText(QString::number(temp->count));
|
||||||
|
for (int i = 0; i < temp->len; i++)
|
||||||
{
|
{
|
||||||
dataString.Append("0x");
|
dataString.append(Utility::formatNumber(temp->data[i]));
|
||||||
dataString.Append(temp.data[i].ToString("X2"));
|
dataString.append(" ");
|
||||||
dataString.Append(" ");
|
|
||||||
}
|
}
|
||||||
dataGridView1.Rows[gridLine].Cells[4].Value = dataString.ToString();
|
ui->tableSender->item(gridLine, 4)->setText(dataString);
|
||||||
|
inhibitChanged = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public delegate void GotCANDelegate(CANFrame frame);
|
void FrameSenderWindow::processCellChange(int line, int col)
|
||||||
/// <summary>
|
|
||||||
/// Event callback for reception of canbus frames
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="frame">The frame that came in</param>
|
|
||||||
public void GotCANFrame(CANFrame frame)
|
|
||||||
{
|
|
||||||
if (this.InvokeRequired)
|
|
||||||
{
|
|
||||||
this.Invoke(new GotCANDelegate(GotCANFrame), frame);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//search list of frames and add if no frame with this ID is found
|
|
||||||
//or update if one was found.
|
|
||||||
bool found = false;
|
|
||||||
for (int a = 0; a < frames.Count; a++)
|
|
||||||
{
|
|
||||||
if ((frame.ID == frames[a].ID) && (frame.bus == frames[a].bus))
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
frames[a].len = frame.len;
|
|
||||||
frames[a].data = frame.data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found)
|
|
||||||
{
|
|
||||||
frames.Add(frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
//now that frame cache has been updated, try to see if this incoming frame
|
|
||||||
//satisfies any triggers
|
|
||||||
|
|
||||||
for (int b = 0; b < sendingData.Count; b++)
|
|
||||||
{
|
|
||||||
if (sendingData[b].triggers == null) continue;
|
|
||||||
for (int c = 0; c < sendingData[b].triggers.Length; c++)
|
|
||||||
{
|
|
||||||
Trigger thisTrigger = sendingData[b].triggers[c];
|
|
||||||
if (thisTrigger.ID > 0)
|
|
||||||
{
|
|
||||||
if ((thisTrigger.bus == frame.bus) || (thisTrigger.bus == -1))
|
|
||||||
{
|
|
||||||
if (thisTrigger.ID == frame.ID)
|
|
||||||
{
|
|
||||||
//seems to match this trigger.
|
|
||||||
if (thisTrigger.currCount < thisTrigger.maxCount)
|
|
||||||
{
|
|
||||||
if (thisTrigger.milliseconds == 0) //don't want to time the frame, send it right away
|
|
||||||
{
|
|
||||||
sendingData[b].triggers[c].currCount++;
|
|
||||||
sendingData[b].count++;
|
|
||||||
doModifiers(b);
|
|
||||||
updateGridRow(b);
|
|
||||||
parent.SendCANFrame(sendingData[b], sendingData[b].bus);
|
|
||||||
}
|
|
||||||
else //instead of immediate sending we start the timer
|
|
||||||
{
|
|
||||||
sendingData[b].triggers[c].readyCount = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void dataGridView1_RowsRemoved(object sender, DataGridViewRowsRemovedEventArgs e)
|
|
||||||
{
|
|
||||||
int rec = e.RowIndex;
|
|
||||||
if (rec != -1) sendingData.RemoveAt(rec);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processCellChange(int line, int col)
|
|
||||||
{
|
{
|
||||||
|
qDebug() << "processCellChange";
|
||||||
FrameSendData tempData;
|
FrameSendData tempData;
|
||||||
|
QStringList tokens;
|
||||||
int tempVal;
|
int tempVal;
|
||||||
|
|
||||||
//if this is a new line then create the base object for the line
|
//if this is a new line then create the base object for the line
|
||||||
if ((line >= sendingData.Count) || (sendingData[line] == null))
|
if (line >= sendingData.count())
|
||||||
{
|
{
|
||||||
tempData = new FrameSendData();
|
FrameSendData tempData;
|
||||||
sendingData.Add(tempData);
|
tempData.enabled = false;
|
||||||
|
sendingData.append(tempData);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendingData[line].count = 0;
|
sendingData[line].count = 0;
|
||||||
@@ -496,28 +702,31 @@ private void processCellChange(int line, int col)
|
|||||||
switch (col)
|
switch (col)
|
||||||
{
|
{
|
||||||
case 0: //Enable check box
|
case 0: //Enable check box
|
||||||
if (dataGridView1.Rows[line].Cells[0].Value != null)
|
if (ui->tableSender->item(line, 0)->checkState() == Qt::Checked)
|
||||||
{
|
{
|
||||||
sendingData[line].enabled = (bool)dataGridView1.Rows[line].Cells[0].Value;
|
sendingData[line].enabled = true;
|
||||||
}
|
}
|
||||||
else sendingData[line].enabled = false;
|
else sendingData[line].enabled = false;
|
||||||
|
qDebug() << "Setting enabled to " << sendingData[line].enabled;
|
||||||
break;
|
break;
|
||||||
case 1: //Bus designation
|
case 1: //Bus designation
|
||||||
tempVal = Utility.ParseStringToNum((string)dataGridView1.Rows[line].Cells[1].Value);
|
tempVal = Utility::ParseStringToNum(ui->tableSender->item(line, 1)->text());
|
||||||
if (tempVal < 0) tempVal = 0;
|
if (tempVal < 0) tempVal = 0;
|
||||||
if (tempVal > 1) tempVal = 1;
|
if (tempVal > 1) tempVal = 1;
|
||||||
sendingData[line].bus = tempVal;
|
sendingData[line].bus = tempVal;
|
||||||
|
qDebug() << "Setting bus to " << tempVal;
|
||||||
break;
|
break;
|
||||||
case 2: //ID field
|
case 2: //ID field
|
||||||
tempVal = Utility.ParseStringToNum((string)dataGridView1.Rows[line].Cells[2].Value);
|
tempVal = Utility::ParseStringToNum(ui->tableSender->item(line, 2)->text());
|
||||||
if (tempVal < 1) tempVal = 1;
|
if (tempVal < 1) tempVal = 1;
|
||||||
if (tempVal > 0x7FFFFFFF) tempVal = 0x7FFFFFFF;
|
if (tempVal > 0x7FFFFFFF) tempVal = 0x7FFFFFFF;
|
||||||
sendingData[line].ID = tempVal;
|
sendingData[line].ID = tempVal;
|
||||||
if (sendingData[line].ID <= 0x7FF) sendingData[line].extended = false;
|
if (sendingData[line].ID <= 0x7FF) sendingData[line].extended = false;
|
||||||
else sendingData[line].extended = true;
|
else sendingData[line].extended = true;
|
||||||
|
qDebug() << "setting ID to " << tempVal;
|
||||||
break;
|
break;
|
||||||
case 3: //length field
|
case 3: //length field
|
||||||
tempVal = Utility.ParseStringToNum((string)dataGridView1.Rows[line].Cells[3].Value);
|
tempVal = Utility::ParseStringToNum(ui->tableSender->item(line, 3)->text());
|
||||||
if (tempVal < 0) tempVal = 0;
|
if (tempVal < 0) tempVal = 0;
|
||||||
if (tempVal > 8) tempVal = 8;
|
if (tempVal > 8) tempVal = 8;
|
||||||
sendingData[line].len = tempVal;
|
sendingData[line].len = tempVal;
|
||||||
@@ -525,10 +734,10 @@ private void processCellChange(int line, int col)
|
|||||||
case 4: //Data bytes
|
case 4: //Data bytes
|
||||||
for (int i = 0; i < 8; i++) sendingData[line].data[i] = 0;
|
for (int i = 0; i < 8; i++) sendingData[line].data[i] = 0;
|
||||||
|
|
||||||
string[] tokens = ((string)dataGridView1.Rows[line].Cells[4].Value).Split(' ');
|
tokens = ui->tableSender->item(line, 4)->text().split(" ");
|
||||||
for (int j = 0; j < tokens.Length; j++)
|
for (int j = 0; j < tokens.count(); j++)
|
||||||
{
|
{
|
||||||
sendingData[line].data[j] = (byte)Utility.ParseStringToNum(tokens[j]);
|
sendingData[line].data[j] = (uint8_t)Utility::ParseStringToNum(tokens[j]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 5: //triggers
|
case 5: //triggers
|
||||||
@@ -540,126 +749,3 @@ private void processCellChange(int line, int col)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
|
|
||||||
{
|
|
||||||
processCellChange(e.RowIndex, e.ColumnIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadFromFileToolStripMenuItem_Click(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
DialogResult res;
|
|
||||||
//First zap all existing data. Ask first. Might not need to actually ask here since you can abort the file open
|
|
||||||
//and be OK that way too.
|
|
||||||
if (sendingData.Count > 0)
|
|
||||||
{
|
|
||||||
res = MessageBox.Show("Proceding will erase the current\ncontents of the grid.", "Warning", MessageBoxButtons.YesNo);
|
|
||||||
if (res == DialogResult.No) return;
|
|
||||||
}
|
|
||||||
res = openFileDialog1.ShowDialog();
|
|
||||||
if (res == DialogResult.OK)
|
|
||||||
{
|
|
||||||
sendingData.Clear();
|
|
||||||
dataGridView1.Rows.Clear();
|
|
||||||
Stream inputFile = openFileDialog1.OpenFile();
|
|
||||||
StreamReader inputReader = new StreamReader(inputFile);
|
|
||||||
string line;
|
|
||||||
int row;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
while (!inputReader.EndOfStream)
|
|
||||||
{
|
|
||||||
line = inputReader.ReadLine();
|
|
||||||
string[] tokens = line.Split('#');
|
|
||||||
row = dataGridView1.Rows.Add();
|
|
||||||
if (tokens[0] == "T")
|
|
||||||
{
|
|
||||||
dataGridView1.Rows[row].Cells[0].Value = true;
|
|
||||||
}
|
|
||||||
else dataGridView1.Rows[row].Cells[0].Value = false;
|
|
||||||
for (int j = 1; j < 7; j++)
|
|
||||||
{
|
|
||||||
dataGridView1.Rows[row].Cells[j].Value = tokens[j];
|
|
||||||
}
|
|
||||||
for (int k = 0; k < 7; k++) processCellChange(row, k);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ee)
|
|
||||||
{
|
|
||||||
Debug.Print(ee.ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void saveGridToolStripMenuItem_Click(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
StringBuilder buildStr = new StringBuilder();
|
|
||||||
DialogResult res;
|
|
||||||
res = saveFileDialog1.ShowDialog();
|
|
||||||
if (res == DialogResult.OK)
|
|
||||||
{
|
|
||||||
Stream outputFile = saveFileDialog1.OpenFile();
|
|
||||||
StreamWriter outputWriter = new StreamWriter(outputFile);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
for (int i = 0; i < sendingData.Count; i++)
|
|
||||||
{
|
|
||||||
buildStr.Clear();
|
|
||||||
if (dataGridView1.Rows[i].Cells[0].Value != null)
|
|
||||||
{
|
|
||||||
if ((bool)dataGridView1.Rows[i].Cells[0].Value == true)
|
|
||||||
{
|
|
||||||
buildStr.Append("T");
|
|
||||||
}
|
|
||||||
else buildStr.Append("F");
|
|
||||||
}
|
|
||||||
else buildStr.Append("F");
|
|
||||||
buildStr.Append("#");
|
|
||||||
for (int j = 1; j < 7; j++)
|
|
||||||
{
|
|
||||||
buildStr.Append(dataGridView1.Rows[i].Cells[j].Value);
|
|
||||||
buildStr.Append("#");
|
|
||||||
}
|
|
||||||
outputWriter.WriteLine(buildStr.ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ee)
|
|
||||||
{
|
|
||||||
Debug.Print(ee.ToString());
|
|
||||||
}
|
|
||||||
outputWriter.Flush();
|
|
||||||
outputWriter.Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Note for the below three functions that they all handle the fact that a data view grid will always have an extra row that is blank
|
|
||||||
//and available for a new record. Because of this the grid count is always one too high.
|
|
||||||
private void button1_Click(object sender, EventArgs e) //enable all lines in the grid
|
|
||||||
{
|
|
||||||
for (int i = 0; i < dataGridView1.Rows.Count - 1; i++)
|
|
||||||
{
|
|
||||||
dataGridView1.Rows[i].Cells[0].Value = true;
|
|
||||||
sendingData[i].enabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void button2_Click(object sender, EventArgs e) //disable all lines in the grid
|
|
||||||
{
|
|
||||||
for (int i = 0; i < dataGridView1.Rows.Count - 1; i++)
|
|
||||||
{
|
|
||||||
dataGridView1.Rows[i].Cells[0].Value = false;
|
|
||||||
sendingData[i].enabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void button3_Click(object sender, EventArgs e) //delete all entries in the grid and data struct
|
|
||||||
{
|
|
||||||
if (dataGridView1.Rows.Count == 1) return;
|
|
||||||
for (int i = dataGridView1.Rows.Count - 2; i >= 0; i--)
|
|
||||||
{
|
|
||||||
sendingData[i].enabled = false;
|
|
||||||
sendingData.RemoveAt(i);
|
|
||||||
dataGridView1.Rows.RemoveAt(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|||||||
+21
-1
@@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <QElapsedTimer>
|
||||||
|
#include <QTime>
|
||||||
#include "can_structs.h"
|
#include "can_structs.h"
|
||||||
#include "can_trigger_structs.h"
|
#include "can_trigger_structs.h"
|
||||||
|
|
||||||
@@ -21,14 +23,26 @@ public:
|
|||||||
private slots:
|
private slots:
|
||||||
void onCellChanged(int, int);
|
void onCellChanged(int, int);
|
||||||
void handleTick();
|
void handleTick();
|
||||||
|
void enableAll();
|
||||||
|
void disableAll();
|
||||||
|
void clearGrid();
|
||||||
|
void saveGrid();
|
||||||
|
void loadGrid();
|
||||||
|
void updatedFrames(int);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void sendCANFrame(const CANFrame *, int);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::FrameSenderWindow *ui;
|
Ui::FrameSenderWindow *ui;
|
||||||
QList<FrameSendData> sendingData;
|
QList<FrameSendData> sendingData;
|
||||||
QList<CANFrame> frameCache;
|
QHash<int, CANFrame> frameCache; //hash with frame ID as the key and the most recent frame as the value
|
||||||
const QVector<CANFrame> *modelFrames;
|
const QVector<CANFrame> *modelFrames;
|
||||||
QTimer *intervalTimer;
|
QTimer *intervalTimer;
|
||||||
|
QElapsedTimer elapsedTimer;
|
||||||
|
bool inhibitChanged = false;
|
||||||
|
|
||||||
|
void createBlankRow();
|
||||||
void doModifiers(int);
|
void doModifiers(int);
|
||||||
int fetchOperand(int, ModifierOperand);
|
int fetchOperand(int, ModifierOperand);
|
||||||
CANFrame* lookupFrame(int, int);
|
CANFrame* lookupFrame(int, int);
|
||||||
@@ -36,6 +50,12 @@ private:
|
|||||||
void processTriggerText(int);
|
void processTriggerText(int);
|
||||||
void parseOperandString(QStringList tokens, ModifierOperand&);
|
void parseOperandString(QStringList tokens, ModifierOperand&);
|
||||||
ModifierOperationType parseOperation(QString);
|
ModifierOperationType parseOperation(QString);
|
||||||
|
void saveSenderFile(QString filename);
|
||||||
|
void loadSenderFile(QString filename);
|
||||||
|
void updateGridRow(int idx);
|
||||||
|
void processCellChange(int line, int col);
|
||||||
|
void buildFrameCache();
|
||||||
|
void processIncomingFrame(CANFrame *frame);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FRAMESENDERWINDOW_H
|
#endif // FRAMESENDERWINDOW_H
|
||||||
|
|||||||
@@ -24,21 +24,21 @@
|
|||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="pushButton_2">
|
<widget class="QPushButton" name="btnEnableAll">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Enable All</string>
|
<string>Enable All</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="pushButton_3">
|
<widget class="QPushButton" name="btnDisableAll">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Disable All</string>
|
<string>Disable All</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="pushButton_5">
|
<widget class="QPushButton" name="btnClearGrid">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Clear Grid</string>
|
<string>Clear Grid</string>
|
||||||
</property>
|
</property>
|
||||||
@@ -61,14 +61,14 @@
|
|||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="pushButton_4">
|
<widget class="QPushButton" name="btnLoadGrid">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Load to Grid</string>
|
<string>Load to Grid</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="pushButton">
|
<widget class="QPushButton" name="btnSaveGrid">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Save Grid</string>
|
<string>Save Grid</string>
|
||||||
</property>
|
</property>
|
||||||
|
|||||||
Reference in New Issue
Block a user