HAL  v4.5.0-83-g30c8f0afc
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
waveform_viewer.cpp
Go to the documentation of this file.
2 
8 
10 
15 #include "hal_core/netlist/gate.h"
16 #include "hal_core/netlist/net.h"
18 #include "hal_core/utilities/log.h"
20 #include "gui/gui_globals.h"
21 #include "gui/gui_utils/graphics.h"
22 #include "gui/toolbar/toolbar.h"
23 
24 #include <QFile>
25 #include <QDate>
26 #include <QColor>
27 #include <QFileDialog>
28 #include <QStatusBar>
29 #include <QAction>
30 #include <QMenu>
31 #include <QDebug>
32 #include <QApplication>
33 #include <QScreen>
34 #include <QVBoxLayout>
35 #include <QProgressBar>
36 #include <QInputDialog>
37 #include <QTabBar>
39 
40 namespace hal
41 {
42 
44  {
45  return new WaveformViewer;
46  }
47 
49  {
50  NetlistSimulatorControllerPlugin* ctrlPlug = static_cast<NetlistSimulatorControllerPlugin*>(plugin_manager::get_plugin_instance("netlist_simulator_controller"));
51  if (!ctrlPlug || !ctrlPlug->sSimulatorSerializer)
52  {
53  return;
54  }
55  for (std::unique_ptr<NetlistSimulatorController>& ctrlRef : ctrlPlug->sSimulatorSerializer->restore())
56  {
57  if (!ctrlRef) continue;
58  takeControllerOwnership(ctrlRef, false); // already created by restore()
59  }
60  }
61 
63  : ExternalContentWidget("waveform_viewer","WaveformViewer",parent),
64  mVisualizeNetState(false), mOwnershipRequired(false), mCurrentWaveWidget(nullptr)
65  {
67  mCreateControlAction = new QAction(this);
68  mSimulSettingsAction = new QAction(this);
69  mOpenInputfileAction = new QAction(this);
70  mSaveWaveformsAction = new QAction(this);
71  mInvokeSWizardAction = new QAction(this);
72  mAddResultWaveAction = new QAction(this);
73  mToggleMaxZoomAction = new QAction(this);
74  mUndoZoomShiftAction = new QAction(this);
75 
76  mCreateControlAction->setIcon(gui_utility::getStyledSvgIcon("all->#FFFFFF",":/icons/plus"));
77  mAddResultWaveAction->setIcon(QIcon(":/icons/add_waveform"));
78  mToggleMaxZoomAction->setIcon(QIcon(":/icons/zoom_waveform"));
79  mUndoZoomShiftAction->setIcon(gui_utility::getStyledSvgIcon("all->#FFFFFF",":/icons/undo2"));
80 
81  mCreateControlAction->setToolTip("Create simulation controller");
82  mSimulSettingsAction->setToolTip("Simulation settings");
83  mOpenInputfileAction->setToolTip("Open input file");
84  mSaveWaveformsAction->setToolTip("Save waveform data to file");
85  mInvokeSWizardAction->setToolTip("Invoke simulation wizard");
86  mAddResultWaveAction->setToolTip("Add waveform net");
87  mToggleMaxZoomAction->setToolTip("Toggle max/min zoom");
88  mUndoZoomShiftAction->setToolTip("Undo last zoom or horizontal scroll");
89 
90  connect(mCreateControlAction, &QAction::triggered, this, &WaveformViewer::handleCreateControl);
91  connect(mSimulSettingsAction, &QAction::triggered, this, &WaveformViewer::handleSimulSettings);
92  connect(mOpenInputfileAction, &QAction::triggered, this, &WaveformViewer::handleOpenInputFile);
93  connect(mSaveWaveformsAction, &QAction::triggered, this, &WaveformViewer::handleSaveWaveforms);
94  connect(mInvokeSWizardAction, &QAction::triggered, this, &WaveformViewer::handleInvokeWizzard);
95  connect(mAddResultWaveAction, &QAction::triggered, this, &WaveformViewer::handleAddResultWave);
96  connect(mToggleMaxZoomAction, &QAction::triggered, this, &WaveformViewer::handleToggleMaxZoom);
97  connect(mUndoZoomShiftAction, &QAction::triggered, this, &WaveformViewer::handleUndoZoomShift);
98 
99  mTabWidget = new QTabWidget(this);
100  mTabWidget->setTabsClosable(true);
102  connect(mTabWidget,&QTabWidget::tabCloseRequested,this,&WaveformViewer::handleTabClosed);
104  mContentLayout->addWidget(mTabWidget);
105  mStatusBar = new QStatusBar(this);
106  mProgress = new QProgressBar(mStatusBar);
107  mProgress->setFormat("Import waveform data : %p%");
108  mProgress->setTextVisible(true);
109  mProgress->setRange(0,100);
110  mStatusBar->addWidget(mProgress,100);
111  mProgress->hide();
113  mContentLayout->addWidget(mStatusBar);
114  if (gSelectionRelay)
115  connect(gSelectionRelay,&SelectionRelay::selectionChanged,this,&WaveformViewer::handleSelectionChanged);
116 
123  }
124 
126  {
127  closeEvent(nullptr);
128  }
129 
131  {
132  Q_UNUSED(event);
136  }
137 
139  {
140  if (percent < 0)
141  {
142  mProgress->setValue(0);
143  mProgress->hide();
145  }
146  else if (percent != mProgress->value())
147  {
148  mStatusBar->clearMessage();
149  mProgress->show();
150  mProgress->setValue(percent);
151  }
152  }
153 
155  {
156  if (inx >= 0 && mCurrentWaveWidget == mTabWidget->widget(inx)) return;
157  if (mCurrentWaveWidget)
159  if (inx < 0)
160  {
161  mCurrentWaveWidget = nullptr;
163  return;
164  }
165  mCurrentWaveWidget = static_cast<WaveWidget*>(mTabWidget->widget(inx));
168  }
169 
171  {
172  if (!mCurrentWaveWidget) return;
173  mAddResultWaveAction->setEnabled(mCurrentWaveWidget->canImportWires());
174  }
175 
177  {
178  if (!mCurrentWaveWidget)
179  mUndoZoomShiftAction->setDisabled(true);
180  else
181  mUndoZoomShiftAction->setEnabled(mCurrentWaveWidget->graphicCanvas()->canUndoZoom());
182  mUndoZoomShiftAction->setIcon(gui_utility::getStyledSvgIcon(mUndoZoomShiftAction->isEnabled() ? "all->#FFFFFF" : "all->#808080",":/icons/undo2"));
183  }
184 
186  {
187  mOpenInputfileAction->setEnabled(true);
188  mInvokeSWizardAction->setEnabled(true);
189  mOpenInputfileAction->setIcon(gui_utility::getStyledSvgIcon("all->#3192C5",":/icons/folder"));
191  {
192  mSimulSettingsAction->setDisabled(true);
193  mSaveWaveformsAction->setDisabled(true);
194 
195  // TODO: das ganze muss anders gestartet werden sonst fehlen einpar ptr
196  mInvokeSWizardAction->setDisabled(true);
197  mAddResultWaveAction->setDisabled(true);
198  mToggleMaxZoomAction->setDisabled(true);
199  }
200  else
201 
202  {
203  mSimulSettingsAction->setEnabled(true);
205 
206  //mInvokeSWizardAction->setEnabled(state == NetlistSimulatorController::ParameterReady);
207  mToggleMaxZoomAction->setEnabled(!mCurrentWaveWidget->isEmpty());
208  }
209  mSimulSettingsAction->setIcon(gui_utility::getStyledSvgIcon(mSimulSettingsAction->isEnabled() ? "all->#FFFFFF" : "all->#808080",":/icons/preferences"));
210 
211  mSaveWaveformsAction->setIcon(gui_utility::getStyledSvgIcon(mSaveWaveformsAction->isEnabled() ? "all->#3192C5" : "all->#808080",":/icons/save"));
212  mInvokeSWizardAction->setIcon(gui_utility::getStyledSvgIcon(mInvokeSWizardAction->isEnabled() ? "all->#20FF80" : "all->#808080",":/icons/run"));
213  testUndoEnable();
214 
215  if (!mCurrentWaveWidget)
217  else
218  {
219  mAddResultWaveAction->setEnabled(mCurrentWaveWidget->canImportWires());
220  switch (state) {
221  case NetlistSimulatorController::NoGatesSelected: displayStatusMessage("Select gates to create (partial) netlist for simulation"); break;
222  case NetlistSimulatorController::ParameterSetup: displayStatusMessage("Setup parameter for simulation"); break;
223  case NetlistSimulatorController::ParameterReady: displayStatusMessage("Continue parameter setup or start simulation"); break;
224  case NetlistSimulatorController::SimulationRun: displayStatusMessage("Simulation engine running, please wait ..."); break;
225  case NetlistSimulatorController::ShowResults: displayStatusMessage("Simulation successful, add waveform data to visualize results"); break;
226  case NetlistSimulatorController::EngineFailed: displayStatusMessage("Simulation engine failed"); break;
227  }
228  }
229  }
230 
232  {
233  if (msg.isEmpty())
234  {
235  mStatusBar->showMessage("Create new simulation controller");
236  }
237  else
238  mStatusBar->showMessage(msg);
239  }
240 
242  {
243  toolbar->addAction(mCreateControlAction);
244  toolbar->addAction(mInvokeSWizardAction);
245  toolbar->addAction(mSimulSettingsAction);
246  toolbar->addAction(mOpenInputfileAction);
247  toolbar->addAction(mSaveWaveformsAction);
248  toolbar->addAction(mAddResultWaveAction);
249  toolbar->addAction(mToggleMaxZoomAction);
250  toolbar->addAction(mUndoZoomShiftAction);
251  }
252 
253  void WaveformViewer::handleTabClosed(int inx)
254  {
255  WaveWidget* ww = static_cast<WaveWidget*>(mTabWidget->widget(inx));
256  if (!ww->triggerClose())
257  log_warning(ww->controller()->get_name(), "Cannot close tab for externally owned controller.");
258  }
259 
260  void WaveformViewer::handleCreateControl()
261  {
262  NetlistSimulatorControllerPlugin* ctrlPlug = static_cast<NetlistSimulatorControllerPlugin*>(plugin_manager::get_plugin_instance("netlist_simulator_controller"));
263  if (!ctrlPlug)
264  {
265  log_warning("waveform_viewer", "Plugin 'netlist_simulator_controller' not found");
266  return;
267  }
268  std::unique_ptr<NetlistSimulatorController> ctrlRef = ctrlPlug->create_simulator_controller();
269  if (ctrlRef)
270  takeControllerOwnership(ctrlRef, false);
271  }
272 
273  void WaveformViewer::handleSimulSettings()
274  {
275  QMenu* settingMenu = new QMenu(this);
276  QAction* act;
277 
278  act = new QAction("Show output of engine");
279  connect(act, &QAction::triggered, this, &WaveformViewer::handleShowEngineOutput);
280  settingMenu->addAction(act);
281 
282  settingMenu->addSeparator();
283  act = new QAction("Refresh net names", settingMenu);
284  connect(act, &QAction::triggered, this, &WaveformViewer::handleRefreshNetNames);
285  settingMenu->addAction(act);
286 
287  act = new QAction("Visualize net state by color", settingMenu);
288  act->setCheckable(true);
289  act->setChecked(mVisualizeNetState);
290  connect (act, &QAction::triggered, this, &WaveformViewer::setVisualizeNetState);
291  settingMenu->addAction(act);
292 
293  act = new QAction("Settings ...");
294  connect(act, &QAction::triggered, this, &WaveformViewer::handleOpenSettingsDialog);
295  settingMenu->addAction(act);
296 
297  settingMenu->exec(mapToGlobal(QPoint(10,3)));
298  }
299 
300  void WaveformViewer::handleOpenSettingsDialog()
301  {
302  SimulationSettingDialog ssd(NetlistSimulatorControllerPlugin::sSimulationSettings,this);
303  ssd.exec();
304  }
305 
306  void WaveformViewer::handleShowEngineOutput()
307  {
308  if (!mCurrentWaveWidget) return;
310  QFile log(fname);
311  if (!log.open(QIODevice::ReadOnly)) return;
312  QTextEdit* browser = new QTextEdit;
313  browser->setReadOnly(true);
314  browser->setHtml(QString::fromUtf8(log.readAll()));
315  QSize scrSize = QGuiApplication::primaryScreen()->size();
316  browser->setGeometry(scrSize.width()/10,scrSize.height()/10,scrSize.width()*4/5,scrSize.height()*4/5);
317  browser->setWindowTitle("Simulation engine log <" + fname + ">");
318  browser->show();
319  }
320 
321  void WaveformViewer::handleRefreshNetNames()
322  {
323  for (int inx=0; inx<mTabWidget->count(); inx++)
324  {
325  WaveWidget* ww = static_cast<WaveWidget*>(mTabWidget->widget(inx));
326  ww->refreshNetNames();
327  }
328  }
329 
330  void WaveformViewer::setVisualizeNetState(bool state)
331  {
332  if (state == mVisualizeNetState) return;
333  mVisualizeNetState = state;
334  for (int inx=0; inx < mTabWidget->count(); inx++)
335  {
336  WaveWidget* ww = static_cast<WaveWidget*>(mTabWidget->widget(inx));
337  ww->setVisualizeNetState(mVisualizeNetState, inx==mTabWidget->currentIndex());
338  }
339  }
340 
342  {
343  // nothing to do here, viewer will open widget when taking over ownership
344  if (mOwnershipRequired) return;
345 
346  // check whether controller already added
347  for (int inx=0; inx<mTabWidget->count(); inx++)
348  {
349  WaveWidget* ww = static_cast<WaveWidget*>(mTabWidget->widget(inx));
350  if (controllerId == ww->controllerId()) return;
351  }
353  if (!nsc) return;
354  WaveWidget* ww = new WaveWidget(nsc, mTabWidget);
355  mTabWidget->addTab(ww,nsc->name());
356  showCloseButton();
357  }
358 
360  {
361  for (int inx=0; inx<mTabWidget->count(); inx++)
362  {
363  WaveWidget* ww = static_cast<WaveWidget*>(mTabWidget->widget(inx));
364  if (ww->controllerId() == controllerId || ww->controllerId() == 0)
365  {
366  mTabWidget->removeTab(inx);
367  ww->deleteLater();
368  }
369  }
370  }
371 
372  void WaveformViewer::handleOpenInputFile()
373  {
374  QString filter = QString("Saved data (%1)").arg(NetlistSimulatorController::sPersistFile);
375  if (mCurrentWaveWidget)
376  filter += ";; VCD files (*.vcd);; CSV files (*.csv)";
377 
378  QString filename =
379  QFileDialog::getOpenFileName(this, "Load input wave file", ".", filter);
380  if (filename.isEmpty()) return;
382  {
383  NetlistSimulatorControllerPlugin* ctrlPlug = static_cast<NetlistSimulatorControllerPlugin*>(plugin_manager::get_plugin_instance("netlist_simulator_controller"));
384  if (ctrlPlug)
385  {
386  mOwnershipRequired = true;
387  std::unique_ptr<NetlistSimulatorController> ctrlRef = ctrlPlug->restore_simulator_controller(gNetlist,filename.toStdString());
388  takeControllerOwnership(ctrlRef, true);
389  mOwnershipRequired = false;
390  }
391  }
392  else if (mCurrentWaveWidget && mCurrentWaveWidget->controller()->can_import_data() && filename.toLower().endsWith(".vcd"))
394  else if (mCurrentWaveWidget && mCurrentWaveWidget->controller()->can_import_data() && filename.toLower().endsWith(".csv"))
396  else if (mCurrentWaveWidget)
397  log_warning(mCurrentWaveWidget->controller()->get_name(), "Cannot parse file '{}' (unknown extension ore wrong state).", filename.toStdString());
398  else
399  log_warning("simulation_plugin", "Unable to restore saved data from file '{}'.", filename.toStdString());
400  }
401 
402  void WaveformViewer::showCloseButton()
403  {
404  for (int i=0; i<mTabWidget->count(); i++)
405  {
406  bool own = static_cast<const WaveWidget*>(mTabWidget->widget(i))->hasOwnership();
407  for (int j=0; j<2; j++)
408  {
409  QWidget* closeBut = mTabWidget->tabBar()->tabButton(i,j?QTabBar::LeftSide:QTabBar::RightSide);
410  if (closeBut && closeBut->metaObject()->className() == QByteArray("CloseButton"))
411  {
412  if (own)
413  {
414  if (!closeBut->isVisible())
415  closeBut->show();
416  }
417  else
418  {
419  if (closeBut->isVisible())
420  closeBut->hide();
421  }
422  }
423  }
424  }
425  }
426 
427  void WaveformViewer::takeControllerOwnership(std::unique_ptr<NetlistSimulatorController> &ctrlRef, bool create)
428  {
429  NetlistSimulatorController* nsc = ctrlRef.get();
430 
431  WaveWidget* ww = nullptr;
432  if (create)
433  {
434  ww = new WaveWidget(nsc, mTabWidget);
435  mTabWidget->addTab(ww,nsc->name());
436  }
437  else
438  {
439  for (int inx=0; inx<mTabWidget->count(); inx++)
440  {
441  WaveWidget* wwTest = static_cast<WaveWidget*>(mTabWidget->widget(inx));
442  if (ctrlRef.get()->get_id() == wwTest->controllerId())
443  {
444  ww = wwTest;
445  break;
446  }
447  }
448 
449  }
450  Q_ASSERT(ww);
451  ww->takeOwnership(ctrlRef);
452  showCloseButton();
453  }
454 
455  void WaveformViewer::handleSaveWaveforms()
456  {
457  if (!mCurrentWaveWidget) return;
458 
459  QString filename =
460  QFileDialog::getSaveFileName(this, "Save waveform data to file", ".", ("VCD Files (*.vcd)") );
461  if (filename.isEmpty()) return;
463  }
464 
465  void WaveformViewer::handleInvokeWizzard()
466  {
467  if (!mCurrentWaveWidget) return;
469  wizard.exec();
470  }
471 
472  void WaveformViewer::handleToggleMaxZoom()
473  {
474  if (!mCurrentWaveWidget) return;
476  }
477 
478  void WaveformViewer::handleUndoZoomShift()
479  {
480  if (!mCurrentWaveWidget) return;
482  }
483 
484  void WaveformViewer::handleAddResultWave()
485  {
486  if (!mCurrentWaveWidget) return;
488  mAddResultWaveAction->setEnabled(mCurrentWaveWidget->canImportWires());
489  }
490 
491  void WaveformViewer::setGates(std::vector<Gate*> gates)
492  {
493  if (!mCurrentWaveWidget) return;
495  }
496 
497  void WaveformViewer::handleSelectionChanged(void* sender)
498  {
499  Q_UNUSED(sender);
500  /*
501  for (u32 nid : gSelectionRelay->selectedNetsList())
502  {
503  Net* n = gNetlist->get_net_by_id(nid);
504  if (!n) continue;
505  const WaveData* wd = mResultMap.value(n->get_id());
506  if (!wd) continue;
507  WaveData* wdCopy = new WaveData(*wd);
508 // TODO mWaveWidget->addOrReplaceWave(wdCopy);
509  }
510  */
511  }
512 } // namespace hal
QVBoxLayout * mContentLayout
std::shared_ptr< spdlog::logger > add_channel(const std::string &channel_name, const std::vector< std::shared_ptr< log_sink >> &sinks, const std::string &level="info")
Definition: log.cpp:100
static std::shared_ptr< log_sink > create_gui_sink()
Definition: log.cpp:274
static std::shared_ptr< log_sink > create_file_sink(const std::filesystem::path &file_name="", const bool truncate=false)
Definition: log.cpp:247
static std::shared_ptr< log_sink > create_stdout_sink(const bool colored=true)
Definition: log.cpp:216
static LogManager * get_instance(const std::filesystem::path &file_name="")
Definition: log.cpp:61
bool import_vcd(const std::string &filename, FilterInputFlag filter)
bool generate_vcd(const std::filesystem::path &path, u32 start_time=0, u32 end_time=0, std::set< const Net * > nets={}) const
void import_csv(const std::string &filename, FilterInputFlag filter, u64 timescale=1000000000)
NetlistSimulatorController * controller(u32 id) const
static NetlistSimulatorControllerMap * instance()
std::unique_ptr< NetlistSimulatorController > restore_simulator_controller(Netlist *nl, const std::string &filename) const
void selectionChanged(void *sender)
std::vector< std::unique_ptr< NetlistSimulatorController > > restore()
Toolbar for all ContentFrames and ContentWidgets.
Definition: toolbar.h:39
WaveGraphicsCanvas * graphicCanvas()
Definition: wave_widget.h:78
NetlistSimulatorController * controller() const
Definition: wave_widget.h:63
void setGates(const std::vector< Gate * > &gats)
bool isEmpty() const
u32 controllerId() const
void stateChanged(hal::NetlistSimulatorController::SimulationState state)
NetlistSimulatorController::SimulationState state() const
void refreshNetNames()
bool canImportWires() const
ExternalContentWidget * contentFactory() const
void setGates(std::vector< Gate * > gates)
void showProgress(int percent)
WaveformViewer(QWidget *parent=nullptr)
void handleControllerAdded(u32 controllerId)
void restoreFromProject() override
virtual void setupToolbar(Toolbar *toolbar) override
void handleControllerRemoved(u32 controllerId)
void displayStatusMessage(const QString &msg=QString())
void currentStateChanged(NetlistSimulatorController::SimulationState state)
void closeEvent(QCloseEvent *event) override
void currentTabChanged(int inx)
WaveWidget * mCurrentWaveWidget
uint32_t u32
Definition: defines.h:41
#define log_warning(channel,...)
Definition: log.h:76
QIcon getStyledSvgIcon(const QString &from_to_colors_enabled, const QString &svg_path, QString from_to_colors_disabled=QString())
Definition: graphics.cpp:60
BasePluginInterface * get_plugin_instance(const std::string &plugin_name, bool initialize=true, bool silent=false)
Definition: defines.h:45
SelectionRelay * gSelectionRelay
Definition: plugin_gui.cpp:83
Netlist * gNetlist
Definition: gui_globals.h:69
void setCheckable(bool)
void setChecked(bool)
void setEnabled(bool)
void setIcon(const QIcon &icon)
void setDisabled(bool b)
void setToolTip(const QString &tip)
void triggered(bool checked)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
QString absoluteFilePath(const QString &fileName) const const
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options)
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options)
QAction * addAction(const QString &text)
QAction * addSeparator()
QAction * exec()
const char * className() const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void deleteLater()
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
virtual const QMetaObject * metaObject() const const
QObject * sender() const const
void setFormat(const QString &format)
void setRange(int minimum, int maximum)
void setTextVisible(bool visible)
void setValue(int value)
int height() const const
int width() const const
void addWidget(QWidget *widget, int stretch)
void clearMessage()
void showMessage(const QString &message, int timeout)
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
QString fromStdString(const std::string &str)
QString fromUtf8(const char *str, int size)
bool isEmpty() const const
QString toLower() const const
std::string toStdString() const const
QueuedConnection
QWidget * tabButton(int index, QTabBar::ButtonPosition position) const const
int addTab(QWidget *page, const QString &label)
void currentChanged(int index)
void removeTab(int index)
QTabBar * tabBar() const const
void tabCloseRequested(int index)
void setTabsClosable(bool closeable)
QWidget * widget(int index) const const
void setHtml(const QString &text)
void setReadOnly(bool ro)
QAction * addAction(const QString &text)
void create(WId window, bool initializeWindow, bool destroyOldWindow)
virtual bool event(QEvent *event) override
void hide()
QPoint mapToGlobal(const QPoint &pos) const const
void setGeometry(int x, int y, int w, int h)
void show()
void setSizePolicy(QSizePolicy)
bool isVisible() const const
void setWindowTitle(const QString &)