1 #include "canframemodel.h"
2 
3 #include <QFile>
4 #include <QApplication>
5 #include <QPalette>
6 #include <QDateTime>
7 #include "utility.h"
8 
~CANFrameModel()9 CANFrameModel::~CANFrameModel()
10 {
11     frames.clear();
12     filteredFrames.clear();
13     filters.clear();
14     busFilters.clear();
15 }
16 
rowCount(const QModelIndex & parent) const17 int CANFrameModel::rowCount(const QModelIndex &parent) const
18 {
19     Q_UNUSED(parent);
20     if (filteredFrames.data())
21     {
22         int rows = filteredFrames.count();
23         return rows;
24     }
25 
26      //just in case somehow data is invalid which I have seen before.
27     //But, this should not happen so issue a debugging message too
28     qDebug() << "Invalid data for filteredFrames. Returning 0.";
29     return 0;
30 }
31 
totalFrameCount()32 int CANFrameModel::totalFrameCount()
33 {
34     int count;
35     count = frames.count();
36     return count;
37 }
38 
columnCount(const QModelIndex & index) const39 int CANFrameModel::columnCount(const QModelIndex &index) const
40 {
41     Q_UNUSED(index);
42     return (int)Column::NUM_COLUMN;
43 }
44 
CANFrameModel(QObject * parent)45 CANFrameModel::CANFrameModel(QObject *parent)
46     : QAbstractTableModel(parent)
47 {
48 
49     if (QSysInfo::WordSize > 32)
50     {
51         qDebug() << "64 bit OS detected. Requesting a large preallocation";
52         preallocSize = 10000000;
53     }
54     else //if compiling for 32 bit you can't ask for gigabytes of preallocation so tone it down.
55     {
56         qDebug() << "32 bit OS detected. Requesting a much restricted prealloc";
57         preallocSize = 2000000;
58     }
59 
60     frames.reserve(preallocSize);
61     filteredFrames.reserve(preallocSize); //the goal is to prevent a reallocation from ever happening
62 
63     dbcHandler = DBCHandler::getReference();
64     interpretFrames = false;
65     overwriteDups = false;
66     useHexMode = true;
67     timeSeconds = false;
68     timeOffset = 0;
69     needFilterRefresh = false;
70     lastUpdateNumFrames = 0;
71     timeFormat =  "MMM-dd HH:mm:ss.zzz";
72     sortDirAsc = false;
73 }
74 
setHexMode(bool mode)75 void CANFrameModel::setHexMode(bool mode)
76 {
77     if (useHexMode != mode)
78     {
79         this->beginResetModel();
80         useHexMode = mode;
81         Utility::decimalMode = !useHexMode;
82         this->endResetModel();
83     }
84 }
85 
setSecondsMode(bool mode)86 void CANFrameModel::setSecondsMode(bool mode)
87 {
88     if (Utility::secondsMode != mode)
89     {
90         this->beginResetModel();
91         Utility::secondsMode = mode;
92         this->endResetModel();
93     }
94 }
95 
setSysTimeMode(bool mode)96 void CANFrameModel::setSysTimeMode(bool mode)
97 {
98     if (Utility::sysTimeMode != mode)
99     {
100         this->beginResetModel();
101         Utility::sysTimeMode = mode;
102         this->endResetModel();
103     }
104 }
105 
setInterpretMode(bool mode)106 void CANFrameModel::setInterpretMode(bool mode)
107 {
108     //if the state of interpretFrames changes then we need to reset the model
109     //so that QT will refresh the view properly
110     if (interpretFrames != mode)
111     {
112         this->beginResetModel();
113         interpretFrames = mode;
114         this->endResetModel();
115     }
116 }
117 
getInterpretMode()118 bool CANFrameModel::getInterpretMode()
119 {
120     return interpretFrames;
121 }
122 
setTimeFormat(QString format)123 void CANFrameModel::setTimeFormat(QString format)
124 {
125     Utility::timeFormat = format;
126     beginResetModel(); //reset model to show new time format
127     endResetModel();
128 }
129 
130 /*
131  * Scan all frames for the smallest timestamp and offset all timestamps so that smallest one is at 0
132 */
normalizeTiming()133 void CANFrameModel::normalizeTiming()
134 {
135     mutex.lock();
136     if (frames.count() == 0) return;
137     timeOffset = frames[0].timeStamp().microSeconds();
138     qint64 prevStamp = 0;
139 
140     //find the absolute lowest timestamp in the whole time. Needed because maybe timestamp was reset in the middle.
141     for (int j = 0; j < frames.count(); j++)
142     {
143         if (frames[j].timeStamp().microSeconds() < timeOffset) timeOffset = frames[j].timeStamp().microSeconds();
144     }
145 
146     for (int i = 0; i < frames.count(); i++)
147     {
148         qint64 thisStamp = frames[i].timeStamp().microSeconds() - timeOffset;
149         if (thisStamp <= prevStamp)
150         {
151             timeOffset -= prevStamp;
152         }
153         frames[i].setTimeStamp(QCanBusFrame::TimeStamp(0, thisStamp));
154     }
155 
156     this->beginResetModel();
157     for (int i = 0; i < filteredFrames.count(); i++)
158     {
159         filteredFrames[i].setTimeStamp(QCanBusFrame::TimeStamp(0, filteredFrames[i].timeStamp().microSeconds() - timeOffset));
160     }
161     this->endResetModel();
162 
163     mutex.unlock();
164 }
165 
setOverwriteMode(bool mode)166 void CANFrameModel::setOverwriteMode(bool mode)
167 {
168     beginResetModel();
169     overwriteDups = mode;
170     recalcOverwrite();
171     endResetModel();
172 }
173 
setFilterState(unsigned int ID,bool state)174 void CANFrameModel::setFilterState(unsigned int ID, bool state)
175 {
176     if (!filters.contains(ID)) return;
177     filters[ID] = state;
178     sendRefresh();
179 }
180 
setBusFilterState(unsigned int BusID,bool state)181 void CANFrameModel::setBusFilterState(unsigned int BusID, bool state)
182 {
183     if (!busFilters.contains(BusID)) return;
184     busFilters[BusID] = state;
185     sendRefresh();
186 }
187 
setAllFilters(bool state)188 void CANFrameModel::setAllFilters(bool state)
189 {
190     QMap<int, bool>::iterator it;
191     for (it = filters.begin(); it != filters.end(); ++it)
192     {
193         it.value() = state;
194     }
195     sendRefresh();
196 }
197 
198 /*
199  * There is probably a more correct way to have done this but below are several functions that collectively implement
200  * quicksort on the columns and interpret the columns numerically. But, correct or not, this implementation is quite fast
201  * and sorts the columns properly.
202 */
getCANFrameVal(int row,Column col)203 uint64_t CANFrameModel::getCANFrameVal(int row, Column col)
204 {
205     uint64_t temp = 0;
206     if (row >= frames.count()) return 0;
207     CANFrame frame = frames[row];
208     switch (col)
209     {
210     case Column::TimeStamp:
211         if (overwriteDups) return frame.timedelta;
212         return frame.timeStamp().microSeconds();
213     case Column::FrameId:
214         return frame.frameId();
215     case Column::Extended:
216         if (frame.hasExtendedFrameFormat()) return 1;
217         return 0;
218     case Column::Remote:
219         if (overwriteDups) return frame.frameCount;
220         if (frame.frameType() == QCanBusFrame::RemoteRequestFrame) return 1;
221         return 0;
222     case Column::Direction:
223         if (frame.isReceived) return 1;
224         return 0;
225     case Column::Bus:
226         return static_cast<uint64_t>(frame.bus);
227     case Column::Length:
228         return static_cast<uint64_t>(frame.payload().length());
229     case Column::ASCII: //sort both the same for now
230     case Column::Data:
231         for (int i = 0; i < frame.payload().length(); i++) temp += (static_cast<uint64_t>(frame.payload()[i]) << (56 - (8 * i)));
232         //qDebug() << temp;
233         return temp;
234     case Column::NUM_COLUMN:
235         return 0;
236     }
237     return 0;
238 }
239 
qSortCANFrameAsc(QVector<CANFrame> * frames,Column column,int lowerBound,int upperBound)240 void CANFrameModel::qSortCANFrameAsc(QVector<CANFrame> *frames, Column column, int lowerBound, int upperBound)
241 {
242     int p, i, j;
243     qDebug() << "Lower " << lowerBound << " Upper" << upperBound;
244     if (lowerBound < upperBound)
245     {
246         uint64_t piv = getCANFrameVal(lowerBound + (upperBound - lowerBound) / 2, column);
247         i = lowerBound - 1;
248         j = upperBound + 1;
249         for (;;){
250             do {
251                 i++;
252             } while ((i < upperBound) && getCANFrameVal(i, column) < piv);
253 
254             do
255             {
256                 j--;
257             } while ((j > lowerBound) && getCANFrameVal(j, column) > piv);
258             if (i < j) {
259                 CANFrame temp = frames->at(i);
260                 frames->replace(i, frames->at(j));
261                 frames->replace(j, temp);
262             }
263             else {p = j; break;}
264         }
265 
266         qSortCANFrameAsc(frames, column, lowerBound, p);
267         qSortCANFrameAsc(frames, column, p+1, upperBound);
268     }
269 }
270 
qSortCANFrameDesc(QVector<CANFrame> * frames,Column column,int lowerBound,int upperBound)271 void CANFrameModel::qSortCANFrameDesc(QVector<CANFrame> *frames, Column column, int lowerBound, int upperBound)
272 {
273     int p, i, j;
274     qDebug() << "Lower " << lowerBound << " Upper" << upperBound;
275     if (lowerBound < upperBound)
276     {
277         uint64_t piv = getCANFrameVal(lowerBound + (upperBound - lowerBound) / 2, column);
278         i = lowerBound - 1;
279         j = upperBound + 1;
280         for (;;){
281             do {
282                 i++;
283             } while ((i < upperBound) && getCANFrameVal(i, column) > piv);
284 
285             do
286             {
287                 j--;
288             } while ((j > lowerBound) && getCANFrameVal(j, column) < piv);
289             if (i < j) {
290                 CANFrame temp = frames->at(i);
291                 frames->replace(i, frames->at(j));
292                 frames->replace(j, temp);
293             }
294             else {p = j; break;}
295         }
296 
297         qSortCANFrameDesc(frames, column, lowerBound, p);
298         qSortCANFrameDesc(frames, column, p+1, upperBound);
299     }
300 }
301 
sortByColumn(int column)302 void CANFrameModel::sortByColumn(int column)
303 {
304     sortDirAsc = !sortDirAsc;
305     //beginResetModel();
306     if (sortDirAsc) qSortCANFrameAsc(&frames, Column(column), 0, frames.count()-1);
307     else qSortCANFrameDesc(&frames, Column(column), 0, frames.count()-1);
308     //endResetModel();
309     sendRefresh();
310 }
311 
312 //End of custom sorting code
313 
recalcOverwrite()314 void CANFrameModel::recalcOverwrite()
315 {
316     if (!overwriteDups) return; //no need to do a thing if mode is disabled
317 
318     qDebug() << "recalcOverwrite called in model";
319 
320     mutex.lock();
321     beginResetModel();
322 
323     //Look at the current list of frames and turn it into just a list of unique IDs
324     QHash<uint64_t, CANFrame> overWriteFrames;
325     uint64_t idAugmented; //id in lower 29 bits, bus number shifted up 29 bits
326     foreach(CANFrame frame, frames)
327     {
328         if (frame.frameType() != frame.DataFrame) continue;
329 
330         idAugmented = frame.frameId();
331         idAugmented = idAugmented + (frame.bus << 29ull);
332         if (!overWriteFrames.contains(idAugmented))
333         {
334             frame.timedelta = 0;
335             frame.frameCount = 1;
336             overWriteFrames.insert(idAugmented, frame);
337         }
338         else
339         {
340             frame.timedelta = frame.timeStamp().microSeconds() - overWriteFrames[idAugmented].timeStamp().microSeconds();
341             frame.frameCount = overWriteFrames[idAugmented].frameCount + 1;
342             overWriteFrames[idAugmented] = frame;
343         }
344     }
345     //Then replace the old list of frames with just the unique list
346     frames.clear();
347     frames.append(overWriteFrames.values().toVector());
348 
349     filteredFrames.clear();
350     filteredFrames.reserve(preallocSize);
351 
352     for (int i = 0; i < frames.count(); i++)
353     {
354         if (filters[frames[i].frameId()] && busFilters[frames[i].bus])
355         {
356             filteredFrames.append(frames[i]);
357         }
358     }
359 
360     endResetModel();
361     mutex.unlock();
362 }
363 
data(const QModelIndex & index,int role) const364 QVariant CANFrameModel::data(const QModelIndex &index, int role) const
365 {
366     QString tempString;
367     CANFrame thisFrame;
368     static bool rowFlip = false;
369     QVariant ts;
370 
371     if (!index.isValid())
372         return QVariant();
373 
374     if (index.row() >= (filteredFrames.count()))
375         return QVariant();
376 
377     thisFrame = filteredFrames.at(index.row());
378 
379     const unsigned char *data = reinterpret_cast<const unsigned char *>(thisFrame.payload().constData());
380     int dataLen = thisFrame.payload().count();
381 
382     if (role == Qt::BackgroundColorRole)
383     {
384         if (dbcHandler != nullptr && interpretFrames)
385         {
386             DBC_MESSAGE *msg = dbcHandler->findMessage(thisFrame);
387             if (msg != nullptr)
388             {
389                 return msg->bgColor;
390             }
391         }
392         rowFlip = (index.row() % 2);
393         if (rowFlip) return QApplication::palette().color(QPalette::Base);
394         else return QApplication::palette().color(QPalette::AlternateBase);
395     }
396 
397     if (role == Qt::TextAlignmentRole)
398     {
399         switch(Column(index.column()))
400         {
401         case Column::TimeStamp:
402             return Qt::AlignRight;
403         case Column::FrameId:
404         case Column::Direction:
405         case Column::Extended:
406         case Column::Bus:
407         case Column::Remote:
408         case Column::Length:
409             return Qt::AlignHCenter;
410         default:
411             return Qt::AlignLeft;
412         }
413     }
414 
415     if (role == Qt::TextColorRole)
416     {
417         if (dbcHandler != nullptr && interpretFrames)
418         {
419             DBC_MESSAGE *msg = dbcHandler->findMessage(thisFrame);
420             if (msg != nullptr)
421             {
422                 return msg->fgColor;
423             }
424         }
425         return QApplication::palette().color(QPalette::WindowText);
426     }
427 
428     if (role == Qt::DisplayRole) {
429         switch (Column(index.column()))
430         {
431         case Column::TimeStamp:
432             //Reformatting the output a bit with custom code
433             if (overwriteDups)
434             {
435                 if (timeSeconds) return QString::number(thisFrame.timedelta / 1000000.0, 'f', 5);
436                 return QString::number(thisFrame.timedelta);
437             }
438             else ts = Utility::formatTimestamp(thisFrame.timeStamp().microSeconds());
439             if (ts.type() == QVariant::Double) return QString::number(ts.toDouble(), 'f', 5); //never scientific notation, 5 decimal places
440             if (ts.type() == QVariant::LongLong) return QString::number(ts.toLongLong()); //never scientific notion, all digits shown
441             if (ts.type() == QVariant::DateTime) return ts.toDateTime().toString(timeFormat); //custom set format for dates and times
442             return Utility::formatTimestamp(thisFrame.timeStamp().microSeconds());
443         case Column::FrameId:
444             return Utility::formatCANID(thisFrame.frameId(), thisFrame.hasExtendedFrameFormat());
445         case Column::Extended:
446             return QString::number(thisFrame.hasExtendedFrameFormat());
447         case Column::Remote:
448             if (!overwriteDups) return QString::number(thisFrame.frameType() == QCanBusFrame::RemoteRequestFrame);
449             return QString::number(thisFrame.frameCount);
450         case Column::Direction:
451             if (thisFrame.isReceived) return QString(tr("Rx"));
452             return QString(tr("Tx"));
453         case Column::Bus:
454             return QString::number(thisFrame.bus);
455         case Column::Length:
456             return QString::number(dataLen);
457         case Column::ASCII:
458             if (thisFrame.frameId() >= 0x7FFFFFF0ull)
459             {
460                 tempString.append("MARK ");
461                 tempString.append(QString::number(thisFrame.frameId() & 0x7));
462                 return tempString;
463             }
464             if (thisFrame.frameType() == QCanBusFrame::DataFrame) {
465                 if (dataLen < 0) dataLen = 0;
466                 //if (dLen > 8) dLen = 8;
467                 for (int i = 0; i < dataLen; i++)
468                 {
469                     char byt = thisFrame.payload()[i];
470                     //0x20 through 0x7E are printable characters. Outside of that range they aren't. So use dots instead
471                     if (byt < 0x20) byt = 0x2E; //dot character
472                     if (byt > 0x7E) byt = 0x2E;
473                     tempString.append(QString::fromUtf8(&byt, 1));
474                 }
475             }
476             if (thisFrame.frameType() == QCanBusFrame::ErrorFrame)
477             {
478                  tempString = "ERROR";
479             }
480             return tempString;
481         case Column::Data:
482             if (dataLen < 0) dataLen = 0;
483             //if (useHexMode) tempString.append("0x ");
484             if (thisFrame.frameType() == QCanBusFrame::RemoteRequestFrame) {
485                 return tempString;
486             }
487             for (int i = 0; i < dataLen; i++)
488             {
489                 if (useHexMode) tempString.append( QString::number(data[i], 16).toUpper().rightJustified(2, '0'));
490                 else tempString.append(QString::number(data[i], 10));
491                 tempString.append(" ");
492             }
493             if (thisFrame.frameType() == thisFrame.ErrorFrame)
494             {
495                 if (thisFrame.error() & thisFrame.TransmissionTimeoutError) tempString.append("\nTX Timeout");
496                 if (thisFrame.error() & thisFrame.LostArbitrationError) tempString.append("\nLost Arbitration");
497                 if (thisFrame.error() & thisFrame.ControllerError) tempString.append("\nController Error");
498                 if (thisFrame.error() & thisFrame.ProtocolViolationError) tempString.append("\nProtocol Violation");
499                 if (thisFrame.error() & thisFrame.TransceiverError) tempString.append("\nTransceiver Error");
500                 if (thisFrame.error() & thisFrame.MissingAcknowledgmentError) tempString.append("\nMissing ACK");
501                 if (thisFrame.error() & thisFrame.BusOffError) tempString.append("\nBus OFF");
502                 if (thisFrame.error() & thisFrame.BusError) tempString.append("\nBus ERR");
503                 if (thisFrame.error() & thisFrame.ControllerRestartError) tempString.append("\nController restart err");
504                 if (thisFrame.error() & thisFrame.UnknownError) tempString.append("\nUnknown error type");
505             }
506             //TODO: technically the actual returned bytes for an error frame encode some more info. Not interpreting it yet.
507 
508             //now, if we're supposed to interpret the data and the DBC handler is loaded then use it
509             if ( (dbcHandler != nullptr) && interpretFrames && (thisFrame.frameType() == thisFrame.DataFrame) )
510             {
511                 DBC_MESSAGE *msg = dbcHandler->findMessage(thisFrame);
512                 if (msg != nullptr)
513                 {
514                     tempString.append("   <" + msg->name + ">\n");
515                     if (msg->comment.length() > 1) tempString.append(msg->comment + "\n");
516                     for (int j = 0; j < msg->sigHandler->getCount(); j++)
517                     {
518                         QString sigString;
519                         DBC_SIGNAL* sig = msg->sigHandler->findSignalByIdx(j);
520 
521                         if ( (sig->multiplexParent == nullptr) && sig->processAsText(thisFrame, sigString))
522                         {
523                             tempString.append(sigString);
524                             tempString.append("\n");
525                             if (sig->isMultiplexor)
526                             {
527                                 qDebug() << "Multiplexor. Diving into the tree";
528                                 tempString.append(sig->processSignalTree(thisFrame));
529                             }
530                         }
531                         else if (sig->isMultiplexed && overwriteDups) //wasn't in this exact frame but is in the message. Use cached value
532                         {
533                             bool isInteger = false;
534                             if (sig->valType == UNSIGNED_INT || sig->valType == SIGNED_INT) isInteger = true;
535                             tempString.append(sig->makePrettyOutput(sig->cachedValue.toDouble(), sig->cachedValue.toLongLong(), true, isInteger));
536                             tempString.append("\n");
537                         }
538                     }
539                 }
540             }
541             return tempString;
542         default:
543             return tempString;
544         }
545     }
546 
547     return QVariant();
548 }
549 
headerData(int section,Qt::Orientation orientation,int role) const550 QVariant CANFrameModel::headerData(int section, Qt::Orientation orientation,
551                                      int role) const
552 {
553     if (role != Qt::DisplayRole)
554         return QVariant();
555 
556     if (orientation == Qt::Horizontal)
557     {
558         switch (Column(section))
559         {
560         case Column::TimeStamp:
561             if (overwriteDups) return QString(tr("Time Delta"));
562             return QString(tr("Timestamp"));
563         case Column::FrameId:
564             return QString(tr("ID"));
565         case Column::Extended:
566             return QString(tr("Ext"));
567         case Column::Remote:
568             if (!overwriteDups) return QString(tr("RTR"));
569             return QString(tr("Cnt"));
570         case Column::Direction:
571             return QString(tr("Dir"));
572         case Column::Bus:
573             return QString(tr("Bus"));
574         case Column::Length:
575             return QString(tr("Len"));
576         case Column::ASCII:
577             return QString(tr("ASCII"));
578         case Column::Data:
579             return QString(tr("Data"));
580         default:
581             return QString("");
582         }
583     }
584 
585     else
586         return QString::number(section + 1);
587 
588     return QVariant();
589 }
590 
any_filters_are_configured(void)591 bool CANFrameModel::any_filters_are_configured(void)
592 {
593     for (auto const &val : filters)
594     {
595         if (val == true)
596             continue;
597         else
598             return true;
599     }
600     return false;
601 }
602 
any_busfilters_are_configured(void)603 bool CANFrameModel::any_busfilters_are_configured(void)
604 {
605     for (auto const &val : busFilters)
606     {
607         if (val == true)
608             continue;
609         else
610             return true;
611     }
612     return false;
613 }
614 
615 
addFrame(const CANFrame & frame,bool autoRefresh=false)616 void CANFrameModel::addFrame(const CANFrame& frame, bool autoRefresh = false)
617 {
618     /*TODO: remove mutex */
619     mutex.lock();
620     CANFrame tempFrame;
621     tempFrame = frame;
622 
623     tempFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, tempFrame.timeStamp().microSeconds() - timeOffset));
624 
625     lastUpdateNumFrames++;
626 
627     //if this ID isn't found in the filters list then add it and show it by default
628     if (!filters.contains(tempFrame.frameId()))
629     {
630         // if there are any filters already configured, leave the new filter disabled
631         if (any_filters_are_configured())
632             filters.insert(tempFrame.frameId(), false);
633         else
634             filters.insert(tempFrame.frameId(), true);
635         needFilterRefresh = true;
636     }
637 
638     //if this BusID isn't found in the busFilters list then add it and show it by default
639     if (!busFilters.contains(tempFrame.bus))
640     {
641         // if there are any busFilters already configured, leave the new filter disabled
642         if (any_busfilters_are_configured())
643             busFilters.insert(tempFrame.bus, false);
644         else
645             busFilters.insert(tempFrame.bus, true);
646         needFilterRefresh = true;
647     }
648 
649     if (!overwriteDups)
650     {
651         frames.append(tempFrame);
652         if (filters[tempFrame.frameId()] && busFilters[tempFrame.bus])
653         {
654             if (autoRefresh) beginInsertRows(QModelIndex(), filteredFrames.count(), filteredFrames.count());
655             tempFrame.frameCount = 1;
656             filteredFrames.append(tempFrame);
657             if (autoRefresh) endInsertRows();
658         }
659     }
660     else //yes, overwrite dups
661     {
662         bool found = false;
663         for (int i = 0; i < frames.count(); i++)
664         {
665             if ( (frames[i].frameId() == tempFrame.frameId()) && (frames[i].bus == tempFrame.bus) )
666             {
667                 tempFrame.frameCount = frames[i].frameCount + 1;
668                 tempFrame.timedelta = tempFrame.timeStamp().microSeconds() - frames[i].timeStamp().microSeconds();
669                 frames.replace(i, tempFrame);
670                 found = true;
671                 break;
672             }
673         }
674         if (!found)
675         {
676             frames.append(tempFrame);
677             if (filters[tempFrame.frameId()] && busFilters[tempFrame.bus])
678             {
679                 if (autoRefresh) beginInsertRows(QModelIndex(), filteredFrames.count(), filteredFrames.count());
680                 tempFrame.frameCount = 1;
681                 tempFrame.timedelta = 0;
682                 filteredFrames.append(tempFrame);
683                 if (autoRefresh) endInsertRows();
684             }
685         }
686         else
687         {
688             for (int j = 0; j < filteredFrames.count(); j++)
689             {
690                 if ( (filteredFrames[j].frameId() == tempFrame.frameId()) && (filteredFrames[j].bus == tempFrame.bus) )
691                 {
692                     if (autoRefresh) beginResetModel();
693                     filteredFrames.replace(j, tempFrame);
694                     if (autoRefresh) endResetModel();
695                 }
696             }
697         }
698     }
699 
700     mutex.unlock();
701 }
702 
703 
addFrames(const CANConnection *,const QVector<CANFrame> & pFrames)704 void CANFrameModel::addFrames(const CANConnection*, const QVector<CANFrame>& pFrames)
705 {
706     foreach(const CANFrame& frame, pFrames)
707     {
708         addFrame(frame);
709     }
710     if (overwriteDups) //if in overwrite mode we'll update every time frames come in
711     {
712         beginResetModel();
713         endResetModel();
714     }
715 }
716 
sendRefresh()717 void CANFrameModel::sendRefresh()
718 {
719     qDebug() << "Sending mass refresh";
720     QVector<CANFrame> tempContainer;
721     int count = frames.count();
722     for (int i = 0; i < count; i++)
723     {
724         if (filters[frames[i].frameId()] && busFilters[frames[i].bus])
725         {
726             tempContainer.append(frames[i]);
727         }
728     }
729     mutex.lock();
730     beginResetModel();
731     filteredFrames.clear();
732     filteredFrames.reserve(preallocSize);
733     filteredFrames.append(tempContainer);
734 
735     lastUpdateNumFrames = 0;
736     endResetModel();
737     mutex.unlock();
738 }
739 
sendRefresh(int pos)740 void CANFrameModel::sendRefresh(int pos)
741 {
742     beginInsertRows(QModelIndex(), pos, pos);
743     endInsertRows();
744 }
745 
746 //issue a refresh for the last num entries in the model.
747 //used by the serial worker to do batch updates so it doesn't
748 //have to send thousands of messages per second
sendBulkRefresh()749 int CANFrameModel::sendBulkRefresh()
750 {
751     //int num = filteredFrames.count() - lastUpdateNumFrames;
752     if (lastUpdateNumFrames <= 0) return 0;
753 
754     if (lastUpdateNumFrames == 0 && !overwriteDups) return 0;
755     if (filteredFrames.count() == 0) return 0;
756 
757     qDebug() << "Bulk refresh of " << lastUpdateNumFrames;
758 
759     beginResetModel();
760     endResetModel();
761 
762     int num = lastUpdateNumFrames;
763     lastUpdateNumFrames = 0;
764 
765     return num;
766 }
767 
clearFrames()768 void CANFrameModel::clearFrames()
769 {
770     mutex.lock();
771     this->beginResetModel();
772     frames.clear();
773     filteredFrames.clear();
774     filters.clear();
775     busFilters.clear();
776     frames.reserve(preallocSize);
777     filteredFrames.reserve(preallocSize);
778     this->endResetModel();
779     lastUpdateNumFrames = 0;
780     mutex.unlock();
781 
782     emit updatedFiltersList();
783 }
784 
785 /*
786  * Since the getListReference function returns readonly
787  * you can't insert frames with it. Instead this function
788  * allows for a mass import of frames into the model
789  */
insertFrames(const QVector<CANFrame> & newFrames)790 void CANFrameModel::insertFrames(const QVector<CANFrame> &newFrames)
791 {
792     //not resetting the model here because the serial worker automatically does a bulk refresh every 1/4 second
793     //and that refresh will cause the view to update. If you do both it usually ends up thinking you have
794     //double the number of frames.
795     //beginResetModel();
796     mutex.lock();
797     int insertedFiltered = 0;
798     for (int i = 0; i < newFrames.count(); i++)
799     {
800         frames.append(newFrames[i]);
801         if (!filters.contains(newFrames[i].frameId()))
802         {
803             filters.insert(newFrames[i].frameId(), true);
804             needFilterRefresh = true;
805         }
806         if (filters[newFrames[i].frameId()])
807         {
808             busFilters.insert(newFrames[i].bus, true);
809             needFilterRefresh = true;
810         }
811         if (filters[newFrames[i].frameId()] && busFilters[newFrames[i].bus])
812         {
813             insertedFiltered++;
814             filteredFrames.append(newFrames[i]);
815         }
816     }
817     lastUpdateNumFrames = newFrames.count();
818     mutex.unlock();
819     //endResetModel();
820     //beginInsertRows(QModelIndex(), filteredFrames.count() + 1, filteredFrames.count() + insertedFiltered);
821     //endInsertRows();
822     if (needFilterRefresh) emit updatedFiltersList();
823 }
824 
getIndexFromTimeID(unsigned int ID,double timestamp)825 int CANFrameModel::getIndexFromTimeID(unsigned int ID, double timestamp)
826 {
827     int bestIndex = -1;
828     int64_t intTimeStamp = static_cast<int64_t> (timestamp * 1000000l);
829     for (int i = 0; i < frames.count(); i++)
830     {
831         if ((frames[i].frameId() == ID))
832         {
833             if (frames[i].timeStamp().microSeconds() <= intTimeStamp) bestIndex = i;
834             else break; //drop out of loop as soon as we pass the proper timestamp
835         }
836     }
837     return bestIndex;
838 }
839 
loadFilterFile(QString filename)840 void CANFrameModel::loadFilterFile(QString filename)
841 {
842     QFile *inFile = new QFile(filename);
843     QByteArray line;
844     int ID;
845 
846     if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
847         return;
848 
849     filters.clear();
850     busFilters.clear();
851 
852     while (!inFile->atEnd()) {
853         line = inFile->readLine().simplified();
854         if (line.length() > 2)
855         {
856             QList<QByteArray> tokens = line.split(',');
857             ID = tokens[0].toInt(nullptr, 16);
858             if (tokens[1].toUpper() == "T") filters.insert(ID, true);
859                 else filters.insert(ID, false);
860         }
861     }
862     inFile->close();
863 
864     sendRefresh();
865 
866     emit updatedFiltersList();
867 }
868 
saveFilterFile(QString filename)869 void CANFrameModel::saveFilterFile(QString filename)
870 {
871     QFile *outFile = new QFile(filename);
872 
873     if (!outFile->open(QIODevice::WriteOnly | QIODevice::Text))
874         return;
875 
876     QMap<int, bool>::const_iterator it;
877     for (it = filters.begin(); it != filters.end(); ++it)
878     {
879         outFile->write(QString::number(it.key(), 16).toUtf8());
880         outFile->putChar(',');
881         if (it.value()) outFile->putChar('T');
882             else outFile->putChar('F');
883         outFile->write("\n");
884     }
885     outFile->close();
886 }
887 
needsFilterRefresh()888 bool CANFrameModel::needsFilterRefresh()
889 {
890     bool temp = needFilterRefresh;
891     needFilterRefresh = false;
892     return temp;
893 }
894 
895 /*
896  *This used to not be const correct but it is now. So, there's little harm in
897  * allowing external code to peek at our frames. There's just no touching.
898  * This ability to get a direct read-only reference speeds up a variety of
899  * external code that needs to access frames directly and doesn't care about
900  * this model's normal output mechanism.
901  */
getListReference() const902 const QVector<CANFrame>* CANFrameModel::getListReference() const
903 {
904     return &frames;
905 }
906 
getFilteredListReference() const907 const QVector<CANFrame>* CANFrameModel::getFilteredListReference() const
908 {
909     return &filteredFrames;
910 }
911 
getFiltersReference() const912 const QMap<int, bool>* CANFrameModel::getFiltersReference() const
913 {
914     return &filters;
915 }
916 
getBusFiltersReference() const917 const QMap<int, bool>* CANFrameModel::getBusFiltersReference() const
918 {
919     return &busFilters;
920 }
921