summaryrefslogtreecommitdiffstats
path: root/src/electronics/components/ecclockinput.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/electronics/components/ecclockinput.cpp')
-rw-r--r--src/electronics/components/ecclockinput.cpp185
1 files changed, 185 insertions, 0 deletions
diff --git a/src/electronics/components/ecclockinput.cpp b/src/electronics/components/ecclockinput.cpp
new file mode 100644
index 0000000..7f1ec9c
--- /dev/null
+++ b/src/electronics/components/ecclockinput.cpp
@@ -0,0 +1,185 @@
+/***************************************************************************
+ * Copyright (C) 2003-2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "ecclockinput.h"
+
+#include "logic.h"
+#include "libraryitem.h"
+#include "simulator.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+
+#include <cmath>
+
+static inline uint roundDouble( const double x )
+{
+ return uint(std::floor(x+0.5));
+}
+
+Item* ECClockInput::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECClockInput( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECClockInput::libraryItem()
+{
+ return new LibraryItem(
+ QString("ec/clock_input"),
+ i18n("Clock Input"),
+ i18n("Logic"),
+ "clockinput.png",
+ LibraryItem::lit_component,
+ ECClockInput::construct );
+}
+
+ECClockInput::ECClockInput( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, (id) ? id : "clock_input" )
+{
+ m_name = i18n("Clock Input");
+ m_desc = i18n("A square-wave generator, outputing logical high/low at repeating time intervals.");
+ setSize( -16, -8, 32, 16 );
+
+ m_lastSetTime = 0;
+ m_time = 0;
+ m_high_time = 0;
+ m_low_time = 0;
+ m_period = 0;
+ m_bSetStepCallbacks = true;
+ m_pSimulator = Simulator::self();
+
+ for ( unsigned i = 0; i < 1000; i++ )
+ {
+ ComponentCallback * ccb = new ComponentCallback( this, (VoidCallbackPtr)(&ECClockInput::stepCallback) );
+ m_pComponentCallback[i] = new LinkedList<ComponentCallback>(ccb);
+ }
+
+ init1PinRight();
+ m_pOut = createLogicOut( m_pPNode[0], false );
+
+ createProperty( "low-time", Variant::Type::Double );
+ property("low-time")->setUnit("S");
+ property("low-time")->setCaption( i18n("Low Time") );
+ property("low-time")->setMinValue(1.0/LOGIC_UPDATE_RATE);
+ property("low-time")->setValue(0.5);
+
+ createProperty( "high-time", Variant::Type::Double );
+ property("high-time")->setUnit("S");
+ property("high-time")->setCaption( i18n("High Time") );
+ property("high-time")->setMinValue(1.0/LOGIC_UPDATE_RATE);
+ property("high-time")->setValue(0.5);
+
+ addDisplayText( "freq", QRect( -16, -24, 32, 14 ), "", false );
+}
+
+
+ECClockInput::~ECClockInput()
+{
+ for ( unsigned i = 0; i < 1000; i++ )
+ {
+ delete m_pComponentCallback[i]->data();
+ delete m_pComponentCallback[i];
+ }
+}
+
+
+void ECClockInput::dataChanged()
+{
+ m_high_time = roundDouble(dataDouble("high-time")*LOGIC_UPDATE_RATE);
+ m_low_time = roundDouble(dataDouble("low-time")*LOGIC_UPDATE_RATE);
+ m_period = m_low_time+m_high_time;
+
+ const double frequency = 1./(dataDouble("high-time")+dataDouble("low-time"));
+ QString display = QString::number( frequency / getMultiplier(frequency), 'g', 3 ) + getNumberMag(frequency) + "Hz";
+ setDisplayText( "freq", display );
+
+ bool setStepCallbacks = m_period > 100;
+ if ( setStepCallbacks != m_bSetStepCallbacks )
+ {
+ m_bSetStepCallbacks = setStepCallbacks;
+ if (setStepCallbacks)
+ m_pSimulator->detachComponentCallbacks(this);
+ else
+ m_pSimulator->attachComponentCallback( this, (VoidCallbackPtr)(&ECClockInput::stepLogic) );
+ }
+
+ m_bLastStepCallbackOut = false;
+ m_lastSetTime = m_pSimulator->time();
+}
+
+
+void ECClockInput::stepLogic()
+{
+ m_pOut->setHigh( m_time>m_low_time );
+
+ if ( ++m_time > m_period ) {
+ m_time -= int(m_time/m_period)*m_period;
+ }
+}
+
+
+void ECClockInput::stepCallback()
+{
+ m_pOut->setHigh(m_bLastStepCallbackOut);
+ m_bLastStepCallbackOut = !m_bLastStepCallbackOut;
+}
+
+
+void ECClockInput::stepNonLogic()
+{
+ if (!m_bSetStepCallbacks)
+ return;
+
+ bool addingHigh = !m_bLastStepCallbackOut;
+
+ //TODO 100 number shouldn't be hard-coded
+ long long lowerTime = m_pSimulator->time();
+ long long upperTime = lowerTime + 100;
+
+ long long upTo = m_lastSetTime;
+
+ while ( upTo + (addingHigh?m_high_time:m_low_time) < upperTime )
+ {
+ upTo += addingHigh ? m_high_time : m_low_time;
+ addingHigh = !addingHigh;
+
+ long long at = upTo-lowerTime;
+ if ( at >= 0 && at < 100 )
+ m_pSimulator->addStepCallback( at, m_pComponentCallback[at] );
+ }
+
+ m_lastSetTime = upTo;
+}
+
+
+void ECClockInput::drawShape( QPainter &p )
+{
+ initPainter(p);
+
+ int _x = (int)x()-10;
+ int _y = (int)y()-8;
+
+ p.drawRect( _x-6, _y, 32, 16 );
+
+ p.drawLine( _x, _y+8, _x, _y+4 );
+ p.drawLine( _x, _y+4, _x+4, _y+4 );
+ p.drawLine( _x+4, _y+4, _x+4, _y+12 );
+ p.drawLine( _x+4, _y+12, _x+8, _y+12 );
+ p.drawLine( _x+8, _y+12, _x+8, _y+4 );
+ p.drawLine( _x+8, _y+4, _x+12, _y+4 );
+ p.drawLine( _x+12, _y+4, _x+12, _y+12 );
+ p.drawLine( _x+12, _y+12, _x+16, _y+12 );
+ p.drawLine( _x+16, _y+12, _x+16, _y+4 );
+ p.drawLine( _x+16, _y+4, _x+20, _y+4 );
+ p.drawLine( _x+20, _y+4, _x+20, _y+8 );
+
+ deinitPainter(p);
+}
+