You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ktechlab/src/electronics/components/ecclockinput.cpp

186 lines
5.0 KiB

/***************************************************************************
* 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 <tdelocale.h>
#include <tqpainter.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(
TQString("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", TQRect( -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"));
TQString display = TQString::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( TQPainter &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);
}