File indexing completed on 2024-04-28 09:38:51
0001 /*************************************************************************** 0002 * Copyright (C) 2005 by David Saxton * 0003 * david@bluehaze.org * 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 "oscilloscope.h" 0012 #include "ktechlab.h" 0013 #include "oscilloscopedata.h" 0014 #include "oscilloscopeview.h" 0015 #include "probe.h" 0016 #include "probepositioner.h" 0017 #include "simulator.h" 0018 0019 #include <KConfigGroup> 0020 #include <KLocalizedString> 0021 #include <KSharedConfig> 0022 #include <cmath> 0023 0024 // #include <q3button.h> 0025 0026 #include <QLabel> 0027 #include <QScrollBar> 0028 #include <QSlider> 0029 #include <QTimer> 0030 #include <QToolButton> 0031 0032 #include <cassert> 0033 0034 #include <ktechlab_debug.h> 0035 0036 // BEGIN Oscilloscope Class 0037 QColor probeColors[9] = 0038 {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)}; 0039 0040 Oscilloscope *Oscilloscope::m_pSelf = nullptr; 0041 0042 Oscilloscope *Oscilloscope::self(KateMDI::ToolView *parent) 0043 { 0044 if (!m_pSelf) { 0045 assert(parent); 0046 m_pSelf = new Oscilloscope(parent); 0047 } 0048 return m_pSelf; 0049 } 0050 0051 Oscilloscope::Oscilloscope(KateMDI::ToolView *parent) 0052 : QWidget(parent) 0053 { 0054 setupUi(this); 0055 0056 if (parent->layout()) { 0057 parent->layout()->addWidget(this); 0058 qCDebug(KTL_LOG) << " added item selector to parent's layout " << parent; 0059 } else { 0060 qCWarning(KTL_LOG) << " unexpected null layout on parent " << parent; 0061 } 0062 0063 m_nextColor = 0; 0064 m_nextId = 1; 0065 m_oldestId = -1; 0066 m_oldestProbe = nullptr; 0067 // b_isPaused = false; 0068 m_zoomLevel = 0.5; 0069 m_pSimulator = Simulator::self(); 0070 0071 horizontalScroll->setSingleStep(32); 0072 horizontalScroll->setPageStep(oscilloscopeView->width()); 0073 0074 connect(resetBtn, &QPushButton::clicked, this, &Oscilloscope::reset); 0075 connect(zoomSlider, &QSlider::valueChanged, this, &Oscilloscope::slotZoomSliderChanged); 0076 connect(horizontalScroll, &QScrollBar::valueChanged, this, &Oscilloscope::slotSliderValueChanged); 0077 0078 // connect( pauseBtn, SIGNAL(clicked()), this, SLOT(slotTogglePause())); 0079 0080 QTimer *updateScrollTmr = new QTimer(this); 0081 connect(updateScrollTmr, &QTimer::timeout, this, &Oscilloscope::updateScrollbars); 0082 updateScrollTmr->start(20); 0083 0084 // KGlobal::config()->setGroup("Oscilloscope"); 0085 KConfigGroup grOscill(KSharedConfig::openConfig(), "Oscilloscope"); 0086 setZoomLevel(grOscill.readEntry("ZoomLevel", 0.5)); 0087 0088 connect(this, SIGNAL(probeRegistered(int, ProbeData *)), probePositioner, SLOT(slotProbeDataRegistered(int, ProbeData *))); 0089 /*TODO fix error: 'slotProbeDataRegistered(int, ProbeData*)’ is protected within this context 0090 connect(this, &Oscilloscope::probeRegistered, 0091 probePositioner, &ProbePositioner::slotProbeDataRegistered);*/ 0092 connect(this, SIGNAL(probeUnregistered(int)), probePositioner, SLOT(slotProbeDataUnregistered(int))); 0093 /*TODO the same problem 0094 connect(this, &Oscilloscope::probeUnregistered, 0095 probePositioner, &ProbePositioner::slotProbeDataUnregistered);*/ 0096 } 0097 0098 Oscilloscope::~Oscilloscope() 0099 { 0100 m_pSelf = nullptr; 0101 } 0102 0103 bool Oscilloscope::isInstantiated() 0104 { 0105 return m_pSelf != nullptr; 0106 } 0107 0108 void Oscilloscope::slotTogglePause() 0109 { 0110 // b_isPaused = !b_isPaused; 0111 // pauseBtn->setText( b_isPaused ? i18n("Resume") : i18n("Pause")); 0112 // const ProbeDataMap::iterator end = m_probeDataMap.end(); 0113 // for( ProbeDataMap::iterator it = m_probeDataMap.begin(); it != end; ++it) 0114 // (*it)->setPaused(b_isPaused); 0115 } 0116 0117 int Oscilloscope::sliderTicksPerSecond() const 0118 { 0119 return int(1e4); 0120 } 0121 0122 void Oscilloscope::setZoomLevel(double zoomLevel) 0123 { 0124 if (zoomLevel < 0.0) 0125 zoomLevel = 0.0; 0126 0127 else if (zoomLevel > 1.0) 0128 zoomLevel = 1.0; 0129 0130 // KGlobal::config()->setGroup("Oscilloscope"); 0131 KConfigGroup grOscill = KSharedConfig::openConfig()->group("Oscilloscope"); 0132 // KGlobal::config()->writeEntry( "ZoomLevel", zoomLevel); 0133 grOscill.writeEntry("ZoomLevel", zoomLevel); 0134 0135 // We want to maintain the position of the *center* of the view, not the 0136 // left edge, so have to record time at center of view... We also have to 0137 // handle the case where the scroll is at the end separately. 0138 bool wasAtUpperEnd = horizontalScroll->maximum() == horizontalScroll->value(); 0139 int pageLength = int(oscilloscopeView->width() * sliderTicksPerSecond() / pixelsPerSecond()); 0140 int at_ticks = horizontalScroll->value() + (pageLength / 2); 0141 0142 m_zoomLevel = zoomLevel; 0143 zoomSlider->setValue(int((double(zoomSlider->maximum()) * zoomLevel) + 0.5)); 0144 updateScrollbars(); 0145 0146 // And restore the center position of the slider 0147 if (!wasAtUpperEnd) { 0148 int pageLength = int(oscilloscopeView->width() * sliderTicksPerSecond() / pixelsPerSecond()); 0149 horizontalScroll->setValue(at_ticks - (pageLength / 2)); 0150 oscilloscopeView->updateView(); 0151 } 0152 } 0153 0154 void Oscilloscope::slotZoomSliderChanged(int value) 0155 { 0156 setZoomLevel(double(value) / double(zoomSlider->maximum())); 0157 } 0158 0159 ProbeData *Oscilloscope::registerProbe(Probe *probe) 0160 { 0161 if (!probe) 0162 return nullptr; 0163 0164 const uint id = m_nextId++; 0165 0166 ProbeData *probeData = nullptr; 0167 0168 if (dynamic_cast<LogicProbe *>(probe)) { 0169 probeData = new LogicProbeData(id); 0170 m_logicProbeDataMap[id] = static_cast<LogicProbeData *>(probeData); 0171 } else { 0172 probeData = new FloatingProbeData(id); 0173 m_floatingProbeDataMap[id] = static_cast<FloatingProbeData *>(probeData); 0174 } 0175 0176 m_probeDataMap[id] = probeData; 0177 0178 if (!m_oldestProbe) { 0179 m_oldestProbe = probeData; 0180 m_oldestId = id; 0181 } 0182 0183 probeData->setColor(probeColors[m_nextColor]); 0184 m_nextColor = (m_nextColor + 1) % 9; 0185 // probeData->setPaused(b_isPaused); 0186 0187 emit probeRegistered(id, probeData); 0188 return probeData; 0189 } 0190 0191 void Oscilloscope::unregisterProbe(int id) 0192 { 0193 ProbeDataMap::iterator it = m_probeDataMap.find(id); 0194 0195 if (it == m_probeDataMap.end()) 0196 return; 0197 0198 m_logicProbeDataMap.remove(id); 0199 m_floatingProbeDataMap.remove(id); 0200 0201 bool oldestDestroyed = it.value() == m_oldestProbe; 0202 0203 if (it != m_probeDataMap.end()) 0204 m_probeDataMap.erase(it); 0205 0206 if (oldestDestroyed) 0207 getOldestProbe(); 0208 0209 emit probeUnregistered(id); 0210 } 0211 0212 ProbeData *Oscilloscope::probeData(int id) const 0213 { 0214 const ProbeDataMap::const_iterator bit = m_probeDataMap.find(id); 0215 if (bit != m_probeDataMap.end()) 0216 return bit.value(); 0217 0218 return nullptr; 0219 } 0220 0221 int Oscilloscope::probeNumber(int id) const 0222 { 0223 const ProbeDataMap::const_iterator end = m_probeDataMap.end(); 0224 int i = 0; 0225 for (ProbeDataMap::const_iterator it = m_probeDataMap.begin(); it != end; ++it) { 0226 if (it.key() == id) 0227 return i; 0228 i++; 0229 } 0230 return -1; 0231 } 0232 0233 int Oscilloscope::numberOfProbes() const 0234 { 0235 return m_probeDataMap.size(); 0236 } 0237 0238 void Oscilloscope::getOldestProbe() 0239 { 0240 if (m_probeDataMap.isEmpty()) { 0241 m_oldestProbe = nullptr; 0242 m_oldestId = -1; 0243 return; 0244 } 0245 0246 m_oldestProbe = m_probeDataMap.begin().value(); 0247 m_oldestId = m_probeDataMap.begin().key(); 0248 } 0249 0250 void Oscilloscope::reset() 0251 { 0252 const ProbeDataMap::iterator end = m_probeDataMap.end(); 0253 for (ProbeDataMap::iterator it = m_probeDataMap.begin(); it != end; ++it) 0254 (*it)->eraseData(); 0255 0256 oscilloscopeView->updateView(); 0257 } 0258 0259 void Oscilloscope::slotSliderValueChanged(int value) 0260 { 0261 Q_UNUSED(value); 0262 oscilloscopeView->updateView(); 0263 } 0264 0265 void Oscilloscope::updateScrollbars() 0266 { 0267 bool wasAtUpperEnd = horizontalScroll->maximum() == horizontalScroll->value(); 0268 0269 const float pps = pixelsPerSecond(); 0270 0271 int pageLength = int(oscilloscopeView->width() * sliderTicksPerSecond() / pps); 0272 int64_t timeAsTicks = time() * sliderTicksPerSecond() / LOGIC_UPDATE_RATE; 0273 int64_t upper = (timeAsTicks > pageLength) ? (timeAsTicks - pageLength) : 0; 0274 horizontalScroll->setRange(0, upper); 0275 0276 horizontalScroll->setPageStep(uint64_t(oscilloscopeView->width() * sliderTicksPerSecond() / pps)); 0277 0278 if (wasAtUpperEnd) { 0279 horizontalScroll->setValue(horizontalScroll->maximum()); 0280 oscilloscopeView->updateView(); 0281 } 0282 } 0283 0284 uint64_t Oscilloscope::time() const 0285 { 0286 if (!m_oldestProbe) 0287 return 0; 0288 0289 return uint64_t(m_pSimulator->time() - m_oldestProbe->resetTime()); 0290 } 0291 0292 int64_t Oscilloscope::scrollTime() const 0293 { 0294 // if( b_isPaused || numberOfProbes() == 0) 0295 // return 0; 0296 0297 if (numberOfProbes() == 0) 0298 return 0; 0299 0300 if (horizontalScroll->maximum() == 0) { 0301 int64_t lengthAsTime = int64_t(oscilloscopeView->width() * LOGIC_UPDATE_RATE / pixelsPerSecond()); 0302 int64_t ret = m_pSimulator->time() - lengthAsTime; 0303 if (ret < 0) 0304 return 0; 0305 return ret; 0306 } else 0307 return int64_t(m_oldestProbe->resetTime() + (int64_t(horizontalScroll->value()) * LOGIC_UPDATE_RATE / sliderTicksPerSecond())); 0308 } 0309 0310 double Oscilloscope::pixelsPerSecond() const 0311 { 0312 return 2 * MIN_BITS_PER_S * std::pow(2.0, m_zoomLevel * MIN_MAX_LOG_2_DIFF); 0313 } 0314 // END Oscilloscope Class 0315 0316 void addOscilloscopeAsToolView(KTechlab *ktechlab) 0317 { 0318 KateMDI::ToolView *tv; 0319 tv = ktechlab->createToolView(Oscilloscope::toolViewIdentifier(), KMultiTabBar::Bottom, QIcon::fromTheme("oscilloscope"), i18n("Oscilloscope")); 0320 0321 Oscilloscope::self(tv); 0322 } 0323 0324 ProbeData *registerProbe(Probe *probe) 0325 { 0326 if (!Oscilloscope::isInstantiated()) { 0327 qCDebug(KTL_LOG) << "no oscilloscope to register to, doing nothing"; 0328 return nullptr; 0329 } 0330 return Oscilloscope::self()->registerProbe(probe); 0331 } 0332 0333 void unregisterProbe(int id) 0334 { 0335 if (!Oscilloscope::isInstantiated()) { 0336 qCDebug(KTL_LOG) << "no oscilloscope to unregister from, doing nothing"; 0337 return; 0338 } 0339 Oscilloscope::self()->unregisterProbe(id); 0340 } 0341 0342 #include "moc_oscilloscope.cpp"