HAL  v4.5.0-83-g30c8f0afc
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
wave_render_engine.cpp
Go to the documentation of this file.
6 #include <QDebug>
7 #include <QDir>
8 #include <QPaintEvent>
14 
15 namespace hal {
16 
17 
19  const WaveTransform* trans, const WaveScrollbar* sbar, const WaveDataTimeframe &tframe)
20  : QThread(parentItem), mItem(parentItem), mWorkDir(workdir), mTransform(trans), mScrollbar(sbar), mTimeframe(tframe)
21  {;}
22 
23 
25  {
27  const WaveData* wd = mItem->wavedata();
28  switch (wd->netType()) {
29  case WaveData::ClockNet:
30  {
31  try {
32  SimulationInput::Clock clk = static_cast<const WaveDataClock*>(wd)->clock();
33  WaveDataProviderClock wdpClk(clk);
34  mItem->mPainted.generate(&wdpClk,mTransform,mScrollbar,&mItem->mLoop);
36  } catch (...) {
37  mItem->setState(WaveItem::Failed);
38  }
39  break;
41  if (wd->loadPolicy() == WaveData::LoadAllData)
42  {
43  try {
44  const WaveDataBoolean* wdBool = static_cast<const WaveDataBoolean*>(wd);
45  for (WaveData* wdChild : wdBool->children())
46  {
47  if ((u64)wdChild->data().size() < wdChild->fileSize())
48  {
50  break;
51  }
52  }
53  mItem->mPainted.clearPrimitives();
54  if (mItem->isAborted()) return;
55  WaveDataProviderMap wdpMap(wd->data());
57  mItem->mPainted.generate(&wdpMap,mTransform,mScrollbar,&mItem->mLoop);
59  } catch (...) {
60  mItem->setState(WaveItem::Failed);
61  }
62  }
63  else
64  {
65  try {
66  const WaveDataBoolean* wdBool = static_cast<const WaveDataBoolean*>(wd);
67  std::string saleaeDirectory = QDir(mWorkDir).absoluteFilePath("saleae.json").toStdString();
68  WaveDataProviderBoolean wdpBool(saleaeDirectory,wdBool->children(),wdBool->truthTable());
69  mItem->mPainted.clearPrimitives();
70  if (mItem->isAborted()) return;
71  mItem->mPainted.generate(&wdpBool,mTransform,mScrollbar,&mItem->mLoop);
73  } catch (...) {
74  mItem->setState(WaveItem::Failed);
75  }
76  }
77  break;
78  case WaveData::NetGroup:
80  {
81  try {
82  const WaveDataGroup* grp = static_cast<const WaveDataGroup*>(wd);
83  for (WaveData* wdChild : grp->children())
84  {
85  if ((u64)wdChild->data().size() < wdChild->fileSize())
86  {
88  break;
89  }
90  }
91  mItem->mPainted.clearPrimitives();
92  if (mItem->isAborted()) return;
93  WaveDataProviderMap wdpMap(wd->data());
94  wdpMap.setWaveType(WaveData::NetGroup,wd->bits(),wd->valueBase());
95  mItem->mPainted.generate(&wdpMap,mTransform,mScrollbar,&mItem->mLoop);
97  } catch (...) {
98  mItem->setState(WaveItem::Failed);
99  }
100  }
101  break;
103  if (wd->loadPolicy() == WaveData::LoadAllData)
104  {
105  try {
106  const WaveDataTrigger* wdTrig = static_cast<const WaveDataTrigger*>(wd);
107  mItem->mPainted.clearPrimitives();
108  for (WaveData* wdChild : wdTrig->children())
109  {
110  if ((u64)wdChild->data().size() < wdChild->fileSize())
111  {
112  mItem->setState(WaveItem::Aborted);
113  return;
114  }
115  }
116  if (wdTrig->get_filter_wave())
117  {
118  if ((u64)wdTrig->get_filter_wave()->data().size() < wdTrig->get_filter_wave()->fileSize() )
119  {
120  mItem->setState(WaveItem::Aborted);
121  return;
122  }
123  }
124  WaveDataProviderMap wdpMap(wd->data());
125  wdpMap.setWaveType(WaveData::TriggerTime,wd->bits());
126  mItem->mPainted.generate(&wdpMap,mTransform,mScrollbar,&mItem->mLoop);
128  } catch (...) {
129  mItem->setState(WaveItem::Failed);
130  }
131  }
132  else
133  {
134  try {
135  const WaveDataTrigger* wdTrig = static_cast<const WaveDataTrigger*>(wd);
136  std::string saleaeDirectory = QDir(mWorkDir).absoluteFilePath("saleae.json").toStdString();
137  WaveDataProviderTrigger wdpTrig(saleaeDirectory,wdTrig->children(),wdTrig->toValueList(),wdTrig->get_filter_wave());
138  mItem->mPainted.clearPrimitives();
139  if (mItem->isAborted()) return;
140  mItem->mPainted.generate(&wdpTrig,mTransform,mScrollbar,&mItem->mLoop);
142  } catch (...) {
143  mItem->setState(WaveItem::Failed);
144  }
145  }
146  break;
147  break;
148  default:
149  SaleaeInputFile sif(mWorkDir.absoluteFilePath(QString("digital_%1.bin").arg(mItem->wavedata()->fileIndex())).toStdString());
150  if (sif.good())
151  {
152  if (mItem->wavedata()->loadPolicy()==WaveData::LoadAllData)
153  {
154  try {
155 
156  if ((u64)wd->data().size() < wd->fileSize())
157  mItem->loadSaleae();
158  mItem->mPainted.clearPrimitives();
159  if (mItem->isAborted()) return;
160  WaveDataProviderMap wdpMap(wd->data());
161  wdpMap.setWaveType(mItem->wavedata()->netType(),mItem->wavedata()->bits(),mItem->wavedata()->valueBase());
162  mItem->mPainted.generate(&wdpMap,mTransform,mScrollbar,&mItem->mLoop);
164  } catch (...) {
165  mItem->setState(WaveItem::Failed);
166  }
167  }
168  else
169  {
170  try {
171  WaveDataProviderFile wdpFile(sif, mTimeframe);
172  WaveFormPainted shadowPaint(mItem->mPainted);
173  shadowPaint.generate(&wdpFile,mTransform,mScrollbar,&mItem->mLoop);
174 
175  mItem->mMutex.lock();
176  mItem->mPainted = shadowPaint;
177  mItem->mMutex.unlock();
180  {
181  WaveData* wd = (WaveData*) mItem->wavedata();
182  wd->setData(wdpFile.dataMap());
183  wd->setTimeframeSize(wdpFile.dataMap().size());
184  }
185  } catch (...) {
186  mItem->setState(WaveItem::Failed);
187  }
188  }
189  }
190  else
191  mItem->setState(WaveItem::Failed);
192  break;
193  }
194  }
195  }
196  //------------------------
197 
199  {
200  while (mLoop)
201  {
202  int needStillWork = 0;
203  for (WaveItem* wree : mTodoList)
204  {
205  if (!wree->isNull()) continue;
206  ++ needStillWork;
207  if (!wree->mMutex.tryLock()) continue;
208  if (wree->isNull())
209  {
210  wree->setState(WaveItem::Loading);
211  wree->mMutex.unlock();
212  const WaveData* wd = wree->wavedata();
213  if (wd->netType() == WaveData::ClockNet)
214  {
215  try {
216  SimulationInput::Clock clk = static_cast<const WaveDataClock*>(wd)->clock();
217  WaveDataProviderClock wdpClk(clk);
218  wree->mPainted.generate(&wdpClk,mTransform,mScrollbar,&wree->mLoop);
219  wree->setState(WaveItem::Finished);
220  } catch (...) {
221  wree->setState(WaveItem::Failed);
222  }
223  }
224  else
225  {
226  if (wree->wavedata()->loadPolicy() == WaveData::LoadAllData)
227  {
228  try {
229  if ((u64)wd->data().size() < wd->fileSize())
230  wree->loadSaleae();
231  wree->mPainted.clearPrimitives();
232  WaveDataProviderMap wdpMap(wd->data());
233  wdpMap.setWaveType(wree->wavedata()->netType(),wree->wavedata()->bits(),wree->wavedata()->valueBase());
234  wree->mPainted.generate(&wdpMap,mTransform,mScrollbar,&wree->mLoop);
235  wree->setState(WaveItem::Painted);
236  } catch (...) {
237  wree->setState(WaveItem::Failed);
238  }
239  }
240  else
241  {
242  try {
243  WaveDataProvider* wdp = nullptr;
244  std::string saleaeDirectory = mWorkDir.absoluteFilePath("saleae.json").toStdString();
245  switch (wree->wavedata()->netType())
246  {
247  case WaveData::NetGroup:
248  {
249  const WaveDataGroup* wdGrp = static_cast<const WaveDataGroup*>(wree->wavedata());
250  wdp = new WaveDataProviderGroup(saleaeDirectory, wdGrp->children());
251  break;
252  }
254  {
255  const WaveDataBoolean* wdBool = static_cast<const WaveDataBoolean*>(wree->wavedata());
256  wdp = new WaveDataProviderBoolean(saleaeDirectory, wdBool->children(), wdBool->truthTable());
257  break;
258  }
260  {
261  const WaveDataTrigger* wdTrig = static_cast<const WaveDataTrigger*>(wree->wavedata());
262  wdp = new WaveDataProviderTrigger(saleaeDirectory, wdTrig->children(), wdTrig->toValueList(), wdTrig->get_filter_wave());
263  break;
264  }
265  default:
266  {
267  QString dataFilename = mWorkDir.absoluteFilePath(QString("digital_%1.bin").arg(wree->wavedata()->fileIndex()));
268  SaleaeInputFile sif(dataFilename.toStdString());
269  if (sif.good()) wdp = new WaveDataProviderFile(sif, mTimeframe);
270  else
271  qDebug() << "cannot open file" << dataFilename;
272  }
273  }
274  if (wdp)
275  {
276  wree->mPainted.generate(wdp,mTransform,mScrollbar,&wree->mLoop);
277  wree->setState(WaveItem::Painted);
278  delete wdp;
279  }
280  /* TODO : fix for derived classes
281  if (wdp->storeDataState() == WaveDataProviderFile::Complete)
282  {
283  WaveData* wd = (WaveData*) wree->wavedata();
284  wd->setData(wdpFile.dataMap());
285  wd->setTimeframeSize(wdpFile.dataMap().size());
286  }
287  */
288  } catch (...) {
289  wree->setState(WaveItem::Failed);
290  }
291  }
292  }
293  }
294  else
295  wree->mMutex.unlock();
296  if (!mLoop) break;;
297  }
298  if (!needStillWork) break;
299  }
300  }
301 
302  //------------------------
304  : QWidget(parent), mWaveGraphicsCanvas(wsa), mWaveDataList(wdlist), mWaveItemHash(wHash),
305  mY0(0), mHeight(0), mTimerTick(0), mBackbone(nullptr), mOmitHistory(true)
306  {
307  connect(this,&WaveRenderEngine::updateSoon,this,&WaveRenderEngine::callUpdate,Qt::QueuedConnection);
308  mTimer = new QTimer(this);
309  connect(mTimer,&QTimer::timeout,this,&WaveRenderEngine::handleTimeout);
310  mTimer->start(50);
311  }
312 
313  void WaveRenderEngine::handleTimeout()
314  {
315  mWaveItemHash->emptyTrash();
316  bool needUpdate = false;
317  for (WaveItem* wree : mWaveItemHash->values())
318  {
319  if ((wree->isLoading() || wree->isThreadBusy()) && wree->mVisibleRange)
320  {
321  wree->incrementLoadProgress();
322  needUpdate = true;
323  }
324  }
325  if (!needUpdate) return;
326  if (++mTimerTick > 2)
327  {
328  update();
329  }
330  }
331 
332  void WaveRenderEngine::handleBackboneFinished()
333  {
334  WaveLoaderBackbone* toDelete = mBackbone;
335  mBackbone = nullptr;
336  toDelete->deleteLater();
337  }
338 
339  void WaveRenderEngine::callUpdate()
340  {
341  update();
342  }
343 
345  {
346  Q_UNUSED(event);
347  QPainter painter(this);
348 
349  int top = mWaveGraphicsCanvas->verticalScrollBar()->value();
350  const WaveTransform* trans = mWaveGraphicsCanvas->transform();
351  const WaveScrollbar* sbar = static_cast<const WaveScrollbar*>(mWaveGraphicsCanvas->horizontalScrollBar());
352  mTimerTick = 0;
353 
354  WaveZoomShift testValid(trans,sbar);
355 
356  if (testValid != mValidity)
357  {
358  if (mBackbone)
359  mBackbone->mLoop = false;
360 
361  if (!mOmitHistory)
362  {
363  bool wasEmpty = mZoomHistory.isEmpty();
364  if (!testValid.sameHistory(mValidity))
365  {
366  mZoomHistory.append(mValidity);
367  if (wasEmpty) mWaveGraphicsCanvas->emitUndoStateChanged();
368  }
369  }
370 
371  mValidity = testValid;
372  }
373 
374  mOmitHistory = false;
375 
376  mY0 = top;
377  mHeight = height();
378 
379  QString workdir = QString::fromStdString(mWaveDataList->saleaeDirectory().get_directory());
380 
381  for (WaveItem* wree : mWaveItemHash->values())
382  {
383  if (wree->isDeleted()) continue;
384 
385 // if (wree->yPosition() < 3)
386 // qDebug() << "paint" << wree->yPosition() << wree->wavedata()->name() << wree->wavedata()->fileSize() << wree->wavedata()->data().size();
387  if (wree->hasRequest(WaveItem::AddRequest))
388  {
389  wree->setParent(this);
390  connect(wree,&WaveItem::doneLoading,this,&WaveRenderEngine::callUpdate);
391  wree->clearRequest(WaveItem::AddRequest);
392  }
393 
394  int y0 = y0Entry(wree->yPosition());
395 
396  if (y0 < 0 || y0 > mHeight)
397  {
398  wree->mVisibleRange = false;
399  // not in painted range
400  if (wree->isThreadBusy()) continue;
401 
402  if (wree->isLoading() && wree->hasLoader())
403  {
404  if (!wree->mMutex.tryLock())
405  continue;
406  else
407  {
408  wree->abortLoader();
409  wree->mMutex.unlock();
410  }
411  }
412  continue;
413  }
414 
415  wree->mVisibleRange = true;
416  if (!wree->mMutex.tryLock())
417  {
418  continue;
419  }
420  else
421  {
422  if (wree->isNull())
423  {
424  if (wree->isGroup() && wree->wavedata()->loadPolicy()!=WaveData::LoadAllData)
425  {
426  if (wree->mPainted.generateGroup(wree->wavedata(),mWaveItemHash))
427  {
428  wree->setState(WaveItem::Painted);
429  Q_EMIT updateSoon();
430  }
431  }
432  else if (wree->isBoolean() && wree->wavedata()->loadPolicy()!=WaveData::LoadAllData)
433  {
434  if (wree->mPainted.generateBoolean(wree->wavedata(),mWaveDataList,mWaveItemHash))
435  {
436  wree->setState(WaveItem::Painted);
437  Q_EMIT updateSoon();
438  }
439  }
440  else
441  wree->startGeneratePainted(workdir,trans, sbar, mWaveDataList->timeFrame());
442  }
443  else if (wree->isLoading() || wree->isThreadBusy())
444  {
445  QColor barColor = QColor::fromRgb(255,80,66,40);
446  if (wree->isLoading())
447  {
448  if (wree->mLoadValidity == mValidity)
449  barColor = QColor::fromRgb(50,255,66,40);
450  else
451  wree->abortLoader();
452  }
453  painter.fillRect(QRectF(0,y0,wree->loadeProgress(),14),
454  QBrush(barColor));
455  }
456  else if (wree->isPainted())
457  {
458  if (mValidity == wree->mPainted.validity() && !wree->wavedata()->isDirty() &&!wree->hasRequest(WaveItem::DataChanged))
459  {
460  if (wree->isVisibile())
461  {
462  if (wree->isSelected())
463  {
464  painter.fillRect(QRectF(0,y0-4,width(),28), QBrush(QColor(WaveItem::sBackgroundColor)));
466  }
467  else if (wree->isTrigger())
469  else
471  wree->mPainted.paint(y0,painter);
472  }
473  }
474  else
475  {
476  wree->deletePainted();
477  if (wree->isGroup() && wree->wavedata()->loadPolicy()==WaveData::TooBigToLoad)
478  wree->mPainted.generateGroup(wree->wavedata(),mWaveItemHash);
479  else if (wree->isBoolean() && wree->wavedata()->loadPolicy()==WaveData::TooBigToLoad)
480  wree->mPainted.generateBoolean(wree->wavedata(),mWaveDataList,mWaveItemHash);
481  else
482  wree->startGeneratePainted(workdir,trans, sbar, mWaveDataList->timeFrame());
483  wree->clearRequest(WaveItem::DataChanged);
484  }
485  }
486  wree->mMutex.unlock();
487  }
488  }
489 
490  QList<WaveItem*> todoList;
491 
492  for (WaveItem* wree : mWaveItemHash->values())
493  {
494  if (wree->isNull() && !wree->isGroup() && !wree->isDeleted()) todoList.append(wree);
495  }
496 
497  if (!todoList.isEmpty() && !mBackbone)
498  {
499  mBackbone = new WaveLoaderBackbone(todoList, QString::fromStdString(mWaveDataList->saleaeDirectory().get_directory()), trans, sbar, mWaveDataList->timeFrame(), this);
500  connect(mBackbone, &QThread::finished, this, &WaveRenderEngine::handleBackboneFinished);
501  mBackbone->start();
502  }
503 
504 // qDebug() << "render" << y0 << mScale << mTleft << mWidth;
505  }
506 
507  int WaveRenderEngine::y0Entry(int irow) const
508  {
509  return 32 + irow*28 - mY0;
510  }
511 
513  {
514  return (mWaveItemHash->size()+2) * 28;
515  }
516 }
517 
std::string get_directory() const
Get path to SALEAE directory without filename.
QList< WaveData * > children() const
Definition: wave_data.cpp:738
const char * truthTable() const
Definition: wave_data.h:296
virtual QList< WaveData * > children() const
Definition: wave_data.cpp:1047
void setData(const QMap< u64, int > &dat)
Definition: wave_data.cpp:119
virtual LoadPolicy loadPolicy() const
Definition: wave_data.cpp:75
int fileIndex() const
Definition: wave_data.h:109
u64 fileSize() const
Definition: wave_data.h:110
int valueBase() const
Definition: wave_data.h:111
const QMap< u64, int > & data() const
Definition: wave_data.h:108
NetType netType() const
Definition: wave_data.h:105
void setTimeframeSize(u64 siz)
Definition: wave_data.h:120
virtual int bits() const
Definition: wave_data.h:106
SaleaeDirectory & saleaeDirectory()
Definition: wave_data.h:242
const WaveDataTimeframe & timeFrame() const
Definition: wave_data.h:233
const QMap< u64, int > & dataMap() const
StoreData storeDataState() const
void setWaveType(WaveData::NetType type, int bts=1, int base=16)
QList< int > toValueList() const
Definition: wave_data.cpp:916
QList< WaveData * > children() const
Definition: wave_data.cpp:889
WaveData * get_filter_wave() const
Definition: wave_data.h:320
void generate(WaveDataProvider *wdp, const WaveTransform *trans, const WaveScrollbar *sbar, bool *loop)
const WaveTransform * transform() const
const WaveData * wavedata() const
Definition: wave_item.h:129
void doneLoading()
void setState(State stat)
Definition: wave_item.cpp:136
bool isAborted() const
Definition: wave_item.h:115
WaveFormPainted mPainted
Definition: wave_item.h:83
QMutex mMutex
Definition: wave_item.h:85
void loadSaleae()
Definition: wave_item.cpp:254
static const char * sBackgroundColor
Definition: wave_item.h:143
WaveLoaderThread(WaveItem *parentItem, const QString &workdir, const WaveTransform *trans, const WaveScrollbar *sbar, const WaveDataTimeframe &tframe)
void paintEvent(QPaintEvent *event) override
WaveRenderEngine(WaveGraphicsCanvas *wsa, WaveDataList *wdlist, WaveItemHash *wHash, QWidget *parent=nullptr)
int y0Entry(int irow) const
bool sameHistory(const WaveZoomShift &other) const
uint64_t u64
Definition: defines.h:42
Definition: defines.h:45
QScrollBar * horizontalScrollBar() const const
QScrollBar * verticalScrollBar() const const
QColor fromRgb(QRgb rgb)
QString absoluteFilePath(const QString &fileName) const const
int size() const const
QList< T > values() const const
void append(const T &value)
bool isEmpty() const const
int size() const const
void lock()
void unlock()
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void deleteLater()
void fillRect(const QRectF &rectangle, const QBrush &brush)
void setPen(const QColor &color)
QString fromStdString(const std::string &str)
std::string toStdString() const const
QueuedConnection
void finished()
void start(QThread::Priority priority)
void start(int msec)
void timeout()
virtual bool event(QEvent *event) override
void update()