File indexing completed on 2024-05-05 05:46:04
0001 /*************************************************************************** 0002 * Copyright (C) 2003-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 "ecclockinput.h" 0012 0013 #include "libraryitem.h" 0014 #include "logic.h" 0015 #include "simulator.h" 0016 0017 #include <KLocalizedString> 0018 #include <QPainter> 0019 0020 #include <cmath> 0021 0022 #include <ktechlab_debug.h> 0023 0024 using namespace std; 0025 0026 // was a constant, this is my guess for an appropriate name. 0027 //#define TIME_INTERVAL 100 // 2015.09.27 - added proper constant to simulator class 0028 0029 static inline uint roundDouble(const double x) 0030 { 0031 return uint(std::floor(x + 0.5)); 0032 } 0033 0034 Item *ECClockInput::construct(ItemDocument *itemDocument, bool newItem, const char *id) 0035 { 0036 return new ECClockInput(static_cast<ICNDocument *>(itemDocument), newItem, id); 0037 } 0038 0039 LibraryItem *ECClockInput::libraryItem() 0040 { 0041 return new LibraryItem(QStringList(QString("ec/clock_input")), i18n("Clock Input"), i18n("Logic"), "clockinput.png", LibraryItem::lit_component, ECClockInput::construct); 0042 } 0043 0044 ECClockInput::ECClockInput(ICNDocument *icnDocument, bool newItem, const char *id) 0045 : Component(icnDocument, newItem, (id) ? id : "clock_input") 0046 { 0047 m_name = i18n("Clock Input"); 0048 setSize(-16, -8, 32, 16); 0049 0050 m_lastSetTime = 0; 0051 m_time = 0; 0052 m_high_time = 0; 0053 m_low_time = 0; 0054 m_period = 0; 0055 m_bSetStepCallbacks = true; 0056 m_pSimulator = Simulator::self(); 0057 0058 for (unsigned i = 0; i < LOGIC_UPDATE_PER_STEP; i++) { 0059 ComponentCallback *ccb = new ComponentCallback(this, static_cast<VoidCallbackPtr>(&ECClockInput::stepCallback)); 0060 m_pComponentCallback[i] = new list<ComponentCallback>; 0061 m_pComponentCallback[i]->push_back(*ccb); 0062 } 0063 0064 init1PinRight(); 0065 m_pOut = createLogicOut(m_pPNode[0], false); 0066 0067 createProperty("low-time", Variant::Type::Double); 0068 property("low-time")->setUnit("S"); 0069 property("low-time")->setCaption(i18n("Low Time")); 0070 property("low-time")->setMinValue(1.0 / LOGIC_UPDATE_RATE); 0071 property("low-time")->setValue(0.5); 0072 0073 createProperty("high-time", Variant::Type::Double); 0074 property("high-time")->setUnit("S"); 0075 property("high-time")->setCaption(i18n("High Time")); 0076 property("high-time")->setMinValue(1.0 / LOGIC_UPDATE_RATE); 0077 property("high-time")->setValue(0.5); 0078 0079 addDisplayText("freq", QRect(-16, -24, 32, 14), "", false); 0080 } 0081 0082 ECClockInput::~ECClockInput() 0083 { 0084 for (unsigned i = 0; i < LOGIC_UPDATE_PER_STEP; i++) 0085 delete m_pComponentCallback[i]; 0086 } 0087 0088 void ECClockInput::dataChanged() 0089 { 0090 m_high_time = roundDouble(dataDouble("high-time") * LOGIC_UPDATE_RATE); 0091 m_low_time = roundDouble(dataDouble("low-time") * LOGIC_UPDATE_RATE); 0092 m_period = m_low_time + m_high_time; 0093 0094 const double frequency = 1. / (dataDouble("high-time") + dataDouble("low-time")); 0095 QString display = QString::number(frequency / getMultiplier(frequency), 'g', 3) + getNumberMag(frequency) + "Hz"; 0096 setDisplayText("freq", display); 0097 0098 bool setStepCallbacks = m_period > LOGIC_UPDATE_PER_STEP; 0099 if (setStepCallbacks != m_bSetStepCallbacks) { 0100 m_bSetStepCallbacks = setStepCallbacks; 0101 if (setStepCallbacks) { 0102 m_pSimulator->detachComponentCallbacks(*this); 0103 } else { 0104 m_pSimulator->attachComponentCallback(this, static_cast<VoidCallbackPtr>(&ECClockInput::stepLogic)); 0105 } 0106 } 0107 0108 m_bLastStepCallbackOut = false; 0109 m_lastSetTime = m_pSimulator->time(); 0110 if (m_lastSetTime < 0) { 0111 qCWarning(KTL_LOG) << " m_lastSetTime = " << m_lastSetTime; 0112 } 0113 } 0114 0115 void ECClockInput::stepLogic() 0116 { 0117 m_pOut->setHigh(m_time > m_low_time); 0118 0119 ++m_time; 0120 if (m_time > m_period) { 0121 m_time -= int(m_time / m_period) * m_period; 0122 } 0123 } 0124 0125 void ECClockInput::stepCallback() 0126 { 0127 m_pOut->setHigh(m_bLastStepCallbackOut); 0128 m_bLastStepCallbackOut = !m_bLastStepCallbackOut; 0129 } 0130 0131 void ECClockInput::stepNonLogic() 0132 { 0133 if (!m_bSetStepCallbacks) { 0134 return; 0135 } 0136 0137 bool addingHigh = !m_bLastStepCallbackOut; 0138 0139 // { // for testing 0140 // const long long remainingLogicSteps = m_pSimulator->time() % LOGIC_UPDATE_PER_STEP; 0141 // if (remainingLogicSteps != 0) { 0142 // qCWarning(KTL_LOG) << "remainingLogicSteps should be 0, but got " << remainingLogicSteps; 0143 // } 0144 // } 0145 0146 // TODO review this method 0147 0148 long long lowerTime = m_pSimulator->time(); 0149 long long upperTime = lowerTime + LOGIC_UPDATE_PER_STEP; 0150 0151 long long upTo = m_lastSetTime; 0152 0153 while (upTo + (addingHigh ? m_high_time : m_low_time) < upperTime) { 0154 upTo += addingHigh ? m_high_time : m_low_time; 0155 addingHigh = !addingHigh; 0156 0157 long long at = upTo - lowerTime; 0158 if (at >= 0 && at < LOGIC_UPDATE_PER_STEP) 0159 m_pSimulator->addStepCallback(at, &m_pComponentCallback[at]->front()); 0160 } 0161 0162 m_lastSetTime = upTo; 0163 if (m_lastSetTime < 0) { 0164 qCWarning(KTL_LOG) << " m_lastSetTime = " << m_lastSetTime; 0165 } 0166 } 0167 0168 void ECClockInput::drawShape(QPainter &p) 0169 { 0170 initPainter(p); 0171 0172 int _x = int(x()) - 10; 0173 int _y = int(y()) - 8; 0174 0175 p.drawRect(_x - 6, _y, 32, 16); 0176 0177 p.drawLine(_x, _y + 8, _x, _y + 4); 0178 p.drawLine(_x, _y + 4, _x + 4, _y + 4); 0179 p.drawLine(_x + 4, _y + 4, _x + 4, _y + 12); 0180 p.drawLine(_x + 4, _y + 12, _x + 8, _y + 12); 0181 p.drawLine(_x + 8, _y + 12, _x + 8, _y + 4); 0182 p.drawLine(_x + 8, _y + 4, _x + 12, _y + 4); 0183 p.drawLine(_x + 12, _y + 4, _x + 12, _y + 12); 0184 p.drawLine(_x + 12, _y + 12, _x + 16, _y + 12); 0185 p.drawLine(_x + 16, _y + 12, _x + 16, _y + 4); 0186 p.drawLine(_x + 16, _y + 4, _x + 20, _y + 4); 0187 p.drawLine(_x + 20, _y + 4, _x + 20, _y + 8); 0188 0189 deinitPainter(p); 0190 }