diff --git a/config.h b/config.h index 2c04f17..5ec9b26 100644 --- a/config.h +++ b/config.h @@ -1,12 +1,12 @@ #ifndef CONFIG #define CONFIG -#define VERSION 132 +#define VERSION 133 //try to keep this in sync. //SavvyCAN will complain if you connect a GVRET board with a revision //less than this number. -#define CURRENT_GVRET_VER 322 +#define CURRENT_GVRET_VER 323 #endif // CONFIG diff --git a/framesenderwindow.cpp b/framesenderwindow.cpp index 781ffe6..817838e 100644 --- a/framesenderwindow.cpp +++ b/framesenderwindow.cpp @@ -2,6 +2,17 @@ #include "ui_framesenderwindow.h" #include "utility.h" +#include +#include +#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 *frames, QWidget *parent) : QDialog(parent), ui(new Ui::FrameSenderWindow) @@ -16,35 +27,295 @@ FrameSenderWindow::FrameSenderWindow(const QVector *frames, QWidget *p QStringList headers; headers << "En" << "Bus" << "ID" << "Len" << "Data" << "Trigger" << "Modifications" << "Count"; ui->tableSender->setColumnCount(8); - ui->tableSender->setColumnWidth(0, 40); - ui->tableSender->setColumnWidth(1, 40); - ui->tableSender->setColumnWidth(2, 40); - ui->tableSender->setColumnWidth(3, 40); - ui->tableSender->setColumnWidth(4, 200); - ui->tableSender->setColumnWidth(5, 200); - ui->tableSender->setColumnWidth(6, 200); + ui->tableSender->setColumnWidth(0, 50); + ui->tableSender->setColumnWidth(1, 50); + ui->tableSender->setColumnWidth(2, 50); + ui->tableSender->setColumnWidth(3, 50); + ui->tableSender->setColumnWidth(4, 220); + ui->tableSender->setColumnWidth(5, 220); + ui->tableSender->setColumnWidth(6, 220); ui->tableSender->setColumnWidth(7, 80); ui->tableSender->setHorizontalHeaderLabels(headers); - ui->tableSender->insertRow(0); + createBlankRow(); 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() { delete ui; - intervalTimer->stop(); + intervalTimer->stop(); 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 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) { + if (inhibitChanged) return; + qDebug() << "onCellChanged"; if (row == ui->tableSender->rowCount() - 1) { - ui->tableSender->insertRow(ui->tableSender->rowCount()); + createBlankRow(); } + + processCellChange(row, col); } /// @@ -54,29 +325,33 @@ void FrameSenderWindow::onCellChanged(int row, int col) /// void FrameSenderWindow::handleTick() { - FrameSendData sendData; - Trigger trigger; - Modifier modifier; + FrameSendData *sendData; + Trigger *trigger; + int elapsed = elapsedTimer.restart(); + if (elapsed == 0) elapsed = 1; + //Modifier modifier; for (int i = 0; i < sendingData.count(); i++) { - sendData = sendingData.at(i); - if (!sendData.enabled) continue; //abort any processing on this if it is not enabled. - if (sendData.triggers.count() == 0) return; - for (int j = 0; j < sendData.triggers.count(); j++) + sendData = &sendingData[i]; + if (!sendData->enabled) continue; //abort any processing on this if it is not enabled. + if (sendData->triggers.count() == 0) return; + for (int j = 0; j < sendData->triggers.count(); j++) { - trigger = sendData.triggers.at(j); - 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 + 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->readyCount) continue; //don't tick if not ready to tick //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; - sendData.count++; - trigger.currCount++; + trigger->msCounter = 0; + sendData->count++; + trigger->currCount++; doModifiers(i); - //updateGridRow(i); - //parent.SendCANFrame(sendingData[i], sendingData[i].bus); - if (trigger.ID > 0) trigger.readyCount = false; //reset flag if this is a timed ID trigger + updateGridRow(i); + qDebug() << "About to try to send a frame"; + 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 first=0, second=0; - FrameSendData sendData = sendingData.at(idx); - Modifier mod; + FrameSendData *sendData = &sendingData[idx]; + Modifier *mod; 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); - for (int j = 0; j < mod.operations.count(); j++) + mod = &sendData->modifiers[i]; + for (int j = 0; j < mod->operations.count(); j++) { - op = mod.operations.at(j); + op = mod->operations.at(j); if (op.first.ID == -1) { first = shadowReg; @@ -135,7 +412,7 @@ void FrameSenderWindow::doModifiers(int idx) } } //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) /// CANFrame* FrameSenderWindow::lookupFrame(int ID, int bus) { - CANFrame frame; - for (int a = 0; a < frameCache.count(); a++) - { - frame = frameCache.at(a); - if ((ID == frame.ID) && ((bus == frame.bus) || bus == -1)) - { - return &frame; - } - } + if (!frameCache.contains(ID)) return NULL; + + if (bus == -1 || frameCache[ID].bus == bus) return &frameCache[ID]; + return NULL; } @@ -188,6 +460,7 @@ CANFrame* FrameSenderWindow::lookupFrame(int ID, int bus) /// void FrameSenderWindow::processModifierText(int line) { + qDebug() << "processModifierText"; QString modString; int numOps; @@ -266,6 +539,7 @@ void FrameSenderWindow::processModifierText(int line) void FrameSenderWindow::processTriggerText(int line) { + qDebug() << "processTriggerText"; QString trigger; //Example line: @@ -340,6 +614,7 @@ void FrameSenderWindow::processTriggerText(int line) //Turn a set of tokens into an operand void FrameSenderWindow::parseOperandString(QStringList tokens, ModifierOperand &operand) { + qDebug() << "parseOperandString"; //example string -> bus:0:id:200:d3 operand.bus = -1; @@ -370,6 +645,7 @@ void FrameSenderWindow::parseOperandString(QStringList tokens, ModifierOperand & ModifierOperationType FrameSenderWindow::parseOperation(QString op) { + qDebug() << "parseOperation"; if (op == "+") return ADDITION; if (op == "-") return SUBTRACTION; if (op == "*") return MULTIPLICATION; @@ -382,113 +658,43 @@ ModifierOperationType FrameSenderWindow::parseOperation(QString op) if (op == "XOR") return XOR; return ADDITION; } -//The below is c# code from the old project. It won't run as-is and must be ported to C++/Qt -/* /// -/// Updaet the DataGridView with the newest info from sendingData +/// Update the DataGridView with the newest info from sendingData /// /// -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; - StringBuilder dataString = new StringBuilder(); - dataGridView1.Rows[gridLine].Cells[7].Value = temp.count.ToString(); - for (int i = 0; i < temp.len; i++) + QString dataString; + QTableWidgetItem *item = ui->tableSender->item(gridLine, 7); + 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(temp.data[i].ToString("X2")); - dataString.Append(" "); + dataString.append(Utility::formatNumber(temp->data[i])); + 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); -/// -/// Event callback for reception of canbus frames -/// -/// The frame that came in -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) +void FrameSenderWindow::processCellChange(int line, int col) { + qDebug() << "processCellChange"; FrameSendData tempData; + QStringList tokens; int tempVal; //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(); - sendingData.Add(tempData); + FrameSendData tempData; + tempData.enabled = false; + sendingData.append(tempData); } sendingData[line].count = 0; @@ -496,28 +702,31 @@ private void processCellChange(int line, int col) switch (col) { 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; + qDebug() << "Setting enabled to " << sendingData[line].enabled; break; 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 > 1) tempVal = 1; sendingData[line].bus = tempVal; + qDebug() << "Setting bus to " << tempVal; break; 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 > 0x7FFFFFFF) tempVal = 0x7FFFFFFF; sendingData[line].ID = tempVal; if (sendingData[line].ID <= 0x7FF) sendingData[line].extended = false; else sendingData[line].extended = true; + qDebug() << "setting ID to " << tempVal; break; 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 > 8) tempVal = 8; sendingData[line].len = tempVal; @@ -525,10 +734,10 @@ private void processCellChange(int line, int col) case 4: //Data bytes for (int i = 0; i < 8; i++) sendingData[line].data[i] = 0; - string[] tokens = ((string)dataGridView1.Rows[line].Cells[4].Value).Split(' '); - for (int j = 0; j < tokens.Length; j++) + tokens = ui->tableSender->item(line, 4)->text().split(" "); + 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; 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); - } -} - -*/ diff --git a/framesenderwindow.h b/framesenderwindow.h index ea0db57..e80d585 100644 --- a/framesenderwindow.h +++ b/framesenderwindow.h @@ -3,6 +3,8 @@ #include #include +#include +#include #include "can_structs.h" #include "can_trigger_structs.h" @@ -21,14 +23,26 @@ public: private slots: void onCellChanged(int, int); void handleTick(); + void enableAll(); + void disableAll(); + void clearGrid(); + void saveGrid(); + void loadGrid(); + void updatedFrames(int); + +signals: + void sendCANFrame(const CANFrame *, int); private: Ui::FrameSenderWindow *ui; QList sendingData; - QList frameCache; + QHash frameCache; //hash with frame ID as the key and the most recent frame as the value const QVector *modelFrames; QTimer *intervalTimer; + QElapsedTimer elapsedTimer; + bool inhibitChanged = false; + void createBlankRow(); void doModifiers(int); int fetchOperand(int, ModifierOperand); CANFrame* lookupFrame(int, int); @@ -36,6 +50,12 @@ private: void processTriggerText(int); void parseOperandString(QStringList tokens, ModifierOperand&); 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 diff --git a/framesenderwindow.ui b/framesenderwindow.ui index e5ddf0b..4e027bd 100644 --- a/framesenderwindow.ui +++ b/framesenderwindow.ui @@ -24,21 +24,21 @@ - + Enable All - + Disable All - + Clear Grid @@ -61,14 +61,14 @@ - + Load to Grid - + Save Grid