File indexing completed on 2025-04-20 11:09:40
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"