File indexing completed on 2024-06-16 08:27:26

0001 /***************************************************************************
0002  *   Copyright (C) 2005 by John Myers                                      *
0003  *   electronerd@electronerdia.net                                         *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  ***************************************************************************/
0010 
0011 #include "scopescreenview.h"
0012 #include "oscilloscope.h"
0013 #include "oscilloscopedata.h"
0014 #include "probe.h"
0015 #include "probepositioner.h"
0016 #include "simulator.h"
0017 
0018 #include <QPainter>
0019 #include <QTimer>
0020 
0021 #include <cmath>
0022 
0023 #include <ktechlab_debug.h>
0024 
0025 #define FADESPEED 1
0026 
0027 ScopeScreenView::ScopeScreenView(QWidget *parent)
0028     : ScopeViewBase(parent)
0029     , m_intervalsX(10)
0030     , m_ticksPerIntervalX(10000)
0031     , m_offsetX(0)
0032 {
0033     m_updateViewTmr = new QTimer(this);
0034     connect(m_updateViewTmr, SIGNAL(timeout()), this, SLOT(updateViewTimeout()));
0035     m_updateViewTmr->start(50);
0036 }
0037 
0038 ScopeScreenView::~ScopeScreenView()
0039 {
0040 }
0041 
0042 #if 0
0043 void ScopeScreenView::drawContents(QPainter * p)
0044 {
0045     QRect cr = contentsRect();
0046 
0047     for(int i =1; i < m_intervalsX; i++)
0048     {
0049         int x = cr.left() + cr.width()*i/m_intervalsX;
0050         p->drawLine(x, cr.top(), x, cr.bottom());
0051     }
0052     const int ticksPerScreen = m_intervalsX * m_ticksPerIntervalX;
0053     const double pixelsPerTick = cr.width()/double(ticksPerScreen);
0054     const double ticksPerPixel = m_intervalsX * m_ticksPerIntervalX / cr.width();   
0055     //draw the current time
0056     int curTimeX = ((Simulator::self()->time() + m_offsetX) % (ticksPerScreen)) * pixelsPerTick;
0057     //qCDebug(KTL_LOG) << curTimeX;
0058     p->drawLine(curTimeX, cr.top(), curTimeX, cr.bottom());
0059     
0060     //the following is liberally borrowed from OscilloscopeView::drawFloatingData
0061     const FloatingProbeDataMap::iterator end = Oscilloscope::self()->m_floatingProbeDataMap.end();
0062     for ( FloatingProbeDataMap::iterator it = Oscilloscope::self()->m_floatingProbeDataMap.begin(); it != end; ++it )
0063     {
0064         FloatingProbeData * probe = it.value();
0065         StoredData<float> * data = &(probe->m_data);
0066         
0067         if ( data->allocatedUpTo() == 0 )
0068             continue;
0069         
0070         bool logarithmic = probe->scaling() == FloatingProbeData::Logarithmic;
0071         double lowerAbsValue = probe->lowerAbsValue();
0072         double sf = ((cr.height()/Oscilloscope::self()->numberOfProbes())/2) / (logarithmic ? log(probe->upperAbsValue()/lowerAbsValue) : probe->upperAbsValue());
0073         
0074         const int midHeight = Oscilloscope::self()->probePositioner->probePosition(probe);
0075         //const int midHeight = cr.top() + cr.height()/2;       
0076         //const llong timeOffset = Oscilloscope::self()->scrollTime();
0077         const llong timeOffset = Simulator::self()->time() - (FADESPEED * m_intervalsX * m_ticksPerIntervalX);
0078         
0079         // Draw the horizontal line indicating the midpoint of our output
0080         p->setPen( QColor( 228, 228, 228 ) );
0081         p->drawLine( 0, midHeight, width(), midHeight );
0082         
0083         // Set the pen colour according to the colour the user has selected for the probe
0084         p->setPen( probe->color() );
0085         
0086         llong at = probe->findPos(timeOffset); 
0087         const llong maxAt = probe->insertPos();
0088         llong prevTime = probe->toTime(at);
0089         
0090         double v = data->dataAt((at>0)?at:0);
0091         int prevY = int(midHeight - (logarithmic ? ( (v>0) ? log(v/lowerAbsValue) : -log(-v/lowerAbsValue) ) : v) * sf);
0092         int prevX = (int((prevTime - timeOffset)*pixelsPerTick) + curTimeX) % cr.width();
0093         
0094         while ( at < maxAt-1 )
0095         {
0096             at++;
0097             
0098             ullong nextTime = probe->toTime(at);
0099             
0100             double v = data->dataAt((at>0)?at:0);
0101             int nextY = int(midHeight - (logarithmic ? ( (v>0) ? log(v/lowerAbsValue) : -log(-v/lowerAbsValue) ) : v) * sf);
0102             int nextX = (int((nextTime - timeOffset)*pixelsPerTick) + curTimeX) % cr.width();
0103             if(nextX < prevX)
0104             {
0105                 prevX = 0;
0106             }
0107             //qCDebug(KTL_LOG) <<at<<" "<<nextX<<" "<<nextY<<" "<<nextTime;
0108             p->drawLine( prevX, prevY, nextX, nextY );
0109             
0110             prevTime = nextTime;
0111             prevX = nextX;
0112             prevY = nextY;
0113             
0114             //if ( nextX > width() )
0115             //break;
0116         };
0117         
0118         // If we could not draw right to the end; it is because we exceeded
0119         // maxAt
0120         //if ( prevX < curTimeX )
0121         //  p->drawLine( prevX, prevY, curTimeX, prevY );
0122     }
0123     
0124     //and this was liberally borrowed from OscilloscopeView::DrawLogicData
0125     {
0126     const LogicProbeDataMap::iterator end = Oscilloscope::self()->m_logicProbeDataMap.end();
0127     for ( LogicProbeDataMap::iterator it = Oscilloscope::self()->m_logicProbeDataMap.begin(); it != end; ++it )
0128     {
0129         // When searching for the next logic value to display, we look along
0130         // until there is a recorded point which is at least one pixel along
0131         // If we are zoomed out far, there might be thousands of data points
0132         // between each pixel. It is time consuming searching for the next point
0133         // to display one at a time, so we record the average number of data points
0134         // between pixels ( = deltaAt / totalDeltaAt )
0135         llong deltaAt = 1;
0136         int totalDeltaAt = 1;
0137         
0138         LogicProbeData * probe = it.value();
0139         StoredData<LogicDataPoint> * data = &(probe->m_data);
0140         
0141         if ( data->allocatedUpTo() == 0 )
0142             continue;
0143         
0144         const int midHeight = Oscilloscope::self()->probePositioner->probePosition(probe);
0145         const llong timeOffset = Simulator::self()->time() - (FADESPEED * m_intervalsX * m_ticksPerIntervalX);//Oscilloscope::self()->scrollTime();
0146         
0147         const int halfOutputHeight = ((cr.height()/Oscilloscope::self()->numberOfProbes())/2);
0148         
0149         // Draw the horizontal line indicating the midpoint of our output
0150         p->setPen( QColor( 228, 228, 228 ) );
0151         p->drawLine( 0, midHeight, width(), midHeight );
0152         
0153         // Set the pen colour according to the colour the user has selected for the probe
0154         p->setPen( probe->color() );
0155         
0156         // The smallest time step that will display in our oscilloscope
0157         const int minTimeStep = ticksPerPixel;//int(LOGIC_UPDATE_RATE/pixelsPerSecond);
0158         
0159         llong at = probe->findPos(timeOffset);
0160         const llong maxAt = probe->insertPos();
0161         llong prevTime = data->dataAt(at).time;
0162         int prevX = (int((prevTime - timeOffset)*pixelsPerTick) + curTimeX) % cr.width();
0163         bool prevHigh = data->dataAt(at).value;
0164         int prevY = midHeight + int(prevHigh ? -halfOutputHeight : +halfOutputHeight);
0165         while ( at < maxAt )
0166         {
0167             // Search for the next pos which will show up at our zoom level
0168             llong previousAt = at;
0169             llong dAt = deltaAt / totalDeltaAt;
0170             
0171             while ( (dAt > 1) && (at < maxAt) && ( (llong(data->dataAt(at).time) - prevTime) != minTimeStep ) )
0172             {
0173                 // Search forwards until we overshoot
0174                 while ( at < maxAt && ( llong(data->dataAt(at).time) - prevTime ) < minTimeStep )
0175                     at += dAt;
0176                 dAt /= 2;
0177                 
0178                 // Search backwards until we undershoot
0179                 while ( (at < maxAt) && ( llong(data->dataAt(at).time) - prevTime ) > minTimeStep )
0180                 {
0181                     at -= dAt;
0182                     if ( at < 0 )
0183                         at = 0;
0184                 }
0185                 dAt /= 2;
0186             }
0187             
0188             // Possibly increment the value of at found by one (or more if this is the first go)
0189             while ( (previousAt == at) || ((at < maxAt) && ( llong(data->dataAt(at).time) - prevTime ) < minTimeStep) )
0190                 at++;
0191             
0192             if ( at >= maxAt )
0193                 break;
0194             
0195             // Update the average values
0196             deltaAt += at - previousAt;
0197             totalDeltaAt++;
0198             
0199             bool nextHigh = data->dataAt(at).value;
0200             if ( nextHigh == prevHigh )
0201                 continue;
0202             llong nextTime = data->dataAt(at).time;
0203             int nextX = (int((nextTime - timeOffset)*pixelsPerTick) + curTimeX) % cr.width();
0204             int nextY = midHeight + int(nextHigh ? -halfOutputHeight : +halfOutputHeight);
0205             
0206             p->drawLine( prevX, prevY, nextX, prevY );
0207             p->drawLine( nextX, prevY, nextX, nextY );
0208             
0209             prevHigh = nextHigh;
0210             prevTime = nextTime;
0211             prevX = nextX;
0212             prevY = nextY;
0213             
0214             if ( nextX > width() )
0215                 break;
0216         };
0217         
0218         // If we could not draw right to the end; it is because we exceeded
0219         // maxAt
0220         //if ( prevX < width() )
0221         //  p->drawLine( prevX, prevY, width(), prevY );
0222     }
0223     }
0224 }
0225 #endif
0226 void ScopeScreenView::setIntervalsX(int value)
0227 {
0228     m_intervalsX = value;
0229 }
0230 
0231 void ScopeScreenView::setTicksPerIntervalX(int value)
0232 {
0233     m_ticksPerIntervalX = value;
0234 }
0235 
0236 void ScopeScreenView::setOffsetX(int value)
0237 {
0238     m_offsetX = value;
0239 }
0240 
0241 void ScopeScreenView::updateViewTimeout()
0242 {
0243     repaint();
0244 }
0245 
0246 void ScopeScreenView::drawBackground(QPainter &p)
0247 {
0248     QRect cr = contentsRect();
0249 
0250     for (int i = 1; i < m_intervalsX; i++) {
0251         int x = cr.left() + cr.width() * i / m_intervalsX;
0252         p.drawLine(x, cr.top(), x, cr.bottom());
0253     }
0254 
0255     ///\todo REMOVE THIS NOTICE
0256 
0257     p.drawText(cr.left(), cr.top(), "NOT YET IMPLEMENTED");
0258 }
0259 
0260 void ScopeScreenView::drawMidLine(QPainter &p, ProbeData *probe)
0261 {
0262     const int midHeight = Oscilloscope::self()->probePositioner->probePosition(probe);
0263 
0264     // Draw the horizontal line indicating the midpoint of our output
0265     p.setPen(QColor(228, 228, 228));
0266     p.drawLine(0, midHeight, width(), midHeight);
0267 }
0268 
0269 void ScopeScreenView::drawProbe(QPainter & /*p*/, LogicProbeData */*probe*/)
0270 {
0271 }
0272 
0273 void ScopeScreenView::drawProbe(QPainter &/*p*/, FloatingProbeData */*probe*/)
0274 {
0275 }
0276 
0277 #include "moc_scopescreenview.cpp"