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.
186 lines
5.0 KiB
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);
|
|
}
|
|
|