/*************************************************************************** * 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 #include #include 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(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); }