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 }