summaryrefslogtreecommitdiffstats
path: root/src/gui/oscilloscope.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/oscilloscope.cpp')
-rw-r--r--src/gui/oscilloscope.cpp354
1 files changed, 354 insertions, 0 deletions
diff --git a/src/gui/oscilloscope.cpp b/src/gui/oscilloscope.cpp
new file mode 100644
index 0000000..e969f72
--- /dev/null
+++ b/src/gui/oscilloscope.cpp
@@ -0,0 +1,354 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "oscilloscope.h"
+#include "oscilloscopedata.h"
+#include "oscilloscopeview.h"
+#include "probe.h"
+#include "probepositioner.h"
+#include "simulator.h"
+#include "ktechlab.h"
+
+#include <cmath>
+#include <kcombobox.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <knuminput.h>
+#include <qbutton.h>
+#include <qlabel.h>
+#include <qscrollbar.h>
+#include <qslider.h>
+#include <qtimer.h>
+#include <qtoolbutton.h>
+
+#include <assert.h>
+
+//BEGIN Oscilloscope Class
+QColor probeColors[9] = {
+ QColor( 0x52, 0x22, 0x00 ),
+ QColor( 0xB5, 0x00, 0x2F ),
+ QColor( 0xF9, 0xBA, 0x07 ),
+ QColor( 0x53, 0x93, 0x16 ),
+ QColor( 0x00, 0x66, 0x2F ),
+ QColor( 0x00, 0x41, 0x88 ),
+ QColor( 0x1B, 0x2D, 0x83 ),
+ QColor( 0x55, 0x12, 0x7B ),
+ QColor( 0x7B, 0x0C, 0x82 ) };
+
+Oscilloscope * Oscilloscope::m_pSelf = 0l;
+
+Oscilloscope * Oscilloscope::self( KateMDI::ToolView * parent )
+{
+ if ( !m_pSelf )
+ {
+ assert(parent);
+ m_pSelf = new Oscilloscope(parent);
+ }
+ return m_pSelf;
+}
+
+
+Oscilloscope::Oscilloscope( KateMDI::ToolView * parent )
+ : OscilloscopeWidget(parent)
+{
+ m_nextColor = 0;
+ m_nextId = 1;
+ m_oldestId = -1;
+ m_oldestProbe = 0l;
+// b_isPaused = false;
+ m_zoomLevel = 0.5;
+ m_pSimulator = Simulator::self();
+
+ horizontalScroll->setLineStep(32);
+ horizontalScroll->setPageStep( oscilloscopeView->width() );
+
+ connect( resetBtn, SIGNAL(clicked()), this, SLOT(reset()) );
+ connect( zoomSlider, SIGNAL(valueChanged(int)), this, SLOT(slotZoomSliderChanged(int)) );
+ connect( horizontalScroll, SIGNAL(valueChanged(int )), this, SLOT(slotSliderValueChanged(int )) );
+
+// connect( pauseBtn, SIGNAL(clicked()), this, SLOT(slotTogglePause()) );
+
+ QTimer * updateScrollTmr = new QTimer(this);
+ connect( updateScrollTmr, SIGNAL(timeout()), this, SLOT(updateScrollbars()) );
+ updateScrollTmr->start(20);
+
+ KGlobal::config()->setGroup("Oscilloscope");
+ setZoomLevel( KGlobal::config()->readDoubleNumEntry( "ZoomLevel", 0.5 ) );
+
+ connect( this, SIGNAL(probeRegistered(int, ProbeData *)), probePositioner, SLOT(slotProbeDataRegistered(int, ProbeData *)) );
+ connect( this, SIGNAL(probeUnregistered(int )), probePositioner, SLOT(slotProbeDataUnregistered(int )) );
+}
+
+
+Oscilloscope::~Oscilloscope()
+{
+}
+
+
+void Oscilloscope::slotTogglePause()
+{
+// b_isPaused = !b_isPaused;
+// pauseBtn->setText( b_isPaused ? i18n("Resume") : i18n("Pause") );
+// const ProbeDataMap::iterator end = m_probeDataMap.end();
+// for ( ProbeDataMap::iterator it = m_probeDataMap.begin(); it != end; ++it )
+// (*it)->setPaused(b_isPaused);
+}
+
+
+int Oscilloscope::sliderTicksPerSecond() const
+{
+ return int(1e4);
+}
+
+
+void Oscilloscope::setZoomLevel( double zoomLevel )
+{
+ if ( zoomLevel < 0.0 )
+ zoomLevel = 0.0;
+
+ else if ( zoomLevel > 1.0 )
+ zoomLevel = 1.0;
+
+ KGlobal::config()->setGroup("Oscilloscope");
+ KGlobal::config()->writeEntry( "ZoomLevel", zoomLevel );
+
+ // We want to maintain the position of the *center* of the view, not the
+ // left edge, so have to record time at center of view... We also have to
+ // handle the case where the scroll is at the end separately.
+ bool wasAtUpperEnd = horizontalScroll->maxValue() == horizontalScroll->value();
+ int pageLength = int(oscilloscopeView->width()*sliderTicksPerSecond()/pixelsPerSecond());
+ int at_ticks = horizontalScroll->value() + (pageLength/2);
+
+ m_zoomLevel = zoomLevel;
+ zoomSlider->setValue( int((double(zoomSlider->maxValue())*zoomLevel)+0.5) );
+ updateScrollbars();
+
+ // And restore the center position of the slider
+ if (!wasAtUpperEnd)
+ {
+ int pageLength = int(oscilloscopeView->width()*sliderTicksPerSecond()/pixelsPerSecond());
+ horizontalScroll->setValue( at_ticks - (pageLength/2) );
+ oscilloscopeView->updateView();
+ }
+}
+
+
+void Oscilloscope::slotZoomSliderChanged( int value )
+{
+ setZoomLevel( double(value)/double(zoomSlider->maxValue()) );
+}
+
+
+ProbeData * Oscilloscope::registerProbe( Probe * probe )
+{
+ if (!probe)
+ return 0l;
+
+ const uint id = m_nextId++;
+
+ ProbeData * probeData = 0l;
+
+ if ( dynamic_cast<LogicProbe*>(probe) )
+ {
+ probeData = new LogicProbeData(id);
+ m_logicProbeDataMap[id] = static_cast<LogicProbeData*>(probeData);
+ }
+
+ else
+ {
+ probeData = new FloatingProbeData(id);
+ m_floatingProbeDataMap[id] = static_cast<FloatingProbeData*>(probeData);
+ }
+
+ m_probeDataMap[id] = probeData;
+
+ if (!m_oldestProbe)
+ {
+ m_oldestProbe = probeData;
+ m_oldestId = id;
+ }
+
+ probeData->setColor( probeColors[m_nextColor] );
+ m_nextColor = (m_nextColor+1)%9;
+// probeData->setPaused(b_isPaused);
+
+ emit probeRegistered( id, probeData );
+ return probeData;
+}
+
+
+void Oscilloscope::unregisterProbe( int id )
+{
+ ProbeDataMap::iterator it = m_probeDataMap.find(id);
+
+ if ( it == m_probeDataMap.end() )
+ return;
+
+ m_logicProbeDataMap.remove(id);
+ m_floatingProbeDataMap.remove(id);
+
+ bool oldestDestroyed = it.data() == m_oldestProbe;
+
+ if ( it != m_probeDataMap.end() )
+ m_probeDataMap.erase(it);
+
+ if (oldestDestroyed)
+ getOldestProbe();
+
+ emit probeUnregistered(id);
+}
+
+
+ProbeData * Oscilloscope::probeData( int id ) const
+{
+ const ProbeDataMap::const_iterator bit = m_probeDataMap.find(id);
+ if ( bit != m_probeDataMap.end() )
+ return bit.data();
+
+ return 0l;
+}
+
+
+int Oscilloscope::probeNumber( int id ) const
+{
+ const ProbeDataMap::const_iterator end = m_probeDataMap.end();
+ int i=0;
+ for ( ProbeDataMap::const_iterator it = m_probeDataMap.begin(); it != end; ++it )
+ {
+ if ( it.key() == id )
+ return i;
+ i++;
+ }
+ return -1;
+}
+
+
+int Oscilloscope::numberOfProbes() const
+{
+ return m_probeDataMap.size();
+}
+
+
+void Oscilloscope::getOldestProbe()
+{
+ if ( m_probeDataMap.isEmpty() )
+ {
+ m_oldestProbe = 0l;
+ m_oldestId = -1;
+ return;
+ }
+
+ m_oldestProbe = m_probeDataMap.begin().data();
+ m_oldestId = m_probeDataMap.begin().key();
+}
+
+
+void Oscilloscope::reset()
+{
+ const ProbeDataMap::iterator end = m_probeDataMap.end();
+ for ( ProbeDataMap::iterator it = m_probeDataMap.begin(); it != end; ++it )
+ (*it)->eraseData();
+
+ oscilloscopeView->updateView();
+}
+
+
+void Oscilloscope::slotSliderValueChanged( int value )
+{
+ Q_UNUSED(value);
+ oscilloscopeView->updateView();
+}
+
+
+void Oscilloscope::updateScrollbars()
+{
+ bool wasAtUpperEnd = horizontalScroll->maxValue() == horizontalScroll->value();
+
+ const float pps = pixelsPerSecond();
+
+ int pageLength = int(oscilloscopeView->width()*sliderTicksPerSecond()/pps);
+ llong timeAsTicks = time()*sliderTicksPerSecond()/LOGIC_UPDATE_RATE;
+ llong upper = (timeAsTicks > pageLength) ? (timeAsTicks - pageLength) : 0;
+ horizontalScroll->setRange( 0, upper );
+
+ horizontalScroll->setPageStep( ullong(oscilloscopeView->width()*sliderTicksPerSecond()/pps) );
+
+ if (wasAtUpperEnd)
+ {
+ horizontalScroll->setValue( horizontalScroll->maxValue() );
+ oscilloscopeView->updateView();
+ }
+}
+
+
+ullong Oscilloscope::time() const
+{
+ if (!m_oldestProbe)
+ return 0;
+
+ return ullong( m_pSimulator->time() - m_oldestProbe->resetTime() );
+}
+
+
+llong Oscilloscope::scrollTime() const
+{
+// if ( b_isPaused || numberOfProbes() == 0 )
+// return 0;
+
+ if ( numberOfProbes() == 0 )
+ return 0;
+
+ if ( horizontalScroll->maxValue() == 0 )
+ {
+ llong lengthAsTime = llong( oscilloscopeView->width() * LOGIC_UPDATE_RATE / pixelsPerSecond() );
+ return m_pSimulator->time() - lengthAsTime;
+ }
+
+ else
+ return llong( m_oldestProbe->resetTime() + (llong(horizontalScroll->value()) * LOGIC_UPDATE_RATE / sliderTicksPerSecond()) );
+}
+
+
+double Oscilloscope::pixelsPerSecond() const
+{
+ return 2 * MIN_BITS_PER_S * std::pow( 2.0, m_zoomLevel * MIN_MAX_LOG_2_DIFF );
+}
+//END Oscilloscope Class
+
+
+
+void addOscilloscopeAsToolView( KTechlab *ktechlab )
+{
+ KateMDI::ToolView * tv;
+ tv = ktechlab->createToolView( Oscilloscope::toolViewIdentifier(),
+ KMultiTabBar::Bottom,
+ KGlobal::iconLoader()->loadIcon( "oscilloscope", KIcon::Small ),
+ i18n("Oscilloscope") );
+
+ Oscilloscope::self(tv);
+}
+
+
+ProbeData * registerProbe( Probe * probe )
+{
+ return Oscilloscope::self()->registerProbe(probe);
+}
+
+
+void unregisterProbe( int id )
+{
+ Oscilloscope::self()->unregisterProbe(id);
+}
+
+
+#include "oscilloscope.moc"