diff options
Diffstat (limited to 'src/gui/oscilloscope.cpp')
-rw-r--r-- | src/gui/oscilloscope.cpp | 354 |
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" |