diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-24 01:49:02 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-24 01:49:02 +0000 |
commit | 5de3dd4762ca33a0f92e79ffa4fe2ff67069d531 (patch) | |
tree | bad482b7afa4cdf47422d60a5dd2c61c7e333b09 /src/electronics/components | |
download | ktechlab-5de3dd4762ca33a0f92e79ffa4fe2ff67069d531.tar.gz ktechlab-5de3dd4762ca33a0f92e79ffa4fe2ff67069d531.zip |
Added KDE3 version of ktechlab
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/ktechlab@1095338 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/electronics/components')
95 files changed, 11903 insertions, 0 deletions
diff --git a/src/electronics/components/Makefile.am b/src/electronics/components/Makefile.am new file mode 100644 index 0000000..c388cf6 --- /dev/null +++ b/src/electronics/components/Makefile.am @@ -0,0 +1,33 @@ +INCLUDES = -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/electronics -I$(top_srcdir)/src/electronics/components \ + -I$(top_srcdir)/src/electronics/simulation -I$(top_srcdir)/src/gui -I$(top_srcdir)/src/languages \ + -I$(top_srcdir)/src/micro $(glib_cflags) $(all_includes) + +METASOURCES = AUTO +noinst_HEADERS = ecresistor.h ecled.h ecdiode.h ecsevensegment.h eckeypad.h \ + eccapacitor.h ec555.h eccurrentsource.h ecfixedvoltage.h ecbcdto7segment.h \ + ecsignallamp.h ecclockinput.h ecpotentiometer.h ecopamp.h ecvoltagesource.h \ + eccurrentsignal.h ecvoltagesignal.h ecground.h multiinputgate.h fulladder.h multiplexer.h \ + demultiplexer.h externalconnection.h ecsubcircuit.h meter.h probe.h resistordip.h \ + addac.h dependentsource.h flipflop.h toggleswitch.h pushswitch.h ram.h \ + discretelogic.h piccomponent.h piccomponentpin.h binarycounter.h bidirled.h \ + matrixdisplay.h bussplitter.h matrixdisplaydriver.h magnitudecomparator.h \ + serialportcomponent.h parallelportcomponent.h inductor.h ecbjt.h rotoswitch.h + +noinst_LTLIBRARIES = libcomponents.la +libcomponents_la_SOURCES = ecresistor.cpp ecled.cpp ecdiode.cpp \ + ecsevensegment.cpp eckeypad.cpp eccapacitor.cpp ec555.cpp eccurrentsource.cpp \ + ecfixedvoltage.cpp ecbcdto7segment.cpp ecsignallamp.cpp ecclockinput.cpp \ + ecpotentiometer.cpp ecopamp.cpp ecvoltagesource.cpp eccurrentsignal.cpp ecvoltagesignal.cpp \ + ecground.cpp multiinputgate.cpp fulladder.cpp multiplexer.cpp demultiplexer.cpp \ + externalconnection.cpp ecsubcircuit.cpp meter.cpp probe.cpp resistordip.cpp addac.cpp \ + dependentsource.cpp flipflop.cpp toggleswitch.cpp pushswitch.cpp ram.cpp discretelogic.cpp \ + piccomponent.cpp piccomponentpin.cpp binarycounter.cpp bidirled.cpp matrixdisplay.cpp \ + bussplitter.cpp matrixdisplaydriver.cpp magnitudecomparator.cpp serialportcomponent.cpp \ + parallelportcomponent.cpp inductor.cpp ecbjt.cpp rotoswitch.cpp + +libcomponents_la_PCH = AUTO + + +libcomponents_la_LIBADD =\ + $(top_builddir)/src/electronics/simulation/libelements.la diff --git a/src/electronics/components/addac.cpp b/src/electronics/components/addac.cpp new file mode 100644 index 0000000..a58e2d8 --- /dev/null +++ b/src/electronics/components/addac.cpp @@ -0,0 +1,281 @@ +/*************************************************************************** + * Copyright (C) 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 "addac.h" +#include "ecnode.h" +#include "logic.h" +#include "libraryitem.h" +#include "pin.h" +#include "voltagepoint.h" + +#include <cmath> +#include <kiconloader.h> +#include <klocale.h> + + +Item* ADC::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ADC( (ICNDocument*)itemDocument, newItem, id ); +} + + +Item* DAC::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new DAC( (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem* ADC::libraryItem() +{ + return new LibraryItem( + "ec/adc", + i18n("Analog-Digital"), + i18n("Integrated Circuits"), + "ic1.png", + LibraryItem::lit_component, + ADC::construct + ); +} + + +LibraryItem* DAC::libraryItem() +{ + return new LibraryItem( + "ec/dac", + i18n("Digital-Analog"), + i18n("Integrated Circuits"), + "ic1.png", + LibraryItem::lit_component, + DAC::construct + ); +} + + +//BEGIN class ADDAC +ADDAC::ADDAC( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ) +{ + m_numBits = 0; + m_range = 0; + + createProperty( "numBits", Variant::Type::Int ); + property("numBits")->setCaption( i18n("Number Bits") ); + property("numBits")->setMinValue(2); + property("numBits")->setMaxValue(max_ADDAC_bits); + property("numBits")->setValue(2); + + createProperty( "range", Variant::Type::Double ); + property("range")->setCaption( i18n("Input Range") ); + property("range")->setUnit("V"); + property("range")->setMinValue(-1e12); + property("range")->setMaxValue(1e12); + property("range")->setValue(5); +} + +ADDAC::~ADDAC() +{ +} + + +void ADDAC::dataChanged() +{ + m_range = dataDouble("range"); + initPins(); +} + +//END class ADDAC + + + + +//BEGIN class ADC +ADC::ADC( ICNDocument *icnDocument, bool newItem, const char *id ) + : ADDAC( icnDocument, newItem, (id) ? id : "adc" ) +{ + m_name = i18n("ADC"); + m_desc = i18n("Converts an analog signal into a digital output."); + + for ( int i=0; i<max_ADDAC_bits; ++i ) + m_logic[i] = 0l; + + m_realNode = 0l; +} + +ADC::~ADC() +{ +} + + +void ADC::stepNonLogic() +{ + double floatBitValue = m_realNode->pin()->voltage() * (std::pow( 2, double(m_numBits) )-1.) / m_range; + double roundBitValue = std::floor( floatBitValue+0.5 ); + + if ( roundBitValue < 0 ) + { + for ( int i = 0; i<m_numBits; ++i ) + m_logic[i]->setHigh(false); + return; + } + + uint roundedBitValue = uint(roundBitValue); + for ( int i = 0; i<m_numBits; ++i ) + m_logic[i]->setHigh( roundedBitValue & ( 1 << i ) ); +} + + +void ADC::initPins() +{ + int numBits = dataInt("numBits"); + + if ( numBits < 2 ) + numBits = 2; + else if ( numBits > max_ADDAC_bits ) + numBits = max_ADDAC_bits; + + if ( numBits == m_numBits ) + return; + + QStringList pins; + + int inPos = (numBits-1+(numBits%2))/2; + for ( int i=0; i<inPos; ++i ) + pins += ""; + + pins += "In"; + + for ( int i=inPos+1; i<numBits; ++i ) + pins += ""; + + for ( int i=numBits-1; i>=0; --i ) + pins += QString::number(i); + + initDIPSymbol( pins, 64 ); + initDIP(pins); + + if (!m_realNode) + m_realNode = ecNodeWithID("In"); + + + if ( numBits > m_numBits ) + { + for ( int i=m_numBits; i<numBits; ++i ) + { + ECNode *node = ecNodeWithID( QString::number(i) ); + m_logic[i] = createLogicOut( node, false ); + } + } + else + { + for ( int i=numBits; i<m_numBits; ++i ) + { + QString id = QString::number(i); + removeDisplayText(id); + removeElement( m_logic[i], false ); + removeNode(id); + m_logic[i] = 0l; + } + } + + m_numBits = numBits; +} +//END class ADC + + + + +//BEGIN class DAC +DAC::DAC( ICNDocument *icnDocument, bool newItem, const char *id ) + : ADDAC( icnDocument, newItem, (id) ? id : "dac" ) +{ + m_name = i18n("DAC"); + m_desc = i18n("Converts a digital input to an analog output signal."); + + for ( int i=0; i<max_ADDAC_bits; ++i ) + m_logic[i] = 0l; + + m_voltagePoint = 0l; +} + + +DAC::~DAC() +{ +} + + +void DAC::stepNonLogic() +{ + uint value = 0; + for ( int i=0; i<m_numBits; ++i ) + value |= ( m_logic[i]->isHigh() ? 1 : 0 ) << i; + +// double valueAsDouble = double(value); +// double powChange = std::pow( double(m_numBits), 2 )-1.; +// m_voltagePoint->setVoltage( m_range * valueAsDouble / powChange ); + m_voltagePoint->setVoltage( m_range * double(value) / (std::pow( 2, double(m_numBits) )-1.) ); +} + + +void DAC::initPins() +{ + int numBits = dataInt("numBits"); + + if ( numBits < 2 ) + numBits = 2; + else if ( numBits > max_ADDAC_bits ) + numBits = max_ADDAC_bits; + + if ( numBits == m_numBits ) + return; + + QStringList pins; + + for ( int i=0; i<numBits; ++i ) + pins += QString::number(i); + + int inPos = (numBits+1+(numBits%2))/2; + for ( int i=numBits-1; i>=inPos; --i ) + pins += ""; + + pins += "Out"; + + for ( int i=inPos-2; i>=0; --i ) + pins += ""; + + initDIPSymbol( pins, 64 ); + initDIP(pins); + + if (!m_voltagePoint) + m_voltagePoint = createVoltagePoint( ecNodeWithID("Out"), 0. ); + + if ( numBits > m_numBits ) + { + for ( int i=m_numBits; i<numBits; ++i ) + { + ECNode *node = ecNodeWithID( QString::number(i) ); + m_logic[i] = createLogicIn(node); + } + } + else + { + for ( int i=numBits; i<m_numBits; ++i ) + { + QString id = QString::number(i); + removeDisplayText(id); + removeElement( m_logic[i], false ); + removeNode(id); + m_logic[i] = 0l; + } + } + + m_numBits = numBits; +} +//END class DAC + diff --git a/src/electronics/components/addac.h b/src/electronics/components/addac.h new file mode 100644 index 0000000..3d69e88 --- /dev/null +++ b/src/electronics/components/addac.h @@ -0,0 +1,93 @@ +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef ADDAC_H +#define ADDAC_H + +#include "component.h" + +const int max_ADDAC_bits = 32; + +/** +@author David Saxton +*/ +class ADDAC : public Component +{ +public: + public: + ADDAC( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ADDAC(); + virtual bool canFlip() const { return true; } + + protected: + void dataChanged(); + /** + * Add / remove pins according to the number of outputs the user has requested + */ + virtual void initPins() = 0; + + int m_numBits; + double m_range; +}; + + +/** +@author David Saxton + */ +class ADC : public ADDAC +{ + public: + ADC( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ADC(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + + protected: + /** + * Add / remove pins according to the number of outputs the user has requested + */ + virtual void initPins(); + + LogicOut *m_logic[max_ADDAC_bits]; + ECNode *m_realNode; +}; + + +/** +@author David Saxton + */ +class DAC : public ADDAC +{ + public: + DAC( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~DAC(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + + protected: + /** + * Add / remove pins according to the number of outputs the user has requested + */ + virtual void initPins(); + + LogicIn *m_logic[max_ADDAC_bits]; + VoltagePoint *m_voltagePoint; +}; + + +#endif diff --git a/src/electronics/components/bidirled.cpp b/src/electronics/components/bidirled.cpp new file mode 100644 index 0000000..92e242d --- /dev/null +++ b/src/electronics/components/bidirled.cpp @@ -0,0 +1,157 @@ +/*************************************************************************** + * Copyright (C) 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 "bidirled.h" +#include "colorcombo.h" +#include "diode.h" +#include "ecled.h" +#include "ecnode.h" +#include "libraryitem.h" +#include "simulator.h" + +#include <klocale.h> +#include <qpainter.h> + +Item* BiDirLED::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new BiDirLED( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* BiDirLED::libraryItem() +{ + return new LibraryItem ( + "ec/bidir_led", + i18n("Bidirectional LED"), + i18n("Outputs"), + "bidirled.png", + LibraryItem::lit_component, + BiDirLED::construct + ); +} + +BiDirLED::BiDirLED( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "bidir_led" ) +{ + m_name = i18n("Bidirectional LED"); + m_desc = i18n("Bidrectional Light Emitting Diode"); + m_bDynamicContent = true; + + setSize( -8, -16, 16, 32 ); + init1PinLeft(); + init1PinRight(); + setSize( -8, -24, 24, 40 ); + + m_pDiode[0] = createDiode( m_pNNode[0], m_pPNode[0] ); + m_pDiode[1] = createDiode( m_pPNode[0], m_pNNode[0] ); + + avg_brightness[0] = avg_brightness[1] = 255; + lastUpdatePeriod = 0.; + r[0]=r[1]=g[0]=g[1]=b[0]=b[1]=0; + last_brightness[0] = last_brightness[1] = 255; + + createProperty( "0-color1", Variant::Type::Color ); + property("0-color1")->setCaption( i18n("Color 1") ); + property("0-color1")->setColorScheme( ColorCombo::LED ); + + createProperty( "0-color2", Variant::Type::Color ); + property("0-color2")->setCaption( i18n("Colour 2") ); + property("0-color2")->setColorScheme( ColorCombo::LED ); +} + +BiDirLED::~BiDirLED() +{ +} + +void BiDirLED::dataChanged() +{ + QString colors[] = { "0-color1", "0-color2" }; + for ( unsigned i = 0; i < 2; i++ ) + { + QColor color = dataColor(colors[i]); + r[i] = color.red(); + g[i] = color.green(); + b[i] = color.blue(); + r[i] /= 0x100; + g[i] /= 0x100; + b[i] /= 0x100; + } +} + +void BiDirLED::stepNonLogic() +{ + double interval = 1./LINEAR_UPDATE_RATE; + lastUpdatePeriod += interval; + + for ( unsigned i = 0; i < 2; i++ ) + avg_brightness[i] += ECLed::brightness(m_pDiode[i]->current())*interval; +} + +void BiDirLED::drawShape( QPainter &p ) +{ + initPainter(p); + + for ( unsigned i = 0; i < 2; i++ ) + { + uint _b; + if ( lastUpdatePeriod == 0. ) + _b = last_brightness[i]; + + else + { + _b = uint(avg_brightness[i]/lastUpdatePeriod); + last_brightness[i] = _b; + } + avg_brightness[i] = 0.; + + p.setBrush( QColor( uint(255-(255-_b)*(1-r[i])), uint(255-(255-_b)*(1-g[i])), uint(255-(255-_b)*(1-b[i])) ) ); + + + QPointArray pa(3); + if ( i == 0 ) + { + pa[0] = QPoint( 8, -8 ); + pa[1] = QPoint( -8, -16 ); + pa[2] = QPoint( -8, 0 ); + } + else + { + pa[0] = QPoint( -8, 8 ); + pa[1] = QPoint( 8, 0 ); + pa[2] = QPoint( 8, 16 ); + } + + pa.translate( int(x()), int(y()) ); + p.drawPolygon(pa); + p.drawPolyline(pa); + } + lastUpdatePeriod = 0.; + + // Draw the arrows indicating it's a LED + int _x = (int)x()-2; + int _y = (int)y()-21; + + p.drawLine( _x+9, _y+3, _x+12, _y ); // Tail of left arrow + p.drawLine( _x+12, _y, _x+10, _y ); // Left edge of left arrow tip + p.drawLine( _x+12, _y, _x+12, _y+2 ); // Right edge of left arrow tip + + p.drawLine( _x+12, _y+6, _x+15, _y+3 ); // Tail of right arrow + p.drawLine( _x+15, _y+3, _x+13, _y+3 ); // Left edge of right arrow tip + p.drawLine( _x+15, _y+3, _x+15, _y+5 ); // Right edge of right arrow tip + + p.drawLine( _x+10, _y, _x+15, _y+5 ); // Diagonal line that forms base of both arrow tips + + _x = int(x()); + _y = int(y()); + p.drawLine( _x+8, _y-16, _x+8, _y ); + p.drawLine( _x-8, _y, _x-8, _y+16 ); + + deinitPainter(p); +} + diff --git a/src/electronics/components/bidirled.h b/src/electronics/components/bidirled.h new file mode 100644 index 0000000..e80f4e0 --- /dev/null +++ b/src/electronics/components/bidirled.h @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef BIDIRLED_H +#define BIDIRLED_H + +#include <component.h> + +/** +@author David Saxton +*/ +class BiDirLED : public Component +{ + public: + BiDirLED( ICNDocument * icnDocument, bool newItem, const char *id = 0L ); + ~BiDirLED(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void dataChanged(); + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + + private: + virtual void drawShape( QPainter &p ); + + double r[2]; + double g[2]; + double b[2]; + + double avg_brightness[2]; + uint last_brightness[2]; + double lastUpdatePeriod; + Diode *m_pDiode[2]; +}; + +#endif diff --git a/src/electronics/components/binarycounter.cpp b/src/electronics/components/binarycounter.cpp new file mode 100644 index 0000000..f278104 --- /dev/null +++ b/src/electronics/components/binarycounter.cpp @@ -0,0 +1,186 @@ +/*************************************************************************** + * 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 "binarycounter.h" + +#include "logic.h" +#include "libraryitem.h" + +#include <kiconloader.h> +#include <klocale.h> + +Item* BinaryCounter::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new BinaryCounter( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* BinaryCounter::libraryItem() +{ + QStringList ids; + ids << "ec/binary_counter" << "ec/4_bit_binary_counter"; + return new LibraryItem( + ids, + i18n("Binary Counter"), + i18n("Integrated Circuits"), + "ic1.png", + LibraryItem::lit_component, + BinaryCounter::construct + ); +} + +BinaryCounter::BinaryCounter( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "binary_counter" ) +{ + m_name = i18n("Binary Counter"); + m_desc = i18n("Holds an internal count, which changes when the clock input <i>></i> pin is pulsed.<br><br>" + "Normal operation: <i>en</i> (Enable) and <i>u/d</i> (Up/Down) are held high, <i>r</i> (Reset) is low."); + + enLogic = inLogic = rLogic = udLogic = 0L; + + b_reset = false; + b_triggerHigh = true; + b_oldIn = false; + m_value = 0; + b_en = false; + b_ud = false; + m_numBits = 0; + m_maxValue = false; + m_bDoneLogicIn = false; + + createProperty( "trig", Variant::Type::Select ); + property("trig")->setCaption( i18n("Trigger Edge") ); + property("trig")->setAllowed( QStringList::split( ',', "Rising,Falling" ) ); + property("trig")->setValue("Rising"); + + createProperty( "bitcount", Variant::Type::Int ); + property("bitcount")->setCaption( i18n("Bit Count") ); + property("bitcount")->setMinValue(1); + property("bitcount")->setMaxValue(26); + property("bitcount")->setValue(4); +} + + +BinaryCounter::~BinaryCounter() +{ +} + + +void BinaryCounter::dataChanged() +{ + initPins( dataInt("bitcount") ); + + b_triggerHigh = dataString("trig") == "Rising"; + setDisplayText( ">", b_triggerHigh ? "^>" : "_>" ); +} + + +void BinaryCounter::initPins( unsigned numBits ) +{ + if ( m_numBits == numBits ) + return; + + QStringList pins; + pins << "en" << ">" << "u/d" << "r"; + + for ( int i = 0; i < QABS(4-int(numBits)); i++ ) + pins << ""; + + for ( int i = numBits-1; i >= 0; i-- ) + pins << QChar('A'+i); + + initDIPSymbol( pins, 64 ); + initDIP(pins); + + if ( m_numBits < numBits ) + { + for ( unsigned i = m_numBits; i < numBits; i++ ) + m_pLogicOut[i] = createLogicOut( ecNodeWithID( QChar('A'+i) ), false ); + } + else + { + for ( unsigned i = numBits; i < m_numBits; i++ ) + { + QString id = QChar('A'+i); + removeElement( m_pLogicOut[i], false ); + removeDisplayText(id); + removeNode(id); + } + } + + m_numBits = numBits; + m_maxValue = (1<<m_numBits)-1; + + if (!m_bDoneLogicIn) + { + enLogic = createLogicIn( ecNodeWithID("en") ); + inLogic = createLogicIn( ecNodeWithID(">") ); + rLogic = createLogicIn( ecNodeWithID("r") ); + udLogic = createLogicIn( ecNodeWithID("u/d") ); + + enLogic->setCallback( this, (CallbackPtr)(&BinaryCounter::enStateChanged) ); + inLogic->setCallback( this, (CallbackPtr)(&BinaryCounter::inStateChanged) ); + rLogic->setCallback( this, (CallbackPtr)(&BinaryCounter::rStateChanged) ); + udLogic->setCallback( this, (CallbackPtr)(&BinaryCounter::udStateChanged) ); + + m_bDoneLogicIn = true; + } + + outputValue(); +} + + +void BinaryCounter::inStateChanged( bool state ) +{ + if ( (state != b_oldIn) && b_en && !b_reset && state == b_triggerHigh ) + { + m_value += (b_ud) ? 1 : -1; + + if ( m_value < 0 ) + m_value = m_maxValue; + + else if ( m_value > m_maxValue ) + m_value = 0; + + outputValue(); + } + + b_oldIn = state; +} + + +void BinaryCounter::rStateChanged( bool state ) +{ + b_reset = state; + if (b_reset) + { + m_value = 0; + outputValue(); + } +} + + +void BinaryCounter::enStateChanged( bool state ) +{ + b_en = state; +} + + +void BinaryCounter::udStateChanged( bool state ) +{ + b_ud = state; +} + + +void BinaryCounter::outputValue() +{ + for ( unsigned i = 0; i < m_numBits; i++ ) + m_pLogicOut[i]->setHigh( m_value & (1 << i) ); +} + diff --git a/src/electronics/components/binarycounter.h b/src/electronics/components/binarycounter.h new file mode 100644 index 0000000..b15762d --- /dev/null +++ b/src/electronics/components/binarycounter.h @@ -0,0 +1,63 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef EC4BITCOUNTER_H +#define EC4BITCOUNTER_H + +#include "component.h" +#include "logic.h" + +/** +Simple logic counter. 4 Inputs, 4 Outputs. + +Outputs (A-D) represent the stored value (0-15). +The inputs are: +@li en - Enable incrementing of value +@li in - Input (trigger high) +@li r - Reset stored value to 0 +@li ud - Up/Down increment + +@short 4 Bit Binary Counter +@author David Saxton +*/ +class BinaryCounter : public CallbackClass, public Component +{ +public: + BinaryCounter( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~BinaryCounter(); + + virtual bool canFlip() const { return true; } + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + void inStateChanged( bool state ); // Input + void rStateChanged( bool state ); // Reset + void enStateChanged( bool state ); // Enable + void udStateChanged( bool state ); // Up/Down + void outputValue(); + void dataChanged(); + void initPins( unsigned numBits ); + + LogicIn *enLogic, *inLogic, *rLogic, *udLogic; + LogicOut * m_pLogicOut[26]; + + unsigned m_numBits; + bool b_triggerHigh; + bool b_en; // Enable + bool b_ud; // Up/Down + bool b_oldIn; + bool b_reset; + long m_value; + long m_maxValue; + bool m_bDoneLogicIn; +}; + +#endif diff --git a/src/electronics/components/bussplitter.cpp b/src/electronics/components/bussplitter.cpp new file mode 100644 index 0000000..62fbb39 --- /dev/null +++ b/src/electronics/components/bussplitter.cpp @@ -0,0 +1,133 @@ +/*************************************************************************** + * Copyright (C) 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 "bussplitter.h" +#include "ecnode.h" +#include "libraryitem.h" +#include "wire.h" + +#include <klocale.h> +#include <qpainter.h> + +Item* BusSplitter::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new BusSplitter( (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem* BusSplitter::libraryItem() +{ + return new LibraryItem( + "ec/bus", + i18n("Bus"), + i18n("Connections"), + "bus.png", + LibraryItem::lit_component, + BusSplitter::construct ); +} + + +const unsigned MAX_BUS_SIZE = 10000; + + +BusSplitter::BusSplitter( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "Bus" ) +{ + m_name = i18n("Bus Splitter"); + m_desc = i18n("Merges several connections into one."); + + m_busSize = 0; + init1PinLeft(); + m_pInNode = m_pNNode[0]; + + createProperty( "size", Variant::Type::Int ); + property("size")->setCaption( i18n("Size") ); + property("size")->setMinValue(1); + property("size")->setMaxValue(MAX_BUS_SIZE); + property("size")->setValue(8); +} + + +BusSplitter::~BusSplitter() +{ +} + + +void BusSplitter::dataChanged() +{ + unsigned busSize = dataInt("size"); + + if ( busSize < 1 ) + busSize = 1; + + else if ( busSize > MAX_BUS_SIZE ) + busSize = MAX_BUS_SIZE; + + if ( busSize == m_busSize ) + return; + + m_pInNode->setNumPins(busSize); + + if ( busSize > m_busSize ) + { + m_pWires.resize(busSize); + for ( unsigned i = m_busSize; i < unsigned(busSize); i++ ) + { + Pin * pin = createPin( 16, 0, 180, outNodeID(i) )->pin(); + m_pWires[i] = new Wire( m_pInNode->pin(i), pin ); + } + } + else + { + for ( unsigned i = busSize; i < unsigned(m_busSize); i++ ) + { + removeNode( outNodeID(i) ); + delete m_pWires[i]; + } + m_pWires.resize(busSize); + } + m_busSize = busSize; + + // Position pins + setSize( 0, -int(m_busSize+1)*8, 8, int(m_busSize+1)*16, true ); + for ( int i = 0; i < int(m_busSize); i++ ) + m_nodeMap[ outNodeID(i) ].y = 16*i - int(m_busSize+1)*8 + 24; + m_nodeMap["n1"].y = -int(m_busSize+1)*8 + 8; + + updateAttachedPositioning(); +} + + +QString BusSplitter::outNodeID( unsigned node ) const +{ + return QString("out_%1").arg(QString::number(node)); +} + + +void BusSplitter::drawShape( QPainter &p ) +{ + initPainter(p); + +// QPen pen(p.pen()); +// pen.setWidth(); +// p.setPen(pen); + + int _x = int(x()); + int _y = int(y()); + + QRect r = m_sizeRect; + r.moveBy( _x, _y ); + p.drawRect(r); + + deinitPainter(p); +} + + + diff --git a/src/electronics/components/bussplitter.h b/src/electronics/components/bussplitter.h new file mode 100644 index 0000000..ccd1994 --- /dev/null +++ b/src/electronics/components/bussplitter.h @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef BUSSPLITTER_H +#define BUSSPLITTER_H + +#include <component.h> + +#include <qguardedptr.h> +#include <qvaluevector.h> + +class Wire; + +/** +@author David Saxton +*/ +class BusSplitter : public Component +{ + public: + BusSplitter( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~BusSplitter(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual bool canFlip() const { return true; } + + protected: + QString outNodeID( unsigned node ) const; + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + + unsigned m_busSize; + QValueVector<QGuardedPtr<Wire> > m_pWires; + ECNode * m_pInNode; +}; + +#endif diff --git a/src/electronics/components/demultiplexer.cpp b/src/electronics/components/demultiplexer.cpp new file mode 100644 index 0000000..8a01808 --- /dev/null +++ b/src/electronics/components/demultiplexer.cpp @@ -0,0 +1,175 @@ +/*************************************************************************** + * Copyright (C) 2004-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 "demultiplexer.h" + +#include "logic.h" +#include "libraryitem.h" + +#include <kiconloader.h> +#include <klocale.h> + +#include <cmath> + +Item* Demultiplexer::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Demultiplexer( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Demultiplexer::libraryItem() +{ + return new LibraryItem( + "ec/demultiplexer", + i18n("Demultiplexer"), + i18n("Integrated Circuits"), + "ic1.png", + LibraryItem::lit_component, + Demultiplexer::construct + ); +} + +Demultiplexer::Demultiplexer( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "demultiplexer" ) +{ + m_name = i18n("Demultiplexer"); + m_desc = i18n("Seperates the input data stream into components. The value of the input is passed to the \"X\" output selected by the binary number given by the \"A\" inputs."); + + m_input = 0l; + + createProperty( "addressSize", Variant::Type::Int ); + property("addressSize")->setCaption( i18n("Address Size") ); + property("addressSize")->setMinValue(1); + property("addressSize")->setMaxValue(8); + property("addressSize")->setValue(1); + + // For backwards compatibility + createProperty( "numInput", Variant::Type::Int ); + property("numInput")->setMinValue(-1); + property("numInput")->setValue(-1); + property("numInput")->setHidden(true); +} + +Demultiplexer::~Demultiplexer() +{ +} + + +void Demultiplexer::dataChanged() +{ + if ( hasProperty("numInput") && dataInt("numInput") != -1 ) + { + int addressSize = int( std::ceil( std::log( (double)dataInt("numInput") ) / std::log(2.0) ) ); + property("numInput")->setValue(-1); + + if ( addressSize < 1 ) + addressSize = 1; + else if ( addressSize > 8 ) + addressSize = 8; + + // This function will get called again when we set the value of numInput + property("addressSize")->setValue(addressSize); + return; + } + + if ( hasProperty("numInput") ) + { + m_variantData["numInput"]->deleteLater(); + m_variantData.remove("numInput"); + } + + initPins( unsigned(dataInt("addressSize")) ); +} + + +void Demultiplexer::inStateChanged( bool /*state*/ ) +{ + unsigned long long pos = 0; + for ( unsigned i = 0; i < m_aLogic.size(); ++i ) + { + if ( m_aLogic[i]->isHigh() ) + pos += 1 << i; + } + for ( unsigned i = 0; i < m_xLogic.size(); ++i ) + m_xLogic[i]->setHigh( (pos == i) && m_input->isHigh() ); +} + + +void Demultiplexer::initPins( unsigned newAddressSize ) +{ + unsigned oldAddressSize = m_aLogic.size(); + unsigned long long oldXLogicCount = m_xLogic.size(); + unsigned long long newXLogicCount = 1 << newAddressSize; + + if ( newXLogicCount == oldXLogicCount ) + return; + + QStringList pins; + + for ( unsigned i=0; i<newAddressSize; ++i ) + pins += "A"+QString::number(i); + for ( unsigned i=newAddressSize; i<(newXLogicCount+(newXLogicCount%2))/2; ++i ) + pins += ""; + pins += "X"; + for ( unsigned i=(newXLogicCount+(newXLogicCount%2))/2+1; i<newXLogicCount; ++i ) + pins += ""; + for ( int i=newXLogicCount-1; i>=0; --i ) + pins += "X"+QString::number(i); + + initDIPSymbol( pins, 64 ); + initDIP(pins); + + ECNode *node; + + if (!m_input) + { + node = ecNodeWithID("X"); + m_input = createLogicIn(node); + m_input->setCallback( this, (CallbackPtr)(&Demultiplexer::inStateChanged) ); + } + + if ( newXLogicCount > oldXLogicCount ) + { + m_xLogic.resize(newXLogicCount); + for ( unsigned i = oldXLogicCount; i < newXLogicCount; ++i ) + { + node = ecNodeWithID("X"+QString::number(i)); + m_xLogic.insert( i, createLogicOut(node,false) ); + } + + m_aLogic.resize(newAddressSize); + for ( unsigned i = oldAddressSize; i < newAddressSize; ++i ) + { + node = ecNodeWithID("A"+QString::number(i)); + m_aLogic.insert( i, createLogicIn(node) ); + m_aLogic[i]->setCallback( this, (CallbackPtr)(&Demultiplexer::inStateChanged) ); + } + } + else + { + for ( unsigned i = newXLogicCount; i < oldXLogicCount; ++i ) + { + QString id = "X"+QString::number(i); + removeDisplayText(id); + removeElement( m_xLogic[i], false ); + removeNode(id); + } + m_xLogic.resize(newXLogicCount); + + for ( unsigned i = newAddressSize; i < oldAddressSize; ++i ) + { + QString id = "A"+QString::number(i); + removeDisplayText(id); + removeElement( m_aLogic[i], false ); + removeNode(id); + } + m_aLogic.resize(newAddressSize); + } +} + diff --git a/src/electronics/components/demultiplexer.h b/src/electronics/components/demultiplexer.h new file mode 100644 index 0000000..a2b52dd --- /dev/null +++ b/src/electronics/components/demultiplexer.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2004-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. * + ***************************************************************************/ + +#ifndef DEMULTIPLEXER_H +#define DEMULTIPLEXER_H + +#include "component.h" +#include "logic.h" + +#include <qptrvector.h> + +/** +@author David Saxton +*/ +class Demultiplexer : public CallbackClass, public Component +{ +public: + Demultiplexer( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Demultiplexer(); + + virtual bool canFlip() const { return true; } + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + void dataChanged(); + /** + * Add / remove pins according to the number of inputs the user has requested + */ + void initPins( unsigned addressSize ); + + void inStateChanged( bool newState ); + + QPtrVector<LogicIn> m_aLogic; + QPtrVector<LogicOut> m_xLogic; + LogicIn * m_input; +}; + +#endif diff --git a/src/electronics/components/dependentsource.cpp b/src/electronics/components/dependentsource.cpp new file mode 100644 index 0000000..764cc53 --- /dev/null +++ b/src/electronics/components/dependentsource.cpp @@ -0,0 +1,314 @@ +/*************************************************************************** + * Copyright (C) 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 "dependentsource.h" +#include "ecnode.h" +#include "libraryitem.h" +#include "pin.h" + +#include "cccs.h" +#include "ccvs.h" +#include "vccs.h" +#include "vcvs.h" + +#include <klocale.h> +#include <qpainter.h> + +//BEGIN class DependentSource +DependentSource::DependentSource( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ) +{ + setSize( -16, -16, 32, 32 ); + + init2PinLeft(); + init2PinRight(); + + createProperty( "gain", Variant::Type::Double ); + property("gain")->setCaption( i18n("Gain") ); + property("gain")->setValue(1.0); + + addDisplayText( "gain", QRect( -16, -32, 32, 16 ), "" ); +} + + +DependentSource::~DependentSource() +{ +} + + +void DependentSource::drawOutline( QPainter & p ) +{ + const int _x = (int)x()-16; + const int _y = (int)y()-32; + + // Top rectangle + p.drawRect( _x, _y+19, width(), 11 ); + + p.save(); + bool canSetCol = (p.pen().color() != Qt::color0) && (p.pen().color() != Qt::color1); + + // Bottom lines + if (canSetCol) + p.setPen( m_pNNode[1]->isSelected() ? m_selectedCol : Qt::black ); + p.drawLine( _x, _y+40, _x+8, _y+40 ); // Left inny + + if (canSetCol) + p.setPen( m_pPNode[1]->isSelected() ? m_selectedCol : Qt::black ); + p.drawLine( _x+width(), _y+40, _x+24, _y+40 ); // Right inny + + p.restore(); + + // Bottom diamond + QPointArray pa4(4); + pa4[0] = QPoint( _x+6, _y+40 ); + pa4[1] = QPoint( _x+16, _y+32 ); + pa4[2] = QPoint( _x+26, _y+40 ); + pa4[3] = QPoint( _x+16, _y+48 ); + p.drawPolygon(pa4); +} + + +void DependentSource::drawTopArrow( QPainter & p ) +{ + const int _x = (int)x()-16; + const int _y = (int)y()-32; + + if ( p.pen().color() == m_selectedCol ) + p.setPen(Qt::black); + + if ( p.brush().color() == m_brushCol ) + p.setBrush(Qt::black); + + p.drawLine( _x+8, _y+24, _x+24, _y+24 ); + + QPointArray pa3(3); + pa3[0] = QPoint( _x+24, _y+24 ); + pa3[1] = QPoint( _x+19, _y+21 ); + pa3[2] = QPoint( _x+19, _y+27 ); + p.drawPolygon(pa3); +} + + +void DependentSource::drawBottomArrow( QPainter & p ) +{ + const int _x = (int)x()-16; + const int _y = (int)y()-32; + + if ( p.pen().color() == m_selectedCol ) + p.setPen(Qt::black); + + if ( p.brush().color() == m_brushCol ) + p.setBrush(Qt::black); + + p.drawLine( _x+11, _y+40, _x+21, _y+40 ); + + QPointArray pa3(3); + pa3[0] = QPoint( _x+21, _y+40 ); + pa3[1] = QPoint( _x+16, _y+37 ); + pa3[2] = QPoint( _x+16, _y+43 ); + p.drawPolygon(pa3); +} +//END class DependentSource + + +//BEGIN class ECCCCS +Item* ECCCCS::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECCCCS( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECCCCS::libraryItem() +{ + return new LibraryItem( + QString("ec/cccs"), + i18n("CCCS"), + i18n("Sources"), + "cccs.png", + LibraryItem::lit_component, + ECCCCS::construct ); +} + +ECCCCS::ECCCCS( ICNDocument *icnDocument, bool newItem, const char *id ) + : DependentSource( icnDocument, newItem, id ? id : "cccs" ) +{ + m_name = i18n("Current Controlled Currrent Source"); + m_cccs = createCCCS( m_pNNode[0], m_pPNode[0], m_pNNode[1], m_pPNode[1], 1. ); + m_pNNode[1]->pin()->setGroundType( Pin::gt_medium ); +} + +ECCCCS::~ECCCCS() +{ +} + +void ECCCCS::dataChanged() +{ + double gain = dataDouble("gain"); + + QString display = QString::number( gain / getMultiplier(gain), 'g', 3 ) + getNumberMag(gain) + QChar(' '); + setDisplayText( "gain", display ); + + m_cccs->setGain(gain); +} + +void ECCCCS::drawShape( QPainter &p ) +{ + initPainter(p); + drawOutline(p); + drawTopArrow(p); + drawBottomArrow(p); + deinitPainter(p); +} +//END class ECCCCS + + +//BEGIN class ECCCVS +Item* ECCCVS::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECCCVS( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECCCVS::libraryItem() +{ + return new LibraryItem( + QString("ec/ccvs"), + i18n("CCVS"), + i18n("Sources"), + "ccvs.png", + LibraryItem::lit_component, + ECCCVS::construct ); +} + +ECCCVS::ECCCVS( ICNDocument *icnDocument, bool newItem, const char *id ) + : DependentSource( icnDocument, newItem, id ? id : "ccvs" ) +{ + m_name = i18n("Current Controlled Voltage Source"); + m_ccvs = createCCVS( m_pNNode[0], m_pPNode[0], m_pNNode[1], m_pPNode[1], 1. ); + m_pNNode[1]->pin()->setGroundType( Pin::gt_medium ); +} + +ECCCVS::~ECCCVS() +{ +} + +void ECCCVS::dataChanged() +{ + double gain = dataDouble("gain"); + + QString display = QString::number( gain / getMultiplier(gain), 'g', 3 ) + getNumberMag(gain) + QChar(' '); + setDisplayText( "gain", display ); + + m_ccvs->setGain(gain); +} + +void ECCCVS::drawShape( QPainter &p ) +{ + initPainter(p); + drawOutline(p); + drawTopArrow(p); + deinitPainter(p); +} +//END class ECCCVS + + +//BEGIN class ECVCCS +Item* ECVCCS::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECVCCS( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECVCCS::libraryItem() +{ + return new LibraryItem( + QString("ec/vccs"), + i18n("VCCS"), + i18n("Sources"), + "vccs.png", + LibraryItem::lit_component, + ECVCCS::construct ); +} + +ECVCCS::ECVCCS( ICNDocument *icnDocument, bool newItem, const char *id ) + : DependentSource( icnDocument, newItem, id ? id : "vccs" ) +{ + m_name = i18n("Voltage Controlled Current Source"); + m_vccs = createVCCS( m_pNNode[0], m_pPNode[0], m_pNNode[1], m_pPNode[1], 1. ); + m_pNNode[1]->pin()->setGroundType( Pin::gt_medium ); +} + +ECVCCS::~ECVCCS() +{ +} + +void ECVCCS::dataChanged() +{ + double gain = dataDouble("gain"); + + QString display = QString::number( gain / getMultiplier(gain), 'g', 3 ) + getNumberMag(gain) + QChar(' '); + setDisplayText( "gain", display ); + + m_vccs->setGain(gain); +} + +void ECVCCS::drawShape( QPainter &p ) +{ + initPainter(p); + drawOutline(p); + drawBottomArrow(p); + deinitPainter(p); +} +//END class ECVCCS + + +//BEGIN class ECVCVS +Item* ECVCVS::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECVCVS( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECVCVS::libraryItem() +{ + return new LibraryItem( + QString("ec/vcvs"), + i18n("VCVS"), + i18n("Sources"), + "vcvs.png", + LibraryItem::lit_component, + ECVCVS::construct ); +} + +ECVCVS::ECVCVS( ICNDocument *icnDocument, bool newItem, const char *id ) + : DependentSource( icnDocument, newItem, id ? id : "vcvs" ) +{ + m_name = i18n("Voltage Controlled Voltage Source"); + m_vcvs = createVCVS( m_pNNode[0], m_pPNode[0], m_pNNode[1], m_pPNode[1], 1. ); + m_pNNode[1]->pin()->setGroundType( Pin::gt_medium ); +} + +ECVCVS::~ECVCVS() +{ +} + +void ECVCVS::dataChanged() +{ + double gain = dataDouble("gain"); + + QString display = QString::number( gain / getMultiplier(gain), 'g', 3 ) + getNumberMag(gain) + QChar(' '); + setDisplayText( "gain", display ); + + m_vcvs->setGain(gain); +} + +void ECVCVS::drawShape( QPainter &p ) +{ + initPainter(p); + drawOutline(p); + deinitPainter(p); +} +//END class ECVCVS diff --git a/src/electronics/components/dependentsource.h b/src/electronics/components/dependentsource.h new file mode 100644 index 0000000..2bccbb7 --- /dev/null +++ b/src/electronics/components/dependentsource.h @@ -0,0 +1,112 @@ +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef DEPENDENTSOURCE_H +#define DEPENDENTSOURCE_H + +#include "component.h" + +/** +@author David Saxton +*/ +class DependentSource : public Component +{ + public: + DependentSource( ICNDocument *icnDocument, bool newItem, const char *id ); + ~DependentSource(); + virtual bool canFlip() const { return true; } + + protected: + void drawOutline( QPainter & p ); + void drawTopArrow( QPainter & p ); + void drawBottomArrow( QPainter & p ); +}; + +/** +@short Current Controlled Current Source +@author David Saxton +*/ +class ECCCCS : public DependentSource +{ + public: + ECCCCS( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECCCCS(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + protected: + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + + CCCS *m_cccs; +}; + +/** +@short Current Controlled Voltage Source +@author David Saxton +*/ +class ECCCVS : public DependentSource +{ + public: + ECCCVS( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECCCVS(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + protected: + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + + CCVS *m_ccvs; +}; + +/** +@short Voltage Controlled Current Source +@author David Saxton +*/ +class ECVCCS : public DependentSource +{ + public: + ECVCCS( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECVCCS(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + protected: + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + + VCCS *m_vccs; +}; + +/** +@short Voltage Controlled Voltage Source +@author David Saxton +*/ +class ECVCVS : public DependentSource +{ + public: + ECVCVS( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECVCVS(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + protected: + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + + VCVS *m_vcvs; +}; + +#endif diff --git a/src/electronics/components/discretelogic.cpp b/src/electronics/components/discretelogic.cpp new file mode 100644 index 0000000..e2e284e --- /dev/null +++ b/src/electronics/components/discretelogic.cpp @@ -0,0 +1,308 @@ +/*************************************************************************** + * Copyright (C) 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 "canvasitemparts.h" +#include "discretelogic.h" +#include "ecnode.h" +#include "logic.h" +#include "libraryitem.h" +#include "simulator.h" + +#include <klocale.h> +#include <qpainter.h> + + +//BEGIN class Inverter +Item* Inverter::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Inverter( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Inverter::libraryItem() +{ + QStringList ids; + ids << "ec/inverter" << "ec/not"; + return new LibraryItem( + ids, + i18n("Inverter"), + i18n("Logic"), + "not.png", + LibraryItem::lit_component, + Inverter::construct ); +} + +Inverter::Inverter( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "not" ) +{ + m_name = i18n("Inverter"); + m_desc = i18n("The output is the logical inverse of the logic-input state."); + setSize( -8, -8, 16, 16 ); + + init1PinLeft(); + init1PinRight(); + + m_pIn = createLogicIn(m_pNNode[0]); + m_pOut = createLogicOut( m_pPNode[0], true ); + + m_pIn->setCallback( this, (CallbackPtr)(&Inverter::inStateChanged) ); + inStateChanged(false); +} + + +Inverter::~Inverter() +{ +} + + +void Inverter::inStateChanged( bool newState ) +{ + (static_cast<LogicOut*>(m_pOut))->setHigh( !newState ); +} + + +void Inverter::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()-8; + int _y = (int)y()-8; + QPointArray pa(3); + pa[0] = QPoint( _x, _y ); + pa[1] = QPoint( _x+width()-6, _y+(height()/2) ); + pa[2] = QPoint( _x, _y+height() ); + p.drawPolygon(pa); + p.drawPolyline(pa); + p.drawEllipse( _x+width()-6, _y+(height()/2)-3, 7, 7 ); + deinitPainter(p); +} +//END class Inverter + + +//BEGIN class Buffer +Item* Buffer::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Buffer( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Buffer::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/buffer"), + i18n("Buffer"), + i18n("Logic"), + "buffer.png", + LibraryItem::lit_component, + Buffer::construct ); +} + +Buffer::Buffer( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "buffer" ) +{ + m_name = i18n("Buffer"); + m_desc = i18n("Cleans the logic input, with the output high or low depending on input trigger levels."); + setSize( -8, -8, 16, 16 ); + + init1PinLeft(); + init1PinRight(); + + m_pIn = createLogicIn(m_pNNode[0]); + m_pOut = createLogicOut( m_pPNode[0], true ); + + m_pIn->setCallback( this, (CallbackPtr)(&Buffer::inStateChanged) ); + inStateChanged(false); +} + + +Buffer::~Buffer() +{ +} + + +void Buffer::inStateChanged( bool newState ) +{ + m_pOut->setHigh(newState); +} + + +void Buffer::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()-8; + int _y = (int)y()-8; + QPointArray pa(3); + pa[0] = QPoint( _x, _y ); + pa[1] = QPoint( _x+width(), _y+(height()/2) ); + pa[2] = QPoint( _x, _y+height() ); + p.drawPolygon(pa); + p.drawPolyline(pa); + deinitPainter(p); +} +//END class Buffer + + +//BEGIN class ECLogicInput +Item* ECLogicInput::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECLogicInput( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECLogicInput::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/logic_input"), + i18n("Logic Input"), + i18n("Logic"), + "logic_input.png", + LibraryItem::lit_component, + ECLogicInput::construct ); +} + +ECLogicInput::ECLogicInput( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "logic_input" ) +{ + m_name = i18n("Logic Input"); + m_desc = i18n("Provides a user-adjustable logic state.<br><br>" + "Click to pulse high, or drag the mouse off to keep the output high."); + setSize( -8, -8, 16, 16 ); + + b_state = false; + addButton( "button", QRect( -24, -8, 16, 16 ), "", true ); + + createProperty( "useToggle", Variant::Type::Bool ); + property("useToggle")->setCaption( i18n("Use Toggle") ); + property("useToggle")->setValue(true); + + init1PinRight(); + + m_pOut = createLogicOut( m_pPNode[0], false ); +} + + +ECLogicInput::~ECLogicInput() +{ +} + + +void ECLogicInput::dataChanged() +{ + button("button")->setToggle( dataBool("useToggle") ); +} + + +void ECLogicInput::drawShape( QPainter &p ) +{ + initPainter(p); + if (b_state) + p.setBrush( QColor( 255, 166, 0 ) ); + else + p.setBrush( Qt::white ); + p.drawEllipse( (int)x()-4, (int)y()-6, 12, 12 ); + deinitPainter(p); +} + + +void ECLogicInput::buttonStateChanged( const QString &, bool state ) +{ + b_state = state; + m_pOut->setHigh(b_state); +} +//END class ECLogicInput + + +//BEGIN class ECLogicOutput +Item* ECLogicOutput::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECLogicOutput( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECLogicOutput::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/logic_output"), + i18n("Logic Output"), + i18n("Logic"), + "logic_output.png", + LibraryItem::lit_component, + ECLogicOutput::construct ); +} + +ECLogicOutput::ECLogicOutput( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "logic_output" ) +{ + m_name = i18n("Logic Output"); + m_desc = i18n("Shows the logic-state of the input."); + setSize( -8, -8, 16, 16 ); + + init1PinLeft(); + m_pIn = createLogicIn(m_pNNode[0]); + + m_pSimulator = Simulator::self(); + + m_lastDrawState = 0.0; + m_lastSwitchTime = m_lastDrawTime = m_pSimulator->time(); + m_highTime = 0; + m_bLastState = false; + m_bDynamicContent = true; + + m_pIn->setCallback( this, (CallbackPtr)(&ECLogicOutput::inStateChanged) ); +} + +ECLogicOutput::~ECLogicOutput() +{ +} + +void ECLogicOutput::inStateChanged( bool newState ) +{ + if ( m_bLastState == newState ) + return; + + unsigned long long newTime = m_pSimulator->time(); + unsigned long long dt = newTime - m_lastSwitchTime; + + m_lastSwitchTime = newTime; + + m_bLastState = newState; + if (!newState) + { + // Gone from high to low + m_highTime += dt; + } +} + + +void ECLogicOutput::drawShape( QPainter &p ) +{ + unsigned long long newTime = m_pSimulator->time(); + unsigned long long runTime = newTime - m_lastDrawTime; + m_lastDrawTime = newTime; + + if (m_bLastState) + { + // Logic in is currently high + m_highTime += newTime - m_lastSwitchTime; + } + + double state; + + if ( runTime == 0 ) + state = m_lastDrawState; + + else + state = m_lastDrawState = double(m_highTime)/double(runTime); + + initPainter(p); + p.setBrush( QColor( 255, uint(255-state*(255-166)), uint((1-state)*255) ) ); + p.drawEllipse( int(x()-8), int(y()-8), width(), height() ); + deinitPainter(p); + + m_lastSwitchTime = newTime; + m_highTime = 0; +} +//END class ECLogicOutput + diff --git a/src/electronics/components/discretelogic.h b/src/electronics/components/discretelogic.h new file mode 100644 index 0000000..82775bf --- /dev/null +++ b/src/electronics/components/discretelogic.h @@ -0,0 +1,110 @@ +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef DISCRETELOGIC_H +#define DISCRETELOGIC_H + +#include "component.h" +#include "logic.h" + +class Simulator; + +/** +@short Boolean NOT +@author David Saxton +*/ +class Inverter : public CallbackClass, public Component +{ + public: + Inverter( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Inverter(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + protected: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); + + LogicIn * m_pIn; + LogicOut * m_pOut; +}; + +/** +@short Buffer +@author David Saxton +*/ +class Buffer : public CallbackClass, public Component +{ +public: + Buffer( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Buffer(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); + + LogicIn * m_pIn; + LogicOut * m_pOut; +}; + +/** +@short Boolean logic input +@author David Saxton +*/ +class ECLogicInput : public Component +{ +public: + ECLogicInput( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECLogicInput(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + +private: + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + LogicOut * m_pOut; + bool b_state; +}; + +/** +@short Boolean logic output +@author David Saxton +*/ +class ECLogicOutput : public CallbackClass, public Component +{ + public: + ECLogicOutput( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECLogicOutput(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + protected: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); + + unsigned long long m_lastDrawTime; + unsigned long long m_lastSwitchTime; + unsigned long long m_highTime; + bool m_bLastState; + + double m_lastDrawState; + LogicIn * m_pIn; + Simulator * m_pSimulator; +}; + +#endif diff --git a/src/electronics/components/ec555.cpp b/src/electronics/components/ec555.cpp new file mode 100644 index 0000000..eccf2bd --- /dev/null +++ b/src/electronics/components/ec555.cpp @@ -0,0 +1,172 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "ec555.h" + +#include "ecnode.h" +#include "libraryitem.h" +#include "pin.h" +#include "resistance.h" + +#include <kiconloader.h> +#include <klocale.h> +#include <qpainter.h> + +Item* EC555::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new EC555( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* EC555::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/555"), + i18n("555"), + i18n("Integrated Circuits"), + "ic1.png", + LibraryItem::lit_component, + EC555::construct + ); +} + +EC555::EC555( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "555" ) +{ + m_name = i18n("555"); + m_desc = i18n("Common timer IC"); +// m_pins = QStringList::split( ',', "Gnd,Trg,Out,Res,CV,Th,Dis,Vcc" ); +// m_pins = QStringList::split( ',', "Dis,Th,Trg,Gnd,CV,Out,Res,Vcc" ); + + old_com1 = false; + old_com2 = false; + old_q = false; + + setSize( -32, -32, 64, 64 ); + + + // Pins down left + + // Pin 7 + discharge = createPin( -40, -16, 0, "Dis" )->pin(); + addDisplayText( "dis", QRect( -32, -24, 24, 16 ), "Dis" ); + + // Pin 6 + threshold = createPin( -40, 0, 0, "Th" )->pin(); + addDisplayText( "th", QRect( -32, -8, 24, 16 ), "Th" ); + + // Pin 2 + trigger = createPin( -40, 16, 0, "Trg" )->pin(); + addDisplayText( "trg", QRect( -32, 8, 24, 16 ), "Trg" ); + + + + // Top two + + // Pin 8 + vcc = createPin( -16, -40, 90, "Vcc" )->pin(); + addDisplayText( "vcc", QRect( -24, -32, 16, 8 ), "+" ); + + // Pin 4 + reset = createPin( 16, -40, 90, "Res" )->pin(); + addDisplayText( "res", QRect( 8, -28, 16, 16 ), "Res" ); + + + + // Bottom two + + // Pin 1 + ground = createPin( -16, 40, 270, "Gnd" )->pin(); + addDisplayText( "gnd", QRect( -24, 20, 16, 8 ), "-" ); + + // Pin 5 + control = createPin( 16, 40, 270, "CV" )->pin(); + addDisplayText( "cv", QRect( 8, 12, 16, 16 ), "CV" ); + + + + // Output on right + + // Pin 3 + output = createPin( 40, 0, 180, "Out" )->pin(); + addDisplayText( "out", QRect( 8, -8, 16, 16 ), "Out" ); + + + + m_r1 = createResistance( vcc, control, 5e3 ); + m_r23 = createResistance( control, ground, 1e4 ); + m_po_sink = createResistance( output, ground, 0. ); + m_po_source = createResistance( output, vcc, 0. ); + m_po_source->setConductance(0.); + m_r_discharge = createResistance( discharge, ground, 0. ); +} + + +EC555::~EC555() +{ +} + +void EC555::stepNonLogic() +{ + double v_threshold = threshold->voltage(); + double v_control = control->voltage(); + double v_ground = ground->voltage(); + double v_trigger = trigger->voltage(); + double v_reset = reset->voltage(); + double v_vcc = vcc->voltage(); + + double v_r = (v_control+v_ground)/2; + + bool com1 = ( v_threshold == v_control ) ? old_com1 : ( v_threshold < v_control ); + bool com2 = ( v_r == v_trigger ) ? old_com2 : ( v_r > v_trigger ); + bool reset = ( v_reset >= (v_control-v_ground)/2 + v_ground ); + old_com1 = com1; + old_com2 = com2; + + bool r = ( !reset || !com1 ); + bool s = com2; + + bool q = old_q; + if ( v_vcc - v_ground >= 2.5 ) + { + if ( s && !r ) + { + q = true; + } + else if ( r && !s ) + { + q = false; + } + } + else + { + q = false; + } + old_q = q; + + + m_r_discharge->setConductance(0.); + + if (q) + { + m_po_source->setResistance(10.); + m_po_sink->setConductance(0.); + } + else + { + m_po_source->setConductance(0.); + m_po_sink->setResistance(10.); + if ( v_ground+0.7 <= v_vcc ) + { + m_r_discharge->setResistance(10.); + } + } +} + + diff --git a/src/electronics/components/ec555.h b/src/electronics/components/ec555.h new file mode 100644 index 0000000..edeb2a5 --- /dev/null +++ b/src/electronics/components/ec555.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef EC555_H +#define EC555_H + +#include "component.h" + +#include <qstringlist.h> + +/** +@short 555 IC +@author David Saxton +*/ +class EC555 : public Component +{ +public: + EC555( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~EC555(); + + virtual bool canFlip() const { return true; } + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + +private: + Pin * ground; + Pin * trigger; + Pin * output; + Pin * reset; + Pin * control; + Pin * threshold; + Pin * discharge; + Pin * vcc; + + Resistance *m_r1; + Resistance *m_r23; + Resistance *m_po_sink; + Resistance *m_po_source; + Resistance *m_r_discharge; + + bool old_com1; + bool old_com2; + bool old_q; +}; + +#endif diff --git a/src/electronics/components/ecbcdto7segment.cpp b/src/electronics/components/ecbcdto7segment.cpp new file mode 100644 index 0000000..fb210ea --- /dev/null +++ b/src/electronics/components/ecbcdto7segment.cpp @@ -0,0 +1,158 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "ecbcdto7segment.h" + +#include "logic.h" +#include "libraryitem.h" + +#include <kiconloader.h> +#include <klocale.h> + +// Values for a,b,c,d,e,f,g of common-anode 7 segment display +bool numbers[16][7] = + { { 1, 1, 1, 1, 1, 1, 0 }, // 0 + { 0, 1, 1, 0, 0, 0, 0 }, // 1 + { 1, 1, 0, 1, 1, 0, 1 }, // 2 + { 1, 1, 1, 1, 0, 0, 1 }, // 3 + { 0, 1, 1, 0 ,0, 1, 1 }, // 4 + { 1, 0, 1, 1, 0, 1, 1 }, // 5 + { 1, 0, 1, 1, 1, 1, 1 }, // 6 + { 1, 1, 1, 0, 0, 0, 0 }, // 7 + { 1, 1, 1, 1, 1, 1, 1 }, // 8 + { 1, 1, 1, 0, 0, 1, 1 }, // 9 + { 1, 1, 1, 0, 1, 1, 1 }, // A + { 0, 0, 1, 1, 1, 1, 1 }, // b + { 1, 0, 0, 1, 1, 1, 0 }, // C + { 0, 1, 1, 1, 1, 0, 1 }, // d + { 1, 0, 0, 1, 1, 1, 1 }, // E + { 1, 0, 0, 0, 1, 1, 1 } }; // F + +Item* ECBCDTo7Segment::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECBCDTo7Segment( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECBCDTo7Segment::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/bcd_to_seven_segment"), + i18n("BCD to 7 Segment"), + i18n("Integrated Circuits"), + "ic2.png", + LibraryItem::lit_component, + ECBCDTo7Segment::construct + ); +} + +ECBCDTo7Segment::ECBCDTo7Segment( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "bcd_to_seven_segment" ) +{ + m_name = i18n("BCD to Seven Segment"); + m_desc = i18n("Converts a binary-coded-input to a form displayable by a seven segment display.<br><br>" + "Normal operation: <i>lt</i> (Lamp Test) and the <i>rb</i> (Ripple Blanking) are held high, <i>en</i> (Enable) is held low."); + + ALogic = BLogic = CLogic = DLogic = 0L; + ltLogic = rbLogic = enLogic = 0L; + + for ( int i=0; i<7; i++ ) + { + outLogic[i] = 0L; + oldOut[i] = false; + } + + QStringList pins = QStringList::split( ',', "A,B,C,D,,lt,rb,en,d,e,f,g,,a,b,c", true ); + initDIPSymbol( pins, 48 ); + initDIP(pins); + + ALogic = createLogicIn( ecNodeWithID("A") ); + BLogic = createLogicIn( ecNodeWithID("B") ); + CLogic = createLogicIn( ecNodeWithID("C") ); + DLogic = createLogicIn( ecNodeWithID("D") ); + ltLogic = createLogicIn( ecNodeWithID("lt") ); + rbLogic = createLogicIn( ecNodeWithID("rb") ); + enLogic = createLogicIn( ecNodeWithID("en") ); + + ALogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) ); + BLogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) ); + CLogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) ); + DLogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) ); + ltLogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) ); + rbLogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) ); + enLogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) ); + + for ( uint i=0; i<7; ++i ) + { + outLogic[i] = createLogicOut( ecNodeWithID( QChar('a'+i) ), false ); + outLogic[i]->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) ); + } + inStateChanged(false); +} + +ECBCDTo7Segment::~ECBCDTo7Segment() +{ +} + +void ECBCDTo7Segment::inStateChanged(bool) +{ + bool A = ALogic->isHigh(); + bool B = BLogic->isHigh(); + bool C = CLogic->isHigh(); + bool D = DLogic->isHigh(); + bool lt = ltLogic->isHigh(); // Lamp test + bool rb = rbLogic->isHigh(); // Ripple Blank + bool en = enLogic->isHigh(); // Enable (store) + + int n = A + 2*B + 4*C + 8*D; +// if ( n > 9 ) n = 0; + + bool out[7]; + + if (lt) // Lamp test + { + if (rb) // Ripple blanking + { + if (en) // Enable (store) + { + for ( int i=0; i<7; i++ ) + { + out[i] = oldOut[i]; + } + } + else + { + for ( int i=0; i<7; i++ ) + { + out[i] = numbers[n][i]; + oldOut[i] = out[i]; + } + } + } + else + { + for ( int i=0; i<7; i++ ) + { + out[i] = false; + } + } + } + else + { + for ( int i=0; i<7; i++ ) + { + out[i] = true; + } + } + + for ( int i=0; i<7; i++ ) + { + outLogic[i]->setHigh( out[i] ); + } +} diff --git a/src/electronics/components/ecbcdto7segment.h b/src/electronics/components/ecbcdto7segment.h new file mode 100644 index 0000000..03d4c2b --- /dev/null +++ b/src/electronics/components/ecbcdto7segment.h @@ -0,0 +1,41 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef ECBCDTO7SEGMENT_H +#define ECBCDTO7SEGMENT_H + +#include "component.h" +#include "logic.h" + +/** +@short Converts a BCD input to 7-Segment Output +@author David Saxton +*/ +class ECBCDTo7Segment : public CallbackClass, public Component +{ +public: + ECBCDTo7Segment( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECBCDTo7Segment(); + + virtual bool canFlip() const { return true; } + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void inStateChanged( bool newState ); + LogicIn *ALogic, *BLogic, *CLogic, *DLogic; + LogicIn *ltLogic, *rbLogic, *enLogic; + LogicOut *outLogic[7]; + + // Old values + bool oldOut[7]; +}; + +#endif diff --git a/src/electronics/components/ecbjt.cpp b/src/electronics/components/ecbjt.cpp new file mode 100644 index 0000000..b4b59f2 --- /dev/null +++ b/src/electronics/components/ecbjt.cpp @@ -0,0 +1,153 @@ +/*************************************************************************** + * 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 "bjt.h" +#include "ecbjt.h" +#include "ecnode.h" +#include "libraryitem.h" + +#include <kiconloader.h> +#include <klocale.h> +#include <qpainter.h> + +Item * ECBJT::constructNPN( ItemDocument * itemDocument, bool newItem, const char * id ) +{ + return new ECBJT( true, (ICNDocument*)itemDocument, newItem, id ); +} + + +Item * ECBJT::constructPNP( ItemDocument * itemDocument, bool newItem, const char * id ) +{ + return new ECBJT( false, (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem* ECBJT::libraryItemNPN() +{ + return new LibraryItem( + "ec/npnbjt", + i18n("NPN"), + i18n("Discrete"), + "npn.png", + LibraryItem::lit_component, + ECBJT::constructNPN ); +} + + +LibraryItem* ECBJT::libraryItemPNP() +{ + return new LibraryItem( + "ec/pnpbjt", + i18n("PNP"), + i18n("Discrete"), + "pnp.png", + LibraryItem::lit_component, + ECBJT::constructPNP ); +} + + +ECBJT::ECBJT( bool isNPN, ICNDocument * icnDocument, bool newItem, const char * id ) + : Component( icnDocument, newItem, id ? id : (isNPN ? "npnbjt" : "pnpbjt") ) +{ + m_bIsNPN = isNPN; + if ( m_bIsNPN ) + m_name = i18n("NPN Transistor"); + else + m_name = i18n("PNP Transistor"); + + setSize( -8, -8, 16, 16 ); + m_pBJT = createBJT( createPin( 8, -16, 90, "c" ), createPin( -16, 0, 0, "b" ), createPin( 8, 16, 270, "e" ), m_bIsNPN ); + + BJTSettings s; // will be created with the default settings + + Variant * v = createProperty( "I_S", Variant::Type::Double ); + v->setCaption("Saturation Current"); + v->setUnit("A"); + v->setMinValue(1e-20); + v->setMaxValue(1e-0); + v->setValue( s.I_S ); + v->setAdvanced(true); + + v = createProperty( "N_F", Variant::Type::Double ); + v->setCaption( i18n("Forward Coefficient") ); + v->setMinValue(1e0); + v->setMaxValue(1e1); + v->setValue( s.N_F ); + v->setAdvanced(true); + + v = createProperty( "N_R", Variant::Type::Double ); + v->setCaption( i18n("Reverse Coefficient") ); + v->setMinValue(1e0); + v->setMaxValue(1e1); + v->setValue( s.N_R ); + v->setAdvanced(true); + + v = createProperty( "B_F", Variant::Type::Double ); + v->setCaption( i18n("Forward Beta") ); + v->setMinValue(1e-1); + v->setMaxValue(1e3); + v->setValue( s.B_F ); + v->setAdvanced(true); + + v = createProperty( "B_R", Variant::Type::Double ); + v->setCaption( i18n("Reverse Beta") ); + v->setMinValue(1e-1); + v->setMaxValue(1e3); + v->setValue( s.B_R ); + v->setAdvanced(true); +} + +ECBJT::~ECBJT() +{ +} + + +void ECBJT::dataChanged() +{ + BJTSettings s; + s.I_S = dataDouble( "I_S" ); + s.N_F = dataDouble( "N_F" ); + s.N_R = dataDouble( "N_R" ); + s.B_F = dataDouble( "B_F" ); + s.B_R = dataDouble( "B_R" ); + + m_pBJT->setBJTSettings( s ); +} + + +void ECBJT::drawShape( QPainter &p ) +{ + const int _x = int(x()); + const int _y = int(y()); + + initPainter(p); + + p.drawLine( _x-8, _y-8, _x-8, _y+8 ); + p.drawLine( _x+8, _y-8, _x-8, _y ); + p.drawLine( _x+8, _y+8, _x-8, _y ); + + QPointArray pa(3); + if ( m_bIsNPN ) + { + pa[0] = QPoint( _x+6, _y+7 ); + pa[1] = QPoint( _x+2, _y+8 ); + pa[2] = QPoint( _x+6, _y+3 ); + } + else + { + pa[0] = QPoint( _x-7, _y+1 ); + pa[1] = QPoint( _x-4, _y+5 ); + pa[2] = QPoint( _x-2, _y ); + } + p.setBrush( p.pen().color() ); + p.drawPolygon(pa); + + deinitPainter(p); +} diff --git a/src/electronics/components/ecbjt.h b/src/electronics/components/ecbjt.h new file mode 100644 index 0000000..17a63e9 --- /dev/null +++ b/src/electronics/components/ecbjt.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef ECBJT_H +#define ECBJT_H + +#include "component.h" + +class BJT; + +/** +@short Simulates a BJT +@author David Saxton +*/ +class ECBJT : public Component +{ + public: + ECBJT( bool isNPN, ICNDocument *icnDocument, bool newItem, const char * id = 0L ); + ~ECBJT(); + virtual bool canFlip() const { return true; } + + static Item * constructNPN( ItemDocument * itemDocument, bool newItem, const char * id ); + static Item * constructPNP( ItemDocument * itemDocument, bool newItem, const char * id ); + static LibraryItem * libraryItemNPN(); + static LibraryItem * libraryItemPNP(); + + protected: + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + + bool m_bIsNPN; + BJT * m_pBJT; +}; + +#endif diff --git a/src/electronics/components/eccapacitor.cpp b/src/electronics/components/eccapacitor.cpp new file mode 100644 index 0000000..76a09b0 --- /dev/null +++ b/src/electronics/components/eccapacitor.cpp @@ -0,0 +1,92 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "capacitance.h" +#include "eccapacitor.h" +#include "ecnode.h" +#include "libraryitem.h" + +#include <klocale.h> +#include <qpainter.h> + +Item* ECCapacitor::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECCapacitor( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECCapacitor::libraryItem() +{ + return new LibraryItem( + "ec/capacitor", + i18n("Capacitor"), + i18n("Discrete"), + "capacitor.png", + LibraryItem::lit_component, + ECCapacitor::construct + ); +} + +ECCapacitor::ECCapacitor( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "capacitor" ) +{ + m_name = i18n("Capacitor"); + m_desc = i18n("Stores electrical charge.<br><br>" + "The voltage across the capacitor and capacitance are related by <i>Charge = Capacitance x Voltage</i>."); + setSize( -8, -8, 16, 16 ); + + init1PinLeft(); + init1PinRight(); + + m_capacitance = createCapacitance( m_pNNode[0], m_pPNode[0], 0.001 ); + + createProperty( "Capacitance", Variant::Type::Double ); + property("Capacitance")->setCaption( i18n("Capacitance") ); + property("Capacitance")->setUnit("F"); + property("Capacitance")->setMinValue(1e-12); + property("Capacitance")->setMaxValue(1e12); + property("Capacitance")->setValue(1e-3); + + addDisplayText( "capacitance", QRect( -8, -24, 16, 16 ), "", false ); +} + +ECCapacitor::~ECCapacitor() +{ +} + +void ECCapacitor::dataChanged() +{ + double capacitance = dataDouble("Capacitance"); + + QString display = QString::number( capacitance / getMultiplier(capacitance), 'g', 3 ) + getNumberMag(capacitance) + "F"; + setDisplayText( "capacitance", display ); + + m_capacitance->setCapacitance(capacitance); +} + +void ECCapacitor::drawShape( QPainter &p ) +{ + initPainter(p); + + int _y = (int)y()-8; + int _x = (int)x()-8; + + QPen pen; + pen.setWidth(1); + pen.setColor( p.pen().color() ); + p.setPen(pen); + p.drawRect( _x, _y, 5, 16 ); + p.drawRect( _x+11, _y, 5, 16 ); + + + deinitPainter(p); +// p.drawPolyline( areaPoints() ); +} + + diff --git a/src/electronics/components/eccapacitor.h b/src/electronics/components/eccapacitor.h new file mode 100644 index 0000000..4dd0ee6 --- /dev/null +++ b/src/electronics/components/eccapacitor.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef ECCAPACITOR_H +#define ECCAPACITOR_H + +#include "component.h" + +class Capacitance; +class ECNode; + +/** +@short Capacitor +Simple capacitor +@author David Saxton +*/ +class ECCapacitor : public Component +{ +public: + ECCapacitor( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECCapacitor(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void dataChanged(); + virtual void drawShape( QPainter &p ); + + Capacitance * m_capacitance; +}; + +#endif 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); +} + diff --git a/src/electronics/components/ecclockinput.h b/src/electronics/components/ecclockinput.h new file mode 100644 index 0000000..c7f7d14 --- /dev/null +++ b/src/electronics/components/ecclockinput.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef ECCLOCKINPUT_H +#define ECCLOCKINPUT_H + +#include "component.h" + +class ComponentCallback; +class Simulator; + +template <typename T> +class LinkedList; + +/** +@short Boolean clock input +@author David Saxton +*/ +class ECClockInput : public Component +{ +public: + ECClockInput( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECClockInput(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + void stepCallback(); + void stepLogic(); + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + +protected: + virtual void drawShape( QPainter &p ); + void dataChanged(); + + uint m_time; + uint m_high_time; + uint m_low_time; + uint m_period; + long long m_lastSetTime; + LogicOut * m_pOut; + bool m_bSetStepCallbacks; + bool m_bLastStepCallbackOut; + Simulator * m_pSimulator; + LinkedList<ComponentCallback> * m_pComponentCallback[1000]; +}; + +#endif diff --git a/src/electronics/components/eccurrentsignal.cpp b/src/electronics/components/eccurrentsignal.cpp new file mode 100644 index 0000000..e6dc351 --- /dev/null +++ b/src/electronics/components/eccurrentsignal.cpp @@ -0,0 +1,92 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "currentsignal.h" +#include "eccurrentsignal.h" +#include "ecnode.h" +#include "libraryitem.h" +#include "pin.h" +#include "simulator.h" + +#include <klocale.h> +#include <qpainter.h> + +Item* ECCurrentSignal::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECCurrentSignal( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECCurrentSignal::libraryItem() +{ + return new LibraryItem( + QString("ec/ac_current"), + i18n("Current Signal"), + i18n("Sources"), + "currentsignal.png", + LibraryItem::lit_component, + ECCurrentSignal::construct ); +} + +ECCurrentSignal::ECCurrentSignal( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "current_signal" ) +{ + m_name = i18n("Current Signal"); + m_desc = i18n("Provides a variety of current signals"); + setSize( -8, -8, 16, 16 ); + + init1PinLeft(); + init1PinRight(); + + m_pNNode[0]->pin()->setGroundType( Pin::gt_low ); + m_currentSignal = createCurrentSignal( m_pNNode[0], m_pPNode[0], 0. ); + m_currentSignal->setStep( 1./LINEAR_UPDATE_RATE, ElementSignal::st_sinusoidal, 50. ); + + createProperty( "1-frequency", Variant::Type::Double ); + property("1-frequency")->setCaption( i18n("Frequency") ); + property("1-frequency")->setUnit("Hz"); + property("1-frequency")->setMinValue(1e-9); + property("1-frequency")->setMaxValue(1e3); + property("1-frequency")->setValue(50.0); + + createProperty( "1-current", Variant::Type::Double ); + property("1-current")->setCaption( i18n("Current Range") ); + property("1-current")->setUnit("A"); + property("1-current")->setMinValue(-1e12); + property("1-current")->setMaxValue(1e12); + property("1-current")->setValue(0.02); + + addDisplayText( "~", QRect( -8, -8, 16, 16 ), "~" ); + addDisplayText( "current", QRect( -16, -24, 32, 16 ), "" ); +} + + +ECCurrentSignal::~ECCurrentSignal() +{ +} + +void ECCurrentSignal::dataChanged() +{ + const double current = dataDouble("1-current"); + const double frequency = dataDouble("1-frequency"); + + QString display = QString::number( current / getMultiplier(current), 'g', 3 ) + getNumberMag(current) + "A"; + setDisplayText( "current", display ); + + m_currentSignal->setStep( 1./LINEAR_UPDATE_RATE, ElementSignal::st_sinusoidal, frequency ); + m_currentSignal->setCurrent(current); +} + +void ECCurrentSignal::drawShape( QPainter &p ) +{ + initPainter(p); + p.drawEllipse( (int)x()-8, (int)y()-8, width(), height() ); + deinitPainter(p); +} + diff --git a/src/electronics/components/eccurrentsignal.h b/src/electronics/components/eccurrentsignal.h new file mode 100644 index 0000000..88dd276 --- /dev/null +++ b/src/electronics/components/eccurrentsignal.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef ECCURRENTSIGNAL_H +#define ECCURRENTSIGNAL_H + +#include "component.h" + +/** +@short Provides a current signal (sinusoidal, square, etc) +@author David Saxton +*/ +class ECCurrentSignal : public Component +{ +public: + ECCurrentSignal( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECCurrentSignal(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + virtual void drawShape( QPainter &p ); + void dataChanged(); + + CurrentSignal *m_currentSignal; +}; + +#endif diff --git a/src/electronics/components/eccurrentsource.cpp b/src/electronics/components/eccurrentsource.cpp new file mode 100644 index 0000000..76ecf3e --- /dev/null +++ b/src/electronics/components/eccurrentsource.cpp @@ -0,0 +1,94 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "currentsource.h" +#include "eccurrentsource.h" +#include "ecnode.h" +#include "libraryitem.h" +#include "pin.h" + +#include <klocale.h> +#include <qpainter.h> + +Item* ECCurrentSource::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECCurrentSource( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECCurrentSource::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/current_source"), + i18n("Current Source"), + i18n("Sources"), + "current_source.png", + LibraryItem::lit_component, + ECCurrentSource::construct ); +} + +ECCurrentSource::ECCurrentSource( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "current_source" ) +{ + m_name = i18n("Current Source"); + m_desc = i18n("Provides a fixed current source."); + setSize( -16, -8, 24, 24 ); + + init1PinLeft(8); + init1PinRight(8); + m_pNNode[0]->pin()->setGroundType( Pin::gt_low ); + + m_currentSource = createCurrentSource( m_pNNode[0], m_pPNode[0], 0. ); + + createProperty( "current", Variant::Type::Double ); + property("current")->setCaption( i18n("Current") ); + property("current")->setUnit("A"); + property("current")->setMinValue(-1e12); + property("current")->setMaxValue(1e12); + property("current")->setValue(0.02); + + addDisplayText("current", QRect( -16, -16, 24, 0 ), "" ); +} + + +ECCurrentSource::~ECCurrentSource() +{ +} + +void ECCurrentSource::dataChanged() +{ + double current = dataDouble("current"); + m_currentSource->setCurrent(current); + + QString display = QString::number( current / getMultiplier(current), 'g', 3 ) + getNumberMag(current) + "A"; + setDisplayText("current", display ); +} + +void ECCurrentSource::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()-16; + int _y = (int)y()-24; + + // Top arrow indicating current direction + p.drawLine( _x+width(), _y+19, _x, _y+19 ); + p.drawLine( _x+width(), _y+19, _x+width()-3, _y+16 ); + p.drawLine( _x+width(), _y+19, _x+width()-3, _y+22 ); + + // Double circules + p.drawEllipse( _x, _y+24, 16, 16 ); + p.drawEllipse( _x+8, _y+24, 16, 16 ); + + deinitPainter(p); +} + + + diff --git a/src/electronics/components/eccurrentsource.h b/src/electronics/components/eccurrentsource.h new file mode 100644 index 0000000..6332eba --- /dev/null +++ b/src/electronics/components/eccurrentsource.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef ECCURRENTSOURCE_H +#define ECCURRENTSOURCE_H + +#include "component.h" + +/** +@short Fixed current source +@author David Saxton +*/ +class ECCurrentSource : public Component +{ +public: + ECCurrentSource( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECCurrentSource(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + virtual void drawShape( QPainter &p ); + void dataChanged(); + + CurrentSource *m_currentSource; +}; + +#endif diff --git a/src/electronics/components/ecdiode.cpp b/src/electronics/components/ecdiode.cpp new file mode 100644 index 0000000..1d63bce --- /dev/null +++ b/src/electronics/components/ecdiode.cpp @@ -0,0 +1,120 @@ +/*************************************************************************** + * 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 "diode.h" +#include "ecdiode.h" +#include "ecnode.h" +#include "libraryitem.h" + +#include <klocale.h> +#include <qpainter.h> + +Item* ECDiode::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECDiode( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECDiode::libraryItem() +{ + return new LibraryItem( + "ec/diode", + i18n("Diode"), + i18n("Discrete"), + "diode.png", + LibraryItem::lit_component, + ECDiode::construct ); +} + +ECDiode::ECDiode( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "diode" ) +{ + m_name = i18n("Diode"); + m_desc = i18n("Allows current to flow in the direction indicated by the arrow when a certain voltage difference has been reached."); + + setSize( -8, -8, 16, 16 ); + + init1PinLeft(); + init1PinRight(); + + m_diode = createDiode( m_pNNode[0], m_pPNode[0] ); + + DiodeSettings ds; // it will have the default properties that we use + + createProperty( "I_S", Variant::Type::Double ); + property("I_S")->setCaption("Saturation Current"); + property("I_S")->setUnit("A"); + property("I_S")->setMinValue(1e-20); + property("I_S")->setMaxValue(1e-0); + property("I_S")->setValue( ds.I_S ); + property("I_S")->setAdvanced(true); + + createProperty( "N", Variant::Type::Double ); + property("N")->setCaption( i18n("Emission Coefficient") ); + property("N")->setMinValue(1e0); + property("N")->setMaxValue(1e1); + property("N")->setValue( ds.N ); + property("N")->setAdvanced(true); + + createProperty( "V_B", Variant::Type::Double ); + property("V_B")->setCaption( i18n("Breakdown Voltage") ); + property("V_B")->setUnit("V"); + property("V_B")->setMinAbsValue(1e-5); + property("V_B")->setMaxValue(1e10); + property("V_B")->setValue( ds.V_B ); + property("V_B")->setAdvanced(true); + +// createProperty( "R", Variant::Type::Double ); +// property("R")->setCaption( i18n("Series Resistance") ); +// property("R")->setUnit( QChar(0x3a9) ); +// property("R")->setMinValue(1e-5); +// property("R")->setMaxValue(1e0); +// property("R")->setValue( ds.R ); +// property("R")->setAdvanced(true); +} + + +ECDiode::~ECDiode() +{ +} + + +void ECDiode::dataChanged() +{ + DiodeSettings ds; + + ds.I_S = dataDouble("I_S"); + ds.V_B = dataDouble("V_B"); + ds.N = dataDouble("N"); +// ds.R = dataDouble("R"); + + m_diode->setDiodeSettings( ds ); +} + + +void ECDiode::drawShape( QPainter & p ) +{ + initPainter(p); + + int _x = int(x()); + int _y = int(y()); + + QPointArray pa(3); + pa[0] = QPoint( 8, 0 ); + pa[1] = QPoint( -8, -8 ); + pa[2] = QPoint( -8, 8 ); + pa.translate( _x, _y ); + p.drawPolygon(pa); + p.drawPolyline(pa); + + p.drawLine( _x+8, _y-8, _x+8, _y+8 ); + + deinitPainter(p); +} + diff --git a/src/electronics/components/ecdiode.h b/src/electronics/components/ecdiode.h new file mode 100644 index 0000000..fa8d034 --- /dev/null +++ b/src/electronics/components/ecdiode.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef ECDIODE_H +#define ECDIODE_H + +#include "component.h" + +/** +@short Simple diode +@author David Saxton +*/ +class ECDiode : public Component +{ +public: + ECDiode( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECDiode(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + void drawShape( QPainter & p ); + void dataChanged(); + Diode *m_diode; +}; + +#endif diff --git a/src/electronics/components/ecfixedvoltage.cpp b/src/electronics/components/ecfixedvoltage.cpp new file mode 100644 index 0000000..06eb707 --- /dev/null +++ b/src/electronics/components/ecfixedvoltage.cpp @@ -0,0 +1,77 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "ecfixedvoltage.h" + +#include "ecnode.h" +#include "voltagepoint.h" +#include "libraryitem.h" + +#include <klocale.h> +#include <qpainter.h> + +Item* ECFixedVoltage::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECFixedVoltage( (ICNDocument*)itemDocument, newItem, id ); +} +LibraryItem* ECFixedVoltage::libraryItem() +{ + return new LibraryItem( + "ec/fixed_voltage", + i18n("Fixed Voltage"), + i18n("Sources"), + "voltage.png", + LibraryItem::lit_component, + ECFixedVoltage::construct ); +} + +ECFixedVoltage::ECFixedVoltage( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "fixed_voltage" ) +{ + m_name = i18n("Fixed Voltage"); + m_desc = i18n("Provides a fixed voltage point to connect components to."); + setSize( -8, -8, 16, 16 ); + + init1PinRight(); + m_voltagePoint = createVoltagePoint( m_pPNode[0], 5.0 ); + + addDisplayText( "voltage", QRect( -24, -20, width()+32, 12 ), "" ); + + createProperty( "voltage", Variant::Type::Double ); + property("voltage")->setUnit("V"); + property("voltage")->setCaption( i18n("Voltage") ); + property("voltage")->setMinValue(-1e15); + property("voltage")->setMaxValue(1e15); + property("voltage")->setValue(5.0); +} + +ECFixedVoltage::~ECFixedVoltage() +{ +} + +void ECFixedVoltage::dataChanged() +{ + const double voltage = dataDouble("voltage"); + QString display = QString::number( voltage / getMultiplier(voltage), 'g', 3 ) + getNumberMag(voltage) + "V"; + setDisplayText( "voltage", display ); + m_voltagePoint->setVoltage(voltage); +} + +void ECFixedVoltage::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = int(x()); + int _y = int(y()); + p.drawEllipse( _x-4, _y-4, 8, 8 ); + p.setPen( m_pPNode[0]->isSelected() ? m_selectedCol : Qt::black ); + p.drawLine( _x+4, _y, _x+8, _y ); + deinitPainter(p); +} + diff --git a/src/electronics/components/ecfixedvoltage.h b/src/electronics/components/ecfixedvoltage.h new file mode 100644 index 0000000..ba20358 --- /dev/null +++ b/src/electronics/components/ecfixedvoltage.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef ECFIXEDVOLTAGE_H +#define ECFIXEDVOLTAGE_H + +#include "component.h" + +/** +@short Fixed voltage source +@author David Saxton +*/ +class ECFixedVoltage : public Component +{ +public: + ECFixedVoltage( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECFixedVoltage(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + virtual void drawShape( QPainter &p ); + void dataChanged(); + VoltagePoint *m_voltagePoint; +}; + +#endif diff --git a/src/electronics/components/ecground.cpp b/src/electronics/components/ecground.cpp new file mode 100644 index 0000000..efbfc41 --- /dev/null +++ b/src/electronics/components/ecground.cpp @@ -0,0 +1,66 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "ecground.h" + +#include "ecnode.h" +#include "libraryitem.h" +#include "pin.h" + +#include <klocale.h> +#include <qpainter.h> + +Item* ECGround::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECGround( (ICNDocument*)itemDocument, newItem, id ); +} +LibraryItem* ECGround::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/ground"), + i18n("Ground (0V)"), + i18n("Sources"), + "ground.png", + LibraryItem::lit_component, + ECGround::construct ); +} + +ECGround::ECGround( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "ground" ) +{ + m_name = i18n("Ground"); + m_desc = i18n("Ground (0V) point"); + setSize( -8, -8, 16, 16 ); + init1PinRight(); + m_pPNode[0]->pin()->setGroundType( Pin::gt_always ); + setAngleDegrees(270); +} + +ECGround::~ECGround() +{ +} + +void ECGround::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()-8; + int _y = (int)y()-8; + QPen pen; + pen.setWidth(2); + pen.setColor( p.pen().color() ); + p.setPen(pen); + p.drawLine( _x+15, _y, _x+15, _y+16 ); + p.drawLine( _x+10, _y+3, _x+10, _y+13 ); + p.drawLine( _x+5, _y+6, _x+5, _y+10 ); + deinitPainter(p); +} + + + diff --git a/src/electronics/components/ecground.h b/src/electronics/components/ecground.h new file mode 100644 index 0000000..0cf97bc --- /dev/null +++ b/src/electronics/components/ecground.h @@ -0,0 +1,33 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef ECGROUND_H +#define ECGROUND_H + +#include "component.h" + +/** +@short Fixed voltage source +@author David Saxton +*/ +class ECGround : public Component +{ +public: + ECGround( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECGround(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + virtual void drawShape( QPainter &p ); +}; + +#endif diff --git a/src/electronics/components/eckeypad.cpp b/src/electronics/components/eckeypad.cpp new file mode 100644 index 0000000..89d2659 --- /dev/null +++ b/src/electronics/components/eckeypad.cpp @@ -0,0 +1,199 @@ +/*************************************************************************** + * 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 "canvasitemparts.h" +#include "eckeypad.h" +#include "libraryitem.h" +#include "switch.h" + +#include "ecnode.h" +#include <klocale.h> + +Item* ECKeyPad::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECKeyPad( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECKeyPad::libraryItem() +{ + return new LibraryItem( + QString("ec/keypad"), + i18n("Keypad"), + i18n("Switches"), + "keypad.png", + LibraryItem::lit_component, + ECKeyPad::construct ); +} + +const QString text[4][9] = + { { "1","2","3","A","E","I","M","Q","U" }, + { "4","5","6","B","F","J","N","R","V" }, + { "7","8","9","C","G","K","O","S","W" }, + { "*","0","#","D","H","L","P","T","X" } }; + +ECKeyPad::ECKeyPad( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "keypad" ) +{ + m_name = i18n("Keypad"); + m_desc = i18n("Provides a numeric array of Push-to-Make switches, with 4 rows and a configurable number of columns."); + + createProperty( "useToggles", Variant::Type::Bool ); + property("useToggles")->setCaption( i18n("Use Toggles") ); + property("useToggles")->setValue(false); + + createProperty( "numCols", Variant::Type::Int ); + property("numCols")->setCaption( i18n("Columns") ); + property("numCols")->setMinValue(3); + property("numCols")->setMaxValue(9); + property("numCols")->setValue(3); + + Variant * v = createProperty( "bounce", Variant::Type::Bool ); + v->setCaption("Bounce"); + v->setAdvanced(true); + v->setValue(false); + + v = createProperty( "bounce_period", Variant::Type::Double ); + v->setCaption("Bounce Period"); + v->setAdvanced(true); + v->setUnit("s"); + v->setValue(5e-3); + + for ( int i = 0; i < 4; i++ ) + createPin( 0, -32+i*24, 0, QString("row_%1").arg(QString::number(i)) ); + + m_numCols = 0; +} + + +ECKeyPad::~ECKeyPad() +{ +} + + +QString ECKeyPad::buttonID( int row, int col ) const +{ + return QString("b_%1_%2").arg(QString::number(row)).arg(QString::number(col)); +} + + +int ECKeyPad::sideLength( unsigned numButtons ) const +{ + return 8 + 24*numButtons; +} + + +void ECKeyPad::dataChanged() +{ + initPins( dataInt("numCols") ); + + bool useToggle = dataBool("useToggles"); + bool bounce = dataBool("bounce"); + int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3); + + for ( unsigned i = 0; i < 4; i++ ) + { + for ( unsigned j = 0; j < m_numCols; j++ ) + { + button( buttonID(i,j) )->setToggle(useToggle); + m_switch[i][j]->setBounce( bounce, bouncePeriod_ms ); + } + } +} + + +void ECKeyPad::initPins( unsigned numCols ) +{ + if ( numCols < 3 ) + numCols = 3; + else if ( numCols > 9 ) + numCols = 9; + + if ( numCols == m_numCols ) + return; + + int w = sideLength(numCols); + int h = sideLength(4); + setSize( -int(w/16)*8, -int(h/16)*8, w, h, true ); + + if ( numCols > m_numCols ) + { + // Adding columns + + for ( unsigned i = 0; i < 4; i++ ) + { + for ( unsigned j = m_numCols; j < numCols; j++ ) + addButton( buttonID(i,j), QRect( 0, 0, 20, 20 ), text[i][j] ); + } + + ECNode * cols[numCols]; + + for ( unsigned j = m_numCols; j < numCols; j++ ) + cols[j] = createPin( 0, 64, 270, "col_" + QString::number(j) ); + + for ( unsigned i = 0; i < 4; i++ ) + { + ECNode * row = ecNodeWithID("row_"+QString::number(i)); + for ( unsigned j = m_numCols; j < numCols; j++ ) + m_switch[i][j] = createSwitch( cols[j], row, true ); + } + } + else + { + // Remove columns + + for ( unsigned i = 0; i < 4; i++ ) + { + for ( unsigned j = numCols; j < m_numCols; j++ ) + removeWidget( buttonID(i,j) ); + } + + for ( unsigned j = numCols; j < m_numCols; j++ ) + removeNode( "col_" + QString::number(j) ); + + for ( unsigned i = 0; i < 4; i++ ) + { + for ( unsigned j = m_numCols; j < numCols; j++ ) + removeSwitch( m_switch[i][j] ); + } + } + + //BEGIN Update Positions + m_numCols = numCols; + + for ( int i = 0; i < 4; i++ ) + { + for ( int j = 0; j < int(m_numCols); j++ ) + { + widgetWithID( buttonID(i,j) )->setOriginalRect( + QRect( offsetX() + 6 + 24*j, offsetY() + 6 + 24*i, 20, 20 ) ); + } + } + + for ( int i = 0; i < 4; i++ ) + m_nodeMap["row_" + QString::number(i)].x = width()+offsetX(); + + for ( int j = 0; j < int(m_numCols); j++ ) + m_nodeMap["col_" + QString::number(j)].x = 24*j+offsetX()+16; + + updateAttachedPositioning(); + //END Update Positions +} + + +void ECKeyPad::buttonStateChanged( const QString &id, bool state ) +{ + if ( !id.startsWith("b_") ) + return; + + QStringList tags = QStringList::split( '_', id ); + const int i = tags[1].toInt(); + const int j = tags[2].toInt(); + m_switch[i][j]->setState( state ? Switch::Closed : Switch::Open ); +} diff --git a/src/electronics/components/eckeypad.h b/src/electronics/components/eckeypad.h new file mode 100644 index 0000000..18a497c --- /dev/null +++ b/src/electronics/components/eckeypad.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef ECKEYPAD_H +#define ECKEYPAD_H + +#include "component.h" + +/** +@short 4x3 PTM Keypad +@author David Saxton +*/ +class ECKeyPad : public Component +{ + public: + ECKeyPad( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECKeyPad(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual bool canFlip() const { return true; } + + protected: + virtual void dataChanged(); + void initPins( unsigned numCols); + QString buttonID( int row, int col ) const; + int sideLength( unsigned numButtons ) const; + + Switch *m_switch[4][11]; + unsigned m_numCols; +}; + +#endif diff --git a/src/electronics/components/ecled.cpp b/src/electronics/components/ecled.cpp new file mode 100644 index 0000000..c865de6 --- /dev/null +++ b/src/electronics/components/ecled.cpp @@ -0,0 +1,134 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "colorcombo.h" +#include "diode.h" +#include "ecled.h" +#include "ecnode.h" +#include "libraryitem.h" +#include "simulator.h" + +#include <klocale.h> +#include <qpainter.h> + +Item* ECLed::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECLed( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECLed::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/led"), + i18n("LED"), + i18n("Outputs"), + "led.png", + LibraryItem::lit_component, + ECLed::construct + ); +} + +ECLed::ECLed( ICNDocument *icnDocument, bool newItem, const char *id ) + : ECDiode( icnDocument, newItem, (id) ? id : "led" ) +{ + m_bDynamicContent = true; + m_name = i18n("LED"); + m_desc = i18n("Light Emitting Diode"); + setSize( -8, -16, 24, 24, true ); + avg_brightness = 255; + lastUpdatePeriod = 0.; + r=g=b=0; + last_brightness = 255; + + createProperty( "0-color", Variant::Type::Color ); + property("0-color")->setCaption( i18n("Color") ); + property("0-color")->setColorScheme( ColorCombo::LED ); +} + +ECLed::~ECLed() +{ +} + +void ECLed::dataChanged() +{ + QColor color = dataColor("0-color"); + r = color.red(); + g = color.green(); + b = color.blue(); + r /= 0x100; + g /= 0x100; + b /= 0x100; +} + +void ECLed::stepNonLogic() +{ + double interval = 1./LINEAR_UPDATE_RATE; + avg_brightness += brightness(m_diode->current())*interval; + lastUpdatePeriod += interval; +} + +void ECLed::drawShape( QPainter &p ) +{ + int _x = int(x()); + int _y = int(y()); + + initPainter(p); + + //BEGIN draw "Diode" part + uint _b; + if ( lastUpdatePeriod == 0. ) + _b = last_brightness; + else + { + _b = (uint)(avg_brightness/lastUpdatePeriod); + last_brightness = _b; + } + avg_brightness = 0.; + lastUpdatePeriod = 0.; + + p.setBrush( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ) ); + + QPointArray pa(3); + pa[0] = QPoint( 8, 0 ); + pa[1] = QPoint( -8, -8 ); + pa[2] = QPoint( -8, 8 ); + pa.translate( _x, _y ); + p.drawPolygon(pa); + p.drawPolyline(pa); + + p.drawLine( _x+8, _y-8, _x+8, _y+8 ); + //END draw "Diode" part + + + + //BEGIN draw "Arrows" part + p.drawLine( _x+7, _y-10, _x+10, _y-13 ); // Tail of left arrow + p.drawLine( _x+10, _y-13, _x+8, _y-13 ); // Left edge of left arrow tip + p.drawLine( _x+10, _y-13, _x+10, _y-11 ); // Right edge of left arrow tip + + p.drawLine( _x+10, _y-7, _x+13, _y-10 ); // Tail of right arrow + p.drawLine( _x+13, _y-10, _x+11, _y-10 ); // Left edge of right arrow tip + p.drawLine( _x+13, _y-10, _x+13, _y-8 ); // Right edge of right arrow tip + + p.drawLine( _x+8, _y-13, _x+13, _y-8 ); // Diagonal line that forms base of both arrow tips + //END draw "Arrows" part1 + + + deinitPainter(p); +} + + +uint ECLed::brightness( double i ) +{ + if ( i > 0.018 ) return 0; + if ( i < 0.002 ) return 255; + return (uint)(255*(1-((i-0.002)/0.016))); +} + diff --git a/src/electronics/components/ecled.h b/src/electronics/components/ecled.h new file mode 100644 index 0000000..ce24598 --- /dev/null +++ b/src/electronics/components/ecled.h @@ -0,0 +1,48 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef ECLED_H +#define ECLED_H + +#include "component.h" +#include "ecdiode.h" + +/** +@short Simulates a LED +@author David Saxton +*/ +class ECLed : public ECDiode +{ +public: + ECLed( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECLed(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + /** + * Returns the brightness for the given current, from 255 (off) -> 0 (on) + */ + static uint brightness( double i ); + + virtual void dataChanged(); + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + +private: + virtual void drawShape( QPainter &p ); + + double r, g, b; + + double avg_brightness; + uint last_brightness; + double lastUpdatePeriod; +}; + +#endif diff --git a/src/electronics/components/ecopamp.cpp b/src/electronics/components/ecopamp.cpp new file mode 100644 index 0000000..dbb7457 --- /dev/null +++ b/src/electronics/components/ecopamp.cpp @@ -0,0 +1,85 @@ +/*************************************************************************** + * Copyright (C) 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 "ecopamp.h" + +#include "ecnode.h" +#include "libraryitem.h" + +#include <klocale.h> +#include <qpainter.h> + +Item* ECOpAmp::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECOpAmp( (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem* ECOpAmp::libraryItem() +{ + return new LibraryItem( + "ec/opamp", + i18n("Op Amp"), + i18n("Integrated Circuits"), + "opamp.png", + LibraryItem::lit_component, + ECOpAmp::construct ); +} + + +ECOpAmp::ECOpAmp( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "opamp" ) +{ + m_name = i18n("Operational Amplifier"); + m_desc = i18n("Ideal amplifier"); + + QPointArray pa(3); + pa[0] = QPoint( -16, -16 ); + pa[1] = QPoint( 16, 0 ); + pa[2] = QPoint( -16, 16 ); + setItemPoints( pa, true ); + + init2PinLeft( -8, 8 ); + init1PinRight(); + createOpAmp( m_pNNode[0], m_pPNode[0], m_pNNode[1] ); +} + + +ECOpAmp::~ECOpAmp() +{ +} + + +void ECOpAmp::drawShape( QPainter & p ) +{ + initPainter(p); + + int _x = int(x()); + int _y = int(y()); + + QPointArray pa(3); + pa[0] = QPoint( _x-16, _y-16 ); + pa[1] = QPoint( _x+16, _y ); + pa[2] = QPoint( _x-16, _y+16 ); + + p.drawPolygon(pa); + p.drawPolyline(pa); + + // Plus symbol + p.drawLine( _x-9, _y-8, _x-9, _y-2 ); + p.drawLine( _x-12, _y-5, _x-6, _y-5 ); + + // Minus symbol + p.drawLine( _x-11, _y+6, _x-7, _y+6 ); + + deinitPainter(p); +} + + diff --git a/src/electronics/components/ecopamp.h b/src/electronics/components/ecopamp.h new file mode 100644 index 0000000..6b6b147 --- /dev/null +++ b/src/electronics/components/ecopamp.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef ECOPAMP_H +#define ECOPAMP_H + +#include "component.h" + +/** +@short Operational Amplifier +@author David Saxton +*/ +class ECOpAmp : public Component +{ + public: + ECOpAmp( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECOpAmp(); + + virtual bool canFlip() const { return true; } + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + protected: + virtual void drawShape( QPainter & p ); +}; + +#endif diff --git a/src/electronics/components/ecpotentiometer.cpp b/src/electronics/components/ecpotentiometer.cpp new file mode 100644 index 0000000..db0fedd --- /dev/null +++ b/src/electronics/components/ecpotentiometer.cpp @@ -0,0 +1,119 @@ +/*************************************************************************** + * 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 "canvasitemparts.h" +#include "ecnode.h" +#include "ecpotentiometer.h" +#include "libraryitem.h" +#include "resistance.h" + +#include <klocale.h> +#include <qpainter.h> +#include <qstyle.h> + +Item* ECPotentiometer::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECPotentiometer( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECPotentiometer::libraryItem() +{ + return new LibraryItem( + "ec/potentiometer", + i18n("Potentiometer"), + i18n("Discrete"), + "potentiometer.png", + LibraryItem::lit_component, + ECPotentiometer::construct ); +} + +ECPotentiometer::ECPotentiometer( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "potentiometer" ) +{ + m_name = i18n("Potentiometer"); + m_desc =i18n("Consists of a resistor connected to the end pins, with a central pin connected at an adjustable point along the resistor"); + setSize( -16, -16, 40, 32 ); + + m_p1 = createPin( 32, 0, 180, "p1" ); + + m_sliderProp = 0.0; + m_resistance = 5000.; + m_r1 = createResistance( createPin( -8, -24, 90, "n1" ), m_p1, 1. ); + m_r2 = createResistance( createPin( -8, 24, 270, "n2" ), m_p1, 1. ); + + Slider * s = addSlider( "slider", 0, 100, 5, 50, Qt::Vertical, QRect( 0, -16, 16, 32 ) ); + m_pSlider = static_cast<QSlider*>(s->widget()); + + createProperty( "resistance", Variant::Type::Double ); + property("resistance")->setCaption( i18n("Resistance") ); + property("resistance")->setUnit( QChar(0x3a9) ); + property("resistance")->setMinValue(1e-6); + property("resistance")->setValue(1e5); + + addDisplayText( "res", QRect( -56, -8, 40, 16 ), "" ); +} + +ECPotentiometer::~ECPotentiometer() +{ +} + +void ECPotentiometer::dataChanged() +{ + m_resistance = dataDouble("resistance"); + + QString display = QString::number( m_resistance / getMultiplier(m_resistance), 'g', 3 ) + getNumberMag(m_resistance) + QChar(0x3a9); + setDisplayText( "res", display ); + + sliderValueChanged( "slider", slider("slider")->value() ); +} + +void ECPotentiometer::sliderValueChanged( const QString &id, int newValue ) +{ + if ( id != "slider" ) + return; + + m_sliderProp = (newValue-50.0)/100.0; + + m_r1->setResistance( m_resistance*(double)newValue/100. ); + m_r2->setResistance( m_resistance*(double)(100.-newValue)/100. ); +} + +void ECPotentiometer::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = int(x()); + int _y = int(y()); + + p.drawRect( _x-14, _y-16, 12, 32 ); + + QPointArray pa(3); + pa[0] = QPoint( 0, 0 ); + pa[1] = QPoint( 4, -3 ); + pa[2] = QPoint( 4, 3 ); + + int space = m_pSlider->style().pixelMetric( QStyle::PM_SliderSpaceAvailable, m_pSlider ); + int base_y = _y + (( angleDegrees() == 0 || angleDegrees() == 270 ) ? 1 : -1) * int( space * m_sliderProp ); + + pa.translate( _x+16, base_y ); + + QColor c = m_p1->isSelected() ? m_selectedCol : black; + + p.setPen(c); + p.setBrush(c); + p.drawPolygon(pa); + + p.drawLine( _x+20, base_y, _x+24, base_y ); + p.drawLine( _x+24, base_y, _x+24, _y ); + + deinitPainter(p); +} + + + diff --git a/src/electronics/components/ecpotentiometer.h b/src/electronics/components/ecpotentiometer.h new file mode 100644 index 0000000..e7ca83b --- /dev/null +++ b/src/electronics/components/ecpotentiometer.h @@ -0,0 +1,43 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef ECPOTENTIOMETER_H +#define ECPOTENTIOMETER_H + +#include "component.h" + +class QSlider; + +/** +@short Potentiometer +@author David Saxton +*/ +class ECPotentiometer : public Component +{ +public: + ECPotentiometer( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECPotentiometer(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void sliderValueChanged( const QString &id, int newValue ); + +private: + void dataChanged(); + virtual void drawShape( QPainter &p ); + + ECNode * m_p1; + Resistance *m_r1, *m_r2; + double m_resistance; + double m_sliderProp; + QSlider * m_pSlider; +}; +#endif diff --git a/src/electronics/components/ecresistor.cpp b/src/electronics/components/ecresistor.cpp new file mode 100644 index 0000000..e4ee7a3 --- /dev/null +++ b/src/electronics/components/ecresistor.cpp @@ -0,0 +1,76 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "ecresistor.h" + +#include "libraryitem.h" +#include "resistance.h" + +#include <klocale.h> +#include <qpainter.h> + +Item* ECResistor::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECResistor( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECResistor::libraryItem() +{ + return new LibraryItem( + "ec/resistor", + i18n("Resistor"), + i18n("Discrete"), + "resistor.png", + LibraryItem::lit_component, + ECResistor::construct ); +} + +ECResistor::ECResistor( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "resistor" ) +{ + m_name = i18n("Resistor"); + m_desc = i18n("Limits the flow of current, obeying Ohms Law"); + setSize( -16, -8, 32, 16 ); + + init1PinLeft(); + init1PinRight(); + m_resistance = createResistance( m_pPNode[0], m_pNNode[0], 1. ); + + createProperty( "resistance", Variant::Type::Double ); + property("resistance")->setCaption( i18n("Resistance") ); + property("resistance")->setUnit( QChar(0x3a9) ); + property("resistance")->setValue(1e4); + property("resistance")->setMinValue(1e-6); + + addDisplayText( "res", QRect( -16, -22, 32, 12 ), "", false ); +} + +ECResistor::~ECResistor() +{ +} + +void ECResistor::dataChanged() +{ + double resistance = dataDouble("resistance"); + + QString display = QString::number( resistance / getMultiplier(resistance), 'g', 3 ) + getNumberMag(resistance) + QChar(0x3a9); + setDisplayText( "res", display ); + + m_resistance->setResistance(resistance); +} + +void ECResistor::drawShape( QPainter &p ) +{ + initPainter(p); + p.drawRect( (int)x()-16, (int)y()-6, width(), 12 ); + deinitPainter(p); +} + + diff --git a/src/electronics/components/ecresistor.h b/src/electronics/components/ecresistor.h new file mode 100644 index 0000000..17e799e --- /dev/null +++ b/src/electronics/components/ecresistor.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef ECRESISTOR_H +#define ECRESISTOR_H + +#include "component.h" + +/** +@short Simple resistor +@author David Saxton +*/ +class ECResistor : public Component +{ + public: + ECResistor( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECResistor(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + protected: + virtual void dataChanged(); + virtual void drawShape( QPainter & p ); + + Resistance * m_resistance; +}; + +#endif diff --git a/src/electronics/components/ecsevensegment.cpp b/src/electronics/components/ecsevensegment.cpp new file mode 100644 index 0000000..ec35776 --- /dev/null +++ b/src/electronics/components/ecsevensegment.cpp @@ -0,0 +1,210 @@ +/*************************************************************************** + * 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 "colorcombo.h" +#include "diode.h" +#include "ecled.h" +#include "ecnode.h" +#include "ecsevensegment.h" +#include "libraryitem.h" +#include "simulator.h" + +#include <klocale.h> +#include <qpainter.h> +#include <qstring.h> + +Item* ECSevenSegment::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECSevenSegment( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECSevenSegment::libraryItem() +{ + return new LibraryItem( + "ec/seven_segment", + i18n("Seven Segment"), + i18n("Outputs"), + "seven_segment.png", + LibraryItem::lit_component, + ECSevenSegment::construct ); +} + +ECSevenSegment::ECSevenSegment( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "seven_segment" ) +{ + m_name = i18n("Seven Segment LED"); + m_desc = i18n("A seven segment display with a decimal point. This can be configured to either have a common cathode or a common anode."); + m_bDynamicContent = true; + + QStringList pins = QStringList::split( ',', "g,f,e,d,"+QString(QChar(0xB7))+",c,b,a" ); + + createProperty( "0-color", Variant::Type::Color ); + property("0-color")->setCaption( i18n("Color") ); + property("0-color")->setColorScheme( ColorCombo::LED ); + + createProperty( "diode-polarity", Variant::Type::Select ); + property("diode-polarity")->setCaption( i18n("Configuration") ); + property("diode-polarity")->setAllowed( QStringList::split(',',"Common Cathode,Common Anode") ); + property("diode-polarity")->setValue("Common Cathode"); + + for ( int i=0; i<8; i++ ) + { + m_diodes[i] = 0L; + m_nodes[i] = 0L; + avg_brightness[i] = 0.; + last_brightness[i] = 255; + } + m_nNode = 0L; + + lastUpdatePeriod = 0.; + + initDIPSymbol( pins, 64 ); + initDIP(pins); + + m_nNode = createPin( width()/2+offsetX(), height()+8+offsetY(), 270, "-v" ); + + for ( int i=0; i<7; i++ ) + m_nodes[i] = ecNodeWithID( QChar('a'+i) ); + + m_nodes[7] = ecNodeWithID(QChar(0xB7)); + + m_bCommonCathode = false; // Force update +} + + +ECSevenSegment::~ECSevenSegment() +{ +} + + +void ECSevenSegment::dataChanged() +{ + QColor color = dataColor("0-color"); + r = color.red(); + g = color.green(); + b = color.blue(); + r /= 0x100; + g /= 0x100; + b /= 0x100; + + bool commonCathode = dataString("diode-polarity") == "Common Cathode"; + if ( commonCathode != m_bCommonCathode ) + { + m_bCommonCathode = commonCathode; + for ( int i=0; i<7; i++ ) + { + removeElement( m_diodes[i], false ); + if (commonCathode) + m_diodes[i] = createDiode( m_nodes[i], m_nNode ); + else + m_diodes[i] = createDiode( m_nNode, m_nodes[i] ); + } + + removeElement( m_diodes[7], false ); + if (commonCathode) + m_diodes[7] = createDiode( m_nodes[7], m_nNode ); + else + m_diodes[7] = createDiode( m_nNode, m_nodes[7] ); + } + + update(); +} + + +void ECSevenSegment::stepNonLogic() +{ + double interval = 1./LINEAR_UPDATE_RATE; + + for ( int i=0; i<8; i++ ) { + avg_brightness[i] += ECLed::brightness( m_diodes[i]->current() )*interval; + } + + lastUpdatePeriod += interval; +} + +void ECSevenSegment::drawShape( QPainter &p ) +{ + CNItem::drawShape(p); + + initPainter(p); + + const int _width = 20; + const int _height = 32; + + const int x1 = (int)x()+offsetX() + (width()-_width)/2 - 1; + const int x2 = x1 + _width; + const int y1 = (int)y()+offsetY() + (height()-_height)/2; + const int y2 = y1 + _height/2; + const int y3 = y1 + _height; + const int ds = 2; // "Slope" + +// QPen pen; +// pen.setWidth(2); +// pen.setCapStyle(Qt::RoundCap); +// p.setPen(pen); + + if ( lastUpdatePeriod != 0. ) + { + for ( uint i=0; i<8; ++i ) + { + last_brightness[i] = (uint)(avg_brightness[i]/lastUpdatePeriod); + } + } + + double _b; + + // Top + _b = last_brightness[0]; + p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) ); + p.drawLine( x1+3+ds, y1+0, x2-3+ds, y1+0 ); + + // Top right + _b = last_brightness[1]; + p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) ); + p.drawLine( x2+0+ds, y1+3, x2+0, y2-3 ); + + // Bottom right + _b = last_brightness[2]; + p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) ); + p.drawLine( x2+0, y2+3, x2+0-ds, y3-3 ); + + // Bottom + _b = last_brightness[3]; + p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) ); + p.drawLine( x2-3-ds, y3+0, x1+3-ds, y3+0 ); + + // Bottom left + _b = last_brightness[4]; + p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) ); + p.drawLine( x1+0-ds, y3-3, x1+0, y2+3 ); + + // Top left + _b = last_brightness[5]; + p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) ); + p.drawLine( x1+0, y2-3, x1+0+ds, y1+3 ); + + // Middle + _b = last_brightness[6]; + p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) ); + p.drawLine( x1+3, y2+0, x2-3, y2+0 ); + + // Decimal point + _b = last_brightness[7]; + p.setBrush( QBrush( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ) ) ); + p.setPen( Qt::NoPen ); + p.drawPie( x2+3, y3-2, 3, 3, 0, 16*360 ); + + lastUpdatePeriod = 0.; + for ( uint i=0; i<8; ++i ) { + avg_brightness[i] = 0.; + } + + deinitPainter(p); +} diff --git a/src/electronics/components/ecsevensegment.h b/src/electronics/components/ecsevensegment.h new file mode 100644 index 0000000..7041c9a --- /dev/null +++ b/src/electronics/components/ecsevensegment.h @@ -0,0 +1,50 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef ECSEVENSEGMENT_H +#define ECSEVENSEGMENT_H + +#include "component.h" + +class Diode; +class ECNode; + +/** +@short Seven segment display component +@author David Saxton +*/ +class ECSevenSegment : public Component +{ +public: + ECSevenSegment( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECSevenSegment(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + virtual void dataChanged(); + virtual bool canFlip() const { return true; } + +private: + virtual void drawShape( QPainter &p ); + + bool m_bCommonCathode; + double lastUpdatePeriod; + double avg_brightness[8]; + uint last_brightness[8]; + Diode *m_diodes[8]; + ECNode *m_nodes[8]; + ECNode *m_nNode; + double r, g, b; +}; + +#endif diff --git a/src/electronics/components/ecsignallamp.cpp b/src/electronics/components/ecsignallamp.cpp new file mode 100644 index 0000000..c7034f7 --- /dev/null +++ b/src/electronics/components/ecsignallamp.cpp @@ -0,0 +1,86 @@ +/*************************************************************************** + * 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 "ecnode.h" +#include "ecsignallamp.h" +#include "element.h" +#include "libraryitem.h" +#include "pin.h" + +#include <klocale.h> +#include <qpainter.h> + +Item* ECSignalLamp::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECSignalLamp( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECSignalLamp::libraryItem() +{ + return new LibraryItem( + QString("ec/signal_lamp"), + i18n("Signal Lamp"), + i18n("Outputs"), + "signal_lamp.png", + LibraryItem::lit_component, + ECSignalLamp::construct ); +} + +ECSignalLamp::ECSignalLamp( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "signal_lamp" ) +{ + m_name = i18n("Signal Lamp"); + m_desc = i18n("A simple filament signal lamp, with a 100 ohms series resistance."); + setSize( -8, -8, 16, 16 ); + + init1PinLeft(); + init1PinRight(); + + createResistance( m_pPNode[0], m_pNNode[0], 100. ); + + advanceSinceUpdate = 0; + avgPower = 0.; + m_bDynamicContent = true; +} + +ECSignalLamp::~ECSignalLamp() +{ +} + +void ECSignalLamp::stepNonLogic() +{ + const double voltage = m_pPNode[0]->pin()->voltage()-m_pNNode[0]->pin()->voltage(); + avgPower = QABS(avgPower*advanceSinceUpdate + (voltage*voltage/100))/++advanceSinceUpdate; +} + +void ECSignalLamp::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = int(x()); + int _y = int(y()); + + // Calculate the brightness as a linear function of power, bounded below by + // 25 milliWatts and above by 500 milliWatts. + int brightness = (avgPower<0.025) ? 255 : ((avgPower>0.5) ? 0 : (int)(255*(1-((avgPower-0.025)/0.475)))); + advanceSinceUpdate = 0; + + p.setBrush( QColor( 255, 255, brightness ) ); + p.drawEllipse( _x-8, _y-8, 16, 16 ); + + // 2*sqrt(2) = 2.828427125... + int pos = 8 - int(16/2.828); + + p.drawLine( _x-8+pos, _y-8+pos, _x+8-pos, _y+8-pos ); + p.drawLine( _x+8-pos, _y-8+pos, _x-8+pos, _y+8-pos ); + + deinitPainter(p); +} diff --git a/src/electronics/components/ecsignallamp.h b/src/electronics/components/ecsignallamp.h new file mode 100644 index 0000000..e56d724 --- /dev/null +++ b/src/electronics/components/ecsignallamp.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef ECSIGNALLAMP_H +#define ECSIGNALLAMP_H + +#include "component.h" + +class Resistance; + +/** +@short Signal Lamp - glows when current flows +@author David Saxton +*/ +class ECSignalLamp : public Component +{ +public: + ECSignalLamp( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECSignalLamp(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + +private: + void drawShape( QPainter &p ); + double avgPower; + uint advanceSinceUpdate; +}; + +#endif diff --git a/src/electronics/components/ecsubcircuit.cpp b/src/electronics/components/ecsubcircuit.cpp new file mode 100644 index 0000000..a69e720 --- /dev/null +++ b/src/electronics/components/ecsubcircuit.cpp @@ -0,0 +1,130 @@ +/*************************************************************************** + * Copyright (C) 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 "canvasitemparts.h" +#include "circuitdocument.h" +#include "ecsubcircuit.h" +#include "node.h" +#include "libraryitem.h" +#include "subcircuits.h" + +#include <kdebug.h> +#include <klocale.h> +#include <qfile.h> + +Item* ECSubcircuit::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECSubcircuit( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECSubcircuit::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/subcircuit"), + QString::null, + QString::null, + QString::null, + LibraryItem::lit_subcircuit, + ECSubcircuit::construct ); +} + +ECSubcircuit::ECSubcircuit( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "subcircuit" ) +{ + m_name = i18n("Subcircuit"); + + createProperty( "id", Variant::Type::Int ); + property("id")->setMinValue(1); + property("id")->setMaxValue(1<<15); + property("id")->setValue(1); + property("id")->setHidden(true); +} + + +ECSubcircuit::~ECSubcircuit() +{ +} + + +void ECSubcircuit::removeItem() +{ + emit subcircuitDeleted(); + Component::removeItem(); +} + + +void ECSubcircuit::setNumExtCon( unsigned numExtCon ) +{ + m_conNames.resize(numExtCon); + + // Remove old pins + const NodeMap::iterator nodeMapEnd = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != nodeMapEnd; ++it ) + { + p_icnDocument->appendDeleteList( p_icnDocument->nodeWithID(it.data().id) ); + } + p_icnDocument->flushDeleteList(); + m_nodeMap.clear(); + + QStringList pins; + for ( unsigned i=0; i<numExtCon; ++i ) + { + pins += QString::number(i); + } + + initDIPSymbol( pins, 80 ); + + // We don't want the text that the dip symbol gave us as we initialize it later... + for ( unsigned i = 0; i < numExtCon; ++i ) + removeDisplayText( QString::number(i) ); + + initDIP(pins); +} + + +void ECSubcircuit::dataChanged() +{ + int subcircuitId = dataInt("id"); + if ( subcircuitId == -1 ) { + return; + } + emit subcircuitDeleted(); + Subcircuits::initECSubcircuit( subcircuitId, this ); +} + + +void ECSubcircuit::setExtConName( unsigned numId, const QString & name ) +{ + if ( numId > m_conNames.size() ) + return; + + m_conNames[numId] = name; +} + + +void ECSubcircuit::doneSCInit() +{ + QStringList pins; + for ( unsigned i = 0; i < m_conNames.size(); ++i ) + pins << m_conNames[i]; + initDIPSymbol( pins, 80 ); +} + + +void ECSubcircuit::drawShape( QPainter &p ) +{ + Component::drawShape(p); +} + + +#include "ecsubcircuit.moc" + + + diff --git a/src/electronics/components/ecsubcircuit.h b/src/electronics/components/ecsubcircuit.h new file mode 100644 index 0000000..eaf21ec --- /dev/null +++ b/src/electronics/components/ecsubcircuit.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef ECSUBCIRCUIT_H +#define ECSUBCIRCUIT_H + +#include <component.h> + +#include <qvaluevector.h> + +/** +"Container" component for subcircuits +@author David Saxton +*/ +class ECSubcircuit : public Component +{ +Q_OBJECT +public: + ECSubcircuit( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECSubcircuit(); + virtual bool canFlip() const { return true; } + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + /** + * Create numExtCon nodes, deleting any old ones + */ + void setNumExtCon( unsigned numExtCon ); + /** + * Give the connecting node at position numId the given name + */ + void setExtConName( unsigned numId, const QString & name ); + /** + * Called from SubcircuitData once the subcircuit has been fully attached + */ + void doneSCInit(); + +public slots: + virtual void removeItem(); + +signals: + /** + * Emitted when the current subcircuit is deleted + */ + void subcircuitDeleted(); + +protected: + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + QValueVector<QString> m_conNames; +}; + +#endif diff --git a/src/electronics/components/ecvoltagesignal.cpp b/src/electronics/components/ecvoltagesignal.cpp new file mode 100644 index 0000000..c338f36 --- /dev/null +++ b/src/electronics/components/ecvoltagesignal.cpp @@ -0,0 +1,95 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "ecnode.h" +#include "ecvoltagesignal.h" +#include "libraryitem.h" +#include "pin.h" +#include "simulator.h" +#include "voltagesignal.h" + +#include <klocale.h> +#include <qpainter.h> + +const double conductance = 1e5; // Internal resistance + +Item* ECVoltageSignal::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECVoltageSignal( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECVoltageSignal::libraryItem() +{ + return new LibraryItem( + QString("ec/voltage_signal"), + i18n("Voltage Signal"), + i18n("Sources"), + "voltagesignal.png", + LibraryItem::lit_component, + ECVoltageSignal::construct ); +} + +ECVoltageSignal::ECVoltageSignal( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "voltage_signal" ) +{ + m_name = i18n("Voltage Signal"); + m_desc = i18n("Provides a variety of voltage signals."); + setSize( -8, -8, 16, 16 ); + + init1PinLeft(); + init1PinRight(); + + m_pNNode[0]->pin()->setGroundType( Pin::gt_medium ); + m_voltageSignal = createVoltageSignal( m_pNNode[0], m_pPNode[0], 0. ); + m_voltageSignal->setStep( 1./LINEAR_UPDATE_RATE, ElementSignal::st_sinusoidal, 50. ); + + createProperty( "frequency", Variant::Type::Double ); + property("frequency")->setCaption( i18n("Frequency") ); + property("frequency")->setUnit("Hz"); + property("frequency")->setMinValue(1e-9); + property("frequency")->setMaxValue(1e3); + property("frequency")->setValue(50.0); + + createProperty( "voltage", Variant::Type::Double ); + property("voltage")->setCaption( i18n("Voltage Range") ); + property("voltage")->setUnit("V"); + property("voltage")->setMinValue(-1e12); + property("voltage")->setMaxValue(1e12); + property("voltage")->setValue(5.0); + + addDisplayText( "~", QRect( -8, -8, 16, 16 ), "~" ); + addDisplayText( "voltage", QRect( -16, -24, 32, 16 ), "" ); +} + + +ECVoltageSignal::~ECVoltageSignal() +{ +} + +void ECVoltageSignal::dataChanged() +{ + const double voltage = dataDouble("voltage"); + const double frequency = dataDouble("frequency"); + + QString display = QString::number( voltage / getMultiplier(voltage), 'g', 3 ) + getNumberMag(voltage) + "V"; + setDisplayText( "voltage", display ); + + m_voltageSignal->setStep( 1./LINEAR_UPDATE_RATE, ElementSignal::st_sinusoidal, frequency ); + m_voltageSignal->setVoltage(voltage); +} + + +void ECVoltageSignal::drawShape( QPainter &p ) +{ + initPainter(p); + p.drawEllipse( (int)x()-8, (int)y()-8, width(), height() ); + deinitPainter(p); +} + diff --git a/src/electronics/components/ecvoltagesignal.h b/src/electronics/components/ecvoltagesignal.h new file mode 100644 index 0000000..7102132 --- /dev/null +++ b/src/electronics/components/ecvoltagesignal.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef ECVOLTAGESIGNAL_H +#define ECVOLTAGESIGNAL_H + +#include "component.h" + +/** +@short Provides an alternating voltage source +@author David Saxton +*/ +class ECVoltageSignal : public Component +{ +public: + ECVoltageSignal( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECVoltageSignal(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + virtual void drawShape( QPainter &p ); + void dataChanged(); + + VoltageSignal *m_voltageSignal; +}; + +#endif diff --git a/src/electronics/components/ecvoltagesource.cpp b/src/electronics/components/ecvoltagesource.cpp new file mode 100644 index 0000000..4b8c543 --- /dev/null +++ b/src/electronics/components/ecvoltagesource.cpp @@ -0,0 +1,93 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "ecvoltagesource.h" + +#include "ecnode.h" +#include "voltagesource.h" +#include "libraryitem.h" +#include "pin.h" + +#include <klocale.h> +#include <qpainter.h> + +const double conductance = 1e5; // Internal resistance + +Item* ECCell::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECCell( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECCell::libraryItem() +{ + QStringList ids; + ids << "ec/battery" << "ec/cell"; + return new LibraryItem( + ids, + i18n("Battery"), + i18n("Sources"), + "cell.png", + LibraryItem::lit_component, + ECCell::construct ); +} + +ECCell::ECCell( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "cell" ) +{ + m_name = i18n("Battery"); + m_desc = i18n("Provides a potential-difference."); + setSize( -8, -8, 16, 16 ); + voltage = 0; + + init1PinLeft(); + init1PinRight(); + + m_pNNode[0]->pin()->setGroundType( Pin::gt_medium ); + m_voltageSource = createVoltageSource( m_pNNode[0], m_pPNode[0], voltage ); + + createProperty( "voltage", Variant::Type::Double ); + property("voltage")->setUnit("V"); + property("voltage")->setCaption( i18n("Voltage") ); + property("voltage")->setMinValue(-1e12); + property("voltage")->setMaxValue(1e12); + property("voltage")->setValue(5.0); + + addDisplayText( "voltage", QRect( -16, -24, 32, 16 ), "" ); +} + +ECCell::~ECCell() +{ +} + +void ECCell::dataChanged() +{ + voltage = dataDouble("voltage"); + m_voltageSource->setVoltage(voltage); + + QString display = QString::number( voltage / getMultiplier(voltage), 'g', 3 ) + getNumberMag(voltage) + "V"; + setDisplayText( "voltage", display ); +} + +void ECCell::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()-8; + int _y = (int)y()-24; + + p.drawLine( _x, _y+20, _x, _y+28 ); + p.drawLine( _x+5, _y+16, _x+5, _y+32 ); + p.drawLine( _x+10, _y+20, _x+10, _y+28 ); + p.drawLine( _x+15, _y+16, _x+15, _y+32 ); + + deinitPainter(p); +// p.drawPolyline( areaPoints() ); +} + diff --git a/src/electronics/components/ecvoltagesource.h b/src/electronics/components/ecvoltagesource.h new file mode 100644 index 0000000..4ba87ef --- /dev/null +++ b/src/electronics/components/ecvoltagesource.h @@ -0,0 +1,37 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef ECCELL_H +#define ECCELL_H + +#include "component.h" + +/** +@short Electrical cell +Simple electrical cell that simulates a PD and internal resistance +@author David Saxton +*/ +class ECCell : public Component +{ +public: + ECCell( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECCell(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void dataChanged(); + virtual void drawShape( QPainter &p ); + VoltageSource *m_voltageSource; + double voltage; +}; + +#endif diff --git a/src/electronics/components/externalconnection.cpp b/src/electronics/components/externalconnection.cpp new file mode 100644 index 0000000..596727a --- /dev/null +++ b/src/electronics/components/externalconnection.cpp @@ -0,0 +1,78 @@ +/*************************************************************************** + * Copyright (C) 2004 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 "externalconnection.h" +#include "libraryitem.h" + +#include <klocale.h> +#include <qpainter.h> + +Item* ExternalConnection::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ExternalConnection( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ExternalConnection::libraryItem() +{ + return new LibraryItem( + "ec/external_connection", + i18n("External Connection"), + i18n("Connections"), + "external_connection.png", + LibraryItem::lit_component, + ExternalConnection::construct ); +} + +ExternalConnection::ExternalConnection( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "external_connection" ) +{ + m_name = i18n("External Connection"); + m_desc = i18n("Point to connect the circuit to an external entity - e.g. a mechanical component or as part of a subcircuit."); + setSize( -8, -8, 16, 16 ); + + createProperty( "name", Variant::Type::Combo ); + property("name")->setCaption( i18n("Name") ); + property("name")->setValue("ExtCon"); + + init1PinLeft(); + + addDisplayText( "name", QRect( -24, 8, 3*width(), 16 ), "ExtCon" ); +} + +ExternalConnection::~ExternalConnection() +{ +} + + +void ExternalConnection::dataChanged() +{ + QString name = dataString("name"); + + QRect r( -width(), 16, 3*width(), 16 ); + setDisplayText( "name", name ); +} + + +void ExternalConnection::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()-8; + int _y = (int)y()-8; + p.drawEllipse( _x, _y, width(), height() ); + + p.drawLine( _x+3, _y+6, _x+12, _y+6 ); + p.drawLine( _x+8, _y+3, _x+12, _y+6 ); + + p.drawLine( _x+3, _y+9, _x+12, _y+9 ); + p.drawLine( _x+3, _y+9, _x+8, _y+12 ); + + deinitPainter(p); +} + diff --git a/src/electronics/components/externalconnection.h b/src/electronics/components/externalconnection.h new file mode 100644 index 0000000..9b733fc --- /dev/null +++ b/src/electronics/components/externalconnection.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2004 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. * + ***************************************************************************/ + +#ifndef EXTERNALCONNECTION_H +#define EXTERNALCONNECTION_H + +#include <component.h> + +/** +For connecting to something "outside" - e.g. a mechanical component, or as part +of a circuit part +@author David Saxton +*/ +class ExternalConnection : public Component +{ +public: + ExternalConnection( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ExternalConnection(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void dataChanged(); + virtual void drawShape( QPainter &p ); +}; + +#endif diff --git a/src/electronics/components/flipflop.cpp b/src/electronics/components/flipflop.cpp new file mode 100644 index 0000000..5c55baf --- /dev/null +++ b/src/electronics/components/flipflop.cpp @@ -0,0 +1,347 @@ +/*************************************************************************** + * Copyright (C) 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 "flipflop.h" +#include "icndocument.h" +#include "logic.h" +#include "libraryitem.h" +#include "node.h" +#include "simulator.h" + +#include <kiconloader.h> +#include <klocale.h> +#include <qpainter.h> + + +//BEGIN class ECDFlipFlop +Item* ECDFlipFlop::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECDFlipFlop( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECDFlipFlop::libraryItem() +{ + return new LibraryItem( + "ec/d_flipflop", + i18n("D Flip-Flop"), + i18n("Integrated Circuits"), + "ic3.png", + LibraryItem::lit_component, + ECDFlipFlop::construct ); +} + +ECDFlipFlop::ECDFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "d_flipflop" ) +{ + m_name = i18n("D-Type Flip-Flop"); + m_desc = i18n("The output state is set from the input state when the clock is pulsed."); + + setSize( -32, -24, 64, 48 ); + + init2PinLeft( -8, 8 ); + init2PinRight( -8, 8 ); + + m_prevD[0] = m_prevD[1] = false; + m_whichPrevD = 0; + m_prevDSimTime = 0; + m_pSimulator = Simulator::self(); + + m_bPrevClock = false; + m_pD = createLogicIn( m_pNNode[0] ); + m_pClock = createLogicIn( m_pNNode[1] ); + m_pQ = createLogicOut( m_pPNode[0], false ); + m_pQBar = createLogicOut( m_pPNode[1], false ); + + setp = createLogicIn( createPin( 0, -32, 90, "set" ) ); + rstp = createLogicIn( createPin( 0, 32, 270, "rst" ) ); + + addDisplayText( "D", QRect( -32, -16, 20, 16 ), "D" ); + addDisplayText( ">", QRect( -32, 0, 20, 16 ), ">" ); + addDisplayText( "Q", QRect( 12, -16, 20, 16 ), "Q" ); + addDisplayText( "Q'", QRect( 12, 0, 20, 16 ), "Q'" ); + addDisplayText( "Set", QRect( -16, -20, 32, 16 ), "Set" ); + addDisplayText( "Rst", QRect( -16, 4, 32, 16 ), "Rst" ); + + m_pD->setCallback( this, (CallbackPtr)(&ECDFlipFlop::inputChanged) ); + m_pClock->setCallback( this, (CallbackPtr)(&ECDFlipFlop::clockChanged) ); + setp->setCallback( this, (CallbackPtr)(&ECDFlipFlop::asyncChanged) ); + rstp->setCallback( this, (CallbackPtr)(&ECDFlipFlop::asyncChanged) ); + + inStateChanged(false); +} + +ECDFlipFlop::~ECDFlipFlop() +{ +} + +void ECDFlipFlop::asyncChanged(bool) +{ + bool set = setp->isHigh(); + bool rst = rstp->isHigh(); + if(set || rst) + { + m_pQ->setHigh(set); + m_pQBar->setHigh(rst); + } +} + +void ECDFlipFlop::inputChanged( bool newState ) +{ + unsigned long long simTime = m_pSimulator->time(); + if ( (simTime == m_prevDSimTime) && (newState == m_prevD[m_whichPrevD]) ) + return; + + m_prevDSimTime = simTime; + m_whichPrevD = 1-m_whichPrevD; + m_prevD[m_whichPrevD] = newState; +} + +void ECDFlipFlop::clockChanged( bool newState ) +{ + bool set = setp->isHigh(); + bool rst = rstp->isHigh(); + + bool fallingEdge = m_bPrevClock && !newState; + m_bPrevClock = newState; + + if( set || rst ) return; + + if (fallingEdge) + { + unsigned long long simTime = m_pSimulator->time(); + bool d = ( simTime == m_prevDSimTime ) ? m_prevD[1-m_whichPrevD] : m_prevD[m_whichPrevD]; + + m_pQ->setHigh(d); + m_pQBar->setHigh(!d); + } +} + +void ECDFlipFlop::inStateChanged(bool) +{ + // Only called when the flipflop is created. + m_pQ->setHigh(false); + m_pQBar->setHigh(true); +} +//END class ECDFlipFlop + + +//BEGIN class ECJKFlipFlop +Item* ECJKFlipFlop::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECJKFlipFlop( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECJKFlipFlop::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/jk_flipflop"), + i18n("JK Flip-Flop"), + i18n("Integrated Circuits"), + "ic3.png", + LibraryItem::lit_component, + ECJKFlipFlop::construct ); +} + +ECJKFlipFlop::ECJKFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "jk_flipflop" ) +{ + m_name = i18n("JK-Type Flip-Flop"); + m_desc = i18n("The output state is set according to J and K when the clock is pulsed."); + + setSize( -32, -32, 64, 64 ); + + init3PinLeft( -16, 0, 16 ); + init2PinRight( -16, 16 ); + + m_pJ = createLogicIn( m_pNNode[0] ); + m_pClock = createLogicIn( m_pNNode[1] ); + m_pK = createLogicIn( m_pNNode[2] ); + + m_pQ = createLogicOut( m_pPNode[0], false ); + m_pQBar = createLogicOut( m_pPNode[1], false ); + + setp = createLogicIn( createPin( 0, -40, 90, "set" ) ); + rstp = createLogicIn( createPin( 0, 40, 270, "rst" ) ); + + addDisplayText( "J", QRect( -32, -24, 20, 16 ), "J" ); + addDisplayText( ">", QRect( -32, -8, 20, 16 ), ">" ); + addDisplayText( "K", QRect( -32, 8, 20, 16 ), "K" ); + addDisplayText( "Q", QRect( 12, -24, 20, 16 ), "Q" ); + addDisplayText( "Q'", QRect( 12, 8, 20, 16 ), "Q'" ); + addDisplayText( "Set", QRect( -16, -28, 32, 16 ), "Set" ); + addDisplayText( "Rst", QRect( -16, 12, 32, 16 ), "Rst" ); + + m_pClock->setCallback( this, (CallbackPtr)(&ECJKFlipFlop::clockChanged) ); + setp->setCallback( this, (CallbackPtr)(&ECJKFlipFlop::asyncChanged) ); + rstp->setCallback( this, (CallbackPtr)(&ECJKFlipFlop::asyncChanged) ); + + inStateChanged(false); +} + +ECJKFlipFlop::~ECJKFlipFlop() +{ +} + +void ECJKFlipFlop::clockChanged(bool newvalue) +{ + bool j = m_pJ->isHigh(); + bool k = m_pK->isHigh(); + bool set = setp->isHigh(); + bool rst = rstp->isHigh(); + + if( set || rst ) return; + +// a JK flip-flop change state when clock do 1->0 + if (!newvalue && (j || k)) { + if ( j && k ) { + m_pQ->setHigh(!prev_state); + m_pQBar->setHigh(prev_state); + prev_state = !prev_state; + } else { + // (J=1 && K=0) || (J=0 && K=1) + m_pQ->setHigh(j); + m_pQBar->setHigh(k); + prev_state = j; + } + } +} + +void ECJKFlipFlop::asyncChanged(bool) +{ + bool set = setp->isHigh(); + bool rst = rstp->isHigh(); + + if (set || rst) { + m_pQ->setHigh(set); + m_pQBar->setHigh(rst); + prev_state = set; + } +} + +void ECJKFlipFlop::inStateChanged(bool) +{ + m_pQBar->setHigh(true); + m_pQ->setHigh(false); + prev_state = false; +} +//END class ECJKFlipFlop + + +//BEGIN class ECSRFlipFlop +Item* ECSRFlipFlop::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECSRFlipFlop( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECSRFlipFlop::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/sr_flipflop"), + i18n("SR Flip-Flop"), + i18n("Integrated Circuits"), + "ic3.png", + LibraryItem::lit_component, + ECSRFlipFlop::construct ); +} + +ECSRFlipFlop::ECSRFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "sr_flipflop" ) +{ + m_name = i18n("SR Flip-Flop"); + m_desc = i18n("The output is made high by holding <i>set</i> high, and low by holding <i>reset</i> high."); + + setSize( -24, -24, 48, 48 ); + + init2PinLeft( -8, 8 ); + init2PinRight( -8, 8 ); + + m_pS = createLogicIn( m_pNNode[0] ); + m_pR = createLogicIn( m_pNNode[1] ); + m_pQ = createLogicOut( m_pPNode[0], true ); + m_pQBar = createLogicOut( m_pPNode[1], false ); + + old_q1 = true; + old_q2 = false; + m_pQ->setHigh(old_q1); + m_pQBar->setHigh(old_q2); + + addDisplayText( "S", QRect( -24, -16, 20, 16 ), "S" ); + addDisplayText( "R", QRect( -24, 0, 20, 16 ), "R" ); + addDisplayText( "Q", QRect( 4, -16, 20, 16 ), "Q" ); + addDisplayText( "Q'", QRect( 4, 0, 20, 16 ), "Q'" ); + + m_pS->setCallback( this, (CallbackPtr)(&ECSRFlipFlop::inStateChanged) ); + m_pR->setCallback( this, (CallbackPtr)(&ECSRFlipFlop::inStateChanged) ); + m_pQ->setCallback( this, (CallbackPtr)(&ECSRFlipFlop::inStateChanged) ); + m_pQBar->setCallback( this, (CallbackPtr)(&ECSRFlipFlop::inStateChanged) ); +} + +ECSRFlipFlop::~ECSRFlipFlop() +{ +} + +void ECSRFlipFlop::inStateChanged(bool) +{ + // Q = v_q1, Q-bar = v_q2 + bool new_q1 = false; + bool new_q2 = false; + + bool s = m_pS->isHigh(); + bool r = m_pR->isHigh(); + bool q1 = m_pQ->isHigh(); + bool q2 = m_pQBar->isHigh(); + + // Easy ones to do :-) + if (!q1) new_q2 = true; + if (!q2) new_q1 = true; + + if ( q1 && q2 ) + { + if ( s && !r ) + { + new_q1 = true; + new_q2 = false; + } + else if ( !s && r ) + { + new_q1 = false; + new_q2 = true; + } + else if ( s && r ) + { + new_q1 = old_q1; + new_q2 = old_q2; + } + else if ( !s && !r ) + { + new_q1 = false; + new_q2 = false; + } + } + else if ( q1 && !q2 ) + { + // Note: We only need to set the value of v_q2 + if ( r && !s ) new_q2 = true; + else new_q2 = false; + } + else if ( !q1 && q2 ) + { + // Note: We only need to set the value of v_q1 + if ( s && !r ) new_q1 = true; + else new_q1 = false; + } + + old_q1 = new_q1; + old_q2 = new_q2; + + m_pQ->setHigh(new_q1); + m_pQBar->setHigh(new_q2); +} +//END class ECSRFlipFlop diff --git a/src/electronics/components/flipflop.h b/src/electronics/components/flipflop.h new file mode 100644 index 0000000..7b9d5b7 --- /dev/null +++ b/src/electronics/components/flipflop.h @@ -0,0 +1,107 @@ +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef FLIPFLOP_H +#define FLIPFLOP_H + +#include "component.h" +#include "logic.h" + +class Simulator; + +/** +@short Boolean D-Type Flip-Flop +@author David Saxton +*/ +class ECDFlipFlop : public CallbackClass, public Component +{ +public: + ECDFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECDFlipFlop(); + virtual bool canFlip() const { return true; } + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void inputChanged( bool newState ); + void inStateChanged( bool newState ); + void asyncChanged(bool newState ); + void clockChanged(bool newState ); + + LogicIn *m_pD; + LogicIn *m_pClock; + LogicOut *m_pQ; + LogicOut *m_pQBar; + LogicIn *setp; + LogicIn *rstp; + bool m_bPrevClock; + + bool m_prevD[2]; + unsigned m_whichPrevD:1; + unsigned long long m_prevDSimTime; + Simulator * m_pSimulator; +}; + + +/** +@short Boolean JK-Type Flip-Flop +@author Couriousous +*/ +class ECJKFlipFlop : public CallbackClass, public Component +{ +public: + ECJKFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECJKFlipFlop(); + virtual bool canFlip() const { return true; } + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void inStateChanged( bool newState ); + void asyncChanged(bool newState ); + void clockChanged(bool newState ); + bool prev_state; + LogicIn *m_pJ; + LogicIn *m_pClock; + LogicIn *m_pK; + LogicIn *setp; + LogicIn *rstp; + LogicOut *m_pQ; + LogicOut *m_pQBar; +}; + + +/** +@short Boolean Set-Reset Flip-Flop +@author David Saxton +*/ +class ECSRFlipFlop : public CallbackClass, public Component +{ +public: + ECSRFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECSRFlipFlop(); + virtual bool canFlip() const { return true; } + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + void inStateChanged( bool newState ); + LogicIn * m_pS; + LogicIn * m_pR; + LogicOut * m_pQ; + LogicOut * m_pQBar; + bool old_q1; + bool old_q2; +}; + +#endif diff --git a/src/electronics/components/fulladder.cpp b/src/electronics/components/fulladder.cpp new file mode 100644 index 0000000..ad5e40c --- /dev/null +++ b/src/electronics/components/fulladder.cpp @@ -0,0 +1,91 @@ +/*************************************************************************** + * Copyright (C) 2004 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 "fulladder.h" + +#include "logic.h" +#include "libraryitem.h" + +#include <kiconloader.h> +#include <klocale.h> + + +Item* FullAdder::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new FullAdder( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* FullAdder::libraryItem() +{ + return new LibraryItem( + QString("ec/adder"), + i18n("Adder"), + i18n("Integrated Circuits"), + "ic1.png", + LibraryItem::lit_component, + FullAdder::construct + ); +} + +FullAdder::FullAdder( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "adder" ) +{ + m_name = i18n("Adder"); +// m_desc = i18n("Insert missing adder help here."); + + ALogic = BLogic = inLogic = 0l; + outLogic = SLogic = 0l; + + QStringList pins = QStringList::split( ',', "A,B,>,,S,C", true ); + initDIPSymbol( pins, 48 ); + initDIP(pins); + + ECNode *node; + + node = ecNodeWithID("S"); + SLogic = createLogicOut( node, false ); + + node = ecNodeWithID("C"); + outLogic = createLogicOut( node, false ); + + node = ecNodeWithID("A"); + ALogic = createLogicIn(node); + + node = ecNodeWithID("B"); + BLogic = createLogicIn(node); + + node = ecNodeWithID(">"); + inLogic = createLogicIn(node); + + + ALogic->setCallback( this, (CallbackPtr)(&FullAdder::inStateChanged) ); + BLogic->setCallback( this, (CallbackPtr)(&FullAdder::inStateChanged) ); + inLogic->setCallback( this, (CallbackPtr)(&FullAdder::inStateChanged) ); +} + +FullAdder::~FullAdder() +{ +} + + +void FullAdder::inStateChanged( bool /*state*/ ) +{ + const bool A = ALogic->isHigh(); + const bool B = BLogic->isHigh(); + const bool in = inLogic->isHigh(); + + const bool out = (!A && B && in) || (A && !B && in) || (A && B); + const bool S = (!A && !B && in) || (!A && B && !in) || (A && !B && !in) || (A && B && in); + + SLogic->setHigh(S); + outLogic->setHigh(out); +} + + diff --git a/src/electronics/components/fulladder.h b/src/electronics/components/fulladder.h new file mode 100644 index 0000000..d4277e5 --- /dev/null +++ b/src/electronics/components/fulladder.h @@ -0,0 +1,37 @@ +/*************************************************************************** + * Copyright (C) 2004 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. * + ***************************************************************************/ + +#ifndef ECFullAdder_H +#define ECFullAdder_H + +#include "component.h" +#include "logic.h" + +/** +@author David Saxton +*/ +class FullAdder : public CallbackClass, public Component +{ +public: + FullAdder( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~FullAdder(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + virtual bool canFlip() const { return true; } + +protected: + void inStateChanged( bool newState ); + + LogicIn *ALogic, *BLogic, *inLogic; + LogicOut *outLogic, *SLogic; +}; + +#endif diff --git a/src/electronics/components/inductor.cpp b/src/electronics/components/inductor.cpp new file mode 100644 index 0000000..9e30b34 --- /dev/null +++ b/src/electronics/components/inductor.cpp @@ -0,0 +1,84 @@ +/*************************************************************************** + * Copyright (C) 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 "inductance.h" +#include "inductor.h" +#include "libraryitem.h" + +#include <klocale.h> +#include <qpainter.h> + +Item* Inductor::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Inductor( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Inductor::libraryItem() +{ + return new LibraryItem( + "ec/inductor", + i18n("Inductor"), + i18n("Discrete"), + "inductor.png", + LibraryItem::lit_component, + Inductor::construct + ); +} + +Inductor::Inductor( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "inductor" ) +{ + m_name = i18n("Inductor"); +// m_desc = i18n("Stores electrical charge.<br><br>" +// "The voltage across the inductor and inductance are related by <i>Charge = Inductance x Voltage</i>."); + setSize( -16, -8, 32, 16 ); + + init1PinLeft(); + init1PinRight(); + + m_pInductance = createInductance( m_pNNode[0], m_pPNode[0], 0.001 ); + + createProperty( "Inductance", Variant::Type::Double ); + property("Inductance")->setCaption( i18n("Inductance") ); + property("Inductance")->setUnit("H"); + property("Inductance")->setMinValue(1e-12); + property("Inductance")->setMaxValue(1e12); + property("Inductance")->setValue(1e-3); + + addDisplayText( "inductance", QRect( -8, -24, 16, 16 ), "", false ); +} + +Inductor::~Inductor() +{ +} + +void Inductor::dataChanged() +{ + double inductance = dataDouble("Inductance"); + + QString display = QString::number( inductance / getMultiplier(inductance), 'g', 3 ) + getNumberMag(inductance) + "H"; + setDisplayText( "inductance", display ); + + m_pInductance->setInductance(inductance); +} + +void Inductor::drawShape( QPainter &p ) +{ + initPainter(p); + int _y = int(y()); + int _x = int(x()); + + p.drawArc( _x-16, _y-5, 11, 11, 0, 180*16 ); + p.drawArc( _x-5, _y-5, 11, 11, 0, 180*16 ); + p.drawArc( _x+6, _y-5, 11, 11, 0, 180*16 ); + + deinitPainter(p); +} + diff --git a/src/electronics/components/inductor.h b/src/electronics/components/inductor.h new file mode 100644 index 0000000..abb4eec --- /dev/null +++ b/src/electronics/components/inductor.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef INDUCTOR_H +#define INDUCTOR_H + +#include <component.h> + +/** +@author David Saxton +*/ +class Inductor : public Component +{ + public: + Inductor( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Inductor(); + + static Item * construct( ItemDocument * itemDocument, bool newItem, const char * id ); + static LibraryItem * libraryItem(); + + private: + void dataChanged(); + virtual void drawShape( QPainter & p ); + + Inductance * m_pInductance; +}; + +#endif diff --git a/src/electronics/components/magnitudecomparator.cpp b/src/electronics/components/magnitudecomparator.cpp new file mode 100644 index 0000000..2659122 --- /dev/null +++ b/src/electronics/components/magnitudecomparator.cpp @@ -0,0 +1,206 @@ +/*************************************************************************** + * Copyright (C) 2005 by Fredy Yanardi * + * * + * 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 "libraryitem.h" +#include "logic.h" +#include "magnitudecomparator.h" +#include "variant.h" + +#include <cmath> +#include <klocale.h> + +Item* MagnitudeComparator::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new MagnitudeComparator( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* MagnitudeComparator::libraryItem() +{ + return new LibraryItem( + QString("ec/magnitudecomparator"), + i18n("Magnitude Comparator"), + i18n("Integrated Circuits"), + "ic1.png", + LibraryItem::lit_component, + MagnitudeComparator::construct + ); +} + +MagnitudeComparator::MagnitudeComparator( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "magnitudecomparator" ) +{ + m_name = i18n("Magnitude Comparator"); +// m_desc = i18n("Compares to two binary number and generates input to indicate which binary number has greater magnitude. It has 3 cascading inputs: I0 for I<SUB>A > B</SUB>, I1 for I<SUB>A < B</SUB>, and I2 for I<SUB>A = B</SUB> and 3 outputs: O0 for O<SUB>A > B</SUB>, O1 for O<SUB>A < B</SUB>, and O2 for O<SUB>A = B</SUB>"); + m_desc = i18n("Compares two binary numbers and generates output to indicate which binary number has the greater magnitude. It has 3 cascading inputs:" + "<ul><li>I: A > B</li>" + "<li>I: A < B</li>" + "<li>I: A = B</li></ul>" + "and 3 outputs:" + "<ul><li>O: A > B</li>" + "<li>O: A < B</li>" + "<li>O: A = B</li></ul>"); + + createProperty( "numInput", Variant::Type::Int ); + property("numInput")->setCaption( i18n("Number Inputs") ); + property("numInput")->setMinValue(1); + property("numInput")->setMaxValue(8); + property("numInput")->setValue(4); + + m_oldABLogicCount = 0; + cascadingInputs = 3; + outputs = 3; + + firstTime = true; +} + +MagnitudeComparator::~MagnitudeComparator() +{ +} + + +void MagnitudeComparator::dataChanged() +{ + initPins(); +} + + +void MagnitudeComparator::inStateChanged() +{ + int i; + + for ( i = 0; i < 3; i++ ) + m_output[i]->setHigh(false); + +// for ( i = dataInt("numInput")-1; i >= 0; i-- ) { + for ( i = m_oldABLogicCount-1; i >= 0; i-- ) { + if (m_aLogic[i]->isHigh() && !m_bLogic[i]->isHigh()) + { + m_output[0]->setHigh(true); + return; + } + else if ( !m_aLogic[i]->isHigh() && m_bLogic[i]->isHigh() ) { + m_output[1]->setHigh(true); + return; + } + } + + if ( m_cLogic[2]->isHigh() ) + m_output[2]->setHigh(true); + else if ( m_cLogic[0]->isHigh() ) + if ( !m_cLogic[1]->isHigh() ) + m_output[0]->setHigh(true); + else + ; + else if ( m_cLogic[1]->isHigh() ) + m_output[1]->setHigh(true); + else { + m_output[0]->setHigh(true); + m_output[1]->setHigh(true); + } +} + + +void MagnitudeComparator::initPins() +{ + const double numInputs = dataInt("numInput"); + int newABLogicCount = (int)numInputs; + + if ( newABLogicCount == m_oldABLogicCount ) + return; + + QStringList leftPins; + int space = 3 - newABLogicCount; + for ( int i = 0; i < space; i++ ) + leftPins << ""; + for ( int i = 0; i < newABLogicCount; i++ ) + leftPins << QString("A%1").arg( QString::number(i) ); + for ( int i = 0; i < newABLogicCount; i++ ) + leftPins << QString("B%1").arg( QString::number(i) ); + for ( int i = 0; i < space; i++ ) + leftPins << ""; + + QStringList rightPins; + space = -space; + for ( int i = 0; i < space; i++ ) + rightPins << ""; + QString inNames[] = { "I: A>B", "I: A<B", "I: A=B" }; + rightPins << inNames[2] << inNames[1] << inNames[0]; + QString outNames[] = { "O: A>B", "O: A<B", "O: A=B" }; + rightPins << outNames[2] << outNames[1] << outNames[0]; + for ( int i = 0; i < space; i++ ) + rightPins << ""; + + QStringList pins = leftPins + rightPins; + + initDIPSymbol( pins, 88 ); + initDIP(pins); + + ECNode *node; + + if (firstTime) { + m_cLogic.resize(3); + for ( int i = 0; i < cascadingInputs; i++ ) + { + node = ecNodeWithID( inNames[i] ); + m_cLogic.insert( i, createLogicIn(node) ); + m_cLogic[i]->setCallback( this, (CallbackPtr)(&MagnitudeComparator::inStateChanged)); + } + + m_output.resize(3); + for ( int i = 0; i < outputs; i++ ) + { + node = ecNodeWithID( outNames[i] ); + m_output.insert( i, createLogicOut(node,false) ); + } + firstTime = false; + } + + if ( newABLogicCount > m_oldABLogicCount ) + { + m_aLogic.resize(newABLogicCount); + for ( int i=m_oldABLogicCount; i<newABLogicCount; ++i ) + { + node = ecNodeWithID("A"+QString::number(i)); + m_aLogic.insert( i, createLogicIn(node) ); + m_aLogic[i]->setCallback( this, (CallbackPtr)(&MagnitudeComparator::inStateChanged) ); + } + + m_bLogic.resize(newABLogicCount); + for ( int i=m_oldABLogicCount; i<newABLogicCount; ++i ) + { + node = ecNodeWithID("B"+QString::number(i)); + m_bLogic.insert( i, createLogicIn(node) ); + m_bLogic[i]->setCallback( this, (CallbackPtr)(&MagnitudeComparator::inStateChanged) ); + } + } + else + { + for ( int i=newABLogicCount; i<m_oldABLogicCount; ++i ) + { + QString id = "A"+QString::number(i); + removeDisplayText(id); + removeElement( m_aLogic[i], false ); + removeNode(id); + } + m_aLogic.resize(newABLogicCount); + for ( int i=newABLogicCount; i<m_oldABLogicCount; ++i ) + { + QString id = "B"+QString::number(i); + removeDisplayText(id); + removeElement( m_bLogic[i], false ); + removeNode(id); + } + m_bLogic.resize(newABLogicCount); + } + + m_oldABLogicCount = newABLogicCount; + inStateChanged(); +} + + diff --git a/src/electronics/components/magnitudecomparator.h b/src/electronics/components/magnitudecomparator.h new file mode 100644 index 0000000..57dc748 --- /dev/null +++ b/src/electronics/components/magnitudecomparator.h @@ -0,0 +1,50 @@ +/*************************************************************************** + * Copyright (C) 2005 by Fredy Yanardi * + * * + * 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. * + ***************************************************************************/ + +#ifndef MAGNITUDECOMPARATOR_H +#define MAGNITUDECOMPARATOR_H + +#include "component.h" +#include "logic.h" + +#include <qbitarray.h> +#include <qptrvector.h> + +/** +@author Fredy Yanardi + */ +class MagnitudeComparator : public CallbackClass, public Component +{ + public: + MagnitudeComparator( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~MagnitudeComparator(); + + virtual bool canFlip() const { return true; } + static Item * construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem * libraryItem(); + + protected: + void initPins(); + virtual void dataChanged(); + void inStateChanged(); + + int m_oldABLogicCount; + int cascadingInputs; + int outputs; + bool firstTime; + + QBitArray m_data; + + QPtrVector<LogicIn> m_aLogic; + QPtrVector<LogicIn> m_bLogic; + QPtrVector<LogicIn> m_cLogic; + QPtrVector<LogicOut> m_output; +}; + +#endif diff --git a/src/electronics/components/matrixdisplay.cpp b/src/electronics/components/matrixdisplay.cpp new file mode 100644 index 0000000..dd40b6a --- /dev/null +++ b/src/electronics/components/matrixdisplay.cpp @@ -0,0 +1,291 @@ +/*************************************************************************** + * Copyright (C) 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 "colorcombo.h" +#include "diode.h" +#include "ecled.h" +#include "ecnode.h" +#include "libraryitem.h" +#include "matrixdisplay.h" +#include "simulator.h" + +#include <kdebug.h> +#include <klocale.h> +#include <qpainter.h> +#include <qstring.h> + +Item* MatrixDisplay::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new MatrixDisplay( (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem* MatrixDisplay::libraryItem() +{ + return new LibraryItem( + "ec/matrix_display", + i18n("Matrix Display"), + i18n("Outputs"), + "matrixdisplay.png", + LibraryItem::lit_component, + MatrixDisplay::construct ); +} + + +MatrixDisplay::MatrixDisplay( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "matrix_display" ) +{ + m_name = i18n("Matrix Display"); + m_desc = i18n("A matrix display of LEDs with a configurable number of columns and rows."); + m_bDynamicContent = true; + + //BEGIN Reset members + for ( unsigned i = 0; i < max_md_height; i++ ) + m_pRowNodes[i] = 0l; + for ( unsigned i = 0; i < max_md_width; i++ ) + m_pColNodes[i] = 0l; + + m_lastUpdatePeriod = 0.0; + m_r = m_g = m_b = 0.0; + m_bRowCathode = true; + m_numRows = 0; + m_numCols = 0; + //END Reset members + + createProperty( "0-rows", Variant::Type::Int ); + property("0-rows")->setCaption( i18n("Rows") ); + property("0-rows")->setMinValue(1); + property("0-rows")->setMaxValue(max_md_height); + property("0-rows")->setValue(7); + + createProperty( "1-cols", Variant::Type::Int ); + property("1-cols")->setCaption( i18n("Columns") ); + property("1-cols")->setMinValue(1); + property("1-cols")->setMaxValue(max_md_width); + property("1-cols")->setValue(5); + + createProperty( "color", Variant::Type::Color ); + property("color")->setCaption( i18n("Color") ); + property("color")->setColorScheme( ColorCombo::LED ); + + createProperty( "diode-configuration", Variant::Type::Select ); + property("diode-configuration")->setCaption( i18n("Configuration") ); + property("diode-configuration")->setAllowed( QStringList::split(',',"Row Cathode,Column Cathode") ); + property("diode-configuration")->setValue("Row Cathode"); + property("diode-configuration")->setAdvanced(true); +} + + +MatrixDisplay::~MatrixDisplay() +{ +} + + +void MatrixDisplay::dataChanged() +{ + QColor color = dataColor("color"); + m_r = double(color.red()) / double(0x100); + m_g = double(color.green()) / double(0x100); + m_b = double(color.blue()) / double(0x100); + + int numRows = dataInt("0-rows"); + int numCols = dataInt("1-cols"); + + bool ledsChanged = (numRows != int(m_numRows)) || (numCols != int(m_numCols)); + + if (ledsChanged) + initPins( numRows, numCols ); + + bool rowCathode = dataString("diode-configuration") == "Row Cathode"; + if ( (rowCathode != m_bRowCathode) || ledsChanged) + { + m_bRowCathode = rowCathode; + + for ( unsigned i = 0; i < m_numCols; i++ ) + { + for ( unsigned j = 0; j < m_numRows; j++ ) + { + removeElement( m_pDiodes[i][j], false ); + if (rowCathode) + m_pDiodes[i][j] = createDiode( m_pColNodes[i], m_pRowNodes[j] ); + else + m_pDiodes[i][j] = createDiode( m_pRowNodes[j], m_pColNodes[i] ); + } + } + } +} + + +void MatrixDisplay::initPins( unsigned numRows, unsigned numCols ) +{ + if ( (numRows == m_numRows) && (numCols == m_numCols) ) + return; + + if ( numRows > max_md_height ) + numRows = max_md_height; + + if ( numCols > max_md_width ) + numCols = max_md_width; + + m_lastUpdatePeriod = 0.0; + + //BEGIN Remove diodes + // All the diodes are going to be readded from dataChanged (where this + // function is called from), so easiest just to delete the diodes now and + // resize. + + for ( unsigned i = 0; i < m_numCols; i++ ) + { + for ( unsigned j = 0; j < m_numRows; j++ ) + removeElement( m_pDiodes[i][j], false ); + } + + m_avgBrightness.resize(numCols); + m_lastBrightness.resize(numCols); + m_pDiodes.resize(numCols); + + for ( unsigned i = 0; i < numCols; i++ ) + { + m_avgBrightness[i].resize(numRows); + m_lastBrightness[i].resize(numRows); + m_pDiodes[i].resize(numRows); + + for ( unsigned j = 0; j < numRows; j++ ) + { + m_avgBrightness[i][j] = 0.0; + m_lastBrightness[i][j] = 255; + m_pDiodes[i][j] = 0l; + } + + } + //END Remove diodes + + + //BEGIN Create or destroy pins + if ( numCols >= m_numCols ) + { + for ( unsigned i = m_numCols; i < numCols; i++ ) + m_pColNodes[i] = createPin( 0, 0, 270, colPinID(i) ); + } + else + { + for ( unsigned i = numCols; i < m_numCols; i++ ) + { + removeNode( colPinID(i) ); + m_pColNodes[i] = 0l; + } + } + m_numCols = numCols; + + if ( numRows >= m_numRows ) + { + for ( unsigned i = m_numRows; i < numRows; i++ ) + m_pRowNodes[i] = createPin( 0, 0, 0, rowPinID(i) ); + } + else + { + for ( unsigned i = numRows; i < m_numRows; i++ ) + { + removeNode( rowPinID(i) ); + m_pRowNodes[i] = 0l; + } + } + m_numRows = numRows; + //END Create or destroy pins + + + //BEGIN Position pins et al + setSize( -int(numCols+1)*8, -int(numRows+1)*8, int(numCols+1)*16, int(numRows+1)*16, true ); + + for ( int i = 0; i < int(m_numCols); i++ ) + { + m_nodeMap[colPinID(i)].x = offsetX() + 16 + 16*i; + m_nodeMap[colPinID(i)].y = offsetY() + height() + 8; + } + + for ( int i = 0; i < int(m_numRows); i++ ) + { + m_nodeMap[rowPinID(i)].x = offsetX() - 8; + m_nodeMap[rowPinID(i)].y = offsetY() + 16 + 16*i; + } + + updateAttachedPositioning(); + //END Position pins et al +} + + +QString MatrixDisplay::colPinID( int col ) const +{ + return QString("col_%1").arg(QString::number(col)); +} +QString MatrixDisplay::rowPinID( int row ) const +{ + return QString("row_%1").arg(QString::number(row)); +} + + +void MatrixDisplay::stepNonLogic() +{ + double interval = 1./LINEAR_UPDATE_RATE; + + for ( unsigned i = 0; i < m_numCols; i++ ) + { + for ( unsigned j = 0; j < m_numRows; j++ ) + m_avgBrightness[i][j] += ECLed::brightness( m_pDiodes[i][j]->current() )*interval; + } + + m_lastUpdatePeriod += interval; +} + + +void MatrixDisplay::drawShape( QPainter &p ) +{ + if ( isSelected() ) + p.setPen(m_selectedCol); + p.drawRect( boundingRect() ); + + initPainter(p); + + const int _x = int(x()+offsetX()); + const int _y = int(y()+offsetY()); + + // To avoid flicker, require at least a 10 ms sample before changing + // the brightness + double minUpdatePeriod = 0.0099; + + for ( int i = 0; i < int(m_numCols); i++ ) + { + for ( int j = 0; j < int(m_numRows); j++ ) + { + if ( m_lastUpdatePeriod > minUpdatePeriod ) + m_lastBrightness[i][j] = unsigned(m_avgBrightness[i][j]/m_lastUpdatePeriod); + + double _b = m_lastBrightness[i][j]; + + QColor brush = QColor( uint(255-(255-_b)*(1-m_r)), uint(255-(255-_b)*(1-m_g)), uint(255-(255-_b)*(1-m_b)) ); + p.setBrush(brush); + p.setPen( Qt::NoPen ); + p.drawEllipse( _x+10+i*16, _y+10+j*16, 12, 12 ); + } + } + + if ( m_lastUpdatePeriod > minUpdatePeriod ) + { + m_lastUpdatePeriod = 0.0; + + for ( unsigned i = 0; i < m_numCols; i++ ) + { + for ( unsigned j = 0; j < m_numRows; j++ ) + m_avgBrightness[i][j] = 0.0; + } + } + + deinitPainter(p); +} diff --git a/src/electronics/components/matrixdisplay.h b/src/electronics/components/matrixdisplay.h new file mode 100644 index 0000000..4851817 --- /dev/null +++ b/src/electronics/components/matrixdisplay.h @@ -0,0 +1,60 @@ +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef MATRIXDISPLAY_H +#define MATRIXDISPLAY_H + +#include <component.h> +#include <qvaluevector.h> + +const unsigned max_md_width = 100; +const unsigned max_md_height = 20; + +/** +@author David Saxton +*/ +class MatrixDisplay : public Component +{ + public: + MatrixDisplay( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~MatrixDisplay(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual bool canFlip() const { return true; } + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + + protected: + virtual void drawShape( QPainter &p ); + virtual void dataChanged(); + void initPins( unsigned numRows, unsigned numCols ); + QString colPinID( int col ) const; + QString rowPinID( int row ) const; + + + QValueVector< QValueVector<double> > m_avgBrightness; + QValueVector< QValueVector<unsigned> > m_lastBrightness; + QValueVector< QValueVector<Diode*> > m_pDiodes; + + ECNode * m_pRowNodes[max_md_height]; + ECNode * m_pColNodes[max_md_width]; + + double m_lastUpdatePeriod; + + double m_r, m_g, m_b; + bool m_bRowCathode; + + unsigned m_numRows; + unsigned m_numCols; +}; + +#endif diff --git a/src/electronics/components/matrixdisplaydriver.cpp b/src/electronics/components/matrixdisplaydriver.cpp new file mode 100644 index 0000000..da00bb7 --- /dev/null +++ b/src/electronics/components/matrixdisplaydriver.cpp @@ -0,0 +1,380 @@ +/*************************************************************************** + * Copyright (C) 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 "libraryitem.h" +#include "logic.h" +#include "matrixdisplaydriver.h" + +#include <klocale.h> +#include <qpainter.h> +#include <qstring.h> + +#include <assert.h> + +// Thank you Scott Dattalo! +// http://www.dattalo.com/gnupic/lcdfont.inc + +static char characterMap[256][5] = { +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //0 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //1 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //2 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //3 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //4 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //5 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //6 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //7 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //8 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //9 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //10 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //11 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //12 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //13 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //14 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //15 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //16 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //17 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //18 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //19 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //20 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //21 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //22 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //23 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //24 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //25 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //26 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //27 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //28 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //29 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //30 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //31 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //32 +{ 0x00, 0x00, 0x7d, 0x00, 0x00 }, //33 +{ 0x00, 0x70, 0x00, 0x70, 0x00 }, //34 +{ 0x14, 0x7f, 0x14, 0x7f, 0x14 }, //35 +{ 0x12, 0x2a, 0x7f, 0x2a, 0x24 }, //36 +{ 0x62, 0x64, 0x08, 0x13, 0x23 }, //37 +{ 0x36, 0x49, 0x55, 0x22, 0x05 }, //38 +{ 0x00, 0x50, 0x60, 0x00, 0x00 }, //39 +{ 0x00, 0x1c, 0x22, 0x41, 0x00 }, //40 +{ 0x00, 0x41, 0x22, 0x1c, 0x00 }, //41 +{ 0x14, 0x08, 0x3e, 0x08, 0x14 }, //42 +{ 0x08, 0x08, 0x3e, 0x08, 0x08 }, //43 +{ 0x00, 0x05, 0x06, 0x00, 0x00 }, //44 +{ 0x08, 0x08, 0x08, 0x08, 0x08 }, //45 +{ 0x00, 0x03, 0x03, 0x00, 0x00 }, //46 +{ 0x02, 0x04, 0x08, 0x10, 0x20 }, //47 +{ 0x3e, 0x45, 0x49, 0x51, 0x3e }, //48 +{ 0x00, 0x21, 0x7f, 0x01, 0x00 }, //49 +{ 0x21, 0x43, 0x45, 0x49, 0x31 }, //50 +{ 0x42, 0x41, 0x51, 0x69, 0x46 }, //51 +{ 0x0c, 0x14, 0x24, 0x7f, 0x04 }, //52 +{ 0x72, 0x51, 0x51, 0x51, 0x4e }, //53 +{ 0x1e, 0x29, 0x49, 0x49, 0x06 }, //54 +{ 0x40, 0x47, 0x48, 0x50, 0x60 }, //55 +{ 0x36, 0x49, 0x49, 0x49, 0x36 }, //56 +{ 0x30, 0x49, 0x49, 0x4a, 0x3c }, //57 +{ 0x00, 0x36, 0x36, 0x00, 0x00 }, //58 +{ 0x00, 0x35, 0x36, 0x00, 0x00 }, //59 +{ 0x08, 0x14, 0x22, 0x41, 0x00 }, //60 +{ 0x14, 0x14, 0x14, 0x14, 0x14 }, //61 +{ 0x41, 0x22, 0x14, 0x08, 0x00 }, //62 +{ 0x20, 0x40, 0x45, 0x48, 0x30 }, //63 +{ 0x26, 0x49, 0x4f, 0x41, 0x3e }, //64 +{ 0x3f, 0x44, 0x44, 0x44, 0x3f }, //65 +{ 0x7f, 0x49, 0x49, 0x49, 0x36 }, //66 +{ 0x3e, 0x41, 0x41, 0x41, 0x22 }, //67 +{ 0x7f, 0x41, 0x41, 0x41, 0x3e }, //68 +{ 0x7f, 0x49, 0x49, 0x49, 0x41 }, //69 +{ 0x7f, 0x48, 0x48, 0x48, 0x40 }, //70 +{ 0x3e, 0x41, 0x49, 0x49, 0x2f }, //71 +{ 0x7f, 0x08, 0x08, 0x08, 0x7f }, //72 +{ 0x00, 0x41, 0x7f, 0x41, 0x00 }, //73 +{ 0x02, 0x01, 0x41, 0x7e, 0x40 }, //74 +{ 0x7f, 0x08, 0x14, 0x22, 0x41 }, //75 +{ 0x7f, 0x01, 0x01, 0x01, 0x01 }, //76 +{ 0x7f, 0x40, 0x20, 0x40, 0x7f }, //77 +{ 0x7f, 0x10, 0x08, 0x04, 0x7f }, //78 +{ 0x3e, 0x41, 0x41, 0x41, 0x3e }, //79 +{ 0x7f, 0x48, 0x48, 0x48, 0x30 }, //80 +{ 0x3e, 0x41, 0x45, 0x42, 0x3d }, //81 +{ 0x7f, 0x48, 0x4c, 0x4a, 0x31 }, //82 +{ 0x31, 0x49, 0x49, 0x49, 0x46 }, //83 +{ 0x40, 0x40, 0x7f, 0x40, 0x40 }, //84 +{ 0x7e, 0x01, 0x01, 0x01, 0x7e }, //85 +{ 0x7c, 0x02, 0x01, 0x02, 0x7c }, //86 +{ 0x7e, 0x01, 0x0e, 0x01, 0x7e }, //87 +{ 0x63, 0x14, 0x08, 0x14, 0x63 }, //88 +{ 0x70, 0x08, 0x07, 0x08, 0x70 }, //89 +{ 0x43, 0x45, 0x49, 0x51, 0x61 }, //90 +{ 0x00, 0x7f, 0x41, 0x41, 0x00 }, //91 +{ 0x54, 0x34, 0x1f, 0x34, 0x54 }, //92 +{ 0x00, 0x41, 0x41, 0x7f, 0x00 }, //93 +{ 0x10, 0x20, 0x40, 0x20, 0x10 }, //94 +{ 0x01, 0x01, 0x01, 0x01, 0x01 }, //95 +{ 0x00, 0x40, 0x20, 0x10, 0x00 }, //96 +{ 0x02, 0x15, 0x15, 0x15, 0x0f }, //97 +{ 0x7f, 0x09, 0x11, 0x11, 0x0e }, //98 +{ 0x0e, 0x11, 0x11, 0x11, 0x02 }, //99 +{ 0x0e, 0x11, 0x11, 0x09, 0x7f }, //100 +{ 0x0e, 0x15, 0x15, 0x15, 0x0c }, //101 +{ 0x08, 0x3f, 0x48, 0x40, 0x20 }, //102 +{ 0x30, 0x49, 0x49, 0x49, 0x7e }, //103 +{ 0x7f, 0x08, 0x10, 0x10, 0x0f }, //104 +{ 0x00, 0x11, 0x5f, 0x01, 0x00 }, //105 +{ 0x02, 0x01, 0x21, 0x7e, 0x00 }, //106 +{ 0x7f, 0x04, 0x0a, 0x11, 0x00 }, //107 +{ 0x00, 0x41, 0x7f, 0x01, 0x00 }, //108 +{ 0x1f, 0x10, 0x0c, 0x10, 0x0f }, //109 +{ 0x1f, 0x08, 0x10, 0x10, 0x0f }, //110 +{ 0x0e, 0x11, 0x11, 0x11, 0x0e }, //111 +{ 0x1f, 0x14, 0x14, 0x14, 0x08 }, //112 +{ 0x08, 0x14, 0x14, 0x0c, 0x1f }, //113 +{ 0x1f, 0x08, 0x10, 0x10, 0x08 }, //114 +{ 0x09, 0x15, 0x15, 0x15, 0x12 }, //115 +{ 0x20, 0x7e, 0x21, 0x01, 0x02 }, //116 +{ 0x1e, 0x01, 0x01, 0x02, 0x1f }, //117 +{ 0x1c, 0x02, 0x01, 0x02, 0x1c }, //118 +{ 0x1e, 0x01, 0x06, 0x01, 0x1e }, //119 +{ 0x11, 0x0a, 0x04, 0x0a, 0x11 }, //120 +{ 0x18, 0x05, 0x05, 0x05, 0x1e }, //121 +{ 0x11, 0x13, 0x15, 0x19, 0x11 }, //122 +{ 0x00, 0x08, 0x36, 0x41, 0x00 }, //123 +{ 0x00, 0x00, 0x7f, 0x00, 0x00 }, //124 +{ 0x00, 0x41, 0x36, 0x08, 0x00 }, //125 +{ 0x08, 0x08, 0x2a, 0x1c, 0x08 }, //126 +{ 0x08, 0x1c, 0x2a, 0x08, 0x08 }, //127 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //128 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //129 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //130 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //131 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //132 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //133 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //134 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //135 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //136 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //137 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //138 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //139 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //140 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //141 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //142 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //143 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //144 +{ 0x07, 0x05, 0x07, 0x00, 0x00 }, //145 +{ 0x00, 0x00, 0x78, 0x40, 0x40 }, //146 +{ 0x01, 0x01, 0x0f, 0x00, 0x00 }, //147 +{ 0x04, 0x02, 0x01, 0x00, 0x00 }, //148 +{ 0x00, 0x0c, 0x0c, 0x00, 0x00 }, //149 +{ 0x28, 0x28, 0x29, 0x2a, 0x3c }, //150 +{ 0x10, 0x11, 0x16, 0x14, 0x18 }, //151 +{ 0x02, 0x04, 0x0f, 0x10, 0x00 }, //152 +{ 0x0c, 0x08, 0x19, 0x09, 0x0e }, //153 +{ 0x09, 0x09, 0x0f, 0x09, 0x09 }, //154 +{ 0x09, 0x0a, 0x0c, 0x1f, 0x08 }, //155 +{ 0x08, 0x1f, 0x08, 0x0a, 0x0c }, //156 +{ 0x01, 0x09, 0x09, 0x0f, 0x01 }, //157 +{ 0x15, 0x15, 0x15, 0x1f, 0x00 }, //158 +{ 0x0c, 0x00, 0x0d, 0x01, 0x0e }, //159 +{ 0x04, 0x04, 0x04, 0x04, 0x04 }, //160 +{ 0x40, 0x41, 0x5e, 0x48, 0x70 }, //161 +{ 0x04, 0x08, 0x1f, 0x20, 0x40 }, //162 +{ 0x38, 0x20, 0x61, 0x22, 0x3c }, //163 +{ 0x11, 0x11, 0x1f, 0x11, 0x11 }, //164 +{ 0x22, 0x24, 0x28, 0x7f, 0x20 }, //165 +{ 0x21, 0x7e, 0x20, 0x21, 0x3e }, //166 +{ 0x28, 0x28, 0x7f, 0x28, 0x28 }, //167 +{ 0x08, 0x31, 0x21, 0x22, 0x3c }, //168 +{ 0x10, 0x60, 0x21, 0x3e, 0x20 }, //169 +{ 0x21, 0x21, 0x21, 0x21, 0x3f }, //170 +{ 0x20, 0x79, 0x22, 0x7c, 0x20 }, //171 +{ 0x29, 0x29, 0x01, 0x02, 0x1c }, //172 +{ 0x21, 0x22, 0x24, 0x2a, 0x31 }, //173 +{ 0x20, 0x7e, 0x21, 0x29, 0x31 }, //174 +{ 0x30, 0x09, 0x01, 0x02, 0x3c }, //175 +{ 0x08, 0x31, 0x29, 0x26, 0x3c }, //176 +{ 0x28, 0x29, 0x3e, 0x48, 0x08 }, //177 +{ 0x30, 0x00, 0x31, 0x02, 0x3c }, //178 +{ 0x10, 0x51, 0x5e, 0x50, 0x10 }, //179 +{ 0x00, 0x7f, 0x08, 0x04, 0x00 }, //180 +{ 0x11, 0x12, 0x7c, 0x10, 0x10 }, //181 +{ 0x01, 0x21, 0x21, 0x21, 0x01 }, //182 +{ 0x21, 0x2a, 0x24, 0x2a, 0x30 }, //183 +{ 0x22, 0x24, 0x6f, 0x34, 0x22 }, //184 +{ 0x00, 0x01, 0x02, 0x7c, 0x00 }, //185 +{ 0x0f, 0x00, 0x20, 0x10, 0x0f }, //186 +{ 0x7e, 0x11, 0x11, 0x11, 0x11 }, //187 +{ 0x20, 0x21, 0x21, 0x22, 0x3c }, //188 +{ 0x10, 0x20, 0x10, 0x08, 0x06 }, //189 +{ 0x26, 0x20, 0x7f, 0x20, 0x26 }, //190 +{ 0x20, 0x24, 0x22, 0x25, 0x38 }, //191 +{ 0x00, 0x2a, 0x2a, 0x2a, 0x01 }, //192 +{ 0x0e, 0x12, 0x22, 0x02, 0x07 }, //193 +{ 0x01, 0x0a, 0x04, 0x0a, 0x30 }, //194 +{ 0x28, 0x3e, 0x29, 0x29, 0x29 }, //195 +{ 0x10, 0x7f, 0x10, 0x14, 0x18 }, //196 +{ 0x01, 0x21, 0x21, 0x3f, 0x01 }, //197 +{ 0x29, 0x29, 0x29, 0x29, 0x3f }, //198 +{ 0x10, 0x50, 0x51, 0x52, 0x1c }, //199 +{ 0x78, 0x01, 0x02, 0x7c, 0x00 }, //200 +{ 0x1f, 0x00, 0x3f, 0x01, 0x06 }, //201 +{ 0x3f, 0x01, 0x02, 0x04, 0x08 }, //202 +{ 0x3f, 0x21, 0x21, 0x21, 0x3f }, //203 +{ 0x38, 0x20, 0x21, 0x22, 0x3c }, //204 +{ 0x21, 0x21, 0x01, 0x02, 0x0c }, //205 +{ 0x20, 0x10, 0x40, 0x20, 0x00 }, //206 +{ 0x70, 0x50, 0x70, 0x00, 0x00 }, //207 +{ 0x0e, 0x11, 0x09, 0x06, 0x19 }, //208 +{ 0x02, 0x55, 0x15, 0x55, 0x0f }, //209 +{ 0x1f, 0x2a, 0x2a, 0x2a, 0x14 }, //210 +{ 0x0a, 0x15, 0x15, 0x11, 0x02 }, //211 +{ 0x3f, 0x02, 0x02, 0x04, 0x3e }, //212 +{ 0x0e, 0x11, 0x19, 0x15, 0x12 }, //213 +{ 0x0f, 0x12, 0x22, 0x22, 0x1c }, //214 +{ 0x1c, 0x22, 0x22, 0x22, 0x3f }, //215 +{ 0x02, 0x01, 0x1e, 0x10, 0x10 }, //216 +{ 0x20, 0x20, 0x00, 0x70, 0x00 }, //217 +{ 0x00, 0x00, 0x10, 0x5f, 0x00 }, //218 +{ 0x28, 0x10, 0x28, 0x00, 0x00 }, //219 +{ 0x18, 0x24, 0x7e, 0x24, 0x08 }, //220 +{ 0x14, 0x7f, 0x15, 0x01, 0x01 }, //221 +{ 0x1f, 0x48, 0x50, 0x50, 0x0f }, //222 +{ 0x0e, 0x51, 0x11, 0x51, 0x0e }, //223 +{ 0x3f, 0x12, 0x22, 0x22, 0x1c }, //224 +{ 0x1c, 0x22, 0x22, 0x12, 0x3f }, //225 +{ 0x3c, 0x52, 0x52, 0x52, 0x3c }, //226 +{ 0x03, 0x05, 0x02, 0x05, 0x06 }, //227 +{ 0x1a, 0x26, 0x20, 0x26, 0x1a }, //228 +{ 0x1e, 0x41, 0x01, 0x42, 0x1f }, //229 +{ 0x63, 0x55, 0x49, 0x41, 0x41 }, //230 +{ 0x22, 0x3c, 0x20, 0x3e, 0x22 }, //231 +{ 0x51, 0x4a, 0x44, 0x4a, 0x51 }, //232 +{ 0x3c, 0x02, 0x02, 0x02, 0x3f }, //233 +{ 0x28, 0x28, 0x3e, 0x28, 0x48 }, //234 +{ 0x22, 0x3c, 0x28, 0x28, 0x2e }, //235 +{ 0x3e, 0x28, 0x38, 0x28, 0x3e }, //236 +{ 0x04, 0x04, 0x15, 0x04, 0x04 }, //237 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //238 +{ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f }, //239 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //240 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //241 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //242 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //243 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //244 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //245 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //246 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //247 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //248 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //249 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //250 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //251 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //252 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //253 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //254 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //255 + }; + + +inline static bool displayBit( unsigned value, unsigned row, unsigned column ) +{ + assert( value < 256 ); + assert( row < 7 ); + assert( column < 5 ); + return characterMap[value][column] & (1 << row); +}; + + +Item* MatrixDisplayDriver::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new MatrixDisplayDriver( (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem * MatrixDisplayDriver::libraryItem() +{ + return new LibraryItem( + "ec/matrix_display_driver", + i18n("Matrix Display Driver"), + i18n("Integrated Circuits"), + "ic2.png", + LibraryItem::lit_component, + MatrixDisplayDriver::construct ); +} + + +MatrixDisplayDriver::MatrixDisplayDriver( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "Matrix Display Driver" ) +{ + m_name = i18n("Matrix Display Driver"); + + m_prevCol = 0; + m_nextCol = 0; + m_scanCount = 2; + + createProperty( "diode-configuration", Variant::Type::Select ); + property("diode-configuration")->setCaption( i18n("Configuration") ); + property("diode-configuration")->setAllowed( QStringList::split(',',"Row Cathode,Column Cathode") ); + property("diode-configuration")->setValue("Row Cathode"); + property("diode-configuration")->setAdvanced(true); + + QStringList pins = QStringList::split( ',', "D0,D1,D2,D3,D4,D5,D6,D7,,,,,,C4,C3,C2,C1,C0,,R0,R1,R2,R3,R4,R5,R6", true ); + initDIPSymbol( pins, 64 ); + initDIP(pins); + + m_pValueLogic.resize( 8, 0l ); + for ( unsigned i = 0; i < 8; ++i ) + m_pValueLogic[i] = createLogicIn( ecNodeWithID("D"+QString::number(i)) ); + + m_pRowLogic.resize( 7, 0l ); + for ( unsigned i = 0; i < 7; ++i ) + { + m_pRowLogic[i] = createLogicOut( ecNodeWithID("R"+QString::number(i)), false ); + m_pRowLogic[i]->setOutputLowConductance( 1.0 ); + m_pRowLogic[i]->setOutputHighVoltage(5.0); + } + + m_pColLogic.resize( 5, 0l ); + for ( unsigned i = 0; i < 5; ++i ) + { + m_pColLogic[i] = createLogicOut( ecNodeWithID("C"+QString::number(i)), false ); + m_pColLogic[i]->setOutputHighVoltage(5.0); + } +} + + +MatrixDisplayDriver::~MatrixDisplayDriver() +{ +} + + +void MatrixDisplayDriver::stepNonLogic() +{ + if ( ++m_scanCount < 5 ) + return; + m_scanCount = 0; + + m_pColLogic[m_prevCol]->setHigh(false); + m_pColLogic[m_nextCol]->setHigh(true); + + unsigned value = 0; + for ( unsigned i = 0; i < 8; ++i ) + value |= ( m_pValueLogic[i]->isHigh() ) ? (1 << i) : 0; + + for ( unsigned row = 0; row < 7; row++ ) + { + m_pRowLogic[row]->setHigh( !displayBit( value, row, m_nextCol) ); + } + + m_prevCol = m_nextCol; + + m_nextCol++; + if ( m_nextCol >= 5 ) + m_nextCol = 0; +} + diff --git a/src/electronics/components/matrixdisplaydriver.h b/src/electronics/components/matrixdisplaydriver.h new file mode 100644 index 0000000..e6b01cc --- /dev/null +++ b/src/electronics/components/matrixdisplaydriver.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef MATRIXDISPLAYDRIVER_H +#define MATRIXDISPLAYDRIVER_H + +#include "matrixdisplay.h" + +/** +@author David Saxton + */ +class MatrixDisplayDriver : public Component +{ + public: + MatrixDisplayDriver( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~MatrixDisplayDriver(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual bool canFlip() const { return true; } + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + + protected: + QValueVector<LogicIn*> m_pValueLogic; + QValueVector<LogicOut*> m_pRowLogic; + QValueVector<LogicOut*> m_pColLogic; + + unsigned m_prevCol; + unsigned m_nextCol; + unsigned m_scanCount; +}; + +#endif diff --git a/src/electronics/components/meter.cpp b/src/electronics/components/meter.cpp new file mode 100644 index 0000000..4437794 --- /dev/null +++ b/src/electronics/components/meter.cpp @@ -0,0 +1,265 @@ +/*************************************************************************** + * Copyright (C) 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 "canvasitemparts.h" +#include "ecnode.h" +#include "element.h" +#include "libraryitem.h" +#include "meter.h" +#include "variant.h" +#include "voltagesource.h" +#include "pin.h" +#include "simulator.h" + +#include <cmath> +#include <klocale.h> +#include <qpainter.h> + + +//BEGIN class Meter +Meter::Meter( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ) +{ + m_bDynamicContent = true; + b_timerStarted = false; + m_timeSinceUpdate = 0.; + m_old_value = 0.; + m_avgValue = 0.; + b_firstRun = true; + setSize( -16, -16, 32, 32 ); + + p_displayText = addDisplayText( "meter", QRect( -16, 16, 32, 16 ), displayText() ); + + createProperty( "0-minValue", Variant::Type::Double ); + property("0-minValue")->setCaption( i18n("Minimum Value") ); + property("0-minValue")->setMinValue(1e-12); + property("0-minValue")->setMaxValue(1e12); + property("0-minValue")->setValue(1e-3); + + createProperty( "1-maxValue", Variant::Type::Double ); + property("1-maxValue")->setCaption( i18n("Maximum Value") ); + property("1-maxValue")->setMinValue(1e-12); + property("1-maxValue")->setMaxValue(1e12); + property("1-maxValue")->setValue(1e3); +} + + +Meter::~Meter() +{ +} + + +void Meter::dataChanged() +{ + m_minValue = dataDouble("0-minValue"); + m_maxValue = dataDouble("1-maxValue"); + setChanged(); +} + +void Meter::stepNonLogic() +{ + if (b_firstRun) + { + p_displayText->setText(displayText()); + updateAttachedPositioning(); + setChanged(); + property("0-minValue")->setUnit(m_unit); + property("1-maxValue")->setUnit(m_unit); + b_firstRun = false; + } + + const double v = meterValue(); + if ( !b_timerStarted && std::abs(((v-m_old_value)/m_old_value)) > 1e-6 ) { + b_timerStarted = true; + } + + if (b_timerStarted) + { + m_timeSinceUpdate += 1./LINEAR_UPDATE_RATE; + m_avgValue += v/LINEAR_UPDATE_RATE; +// setChanged(); + if ( m_timeSinceUpdate > 0.05 ) + { + if ( p_displayText->setText(displayText()) ); + updateAttachedPositioning(); + } + } +} + +void Meter::drawShape( QPainter &p ) +{ + initPainter(p); + p.drawEllipse( (int)x()-16, (int)y()-16, width(), width() ); + p.setPen(QPen(Qt::black,2)); + p.setBrush(Qt::black); + + // The proportion between 0.1mV and 10KV, on a logarithmic scale + double prop; + const double abs_value = std::abs(m_old_value); + if ( abs_value <= m_minValue ) + prop = 0.; + else if ( abs_value >= m_maxValue ) + prop = 1.; + else + prop = std::log10( abs_value/m_minValue ) / std::log10( m_maxValue/m_minValue ); + if ( m_old_value>0 ) + prop *= -1; + double sin_prop = 10*std::sin(prop*1.571); // 1.571 = pi/2 + double cos_prop = 10*std::cos(prop*1.571); // 1.571 = pi/2 + + int cx = int(x()-16+(width()/2)); + int cy = int(y()-16+(height()/2)); + p.drawLine( int(cx-sin_prop), int(cy-cos_prop), int(cx+sin_prop), int(cy+cos_prop) ); + + QPointArray pa(3); + pa[0] = QPoint( int(cx-sin_prop), int(cy-cos_prop) ); // Arrow head + pa[1] = QPoint( int(cx-sin_prop + 8*std::sin(1.571*(-0.3+prop))), int(cy-cos_prop + 8*std::cos(1.571*(-0.3+prop))) ); + pa[2] = QPoint( int(cx-sin_prop + 8*std::sin(1.571*(0.3+prop))), int(cy-cos_prop + 8*std::cos(1.571*(0.3+prop))) ); + p.drawPolygon(pa); + + deinitPainter(p); +} + + +QString Meter::displayText() +{ + double value = m_avgValue/m_timeSinceUpdate; + if ( !std::isfinite(value) ) value = m_old_value; + if ( std::abs((value)) < 1e-9 ) value = 0.; + m_old_value = value; + m_avgValue = 0.; + m_timeSinceUpdate = 0.; + b_timerStarted = false; + return QString::number( value/CNItem::getMultiplier(value), 'g', 3 ) + CNItem::getNumberMag(value) + m_unit; +} +//END class Meter + + +//BEGIN class FrequencyMeter +Item* FrequencyMeter::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new FrequencyMeter( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* FrequencyMeter::libraryItem() +{ + return new LibraryItem( + QString("ec/frequencymeter"), + i18n("Frequency Meter (TODO)"), + i18n("Outputs"), + "frequencymeter.png", + LibraryItem::lit_component, + FrequencyMeter::construct ); +} + +FrequencyMeter::FrequencyMeter( ICNDocument *icnDocument, bool newItem, const char *id ) + : Meter( icnDocument, newItem, (id) ? id : "frequencymeter" ) +{ + m_name = i18n("Frequency Meter"); + m_desc = i18n("Place this at the point where frequency is to be measured."); + m_unit = "Hz"; + + m_probeNode = createPin( 0, -24, 90, "n1" ); +} + +FrequencyMeter::~FrequencyMeter() +{ +} + +double FrequencyMeter::meterValue() +{ + return 0; +} +//END class FrequencyMeter + + +//BEGIN class ECAmmeter +Item* ECAmmeter::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECAmmeter( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECAmmeter::libraryItem() +{ + QStringList ids; + ids << "ec/ammeter" << "ec/ammmeter"; + return new LibraryItem( + ids, + i18n("Ammeter"), + i18n("Outputs"), + "ammeter.png", + LibraryItem::lit_component, + ECAmmeter::construct + ); +} + +ECAmmeter::ECAmmeter( ICNDocument *icnDocument, bool newItem, const char *id ) + : Meter( icnDocument, newItem, (id) ? id : "ammeter" ) +{ + m_name = i18n("Ammeter"); + m_desc = i18n("Place this in series in the circuit to measure the current flowing."); + setSize( -16, -16, 32, 32 ); + m_unit = "A"; + + init1PinLeft(0); + init1PinRight(0); + + m_voltageSource = createVoltageSource( m_pNNode[0], m_pPNode[0], 0. ); +} + +ECAmmeter::~ECAmmeter() +{ +} + +double ECAmmeter::meterValue() +{ + return -m_voltageSource->cbranchCurrent(0); +} +//END class ECAmmeter + + +//BEGIN class ECVoltmeter +Item* ECVoltMeter::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECVoltMeter( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECVoltMeter::libraryItem() +{ + return new LibraryItem( + QString("ec/voltmeter"), + i18n("Voltmeter"), + i18n("Outputs"), + "voltmeter.png", + LibraryItem::lit_component, + ECVoltMeter::construct ); +} + +ECVoltMeter::ECVoltMeter( ICNDocument *icnDocument, bool newItem, const char *id ) + : Meter( icnDocument, newItem, (id) ? id : "voltmeter" ) +{ + m_name = i18n("Voltmeter"); + m_desc = i18n("Place this in parallel in the circuit to meaure the voltage between two points."); + m_unit = "V"; + + init1PinLeft(0); + init1PinRight(0); +} + +ECVoltMeter::~ECVoltMeter() +{ +} + +double ECVoltMeter::meterValue() +{ + return m_pNNode[0]->pin()->voltage() - m_pPNode[0]->pin()->voltage(); +} +//END class ECVoltMeter + diff --git a/src/electronics/components/meter.h b/src/electronics/components/meter.h new file mode 100644 index 0000000..fa52e95 --- /dev/null +++ b/src/electronics/components/meter.h @@ -0,0 +1,103 @@ +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef METER_H +#define METER_H + +#include <component.h> + +/** +@author David Saxton +*/ +class Meter : public Component +{ +public: + Meter( ICNDocument *icnDocument, bool newItem, const char *id ); + ~Meter(); + + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + virtual void drawShape( QPainter &p ); + +protected: + QString displayText(); + virtual void dataChanged(); + /** + * Return the value / current, or whatever the meter is measuring + */ + virtual double meterValue() = 0; + + bool b_firstRun; // If true, then update the text dispalyed + bool b_timerStarted; // The timer to change the text is started on change + double m_timeSinceUpdate; + double m_avgValue; + double m_old_value; + double m_minValue; + double m_maxValue; + Text *p_displayText; + QString m_unit; +}; + +/** +@short Measures the frequency at a point in the circuit +@author David Saxton +*/ +class FrequencyMeter : public Meter +{ +public: + FrequencyMeter( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~FrequencyMeter(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + virtual double meterValue(); + ECNode *m_probeNode; +}; + +/** +@short Simple resistor +@author David Saxton +*/ +class ECAmmeter : public Meter +{ +public: + ECAmmeter( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECAmmeter(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + virtual double meterValue(); + +private: + VoltageSource *m_voltageSource; +}; + +/** +@short Displays voltage across terminals +@author David Saxton +*/ +class ECVoltMeter : public Meter +{ +public: + ECVoltMeter( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECVoltMeter(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + virtual double meterValue(); +}; + +#endif diff --git a/src/electronics/components/multiinputgate.cpp b/src/electronics/components/multiinputgate.cpp new file mode 100644 index 0000000..7453845 --- /dev/null +++ b/src/electronics/components/multiinputgate.cpp @@ -0,0 +1,530 @@ +/*************************************************************************** + * Copyright (C) 2004-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 "ecnode.h" +#include "icndocument.h" +#include "libraryitem.h" +#include "multiinputgate.h" +#include "logic.h" + +#include <cmath> +#include <klocale.h> +#include <qpainter.h> + +//BEGIN class MultiInputGate +MultiInputGate::MultiInputGate( ICNDocument *icnDocument, bool newItem, const char *id, int baseWidth ) + : Component( icnDocument, newItem, id ) +{ + b_doneInit = false; + m_numInputs = 0; + if ( baseWidth == -1 ) { + baseWidth = 32; + } + m_baseWidth = baseWidth; + + for ( int i=0; i<maxGateInput; ++i ) + { + inLogic[i] = 0l; + inNode[i] = 0l; + } + + updateInputs(2); + + init1PinRight(16); + m_pOut = createLogicOut( m_pPNode[0], false ); + + + createProperty( "numInput", Variant::Type::Int ); + property("numInput")->setCaption( i18n("Number Inputs") ); + property("numInput")->setMinValue(2); + property("numInput")->setMaxValue(maxGateInput); + property("numInput")->setValue(2); + + b_doneInit = true; +} + + +MultiInputGate::~MultiInputGate() +{ +} + + +void MultiInputGate::dataChanged() +{ + updateInputs( QMIN( maxGateInput, dataInt("numInput") ) ); +} + + +void MultiInputGate::updateInputs( int newNum ) +{ + if ( newNum == m_numInputs ) { + return; + } + + if ( newNum < 2 ) { + newNum = 2; + } + else if ( newNum > maxGateInput ) { + newNum = maxGateInput; + } + + const int newWidth = m_baseWidth; + + setSize( -newWidth/2, -8*newNum, newWidth, 16*newNum, true ); + + const bool added = ( newNum > m_numInputs ); + if (added) + { + for ( int i = m_numInputs; i<newNum; ++i ) + { + ECNode *node = createPin( 0, 0, 0, "in"+QString::number(i) ); + inNode[i] = node; + inLogic[i] = createLogicIn(node); + inLogic[i]->setCallback( this, (CallbackPtr)(&MultiInputGate::inStateChanged) ); + } + } + else + { + for ( int i=newNum; i<m_numInputs; ++i ) + { + removeNode("in"+QString::number(i)); + removeElement( inLogic[i], false ); + inNode[i] = 0l; + inLogic[i] = 0l; + } + } + + m_numInputs = newNum; + + // We can't call a pure-virtual function if we haven't finished our constructor yet... + if (b_doneInit) + inStateChanged(!added); + + updateAttachedPositioning(); +} + + +void MultiInputGate::updateAttachedPositioning() +{ + // Check that our ndoes have been created before we attempt to use them + if ( !m_nodeMap.contains("p1") || !m_nodeMap.contains("in"+QString::number(m_numInputs-1)) ) + return; + + int _x = offsetX()+8; + int _y = offsetY()+8; + + m_nodeMap["p1"].x = m_baseWidth/2 + 8; + m_nodeMap["p1"].y = 0; + + for ( int i=0; i< m_numInputs; ++i ) + { + m_nodeMap["in"+QString::number(i)].x = _x - 16; + m_nodeMap["in"+QString::number(i)].y = _y + 16*i; + } + + if (b_doneInit) + Component::updateAttachedPositioning(); +} +//END class MultiInputGate + + +//BEGIN class ECXNor +Item* ECXnor::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECXnor( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECXnor::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/xnor"), + i18n("XNOR gate"), + i18n("Logic"), + "xnor.png", + LibraryItem::lit_component, + ECXnor::construct ); +} + +ECXnor::ECXnor( ICNDocument *icnDocument, bool newItem, const char *id ) + : MultiInputGate( icnDocument, newItem, (id) ? id : "xnor", 48 ) +{ + m_name = i18n("XNOR gate"); + m_desc = i18n("Exclusive NOR gate. Output is low when exactly one input is high."); + + inStateChanged(false); +} + +ECXnor::~ECXnor() +{ +} + +void ECXnor::inStateChanged(bool) +{ + int highCount = 0; + for ( int i=0; i<m_numInputs; ++i ) + { + if ( inLogic[i]->isHigh() ) + highCount++; + } + + m_pOut->setHigh( highCount != 1 ); +} + +void ECXnor::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()+offsetX(); + int _y = (int)y()+offsetY(); + + p.save(); + p.setPen( Qt::NoPen ); + p.drawChord( _x-width()+22, _y, 2*width()-28, height(), -16*81, 16*162 ); + p.restore(); + + p.drawArc( _x-width()+22, _y, 2*width()-28, height(), -16*90, 16*180 ); + p.drawArc( _x-8, _y, 16, height(), -16*90, 16*180 ); + p.drawArc( _x, _y, 16, height(), -16*90, 16*180 ); + + p.drawEllipse( _x+width()-6, _y+(height()/2)-3, 6, 6 ); + + const int n = m_numInputs; + for ( int i=0; i<n; ++i ) + { + p.setPen( inNode[i]->isSelected() ? m_selectedCol : Qt::black ); + int pin_x = (int)std::sqrt((double)(64*n*n - (8*n-8-16*i)*(8*n-8-16*i)))/n; + p.drawLine( _x, _y+16*i+8, _x+pin_x, _y+16*i+8 ); + } + + deinitPainter(p); +} +//END class ECXnor + + +//BEGIN class ECXor +Item* ECXor::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECXor( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECXor::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/xor"), + i18n("XOR gate"), + i18n("Logic"), + "xor.png", + LibraryItem::lit_component, + ECXor::construct ); +} + +ECXor::ECXor( ICNDocument *icnDocument, bool newItem, const char *id ) + : MultiInputGate( icnDocument, newItem, (id) ? id : "xor", 48 ) +{ + m_name = i18n("XOR gate"); + m_desc = i18n("Exclusive OR gate. Output is high when exactly one input is high."); + + inStateChanged(false); +} + +ECXor::~ECXor() +{ +} + +void ECXor::inStateChanged(bool) +{ + int highCount = 0; + for ( int i=0; i<m_numInputs; ++i ) + { + if ( inLogic[i]->isHigh() ) + highCount++; + } + + m_pOut->setHigh( highCount == 1 ); +} + +void ECXor::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()+offsetX(); + int _y = (int)y()+offsetY(); + + p.save(); + p.setPen( Qt::NoPen ); + p.drawChord( _x-width()+16, _y, 2*width()-16, height(), -16*81, 16*162 ); + p.restore(); + + p.drawArc( _x-width()+16, _y, 2*width()-16, height(), -16*90, 16*180 ); + p.drawArc( _x-8, _y, 16, height(), -16*90, 16*180 ); + p.drawArc( _x, _y, 16, height(), -16*90, 16*180 ); + + const int n = m_numInputs; + for ( int i=0; i<n; ++i ) + { + p.setPen( inNode[i]->isSelected() ? m_selectedCol : Qt::black ); + int pin_x = (int)std::sqrt((double)(64*n*n - (8*n-8-16*i)*(8*n-8-16*i)))/n; + p.drawLine( _x, _y+16*i+8, _x+pin_x, _y+16*i+8 ); + } + + deinitPainter(p); +} +//END class ECXor + + +//BEGIN class EXOr +Item* ECOr::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECOr( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECOr::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/or"), + i18n("OR gate"), + i18n("Logic"), + "or.png", + LibraryItem::lit_component, + ECOr::construct ); +} + +ECOr::ECOr( ICNDocument *icnDocument, bool newItem, const char *id ) + : MultiInputGate( icnDocument, newItem, (id) ? id : "or", 48 ) +{ + m_name = i18n("OR gate"); + m_desc = i18n("The output is high when at least one of the inputs is high; or low when all of the inputs are off"); + + inStateChanged(false); +} + +ECOr::~ECOr() +{ +} + +void ECOr::inStateChanged(bool) +{ + bool allLow = true; + for ( int i=0; i<m_numInputs && allLow; ++i ) + { + if ( inLogic[i]->isHigh() ) + allLow = false; + } + + m_pOut->setHigh(!allLow); +} + +void ECOr::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()+offsetX(); + int _y = (int)y()+offsetY(); + + p.save(); + p.setPen( Qt::NoPen ); +// p.setBrush( Qt::red ); + p.drawChord( _x-width(), _y, 2*width(), height(), -16*81, 16*162 ); +// p.drawPie( _x-width()+16, _y, 2*width()-16, height(), -16*100, 16*200 ); + p.restore(); + + p.drawArc( _x-width(), _y, 2*width(), height(), -16*90, 16*180 ); + p.drawArc( _x-8, _y, 16, height(), -16*90, 16*180 ); + + const int n = m_numInputs; + for ( int i=0; i<n; ++i ) + { + p.setPen( inNode[i]->isSelected() ? m_selectedCol : Qt::black ); + int pin_x = (int)std::sqrt((double)(64*n*n - (8*n-8-16*i)*(8*n-8-16*i)))/n; + p.drawLine( _x, _y+16*i+8, _x+pin_x, _y+16*i+8 ); + } + + deinitPainter(p); +} +//END class ECOr + + +//BEGIN class ECNor +Item* ECNor::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECNor( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECNor::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/nor"), + i18n("NOR gate"), + i18n("Logic"), + "nor.png", + LibraryItem::lit_component, + ECNor::construct ); +} + +ECNor::ECNor( ICNDocument *icnDocument, bool newItem, const char *id ) + : MultiInputGate( icnDocument, newItem, (id) ? id : "nor", 48 ) +{ + m_name = i18n("NOR Gate"); + m_desc = i18n("The output is high when all inputs are low."); + + inStateChanged(false); +} + +ECNor::~ECNor() +{ +} + +void ECNor::inStateChanged(bool) +{ + bool allLow = true; + for ( int i=0; i<m_numInputs && allLow; ++i ) + { + if ( inLogic[i]->isHigh() ) + allLow = false; + } + + m_pOut->setHigh(allLow); +} + +void ECNor::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()+offsetX(); + int _y = (int)y()+offsetY(); + + p.save(); + p.setPen( Qt::NoPen ); + p.drawChord( _x-width()+6, _y, 2*width()-12, height(), -16*81, 16*162 ); + p.restore(); + + p.drawArc( _x-width()+6, _y, 2*width()-12, height(), -16*90, 16*180 ); + p.drawArc( _x-8, _y, 16, height(), -16*90, 16*180 ); + + p.drawEllipse( _x+width()-6, _y+(height()/2)-3, 6, 6 ); + + const int n = m_numInputs; + for ( int i=0; i<n; ++i ) + { + p.setPen( inNode[i]->isSelected() ? m_selectedCol : Qt::black ); + int pin_x = (int)std::sqrt((double)(64*n*n - (8*n-8-16*i)*(8*n-8-16*i)))/n; + p.drawLine( _x, _y+16*i+8, _x+pin_x, _y+16*i+8 ); + } + + deinitPainter(p); +} +//END class ECNor + + +//BEGIN class ECNand +Item* ECNand::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECNand( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECNand::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/nand"), + i18n("NAND gate"), + i18n("Logic"), + "nand.png", + LibraryItem::lit_component, + ECNand::construct ); +} + +ECNand::ECNand( ICNDocument *icnDocument, bool newItem, const char *id ) + : MultiInputGate( icnDocument, newItem, id ? id : "nand" ) +{ + m_name = i18n("NAND Gate"); + m_desc = i18n("The output is low only when all of the inputs are high."); + + inStateChanged(false); +} + +ECNand::~ECNand() +{ +} + +void ECNand::inStateChanged(bool) +{ + bool allHigh = true; + for ( int i=0; i<m_numInputs && allHigh; ++i ) + { + if ( !inLogic[i]->isHigh() ) + allHigh = false; + } + + m_pOut->setHigh(!allHigh); +} + +void ECNand::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()+offsetX(); + int _y = (int)y()+offsetY(); + p.drawChord( _x-width()+6, _y, 2*width()-12, height(), -16*90, 16*180 ); + p.drawEllipse( _x+width()-6, _y+(height()/2)-3, 6, 6 ); + deinitPainter(p); +} +//END class ECNand + + +//BEGIN class ECAnd +Item* ECAnd::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECAnd( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECAnd::libraryItem() +{ + QStringList idList; + idList << "ec/and" << "ec/and_2"; + return new LibraryItem( + idList, + i18n("AND gate"), + i18n("Logic"), + "and.png", + LibraryItem::lit_component, + ECAnd::construct ); +} + +ECAnd::ECAnd( ICNDocument *icnDocument, bool newItem, const char *id ) + : MultiInputGate( icnDocument, newItem, id ? id : "and" ) +{ + m_name = i18n("AND Gate"); + m_desc = i18n("The output is high if and only if all of the inputs are high."); + + inStateChanged(false); +} + +ECAnd::~ECAnd() +{ +} + +void ECAnd::inStateChanged(bool) +{ + bool allHigh = true; + for ( int i=0; i<m_numInputs && allHigh; ++i ) + { + if ( !inLogic[i]->isHigh() ) + allHigh = false; + } + + m_pOut->setHigh(allHigh); +} + +void ECAnd::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()+offsetX(); + int _y = (int)y()+offsetY(); + p.drawChord( _x-width(), _y, 2*width(), height(), -16*90, 16*180 ); + + deinitPainter(p); +} +//END class ECAnd diff --git a/src/electronics/components/multiinputgate.h b/src/electronics/components/multiinputgate.h new file mode 100644 index 0000000..1981217 --- /dev/null +++ b/src/electronics/components/multiinputgate.h @@ -0,0 +1,160 @@ +/*************************************************************************** + * Copyright (C) 2004-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. * + ***************************************************************************/ + +#ifndef MULTIINPUTGATE_H +#define MULTIINPUTGATE_H + +#include "component.h" +#include "logic.h" + +const int maxGateInput = 256; + +/** +@author David Saxton +*/ +class MultiInputGate : public CallbackClass, public Component +{ +public: + MultiInputGate( ICNDocument *icnDocument, bool newItem, const char *id, int baseWidth = -1 ); + ~MultiInputGate(); + +protected: + virtual void inStateChanged( bool newState ) = 0; + void dataChanged(); + void updateInputs( int newNum ); + + int m_numInputs; + int m_baseWidth; + + LogicIn *inLogic[maxGateInput]; + ECNode *inNode[maxGateInput]; + + LogicOut * m_pOut; + + virtual void updateAttachedPositioning(); + +private: + bool b_doneInit; +}; + + +/** +@short Boolean XNOR +@author David Saxton +*/ +class ECXnor : public MultiInputGate +{ +public: + ECXnor( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECXnor(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); +}; + + +/** +@short Boolean XOR +@author David Saxton +*/ +class ECXor : public MultiInputGate +{ +public: + ECXor( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECXor(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); +}; + + +/** +@short Boolean OR +@author David Saxton +*/ +class ECOr : public MultiInputGate +{ +public: + ECOr( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECOr(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); +}; + +/** +@short Boolean NOR +@author David Saxton +*/ +class ECNor : public MultiInputGate +{ +public: + ECNor( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECNor(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); +}; + +/** +@short Boolean NAND +@author David Saxton +*/ +class ECNand : public MultiInputGate +{ +public: + ECNand( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECNand(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); +}; + +/** +@short Boolean AND +@author David Saxton +*/ +class ECAnd : public MultiInputGate +{ +public: + ECAnd( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECAnd(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); +}; + + + +#endif diff --git a/src/electronics/components/multiplexer.cpp b/src/electronics/components/multiplexer.cpp new file mode 100644 index 0000000..e421fee --- /dev/null +++ b/src/electronics/components/multiplexer.cpp @@ -0,0 +1,176 @@ +/*************************************************************************** + * Copyright (C) 2004-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 "multiplexer.h" + +#include "logic.h" +#include "libraryitem.h" + +#include <kiconloader.h> +#include <klocale.h> + +#include <cmath> + +Item* Multiplexer::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Multiplexer( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Multiplexer::libraryItem() +{ + return new LibraryItem( + QString("ec/multiplexer"), + i18n("Multiplexer"), + i18n("Integrated Circuits"), + "ic1.png", + LibraryItem::lit_component, + Multiplexer::construct + ); +} + +Multiplexer::Multiplexer( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "multiplexer" ) +{ + m_name = i18n("Multiplexer"); + m_desc = i18n("Combines the input data stream into one single stream. The value of the input selected by the \"A\" inputs is passed to the output."); + + m_output = 0l; + + createProperty( "addressSize", Variant::Type::Int ); + property("addressSize")->setCaption( i18n("Address Size") ); + property("addressSize")->setMinValue(1); + property("addressSize")->setMaxValue(8); + property("addressSize")->setValue(1); + + // For backwards compatibility + createProperty( "numInput", Variant::Type::Int ); + property("numInput")->setMinValue(-1); + property("numInput")->setValue(-1); + property("numInput")->setHidden(true); +} + +Multiplexer::~Multiplexer() +{ +} + + +void Multiplexer::dataChanged() +{ + if ( hasProperty("numInput") && dataInt("numInput") != -1 ) + { + int addressSize = int( std::ceil( std::log( (double)dataInt("numInput") ) / std::log(2.0) ) ); + property("numInput")->setValue(-1); + + if ( addressSize < 1 ) + addressSize = 1; + else if ( addressSize > 8 ) + addressSize = 8; + + // This function will get called again when we set the value of numInput + property("addressSize")->setValue(addressSize); + return; + } + + if ( hasProperty("numInput") ) + { + m_variantData["numInput"]->deleteLater(); + m_variantData.remove("numInput"); + } + + initPins( unsigned(dataInt("addressSize")) ); +} + + +void Multiplexer::inStateChanged( bool /*state*/ ) +{ + unsigned long long pos = 0; + for ( unsigned i = 0; i < m_aLogic.size(); ++i ) + { + if ( m_aLogic[i]->isHigh() ) + pos += 1 << i; + } + m_output->setHigh( m_xLogic[pos]->isHigh() ); +} + + +void Multiplexer::initPins( unsigned newAddressSize ) +{ + unsigned oldAddressSize = m_aLogic.size(); + unsigned long long oldXLogicCount = m_xLogic.size(); + unsigned long long newXLogicCount = 1 << newAddressSize; + + if ( newXLogicCount == oldXLogicCount ) + return; + + QStringList pins; + + const int length = newAddressSize + newXLogicCount; + + for ( unsigned i=0; i<newAddressSize; ++i ) + pins += "A"+QString::number(i); + for ( unsigned i=0; i<newXLogicCount; ++i ) + pins += "X"+QString::number(i); + for ( int i=0; i<(length-(length%2))/2; ++i ) + pins += ""; + pins += "X"; + for ( int i=0; i<((length+(length%2))/2)-1; ++i ) + pins += ""; + + initDIPSymbol( pins, 64 ); + initDIP(pins); + + ECNode *node; + + if (!m_output) + { + node = ecNodeWithID("X"); + m_output = createLogicOut( node, false ); + } + + if ( newXLogicCount > oldXLogicCount ) + { + m_xLogic.resize(newXLogicCount); + for ( unsigned i=oldXLogicCount; i<newXLogicCount; ++i ) + { + node = ecNodeWithID("X"+QString::number(i)); + m_xLogic.insert( i, createLogicIn(node) ); + m_xLogic[i]->setCallback( this, (CallbackPtr)(&Multiplexer::inStateChanged) ); + } + + m_aLogic.resize(newAddressSize); + for ( unsigned i=oldAddressSize; i<newAddressSize; ++i ) + { + node = ecNodeWithID("A"+QString::number(i)); + m_aLogic.insert( i, createLogicIn(node) ); + m_aLogic[i]->setCallback( this, (CallbackPtr)(&Multiplexer::inStateChanged) ); + } + } + else + { + for ( unsigned i = newXLogicCount; i < oldXLogicCount; ++i ) + { + QString id = "X"+QString::number(i); + removeDisplayText(id); + removeElement( m_xLogic[i], false ); + removeNode(id); + } + m_xLogic.resize(newXLogicCount); + + for ( unsigned i = newAddressSize; i < oldAddressSize; ++i ) + { + QString id = "A"+QString::number(i); + removeDisplayText(id); + removeElement( m_aLogic[i], false ); + removeNode(id); + } + m_aLogic.resize(newAddressSize); + } +} + diff --git a/src/electronics/components/multiplexer.h b/src/electronics/components/multiplexer.h new file mode 100644 index 0000000..42bcfc1 --- /dev/null +++ b/src/electronics/components/multiplexer.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2004-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. * + ***************************************************************************/ + +#ifndef MULTIPLEXER_H +#define MULTIPLEXER_H + +#include "component.h" +#include "logic.h" + +#include <qptrvector.h> + +/** +@author David Saxton +*/ +class Multiplexer : public CallbackClass, public Component +{ +public: + Multiplexer( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Multiplexer(); + + virtual bool canFlip() const { return true; } + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + void dataChanged(); + /** + * Add / remove pins according to the number of inputs the user has requested + */ + void initPins( unsigned addressSize ); + + void inStateChanged( bool newState ); + + QPtrVector<LogicIn> m_aLogic; + QPtrVector<LogicIn> m_xLogic; + LogicOut * m_output; +}; + +#endif diff --git a/src/electronics/components/parallelportcomponent.cpp b/src/electronics/components/parallelportcomponent.cpp new file mode 100644 index 0000000..9bc17b4 --- /dev/null +++ b/src/electronics/components/parallelportcomponent.cpp @@ -0,0 +1,241 @@ +/*************************************************************************** + * Copyright (C) 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 "port.h" +#include "parallelportcomponent.h" + +#include "ecnode.h" +#include "itemdocument.h" +#include "libraryitem.h" +#include "pin.h" +#include "resistance.h" + +#include <kdebug.h> +#include <klocale.h> +#include <qpainter.h> + +#include <cmath> +#include <termios.h> + +Item* ParallelPortComponent::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ParallelPortComponent( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ParallelPortComponent::libraryItem() +{ + return new LibraryItem( + "ec/parallel_port", + i18n("Parallel Port"), + i18n("Connections"), + "ic1.png", + LibraryItem::lit_component, + ParallelPortComponent::construct + ); +} + +ParallelPortComponent::ParallelPortComponent( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "parallel_port" ) +{ + m_name = i18n("Parallel Port"); + m_desc = i18n("The pins are divided into 3 registers.<br><br>" + "<b>Data Pins</b><br><br>" + "The data pins can be configured as either all input or all output. They are:" + "<ul>" + "<li><b>D<i>[0..7]</i></b></li>" + "</ul><br>" + "<b>Status Pins</b><br><br>" + "The status pins are read-only. They area:" + "<ul>" + "<li><b>ERR</b> - Error</li>" + "<li><b>ON</b> - Online</li>" + "<li><b>PE</b> - Paper End</li>" + "<li><b>ACK</b> - Acknowledge</li>" + "<li><b>BUSY</b> - Busy</li>" + "</ul><br>" + "<b>Control Pins</b>" + "<ul>" + "<li><b>STR</b> - Strobe</li>" + "<li><b>AUT</b> - Auto Feed</li>" + "<li><b>INIT</b> - Init</li>" + "<li><b>SEL</b> - Select</li>" + "</ul><br>" + "The remaining pins are all ground." + ); + + QPointArray pa( 4 ); + pa[0] = QPoint( -32, -112 ); + pa[1] = QPoint( 32, -104 ); + pa[2] = QPoint( 32, 104 ); + pa[3] = QPoint( -32, 112 ); + setItemPoints( pa ); + + m_pParallelPort = new ParallelPort(); + + for ( unsigned i = 0; i < 24; ++i ) + m_pLogic[i] = 0; + + ECNode * pin = 0; + + //BEGIN Data register + for ( int i = 0; i < 8; ++i ) + { + QString id = QString("D%1").arg(i); + QString name = id; + + pin = createPin( -40, -80 + 16*i, 0, id ); + addDisplayText( id, QRect( -28, -88 + 16*i, 28, 16 ), name, true, Qt::AlignLeft | Qt::AlignVCenter ); + + m_pLogic[i] = createLogicOut( pin, false ); + m_pLogic[i]->setCallback( this, (CallbackPtr)(&ParallelPortComponent::dataCallback) ); + } + //END Data register + + + //BEGIN Status register + QString statusNames[] = { "ERR", "ON", "PE", "ACK", "BUSY" }; + + // The statusIDs are referenced in the save file and must not change + QString statusIDs[] = { "ERROR", "ONLINE", "PE", "ACK", "BUSY" }; + + // Bits 0...2 in the Status register are not used + for ( int i = 3; i < 8; ++i ) + { + QString id = statusIDs[i-3]; + QString name = statusNames[i-3]; + + // Bit 3 (pin 15) doesn't not follow the same positioning pattern as + // the other pins in the Status register. + if ( i == 3 ) + { + pin = createPin( 40, -72, 180, id ); + addDisplayText( id, QRect( 0, -80, 28, 16 ), name, true, Qt::AlignRight | Qt::AlignVCenter ); + } + else + { + pin = createPin( -40, -16 + 16*i, 0, id ); + addDisplayText( id, QRect( -28, -24 + 16*i, 28, 16 ), name, true, Qt::AlignLeft | Qt::AlignVCenter ); + } + + m_pLogic[i+8] = createLogicOut( pin, false ); + } + //END Status register + + + //BEGIN Control register + QString controlNames[] = { "STR", "AUT", "INIT", "SEL" }; + + // The controlIDs are referenced in the save file and must not change + QString controlIDs[] = { "STROBE", "AUTO", "INIT", "SELECT" }; + + // Bits 4..7 are not used (well; bit 5 is, but not as a pin) + for ( int i = 0; i < 4; ++i ) + { + QString id = controlIDs[i]; + QString name = controlNames[i]; + + if ( i == 0 ) + { + pin = createPin( -40, -96, 0, id ); + addDisplayText( id, QRect( -28, -104, 28, 16 ), name, true, Qt::AlignLeft | Qt::AlignVCenter ); + } + else if ( i == 1 ) + { + pin = createPin( 40, -88, 180, id ); + addDisplayText( id, QRect( 0, -96, 28, 16 ), name, true, Qt::AlignRight | Qt::AlignVCenter ); + } + else + { + pin = createPin( 40, -88 + i*16, 180, id ); + addDisplayText( id, QRect( 0, -96 + i*16, 28, 16 ), name, true, Qt::AlignRight | Qt::AlignVCenter ); + } + + m_pLogic[i+16] = createLogicOut( pin, false ); + m_pLogic[i+16]->setCallback( this, (CallbackPtr)(&ParallelPortComponent::controlCallback) ); + } + //END Control register + + +#if 0 + // And make the rest of the pins ground + for ( int i = 0; i < 8; ++i ) + { + pin = createPin( 40, -24 + i*16, 180, QString("GND%1").arg( i ) ); + pin->pin()->setGroundType( Pin::gt_always ); + } +#endif + + Variant * v = createProperty( "port", Variant::Type::Combo ); + v->setAllowed( ParallelPort::ports( Port::ExistsAndRW ) ); + v->setCaption( i18n("Port") ); +} + + +ParallelPortComponent::~ParallelPortComponent() +{ + delete m_pParallelPort; +} + + +void ParallelPortComponent::dataChanged() +{ + initPort( dataString("port") ); +} + + +void ParallelPortComponent::initPort( const QString & port ) +{ + if ( port.isEmpty() ) + { + m_pParallelPort->closePort(); + return; + } + + if ( ! m_pParallelPort->openPort( port ) ) + { + p_itemDocument->canvas()->setMessage( i18n("Could not open port %1").arg( port ) ); + return; + } +} + + +void ParallelPortComponent::dataCallback( bool ) +{ + uchar value = 0; + for ( unsigned i = 0; i < 8; ++ i ) + value |= m_pLogic[ i + 0 ]->isHigh() ? 0 : (1 << i); + + m_pParallelPort->writeToData( value ); +} + + +void ParallelPortComponent::controlCallback( bool ) +{ + uchar value = 0; + for ( unsigned i = 0; i < 4; ++ i ) + value |= m_pLogic[ i + 16 ]->isHigh() ? 0 : (1 << i); + + m_pParallelPort->writeToControl( value ); +} + + +void ParallelPortComponent::stepNonLogic() +{ + uchar status = m_pParallelPort->readFromRegister( ParallelPort::Status ); + // Bits 0...2 in the Status register are not used + for ( int i = 3; i < 8; ++i ) + m_pLogic[i + 8]->setHigh( status | (1 << i) ); +} + + +void ParallelPortComponent::drawShape( QPainter & p ) +{ + drawPortShape( p ); +} diff --git a/src/electronics/components/parallelportcomponent.h b/src/electronics/components/parallelportcomponent.h new file mode 100644 index 0000000..89ead80 --- /dev/null +++ b/src/electronics/components/parallelportcomponent.h @@ -0,0 +1,49 @@ +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef PARALLELPORTCOMPONENT_H +#define PARALLELPORTCOMPONENT_H + +#include "logic.h" +#include "component.h" + +class ParallelPort; + +/** +@author David Saxton + */ +class ParallelPortComponent : public CallbackClass, public Component +{ + public: + ParallelPortComponent( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ParallelPortComponent(); + + virtual bool canFlip() const { return true; } + static Item * construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem * libraryItem(); + + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + + protected: + void initPort( const QString & port ); + virtual void dataChanged(); + virtual void drawShape( QPainter & p ); + + void dataCallback( bool ); + void controlCallback( bool ); + + /// Registers: { Data[0...7], Status[0...5], 0[6...7], Control[0...4], 0[5...7] } + LogicOut * m_pLogic[24]; + + ParallelPort * m_pParallelPort; +}; + +#endif diff --git a/src/electronics/components/piccomponent.cpp b/src/electronics/components/piccomponent.cpp new file mode 100644 index 0000000..47320bb --- /dev/null +++ b/src/electronics/components/piccomponent.cpp @@ -0,0 +1,437 @@ +/*************************************************************************** + * 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 "config.h" +#ifndef NO_GPSIM + +#include "canvasitemparts.h" +#include "circuitdocument.h" +#include "docmanager.h" +#include "gpsimprocessor.h" +#include "libraryitem.h" +#include "logic.h" +#include "ktechlab.h" +#include "micropackage.h" +#include "picinfo.h" +#include "microlibrary.h" +#include "piccomponent.h" +#include "piccomponentpin.h" +#include "projectmanager.h" + +#include <kdebug.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <qguardedptr.h> +#include <qstringlist.h> + +#include "gpsim/ioports.h" +#include "gpsim/pic-processor.h" + +const QString _def_PICComponent_fileName = i18n("<Enter location of PIC Program>"); + + +Item* PICComponent::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new PICComponent( (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem* PICComponent::libraryItem() +{ + QStringList IDs; + IDs << "ec/pic" << "ec/picitem" << "ec/picitem_18pin"; + + return new LibraryItem( + IDs, + "PIC", + i18n("Integrated Circuits"), + "ic2.png", + LibraryItem::lit_component, + PICComponent::construct ); +} + +PICComponent::PICComponent( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "pic" ) +{ + m_name = i18n("PIC Micro"); + m_desc = i18n("The PIC component allows the simulation of a PIC program.<br><br>" + "The loadable PIC program must be one of the following formats:" + "<ul><li>Assembly (.asm)</li>" + "<li>FlowCode (.flowcode)</li>" + "<li>Symbol file (.cod)</li>" + "<li>Microbe (.microbe, .basic)</li>" + "<li>C source (.c)</li></ul>" + "Doubleclick on the PIC component to open up the program source file.<br><br>" + "If the program source file is of type assembly, then the the opened text file will automatically be linked to the simulation. " + "You can control the program from the text document using the debug controls.<br><br>" + "Explanation of buttons:" + "<ul><li>Play - Run the PIC program from the point at which it was paused, or from the start otherwise.</li>" + "<li>Pause - Pause the simulation at the current execution point.</li>" + "<li>Stop - Reset all parts of the simulation.</li>" + "<li>Reload - Reread the PIC program from disk and restart gpsim.</li></ul>"); + + m_bCreatedInitialPackage = false; + m_bLoadingProgram = false; + m_pGpsim = 0L; + + addButton( "run", QRect(), KGlobal::iconLoader()->loadIcon( "player_play", KIcon::Small ) ); + addButton( "pause", QRect(), KGlobal::iconLoader()->loadIcon( "player_pause", KIcon::Small ) ); + addButton( "reset", QRect(), KGlobal::iconLoader()->loadIcon( "stop", KIcon::Small ) ); + addButton( "reload", QRect(), KGlobal::iconLoader()->loadIcon( "reload", KIcon::Small ) ); + + if ( icnDocument->ktechlab() ) + connect( icnDocument->ktechlab(), SIGNAL(recentFileAdded(const KURL &)), this, SLOT(slotUpdateFileList()) ); + + connect( ProjectManager::self(), SIGNAL(projectOpened()), this, SLOT(slotUpdateFileList()) ); + connect( ProjectManager::self(), SIGNAL(projectClosed()), this, SLOT(slotUpdateFileList()) ); + connect( ProjectManager::self(), SIGNAL(projectCreated()), this, SLOT(slotUpdateFileList()) ); + connect( ProjectManager::self(), SIGNAL(subprojectCreated()), this, SLOT(slotUpdateFileList()) ); + connect( ProjectManager::self(), SIGNAL(filesAdded()), this, SLOT(slotUpdateFileList()) ); + connect( ProjectManager::self(), SIGNAL(filesRemoved()), this, SLOT(slotUpdateFileList()) ); + + createProperty( "program", Variant::Type::FileName ); + property("program")->setCaption( i18n("Program") ); + property("program")->setFilter("*.flowcode *.asm *.cod *.basic|All Supported Files\n*.flowcode|FlowCode (*.flowcode)\n*.cod|Symbol File (*.cod)\n*.asm|Assembly Code (*.asm)\n*.basic *.microbe|Microbe (*.basic, *.microbe)\n*.c|C (*.c)*|All Files"); + + // Used for restoring the pins on file loading before we have had a change + // to compile the PIC program + createProperty( "lastPackage", Variant::Type::String ); + property("lastPackage")->setHidden( true ); + +// //HACK This is to enable loading with pre-0.3 files (which didn't set a "lastPackage" +// // property). This will allow a P16F84 PIC to be initialized (which agrees with pre-0.3 +// // behaviour), but it will also load it if + + // This to allow loading of the PIC component from pre-0.3 files (which didn't set a + // "lastPackage" property). + if ( !newItem ) + property("lastPackage")->setValue("P16F84"); + + slotUpdateFileList(); + slotUpdateBtns(); + + initPackage( 0 ); +} + + +PICComponent::~PICComponent() +{ + deletePICComponentPins(); + delete m_pGpsim; +} + + +void PICComponent::dataChanged() +{ + initPIC(false); +} + + +void PICComponent::initPIC( bool forceReload ) +{ + if ( !m_bCreatedInitialPackage ) + { + // We are still being created, so other connectors will be expecting us to + // have grown pins soonish. + MicroInfo * microInfo = MicroLibrary::self()->microInfoWithID( dataString("lastPackage") ); + if ( microInfo ) + initPackage( microInfo ); + } + + QString newProgram = KURL( dataString("program") ).path(); + bool newFile = (m_picFile != newProgram); + if ( !newFile && !forceReload ) + return; + + delete m_pGpsim; + m_pGpsim = 0L; + + switch ( GpsimProcessor::isValidProgramFile(newProgram) ) + { + case GpsimProcessor::DoesntExist: + if ( newProgram == _def_PICComponent_fileName && !newProgram.isEmpty() ) + break; + KMessageBox::sorry( 0l, i18n("The file \"%1\" does not exist.").arg( newProgram ) ); + m_picFile = QString::null; + break; + + case GpsimProcessor::IncorrectType: + if ( newProgram == _def_PICComponent_fileName && !newProgram.isEmpty() ) + break; + KMessageBox::sorry( 0L, i18n("\"%1\" is not a valid PIC program.\nThe file must exist, and the extension should be \".cod\", \".asm\", \".flowcode\", \".basic\", \".microbe\" or \".c\".\n\".hex\" is allowed, provided that there is a corresponding \".cod\" file.").arg(newProgram) ); + m_picFile = QString::null; + break; + + case GpsimProcessor::Valid: + m_picFile = newProgram; + m_symbolFile = createSymbolFile(); + break; + } + + slotUpdateBtns(); +} + + +void PICComponent::deletePICComponentPins() +{ + const PICComponentPinMap::iterator picComponentMapEnd = m_picComponentPinMap.end(); + for ( PICComponentPinMap::iterator it = m_picComponentPinMap.begin(); it != picComponentMapEnd; ++it ) + delete it.data(); + m_picComponentPinMap.clear(); +} + + +void PICComponent::initPackage( MicroInfo * microInfo ) +{ + MicroPackage * microPackage = microInfo ? microInfo->package() : 0l; + + if ( microPackage ) + { + m_bCreatedInitialPackage = true; + + //BEGIN Get pin IDs + QStringList allPinIDs = microPackage->pinIDs(); + QStringList ioPinIDs = microPackage->pinIDs( PicPin::type_bidir | PicPin::type_input | PicPin::type_open ); + + // Now, we make the unwanted pin ids blank, so a pin is not created for them + const QStringList::iterator allPinIDsEnd = allPinIDs.end(); + for ( QStringList::iterator it = allPinIDs.begin(); it != allPinIDsEnd; ++it ) + { + if ( !ioPinIDs.contains(*it) ) + *it = ""; + } + //END Get pin IDs + + + //BEGIN Remove old stuff + // Remove old text + TextMap textMapCopy = m_textMap; + const TextMap::iterator textMapEnd = textMapCopy.end(); + for ( TextMap::iterator it = textMapCopy.begin(); it != textMapEnd; ++it ) + removeDisplayText(it.key()); + + // Remove the old pins + deletePICComponentPins(); + + // Remove old nodes + NodeMap nodeMapCopy = m_nodeMap; + const NodeMap::iterator nodeMapEnd = nodeMapCopy.end(); + for ( NodeMap::iterator it = nodeMapCopy.begin(); it != nodeMapEnd; ++it ) + { + if ( !ioPinIDs.contains(it.key()) ) + removeNode( it.key() ); + } + + removeElements(); + //END Remove old stuff + + + + //BEGIN Create new stuff + initDIPSymbol( allPinIDs, 80 ); + initDIP(allPinIDs); + + PicPinMap picPinMap = microPackage->pins( PicPin::type_bidir | PicPin::type_input | PicPin::type_open ); + const PicPinMap::iterator picPinMapEnd = picPinMap.end(); + for ( PicPinMap::iterator it = picPinMap.begin(); it != picPinMapEnd; ++it ) + m_picComponentPinMap[it.key()] = new PICComponentPin( this, it.data() ); + //END Create new stuff + + + removeDisplayText( "no_file" ); + addDisplayText( "picid", QRect(offsetX(), offsetY()-16, width(), 16), microInfo->id() ); + } + else + { + setSize( -48, -72, 96, 144 ); + removeDisplayText( "picid" ); + addDisplayText( "no_file", sizeRect(), i18n("(No\nprogram\nloaded)") ); + } + + + //BEGIN Update button positions + int leftpos = (width()-88)/2+offsetX(); + button("run")->setOriginalRect( QRect( leftpos, height()+4+offsetY(), 20, 20 ) ); + button("pause")->setOriginalRect( QRect( leftpos+23, height()+4+offsetY(), 20, 20 ) ); + button("reset")->setOriginalRect( QRect( leftpos+46, height()+4+offsetY(), 20, 20 ) ); + button("reload")->setOriginalRect( QRect( leftpos+69, height()+4+offsetY(), 20, 20 ) ); + updateAttachedPositioning(); + //END Update button positions +} + + +void PICComponent::attachPICComponentPins() +{ + if ( !m_pGpsim || !m_pGpsim->picProcessor() ) + return; + + pic_processor * picProcessor = m_pGpsim->picProcessor(); + + const PICComponentPinMap::iterator end = m_picComponentPinMap.end(); + for ( PICComponentPinMap::iterator it = m_picComponentPinMap.begin(); it != end; ++it ) + it.data()->attach( picProcessor->get_pin( it.key() ) ); +} + + +void PICComponent::slotUpdateFileList() +{ + QStringList preFileList; + if ( p_icnDocument && p_icnDocument->ktechlab() ) + preFileList += p_icnDocument->ktechlab()->recentFiles(); + + QStringList fileList; + + if ( ProjectInfo * info = ProjectManager::self()->currentProject() ) + { + const KURL::List urls = info->childOutputURLs( ProjectItem::AllTypes, ProjectItem::ProgramOutput ); + KURL::List::const_iterator urlsEnd = urls.end(); + for ( KURL::List::const_iterator it = urls.begin(); it != urlsEnd; ++it ) + fileList << (*it).path(); + } + + const QStringList::iterator end = preFileList.end(); + for ( QStringList::iterator it = preFileList.begin(); it != end; ++it ) + { + QString file = KURL(*it).path(); + if ( (file.endsWith(".flowcode") || file.endsWith(".asm") || file.endsWith(".cod") || file.endsWith(".basic") || file.endsWith(".microbe") ) && !fileList.contains(file) ) { + fileList.append(file); + } + } + + QString fileName = dataString("program"); + + property("program")->setAllowed(fileList); + property("program")->setValue( fileName.isEmpty() ? _def_PICComponent_fileName : fileName ); +} + + +void PICComponent::buttonStateChanged( const QString &id, bool state ) +{ + if (!state) + return; + + if ( id == "reload" ) + { + programReload(); + return; + } + + if (!m_pGpsim) + return; + + if ( id == "run" ) + m_pGpsim->setRunning(true); + + else if ( id == "pause" ) + m_pGpsim->setRunning(false); + + else if ( id == "reset" ) + { + m_pGpsim->reset(); + + // Set all pin outputs to low + const PICComponentPinMap::iterator end = m_picComponentPinMap.end(); + for ( PICComponentPinMap::iterator it = m_picComponentPinMap.begin(); it != end; ++it ) + it.data()->resetOutput(); + } + + slotUpdateBtns(); +} + + +bool PICComponent::mouseDoubleClickEvent ( const EventInfo &eventInfo ) +{ + Q_UNUSED(eventInfo); + if ( m_picFile.isEmpty() || (m_picFile == _def_PICComponent_fileName) ) + return false; + + (void) DocManager::self()->openURL(m_picFile); + + return true; +} + + +QString PICComponent::createSymbolFile() +{ + m_bLoadingProgram = true; + slotUpdateBtns(); + + return GpsimProcessor::generateSymbolFile( dataString("program"), this, SLOT(slotCODCreationSucceeded()), SLOT(slotCODCreationFailed()) ); +} + + +void PICComponent::slotCODCreationSucceeded() +{ + m_bLoadingProgram = false; + + delete m_pGpsim; + m_pGpsim = new GpsimProcessor(m_symbolFile); + + if ( m_pGpsim->codLoadStatus() == GpsimProcessor::CodSuccess ) + { + MicroInfo * microInfo = m_pGpsim->microInfo(); + property("lastPackage")->setValue( microInfo->id() ); + initPackage( microInfo ); + + connect( m_pGpsim, SIGNAL(runningStatusChanged(bool )), this, SLOT(slotUpdateBtns()) ); + attachPICComponentPins(); + } + + else + { + m_pGpsim->displayCodLoadStatus(); + delete m_pGpsim; + m_pGpsim = 0l; + } + + slotUpdateBtns(); +} + + +void PICComponent::slotCODCreationFailed() +{ + m_bLoadingProgram = false; + slotUpdateBtns(); +} + + +void PICComponent::programReload() +{ + delete m_pGpsim; + m_pGpsim = 0L; + + initPIC(true); + + slotUpdateBtns(); +} + + +void PICComponent::slotUpdateBtns() +{ + // We can get called by the destruction of gpsim after our canvas has been set to NULL + if (!canvas()) + return; + + button("run")->setEnabled( m_pGpsim && !m_pGpsim->isRunning() ); + button("pause")->setEnabled( m_pGpsim && m_pGpsim->isRunning() ); + button("reset")->setEnabled( m_pGpsim ); + button("reload")->setEnabled( !m_bLoadingProgram && (dataString("program") != _def_PICComponent_fileName) ); + + canvas()->setChanged( button("run")->boundingRect() ); + canvas()->setChanged( button("pause")->boundingRect() ); + canvas()->setChanged( button("reset")->boundingRect() ); + canvas()->setChanged( button("reload")->boundingRect() ); +} + + +#include "piccomponent.moc" + +#endif diff --git a/src/electronics/components/piccomponent.h b/src/electronics/components/piccomponent.h new file mode 100644 index 0000000..165fbf6 --- /dev/null +++ b/src/electronics/components/piccomponent.h @@ -0,0 +1,97 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef PICCOMPONENT_H +#define PICCOMPONENT_H + +#include "config.h" +#ifndef NO_GPSIM + +#include "component.h" + +#include <qguardedptr.h> +#include <qmap.h> + +class Document; +class ECNode; +class GpsimProcessor; +class IOPIN; +class KTechlab; +class MicroInfo; +class MicroPackage; +class PIC_IOPORT; +class PICComponent; +class PICComponentPin; +class PicPin; +class TextDocument; + +typedef QMap< int, PICComponentPin * > PICComponentPinMap; + +/** +@short Electronic PIC device +@author David Saxton +*/ +class PICComponent : public Component +{ + Q_OBJECT + public: + PICComponent( ICNDocument * icnDocument, bool newItem, const char *id = 0L ); + ~PICComponent(); + + virtual bool canFlip() const { return true; } + static Item * construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem * libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual bool mouseDoubleClickEvent( const EventInfo &eventInfo ); + + void programReload(); + /** + * Sets up the pins, text, etc for the given PIC type. If info is null, + * then a generic rectangle is displayed (used when no file has been + * loaded yet). + */ + void initPackage( MicroInfo * info ); + + public slots: + void slotUpdateFileList(); + void slotUpdateBtns(); + + protected slots: + void slotCODCreationSucceeded(); + void slotCODCreationFailed(); + + protected: + /** + * Attaches all PICComponentPins to the current instance of gpsim. + */ + void attachPICComponentPins(); + void deletePICComponentPins(); + /** + * Attempts to compile the program to a symbol file, and connects the assembly + * finish signal to loadGpsim + */ + QString createSymbolFile(); + virtual void dataChanged(); + /** + * Initializes the PIC from the options the user has selected. + */ + void initPIC( bool forceReload ); + + QGuardedPtr<GpsimProcessor> m_pGpsim; + QString m_picFile; ///< The input program that the user selected + QString m_symbolFile; ///< The symbol file that was generated from m_picFile + bool m_bLoadingProgram; ///< True between createSymbolFile being called and the file being created + PICComponentPinMap m_picComponentPinMap; + bool m_bCreatedInitialPackage; ///< Set true once the initial package is loaded; until then, will load a package from the lastPackage data +}; + +#endif +#endif diff --git a/src/electronics/components/piccomponentpin.cpp b/src/electronics/components/piccomponentpin.cpp new file mode 100644 index 0000000..47ef6cb --- /dev/null +++ b/src/electronics/components/piccomponentpin.cpp @@ -0,0 +1,172 @@ +/*************************************************************************** + * Copyright (C) 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 "config.h" +#ifndef NO_GPSIM + +#include "micropackage.h" +#include "piccomponent.h" +#include "piccomponentpin.h" + +#include <kdebug.h> + +PICComponentPin::PICComponentPin( PICComponent * picComponent, PicPin picPin ) + : m_id( picPin.pinID ) +{ + m_gOutHigh = 0.0; + m_gOutLow = 0.0; + m_picPin = picPin; + m_pPICComponent = picComponent; + m_pLogicOut = 0l; + m_pLogicIn = 0l; + m_pIOPIN = 0l; + m_pStimulusNode = 0l; + Zth = 0.0; + Vth = 0.0; + + switch ( picPin.type ) + { + case PicPin::type_input: + { + m_pLogicIn = picComponent->createLogicIn( picComponent->ecNodeWithID(picPin.pinID) ); + break; + } + case PicPin::type_bidir: + { + m_pLogicOut = picComponent->createLogicOut( picComponent->ecNodeWithID(picPin.pinID), false ); + m_gOutHigh = 0.004; + m_gOutLow = 0.004; + break; + } + case PicPin::type_open: + { + m_pLogicOut = picComponent->createLogicOut( picComponent->ecNodeWithID(picPin.pinID), false ); + m_pLogicOut->setOutputHighVoltage(0.0); + m_pLogicOut->setOutputHighConductance(0.0); + m_gOutHigh = 0.0; + m_gOutLow = 0.004; + break; + } + case PicPin::type_vss: + case PicPin::type_vdd: + case PicPin::type_mclr: + case PicPin::type_osc: + default: + break; + } + + if (m_pLogicIn) + m_pLogicIn->setCallback( this, (CallbackPtr)(&PICComponentPin::logicCallback) ); + if (m_pLogicOut) + m_pLogicOut->setCallback( this, (CallbackPtr)(&PICComponentPin::logicCallback) ); +} + + +PICComponentPin::~PICComponentPin() +{ + delete m_pStimulusNode; +} + + +void PICComponentPin::attach( IOPIN * iopin ) +{ + if (!iopin) + { + kdWarning() << k_funcinfo << " iopin is NULL" << endl; + return; + } + + if (m_pStimulusNode) + { + kdWarning() << k_funcinfo << " Already have a node stimulus" << endl; + return; + } + + if (m_pIOPIN) + { + kdWarning() << k_funcinfo << " Already have an iopin" << endl; + return; + } + + m_pIOPIN = iopin; + m_pStimulusNode = new Stimulus_Node(m_id.ascii()); + m_pStimulusNode->attach_stimulus(iopin); + m_pStimulusNode->attach_stimulus(this); + + + // We need to tell the iopin whether or not we are high + if (m_pLogicOut) + logicCallback( m_pLogicOut->isHigh() ); + else if (m_pLogicIn) + logicCallback( m_pLogicIn->isHigh() ); +} + + +double PICComponentPin::get_Vth( ) +{ + if (!m_pIOPIN) + return 0.0; + + if ( m_pIOPIN->get_direction() == IOPIN::DIR_INPUT ) + return Vth; + else + return m_pIOPIN->get_Vth(); +} + + +void PICComponentPin::set_nodeVoltage( double v ) +{ + Q_UNUSED(v); + + if ( !m_pLogicOut || !m_pIOPIN ) + return; + + if ( m_pIOPIN->get_direction() == IOPIN::DIR_INPUT ) + { + m_pLogicOut->setOutputHighConductance(0.0); + m_pLogicOut->setOutputLowConductance(0.0); + return; + } + + m_pLogicOut->setHigh( m_pIOPIN->getDrivingState() ); + m_pLogicOut->setOutputHighConductance(m_gOutHigh); + m_pLogicOut->setOutputLowConductance(m_gOutLow); +} + + +void PICComponentPin::logicCallback( bool state ) +{ + if (!m_pIOPIN) + return; + + Vth = state ? 5e10 : 0; + bDrivingState = state; + + if ( m_pIOPIN->get_direction() == IOPIN::DIR_INPUT ) + { + Zth = 1e5; + + m_pIOPIN->setDrivenState(state); + if (m_pStimulusNode) + m_pStimulusNode->update(); + } + else + Zth = 0; +} + + +void PICComponentPin::resetOutput() +{ + if ( m_pLogicOut ) + m_pLogicOut->setHigh( false ); +} + +#endif + diff --git a/src/electronics/components/piccomponentpin.h b/src/electronics/components/piccomponentpin.h new file mode 100644 index 0000000..0fc433d --- /dev/null +++ b/src/electronics/components/piccomponentpin.h @@ -0,0 +1,68 @@ +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef PICCOMPONENTPIN_H +#define PICCOMPONENTPIN_H + +#include "config.h" +#ifndef NO_GPSIM + +#include "logic.h" +#include "gpsim/stimuli.h" + +#include <qstring.h> + +/** +@short Controls a pin on the PIC component +@author David Saxton + */ +class PICComponentPin : public CallbackClass, public stimulus +{ + public: + PICComponentPin( PICComponent * picComponent, PicPin picPin ); + ~PICComponentPin(); + /** + * Attach this to gpsim + */ + void attach( IOPIN * iopin ); + /** + * Called when the IOPIN this class is associated with changes state. + * Updates the associated LogicOut / LogicIn / etc according to what + * type of pin this is. + */ + virtual void set_nodeVoltage( double v ); + /** + * Called from our logic pin when the logic changes state. + */ + void logicCallback( bool state ); + /** + * Sets the output (if has one) to low. Called when the user stops the + * PIC. + */ + void resetOutput(); + + virtual double get_Vth(); + + protected: + // Conductance of pin in different configurations + double m_gOutHigh; + double m_gOutLow; + + PicPin m_picPin; + IOPIN * m_pIOPIN; + LogicOut * m_pLogicOut; + LogicIn * m_pLogicIn; + PICComponent * m_pPICComponent; + Stimulus_Node * m_pStimulusNode; + const QString m_id; +}; + +#endif +#endif diff --git a/src/electronics/components/probe.cpp b/src/electronics/components/probe.cpp new file mode 100644 index 0000000..db6725e --- /dev/null +++ b/src/electronics/components/probe.cpp @@ -0,0 +1,291 @@ +/*************************************************************************** + * Copyright (C) 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 "ecnode.h" +#include "libraryitem.h" +#include "logic.h" +#include "pin.h" +#include "probe.h" //HACK: This has to be included before the oscilloscope headers +#include "oscilloscope.h" +#include "oscilloscopedata.h" +#include "simulator.h" +#include "voltagesource.h" + +#include <klocale.h> +#include <qpainter.h> + +//BEGIN class Probe +Probe::Probe( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ) +{ + p_probeData = 0l; + setSize( -16, -8, 32, 16 ); + + createProperty( "color", Variant::Type::Color ); + property("color")->setCaption( i18n("Color") ); + property("color")->setValue( Qt::black ); +} + + +Probe::~ Probe() +{ + delete p_probeData; +} + + +void Probe::dataChanged() +{ + m_color = dataColor("color"); + if (p_probeData) + p_probeData->setColor(m_color); + setChanged(); +} +//END class Probe + + + +//BEGIN class FloatingProbe +FloatingProbe::FloatingProbe( ICNDocument *icnDocument, bool newItem, const char *id ) + : Probe( icnDocument, newItem, id ) +{ + p_probeData = m_pFloatingProbeData = static_cast<FloatingProbeData*>(registerProbe(this)); + property("color")->setValue( p_probeData->color() ); + + createProperty( "scaling", Variant::Type::Select ); + property("scaling")->setCaption( i18n("Scaling") ); + property("scaling")->setAllowed( QStringList::split( ',', "Linear,Logarithmic") ); + property("scaling")->setValue("Linear"); + property("scaling")->setAdvanced( true ); + + createProperty( "upper_abs_value", Variant::Type::Double ); + property("upper_abs_value")->setCaption( i18n("Upper Absolute Value") ); + property("upper_abs_value")->setValue(10.0); + property("upper_abs_value")->setMinValue(0.0); + property("upper_abs_value")->setUnit("V"); + property("upper_abs_value")->setAdvanced(true); + + createProperty( "lower_abs_value", Variant::Type::Double ); + property("lower_abs_value")->setCaption( i18n("Lower Absolute Value") ); + property("lower_abs_value")->setValue(0.1); + property("lower_abs_value")->setMinValue(0.0); + property("lower_abs_value")->setUnit("V"); + property("lower_abs_value")->setAdvanced(true); +} + + +FloatingProbe::~FloatingProbe() +{ +} + + +void FloatingProbe::dataChanged() +{ + Probe::dataChanged(); + + if ( dataString("scaling") == "Linear" ) + m_pFloatingProbeData->setScaling( FloatingProbeData::Linear ); + else + m_pFloatingProbeData->setScaling( FloatingProbeData::Logarithmic ); + + m_pFloatingProbeData->setUpperAbsValue( dataDouble("upper_abs_value") ); + m_pFloatingProbeData->setLowerAbsValue( dataDouble("lower_abs_value") ); +} + + +void FloatingProbe::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = int(x())-16; + int _y = int(y())-8; + + p.drawRect( _x, _y, 32, 16 ); + + QPointArray bezier(4); + + bezier[0] = QPoint( _x+4, _y+10 ); + bezier[1] = QPoint( _x+12, _y-6 ); + bezier[2] = QPoint( _x+20, _y+24 ); + bezier[3] = QPoint( _x+28, _y+4 ); + + p.setPen( QPen( m_color, 2 ) ); + p.drawCubicBezier(bezier); + + deinitPainter(p); +} +//END class FloatingProbe + + + +//BEGIN class VoltageProbe +Item* VoltageProbe::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new VoltageProbe( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* VoltageProbe::libraryItem() +{ + return new LibraryItem( + "ec/voltageprobe", + i18n("Voltage Probe"), + i18n("Outputs"), + "floatingprobe.png", + LibraryItem::lit_component, + VoltageProbe::construct ); +} + +VoltageProbe::VoltageProbe( ICNDocument *icnDocument, bool newItem, const char *id ) + : FloatingProbe( icnDocument, newItem, id ? id : "voltageprobe" ) +{ + m_name = i18n("Voltage Probe"); + m_desc = i18n("Displays the voltage at the probe point on the oscilloscope."); + + init1PinLeft(); + init1PinRight(); + m_pPin1 = m_pNNode[0]->pin(); + m_pPin2 = m_pPNode[0]->pin(); +} + + +VoltageProbe::~VoltageProbe() +{ +} + + +void VoltageProbe::stepNonLogic() +{ + m_pFloatingProbeData->addDataPoint( m_pPin1->voltage() - m_pPin2->voltage() ); +} +//END class VoltageProbe + + + +//BEGIN class CurrentProbe +Item* CurrentProbe::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new CurrentProbe( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* CurrentProbe::libraryItem() +{ + return new LibraryItem( + "ec/currentprobe", + i18n("Current Probe"), + i18n("Outputs"), + "floatingprobe.png", + LibraryItem::lit_component, + CurrentProbe::construct ); +} + +CurrentProbe::CurrentProbe( ICNDocument *icnDocument, bool newItem, const char *id ) + : FloatingProbe( icnDocument, newItem, id ? id : "currentprobe" ) +{ + m_name = i18n("Current Probe"); + m_desc = i18n("Displays the current at the probe point on the oscilloscope."); + + + init1PinLeft(0); + init1PinRight(0); + + m_voltageSource = createVoltageSource( m_pNNode[0], m_pPNode[0], 0. ); +} + + +CurrentProbe::~CurrentProbe() +{ +} + + +void CurrentProbe::stepNonLogic() +{ + m_pFloatingProbeData->addDataPoint( -m_voltageSource->cbranchCurrent(0) ); +} +//END class CurrentProbe + + + + +//BEGIN class LogicProbe +Item* LogicProbe::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new LogicProbe( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* LogicProbe::libraryItem() +{ + QStringList ids; + ids << "ec/probe" << "ec/logicprobe"; + return new LibraryItem( + ids, + i18n("Logic Probe"), + i18n("Outputs"), + "logicprobe.png", + LibraryItem::lit_component, + LogicProbe::construct ); +} + +LogicProbe::LogicProbe( ICNDocument *icnDocument, bool newItem, const char *id ) + : Probe( icnDocument, newItem, id ? id : "probe" ) +{ + m_name = i18n("Logic Probe"); + m_desc = i18n("Connect this probe the the point in the circuit to measure the logic value. The output will be displayed in the Oscilloscope view."); + + init1PinRight(); + m_pIn = createLogicIn( m_pPNode[0] ); + + p_probeData = p_logicProbeData = static_cast<LogicProbeData*>(registerProbe(this)); + property("color")->setValue( p_probeData->color() ); + + m_pSimulator = Simulator::self(); + m_pIn->setCallback( this, (CallbackPtr)(&LogicProbe::logicCallback) ); + logicCallback(false); +} + + +LogicProbe::~LogicProbe() +{ +} + + +void LogicProbe::logicCallback( bool value ) +{ + p_logicProbeData->addDataPoint( LogicDataPoint( value, m_pSimulator->time() ) ); +} + + +void LogicProbe::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = int(x())-16; + int _y = int(y())-8; + + p.drawRect( _x, _y, 32, 16 ); + + p.setPen( QPen( m_color, 2 ) ); + + p.drawLine( _x+4, _y+11, _x+6, _y+11 ); + p.drawLine( _x+6, _y+11, _x+6, _y+4 ); + p.drawLine( _x+6, _y+4, _x+10, _y+4 ); + p.drawLine( _x+10, _y+4, _x+10, _y+11 ); + p.drawLine( _x+10, _y+11, _x+16, _y+11 ); + p.drawLine( _x+16, _y+11, _x+16, _y+4 ); + p.drawLine( _x+16, _y+4, _x+23, _y+4 ); + p.drawLine( _x+23, _y+4, _x+23, _y+11 ); + p.drawLine( _x+23, _y+11, _x+28, _y+11 ); +// p.drawLine( _x+23, _y+11, _x+26, _y+11 ); +// p.drawLine( _x+26, _y+11, _x+26, _y+4 ); +// p.drawLine( _x+26, _y+4, _x+28, _y+4 ); + + deinitPainter(p); +} +//END class LogicProbe + + diff --git a/src/electronics/components/probe.h b/src/electronics/components/probe.h new file mode 100644 index 0000000..9beb62e --- /dev/null +++ b/src/electronics/components/probe.h @@ -0,0 +1,113 @@ +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef PROBE_H +#define PROBE_H + +#include <component.h> + +class LogicProbeData; +class ProbeData; +class FloatingProbeData; + +/** +@author David Saxton +*/ +class Probe : public Component +{ + public: + Probe( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Probe(); + + protected: + virtual void dataChanged(); + + ProbeData * p_probeData; // As obtained via registering with the oscilloscope + QColor m_color; +}; + +/** +@author David Saxton + */ +class FloatingProbe : public Probe +{ + public: + FloatingProbe( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~FloatingProbe(); + + virtual bool doesStepNonLogic() const { return true; } + + protected: + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + + FloatingProbeData * m_pFloatingProbeData; +}; + +/** +@author David Saxton + */ +class VoltageProbe : public FloatingProbe +{ + public: + VoltageProbe( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~VoltageProbe(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void stepNonLogic(); + + protected: + Pin * m_pPin1; + Pin * m_pPin2; +}; + +/** +@author David Saxton + */ +class CurrentProbe : public FloatingProbe +{ + public: + CurrentProbe( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~CurrentProbe(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void stepNonLogic(); + + protected: + VoltageSource *m_voltageSource; +}; + +/** +@author David Saxton + */ +class LogicProbe : public CallbackClass, public Probe +{ + public: + LogicProbe( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~LogicProbe(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + void logicCallback( bool value ); + + protected: + virtual void drawShape( QPainter &p ); + + LogicProbeData * p_logicProbeData; + LogicIn * m_pIn; + Simulator * m_pSimulator; +}; + +#endif diff --git a/src/electronics/components/pushswitch.cpp b/src/electronics/components/pushswitch.cpp new file mode 100644 index 0000000..b7b38b7 --- /dev/null +++ b/src/electronics/components/pushswitch.cpp @@ -0,0 +1,204 @@ +/*************************************************************************** + * Copyright (C) 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 "canvasitemparts.h" +#include "libraryitem.h" +#include "pushswitch.h" +#include "switch.h" + +#include <klocale.h> +#include <qpainter.h> +#include <qpixmap.h> +#include <qpoint.h> +#include <qpointarray.h> + +//BEGIN class ECPTBSwitch +Item* ECPTBSwitch::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECPTBSwitch( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECPTBSwitch::libraryItem() +{ + return new LibraryItem( + QString("ec/ptb_switch"), + i18n("Push-to-Break"), + i18n("Switches"), + "ptb.png", + LibraryItem::lit_component, + ECPTBSwitch::construct ); +} + +ECPTBSwitch::ECPTBSwitch( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "ptb_switch" ) +{ + m_name = i18n("Push to Break"); + setSize( -16, -16, 32, 24 ); + + addButton( "button", QRect( -16, 8, 32, 20 ), "" ); + + createProperty( "button_text", Variant::Type::String ); + property("button_text")->setCaption( i18n("Button Text") ); + + Variant * v = createProperty( "bounce", Variant::Type::Bool ); + v->setCaption( i18n("Bounce") ); + v->setAdvanced(true); + v->setValue(false); + + v = createProperty( "bounce_period", Variant::Type::Double ); + v->setCaption( i18n("Bounce Period") ); + v->setAdvanced(true); + v->setUnit("s"); + v->setValue(5e-3); + + init1PinLeft(0); + init1PinRight(0); + + m_switch = createSwitch( m_pPNode[0], m_pNNode[0], false ); + pressed = false; +} + +ECPTBSwitch::~ECPTBSwitch() +{ +} + + +void ECPTBSwitch::dataChanged() +{ + button("button")->setText( dataString("button_text") ); + + bool bounce = dataBool("bounce"); + int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3); + m_switch->setBounce( bounce, bouncePeriod_ms ); +} + + +void ECPTBSwitch::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()-16; + int _y = (int)y()-8; + const int radius = 2; + const int _height = height()-8; + + int dy = pressed ? 6 : 4; + + p.drawLine( _x+width()/4, _y+dy, _x+(3*width())/4, _y+dy ); // Top horizontal line + p.drawLine( _x, _y+(_height/2)-radius+dy, _x+width(), _y+(_height/2)-radius+dy ); // Bottom horizontal line + p.drawLine( _x+width()/2, _y+dy, _x+width()/2, _y+(_height/2)-radius+dy ); // Vertical line + + p.drawEllipse( _x, _y+(_height/2)-radius, 2*radius, 2*radius ); // Left circle + p.drawEllipse( _x+width()-2*radius+1, _y+(_height/2)-radius, 2*radius, 2*radius ); // Right circle + + deinitPainter(p); +} + +void ECPTBSwitch::buttonStateChanged( const QString &id, bool state ) +{ + if ( id != "button" ) + return; + m_switch->setState( state ? Switch::Open : Switch::Closed ); + pressed = state; +} +//END class ECPTBSwitch + + +//BEGIN class ECPTMSwitch +Item* ECPTMSwitch::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECPTMSwitch( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECPTMSwitch::libraryItem() +{ + return new LibraryItem( + QString("ec/ptm_switch"), + i18n("Push-to-Make"), + i18n("Switches"), + "ptm.png", + LibraryItem::lit_component, + ECPTMSwitch::construct ); +} + +ECPTMSwitch::ECPTMSwitch( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "ptm_switch" ) +{ + m_name = i18n("Push to Make"); + setSize( -16, -16, 32, 24 ); + + addButton( "button", QRect( -16, 8, 32, 20 ), "" ); + + createProperty( "button_text", Variant::Type::String ); + property("button_text")->setCaption( i18n("Button Text") ); + + Variant * v = createProperty( "bounce", Variant::Type::Bool ); + v->setCaption("Bounce"); + v->setAdvanced(true); + v->setValue(false); + + v = createProperty( "bounce_period", Variant::Type::Double ); + v->setCaption("Bounce Period"); + v->setAdvanced(true); + v->setUnit("s"); + v->setValue(5e-3); + + init1PinLeft(0); + init1PinRight(0); + + m_switch = createSwitch( m_pPNode[0], m_pNNode[0], true ); + pressed = false; +} + + +ECPTMSwitch::~ECPTMSwitch() +{ +} + + +void ECPTMSwitch::dataChanged() +{ + button("button")->setText( dataString("button_text") ); + + bool bounce = dataBool("bounce"); + int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3); + m_switch->setBounce( bounce, bouncePeriod_ms ); +} + + +void ECPTMSwitch::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()-16; + int _y = (int)y()-8; + const int radius = 2; + const int _height = height()-8; + + int dy = pressed ? 1 : 3; + + p.drawLine( _x+width()/4, _y-dy, _x+(3*width())/4, _y-dy ); // Top horizontal line + p.drawLine( _x, _y+(_height/2)-radius-dy, _x+width(), _y+(_height/2)-radius-dy ); // Bottom horizontal line + p.drawLine( _x+width()/2, _y-dy, _x+width()/2, _y+(_height/2)-radius-dy ); // Vertical line + + p.drawEllipse( _x, _y+(_height/2)-radius, 2*radius, 2*radius ); // Left circle + p.drawEllipse( _x+width()-2*radius+1, _y+(_height/2)-radius, 2*radius, 2*radius ); // Right circle + + deinitPainter(p); +} + +void ECPTMSwitch::buttonStateChanged( const QString &id, bool state ) +{ + if ( id != "button" ) return; + m_switch->setState( state ? Switch::Closed : Switch::Open ); + pressed = state; +} +//END class ECPTMSwitch + diff --git a/src/electronics/components/pushswitch.h b/src/electronics/components/pushswitch.h new file mode 100644 index 0000000..c22ea93 --- /dev/null +++ b/src/electronics/components/pushswitch.h @@ -0,0 +1,62 @@ +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef PUSHSWITCH_H +#define PUSHSWITCH_H + +#include "component.h" + +/** +@short Push-to-Break switch component +@author David Saxton +*/ +class ECPTBSwitch : public Component +{ +public: + ECPTBSwitch( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECPTBSwitch(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual void dataChanged(); + +private: + virtual void drawShape( QPainter &p ); + Switch *m_switch; + bool pressed; +}; + + +/** +@short Push-to-make switch +@author David Saxton +*/ +class ECPTMSwitch : public Component +{ +public: + ECPTMSwitch( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECPTMSwitch(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual void dataChanged(); + +private: + virtual void drawShape( QPainter &p ); + Switch *m_switch; + bool pressed; +}; + + +#endif diff --git a/src/electronics/components/ram.cpp b/src/electronics/components/ram.cpp new file mode 100644 index 0000000..add745a --- /dev/null +++ b/src/electronics/components/ram.cpp @@ -0,0 +1,232 @@ +/*************************************************************************** + * Copyright (C) 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 "libraryitem.h" +#include "logic.h" +#include "ram.h" +#include "variant.h" + +#include <cmath> +#include <klocale.h> + +Item* RAM::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new RAM( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* RAM::libraryItem() +{ + return new LibraryItem( + QString("ec/ram"), + i18n("RAM"), + i18n("Integrated Circuits"), + "ic2.png", + LibraryItem::lit_component, + RAM::construct + ); +} + +RAM::RAM( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "ram" ) +{ + m_name = i18n("RAM"); + m_desc = i18n("This RAM stores data as a collection of words; each of which contains <i>word size</i> bits of data.<br><br>To read data, set the CS (<i>chip select</i>) and the OE (<i>output enable</i>) pins high, and select the word using the address pins <i>A*</i>. The word is outputted on the data-out pins: <i>DO*</i>.<br><br>To write data, set the CS (<i>chip select</i>) and the WE (<i>write enable</i>) pins high, and select the address to write to with the <i>A*</i> pins. Write to the selected word using the data-in pins: <i>DI*</i>.<br><br>The <i>Address Size</i> is the number of bits that determine an address; so the total number of words stored will be 2^<sup><i>Address Size</i></sup>."); + + m_data = 0l; + m_pCS = 0l; + m_pOE = 0l; + m_pWE = 0l; + m_wordSize = 0; + m_addressSize = 0; + + createProperty( "wordSize", Variant::Type::Int ); + property("wordSize")->setCaption( i18n("Word Size") ); + property("wordSize")->setMinValue(1); + property("wordSize")->setMaxValue(256); + property("wordSize")->setValue(2); + + createProperty( "addressSize", Variant::Type::Int ); + property("addressSize")->setCaption( i18n("Address Size") ); + property("addressSize")->setMinValue(1); + property("addressSize")->setMaxValue(32); + property("addressSize")->setValue(4); + + m_data = createProperty( "data", Variant::Type::Raw )->value().asBitArray(); +} + +RAM::~RAM() +{ +} + + +void RAM::dataChanged() +{ + m_wordSize = dataInt("wordSize"); + m_addressSize = dataInt("addressSize"); + + int newSize = int( m_wordSize * std::pow( 2., m_addressSize ) ); + m_data.resize(newSize); + + initPins(); +} + + +void RAM::inStateChanged( bool newState ) +{ + Q_UNUSED(newState); + + bool cs = m_pCS->isHigh(); + bool oe = m_pOE->isHigh(); + bool we = m_pWE->isHigh(); + + if ( !cs || !oe ) + { + for ( int i = 0; i < m_wordSize; ++i ) + m_dataOut[i]->setHigh(false); + } + + if ( !cs || (!oe && !we) ) + return; + + unsigned address = 0; + for ( int i = 0; i < m_addressSize; ++i ) + address += (m_address[i]->isHigh() ? 1 : 0) << i; + + if (we) + { + for ( int i = 0; i < m_wordSize; ++i ) + m_data[ m_wordSize * address + i ] = m_dataIn[i]->isHigh(); + } + + if (oe) + { + for ( int i = 0; i < m_wordSize; ++i ) + m_dataOut[i]->setHigh( m_data[ m_wordSize * address + i ] ); + } +} + + +void RAM::initPins() +{ + int oldWordSize = m_dataIn.size(); + int oldAddressSize = m_address.size(); + + int newWordSize = dataInt("wordSize"); + int newAddressSize = dataInt("addressSize"); + + if ( newAddressSize == oldAddressSize && + newWordSize == oldWordSize ) + return; + + QStringList leftPins; // Pins on left of IC + leftPins << "CS" << "OE" << "WE"; + for ( int i = 0; i < newAddressSize; ++i ) + leftPins << QString("A%1").arg( QString::number(i) ); + + QStringList rightPins; // Pins on right of IC + for ( unsigned i = newWordSize; i > 0; --i ) + rightPins << QString("DI%1").arg( QString::number(i-1) ); + for ( unsigned i = newWordSize; i > 0; --i ) + rightPins << QString("DO%1").arg( QString::number(i-1) ); + + // Make pin lists of consistent sizes + for ( unsigned i = leftPins.size(); i < rightPins.size(); ++i ) + leftPins.append(""); + for ( unsigned i = rightPins.size(); i < leftPins.size(); ++i ) + rightPins.prepend(""); + + QStringList pins = leftPins + rightPins; + + initDIPSymbol( pins, 72 ); + initDIP(pins); + + ECNode *node; + + if (!m_pCS) + { + node = ecNodeWithID("CS"); + m_pCS = createLogicIn(node); + m_pCS->setCallback( this, (CallbackPtr)(&RAM::inStateChanged) ); + } + + if (!m_pOE) + { + node = ecNodeWithID("OE"); + m_pOE = createLogicIn(node); + m_pOE->setCallback( this, (CallbackPtr)(&RAM::inStateChanged) ); + } + + if (!m_pWE) + { + node = ecNodeWithID("WE"); + m_pWE = createLogicIn(node); + m_pWE->setCallback( this, (CallbackPtr)(&RAM::inStateChanged) ); + } + + if ( newWordSize > oldWordSize ) + { + m_dataIn.resize(newWordSize); + m_dataOut.resize(newWordSize); + + for ( int i = oldWordSize; i < newWordSize; ++i ) + { + node = ecNodeWithID( QString("DI%1").arg( QString::number(i) ) ); + m_dataIn.insert( i, createLogicIn(node) ); + m_dataIn[i]->setCallback( this, (CallbackPtr)(&RAM::inStateChanged) ); + + node = ecNodeWithID( QString("DO%1").arg( QString::number(i) ) ); + m_dataOut.insert( i, createLogicOut(node, false) ); + } + } + else if ( newWordSize < oldWordSize ) + { + for ( int i = newWordSize; i < oldWordSize; ++i ) + { + QString id = QString("DO%1").arg( QString::number(i) ); + removeDisplayText(id); + removeElement( m_dataIn[i], false ); + removeNode(id); + + id = QString("DI%1").arg( QString::number(i) ); + removeDisplayText(id); + removeElement( m_dataOut[i], false ); + removeNode(id); + } + + m_dataIn.resize(newWordSize); + m_dataOut.resize(newWordSize); + } + + if ( newAddressSize > oldAddressSize ) + { + m_address.resize(newAddressSize); + + for ( int i = oldAddressSize; i < newAddressSize; ++i ) + { + node = ecNodeWithID( QString("A%1").arg( QString::number(i) ) ); + m_address.insert( i, createLogicIn(node) ); + m_address[i]->setCallback( this, (CallbackPtr)(&RAM::inStateChanged) ); + } + } + else if ( newAddressSize < oldAddressSize ) + { + for ( int i = newAddressSize; i < oldAddressSize; ++i ) + { + QString id = QString("A%1").arg( QString::number(i) ); + removeDisplayText(id); + removeElement( m_address[i], false ); + removeNode(id); + } + + m_address.resize(newAddressSize); + } +} + + diff --git a/src/electronics/components/ram.h b/src/electronics/components/ram.h new file mode 100644 index 0000000..7b78ee9 --- /dev/null +++ b/src/electronics/components/ram.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef RAM_H +#define RAM_H + +#include "component.h" +#include "logic.h" + +#include <qbitarray.h> +#include <qptrvector.h> + +/** +@author David Saxton +*/ +class RAM : public CallbackClass, public Component +{ + public: + RAM( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~RAM(); + + virtual bool canFlip() const { return true; } + static Item * construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem * libraryItem(); + + protected: + void initPins(); + virtual void dataChanged(); + void inStateChanged( bool newState ); + + QBitArray m_data; + LogicIn * m_pCS; // Chip select + LogicIn * m_pOE; // Output enable + LogicIn * m_pWE; // Write enable + + int m_wordSize; + int m_addressSize; + + QPtrVector<LogicIn> m_address; + QPtrVector<LogicIn> m_dataIn; + QPtrVector<LogicOut> m_dataOut; +}; + +#endif diff --git a/src/electronics/components/resistordip.cpp b/src/electronics/components/resistordip.cpp new file mode 100644 index 0000000..d2c5bdb --- /dev/null +++ b/src/electronics/components/resistordip.cpp @@ -0,0 +1,132 @@ +/*************************************************************************** + * Copyright (C) 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 "libraryitem.h" +#include "node.h" +#include "resistance.h" +#include "resistordip.h" + +#include <kiconloader.h> +#include <klocale.h> +#include <qpainter.h> + +Item* ResistorDIP::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ResistorDIP( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ResistorDIP::libraryItem() +{ + return new LibraryItem( + "ec/resistordip", + i18n("Resistor DIP"), + i18n("Discrete"), + "resistordip.png", + LibraryItem::lit_component, + ResistorDIP::construct + ); +} + +ResistorDIP::ResistorDIP( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "multiplexer" ) +{ + m_name = i18n("Resistor DIP"); + m_desc = i18n("Set of resistors with identical values in a Dual Inline Package."); + + m_resistorCount = 0; + for ( int i=0; i<maxCount; ++i ) + m_resistance[i] = 0l; + + createProperty( "resistance", Variant::Type::Double ); + property("resistance")->setCaption( i18n("Resistance") ); + property("resistance")->setUnit( QChar(0x3a9) ); + property("resistance")->setValue(1e4); + property("resistance")->setMinValue(1e-6); + + createProperty( "count", Variant::Type::Int ); + property("count")->setCaption( i18n("Count") ); + property("count")->setMinValue(2); + property("count")->setMaxValue(maxCount); + property("count")->setValue(8); +} + +ResistorDIP::~ResistorDIP() +{ +} + + +void ResistorDIP::dataChanged() +{ + initPins(); + const double resistance = dataDouble("resistance"); + for ( int i=0; i<m_resistorCount; ++i ) + m_resistance[i]->setResistance(resistance); + + const QString display = QString::number( resistance / getMultiplier(resistance), 'g', 3 ) + getNumberMag(resistance) + QChar(0x3a9); + addDisplayText( "res", QRect( offsetX(), offsetY()-16, 32, 12 ), display ); +} + + +void ResistorDIP::initPins() +{ + const int count = dataInt("count"); + const double resistance = dataDouble("resistance"); + + if ( count == m_resistorCount ) + return; + + if ( count < m_resistorCount ) + { + for ( int i=count; i<m_resistorCount; ++i ) + { + removeElement( m_resistance[i], false ); + m_resistance[i] = 0l; + removeNode( "n"+QString::number(i) ); + removeNode( "p"+QString::number(i) ); + } + } + else + { + for ( int i=m_resistorCount; i<count; ++i ) + { + const QString nid = "n"+QString::number(i); + const QString pid = "p"+QString::number(i); + m_resistance[i] = createResistance( createPin( -24, 0, 0, nid ), createPin( 24, 0, 180, pid ), resistance ); + } + } + m_resistorCount = count; + + setSize( -16, -count*8, 32, count*16, true ); + updateDIPNodePositions(); +} + + +void ResistorDIP::updateDIPNodePositions() +{ + for ( int i=0; i<m_resistorCount; ++i ) + { + m_nodeMap["n"+QString::number(i)].y = offsetY() + 8 + 16*i; + m_nodeMap["p"+QString::number(i)].y = offsetY() + 8 + 16*i; + } + updateAttachedPositioning(); +} + + +void ResistorDIP::drawShape( QPainter &p ) +{ + int _x = int(x()+offsetX()); + int _y = int(y()+offsetY()); + + initPainter(p); + for ( int i=0; i<m_resistorCount; ++i ) + p.drawRect( _x, _y+16*i+2, 32, 12 ); + deinitPainter(p); +} + diff --git a/src/electronics/components/resistordip.h b/src/electronics/components/resistordip.h new file mode 100644 index 0000000..ce1d03a --- /dev/null +++ b/src/electronics/components/resistordip.h @@ -0,0 +1,43 @@ +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef RESISTORDIP_H +#define RESISTORDIP_H + +#include "component.h" + +const int maxCount = 256; + +/** +@author David Saxton +*/ +class ResistorDIP : public Component +{ +public: + ResistorDIP( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ResistorDIP(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + virtual void drawShape( QPainter &p ); + void updateDIPNodePositions(); + virtual void dataChanged(); + /** + * Add / remove pins according to the number of inputs the user has requested + */ + void initPins(); + + int m_resistorCount; + Resistance* m_resistance[maxCount]; +}; + +#endif diff --git a/src/electronics/components/rotoswitch.cpp b/src/electronics/components/rotoswitch.cpp new file mode 100644 index 0000000..872714c --- /dev/null +++ b/src/electronics/components/rotoswitch.cpp @@ -0,0 +1,317 @@ +/*************************************************************************** + * Copyright (C) 2005 by John Myers * + * electronerd@electronerdia.net * + * * + * 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 "rotoswitch.h" + +#include "canvasitemparts.h" +#include "ecnode.h" +#include "libraryitem.h" +#include "switch.h" + +#include <klocale.h> +#include <qpainter.h> +#include <cmath> +#include <assert.h> + +#include <kdebug.h> + +//BEGIN class ECRotoSwitch +Item* ECRotoSwitch::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECRotoSwitch( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECRotoSwitch::libraryItem() +{ + return new LibraryItem( + QString("ec/roto_switch"), + i18n("Rotary"), + i18n("Switches"), + "rotary.png", + LibraryItem::lit_component, + ECRotoSwitch::construct ); +} + + +ECRotoSwitch::ECRotoSwitch( ICNDocument *icnDocument, bool newItem, const char *id ) +: Component( icnDocument, newItem, id ? id : "roto_switch" ), +m_numPositions(0) +{ +// m_name = i18n("Rotary Switch(WIP)"); + m_name = i18n("Rotary Switch"); + m_desc = i18n("Rotary Switch"); ///< \todo better description for rotoswitch + QPointArray pa; + pa.makeArc( -_pinInnerRadius, -_pinInnerRadius, 2*_pinInnerRadius, 2*_pinInnerRadius , 0, 16*360 ); + setItemPoints( pa ); + //setSize( -64, -64, 128, 128 ); + + //half the side length of the buttons + int buttonRadius = 10; + addButton( "go_left", QRect( -_pinOuterRadius/3-buttonRadius, _pinOuterRadius-3*buttonRadius, 2*buttonRadius, 2*buttonRadius ), "<", false ); + addButton( "go_right", QRect(_pinOuterRadius/3-buttonRadius, _pinOuterRadius-3*buttonRadius, 2*buttonRadius, 2*buttonRadius ), ">", false ); + + /*Variant * v = createProperty( "button_map", Variant::Type::String ); + v->setCaption( i18n("Button Map") ); + v->setAdvanced(true); + const QString defButtonMap("SSSSSSSSSSSM"); + v->setValue(defButtonMap); + */ + Variant * v = createProperty( "num_positions", Variant::Type::Int ); + v->setCaption( i18n("Number of Positions") ); + v->setAdvanced(false); + v->setValue(6); + v->setMinValue(3); + m_inNode = createPin(0,height()/2,270,"in"); + + v = createProperty( "bounce", Variant::Type::Bool ); + v->setCaption("Bounce"); + v->setAdvanced(true); + v->setValue(false); + + + v = createProperty( "bounce_period", Variant::Type::Double ); + v->setCaption("Bounce Period"); + v->setAdvanced(true); + v->setUnit("s"); + v->setValue(5e-3); + + + v = createProperty( "cur_position", Variant::Type::Int ); + v->setHidden( true ); + v->setValue( 0 ); + + //v = createProperty( "left_momentary", Variant::Type::Bool ); + //v->setCaption(i18n("Left Momentary" ) ); + //v->setValue(false); +} + + +ECRotoSwitch::~ECRotoSwitch() +{ +} + + +void ECRotoSwitch::dataChanged() +{ + bool bounce = dataBool("bounce"); + int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3); + m_curPosition = dataInt( "cur_position" ); + setUpSwitches(); + if(m_positions[m_curPosition].posSwitch->state() != Switch::Closed) + { + m_positions[m_curPosition].posSwitch->setState(Switch::Closed); + } + for(int i = 0; i < m_numPositions; i++) + { + m_positions[i].posSwitch->setBounce( bounce, bouncePeriod_ms ); + } +} + +inline int roundTo10(int a){return ((a/10)+(a%10<5?0:1))*10;} +void ECRotoSwitch::drawShape( QPainter &p ) +{ + initPainter(p); + + + int cx = static_cast<int>(x()); + int cy = static_cast<int>(y()); + + const int rotorRadius = 5; + + + //draw the rotor + p.drawEllipse(cx - rotorRadius, cy-rotorRadius, 2*rotorRadius, 2*rotorRadius); + //and its connection + p.drawLine(cx, cy+rotorRadius, cx, cy+_pinInnerRadius); + + //draw the output positions + double angleBetweenPositions = (4*M_PI/3)/(m_numPositions - 1); + //kdDebug() << "drawShape: " << bigRadius << " " << angleBetweenPositions << endl; + + /// \internal \brief Round to the nearest multiple of 8 +#define round_8(a) (((a) > 0) ? int(((a)+4)/8)*8 : int(((a)-4)/8)*8) + for(int i = 0; i < m_numPositions ; i++) + { + double angle = (7*M_PI/6) - (i * angleBetweenPositions); + int contactX = static_cast<int>(_contactRingRadius * cos(angle)); + int contactY = static_cast<int>(_contactRingRadius * sin(angle)); + + p.drawEllipse(cx+contactX-_contactRadius, cy-contactY-_contactRadius, 2*_contactRadius, 2*_contactRadius); + int pinX, pinY; + switch(m_positions[i].pinAngle) + { + case 180: + pinX = _pinInnerRadius; + pinY = round_8(contactY); + break; + case 90: + pinX = round_8(contactX); + pinY = _pinInnerRadius; + break; + case 0: + pinX = -_pinInnerRadius; + pinY = round_8(contactY); + break; + default: + assert(!"Bad pin angle"); + } + p.drawLine(cx+contactX, cy-contactY, cx+pinX, cy-pinY); + //kdDebug() << contactX <<", "<< contactY <<endl; + } +#undef round_8 + //draw the connection to the selected position + double angle = (7*M_PI/6) - (m_curPosition * angleBetweenPositions); + int contactX = static_cast<int>(_contactRingRadius * cos(angle)); + int contactY = static_cast<int>(_contactRingRadius * sin(angle)); + int rotorX = static_cast<int>(rotorRadius * cos(angle)); + int rotorY = static_cast<int>(rotorRadius * sin(angle)); + p.drawLine(cx+rotorX, cy-rotorY, cx+contactX, cy-contactY); + + + deinitPainter(p); +} + +void ECRotoSwitch::buttonStateChanged( const QString & id, bool state ) +{ + SwitchPosition& curSP = m_positions[m_curPosition]; + int nextPos = m_curPosition; + if(m_numPositions < 2) + { + return; + } + if(!state) //release + { + if(!curSP.isMomentary) + { + return; + } + + if(m_curPosition == 0) + { + nextPos = m_curPosition + 1; + } + else if(m_curPosition == m_numPositions - 1) + { + nextPos = m_curPosition - 1; + } + + } + else //press + { + if(id == "go_left" && m_curPosition > 0) + { + nextPos = m_curPosition - 1; + } + else if(id == "go_right" && m_curPosition < m_numPositions - 1) + { + nextPos = m_curPosition + 1; + } + + } + if(nextPos != m_curPosition) + { + SwitchPosition& nextSP = m_positions[nextPos]; + + curSP.posSwitch->setState(Switch::Open); + nextSP.posSwitch->setState(Switch::Closed); + + m_curPosition = nextPos; + + property( "cur_position" )->setValue( m_curPosition ); + } +} + + +/*! + Set up the switches according to the button_map + * + * + */ +void ECRotoSwitch::setUpSwitches() +{ + if( dataInt("num_positions") == m_numPositions ) + { + // number of positions didn't change, so we don't have to do anything. + return; + } + //this uses the _old_ value of m_numPositions! + for(int i=0; i<m_numPositions; i++) + { + SwitchPosition& sp = m_positions[i]; + QString pinName = QString("pin_%1").arg(i); + removeNode(pinName); + removeSwitch(sp.posSwitch); + } + + m_numPositions = dataInt("num_positions"); + if(m_curPosition >= m_numPositions ) + { + setActivePosition( m_numPositions - 1 ); + } + m_positions.clear();///\todo readjust old pins + m_positions.reserve(m_numPositions); + double angleBetweenPositions = (4*M_PI/3)/(m_numPositions - 1); + //kdDebug() << "setUpSwitches: " << bigRadius << " " << angleBetweenPositions << endl; + for( int i = 0; i < m_numPositions; i++) + { + double angle = (7*M_PI/6) - (i * angleBetweenPositions); + int contactX = static_cast<int>(_contactRingRadius * cos(angle)); + int contactY = static_cast<int>(_contactRingRadius * sin(angle)); + + SwitchPosition sp; + if(angle > 3*M_PI/4) + { + sp.pinAngle = 0; + contactX = -_pinOuterRadius; + } + else if(angle > M_PI/4) + { + sp.pinAngle = 90; + contactY=_pinOuterRadius; + } + else + { + sp.pinAngle = 180; + contactX = _pinOuterRadius; + } + // kdDebug() << contactX <<", "<< contactY <<endl; + + + sp.node = createPin(contactX,-contactY,sp.pinAngle,QString("pin_%1").arg(i)); + sp.posSwitch = createSwitch(m_inNode, sp.node, true); + sp.isMomentary = false;//(map[i] == 'M'); + m_positions.push_back(sp); + } + updateAttachedPositioning(); + + // redraw ourself + setChanged(); +} + +/*! + * Set the current position to \c newPosition updating the state of the switch. + * \c m_curPosition must reference a valid position to switch away from + * + * \param newPosition the position to switch to + */ +void ECRotoSwitch::setActivePosition(int newPosition) +{ + SwitchPosition& curSP = m_positions[m_curPosition]; + SwitchPosition& nextSP = m_positions[newPosition]; + + curSP.posSwitch->setState(Switch::Open); + nextSP.posSwitch->setState(Switch::Closed); + + m_curPosition = newPosition; + + property( "cur_position" )->setValue( m_curPosition ); + +} +//END class ECRotoSwitch diff --git a/src/electronics/components/rotoswitch.h b/src/electronics/components/rotoswitch.h new file mode 100644 index 0000000..909c0ea --- /dev/null +++ b/src/electronics/components/rotoswitch.h @@ -0,0 +1,70 @@ +/*************************************************************************** + * Copyright (C) 2005 by John Myers * + * electronerd@electronerdia.net * + * * + * 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. * + ***************************************************************************/ + +#ifndef ROTOSWITCH_H +#define ROTOSWITCH_H + +#include "component.h" +#include <qvaluevector.h> + +struct SwitchPosition +{ + ECNode* node; + Switch* posSwitch; + bool isMomentary; + int pinAngle; +}; + +/** + * A rotary switch + * \author John Myers + */ +class ECRotoSwitch : public Component +{ +public: + ECRotoSwitch( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECRotoSwitch(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual void dataChanged(); + +private: + virtual void drawShape( QPainter &p ); + + int m_numPositions; + int m_curPosition; + + ///Half the total width of the component including pins + static const int _pinOuterRadius = 64; + ///The width of the pins + static const int _pinWidth = 8; + ///the radius of the circle centered at the origin and tangent to the inner edge of the rows of pins + static const int _pinInnerRadius = _pinOuterRadius - _pinWidth; + ///gap between pins and contact circles + static const int _wireGap = 7; + ///The radius of the largest circle tangent to the pin circles + static const int _contactOuterRadius = _pinInnerRadius - _wireGap; + ///The radius of the circles used to show positions + static const int _contactRadius = 2; + ///The radius of the ring of positions + static const int _contactRingRadius = _contactOuterRadius - _contactRadius; + + QValueVector<SwitchPosition> m_positions; + ECNode* m_inNode; + +protected: + void setUpSwitches(); +protected: + void setActivePosition(int newPosition); +}; +#endif //ROTOSWITCH_H diff --git a/src/electronics/components/serialportcomponent.cpp b/src/electronics/components/serialportcomponent.cpp new file mode 100644 index 0000000..c8e6a4e --- /dev/null +++ b/src/electronics/components/serialportcomponent.cpp @@ -0,0 +1,242 @@ +/*************************************************************************** + * Copyright (C) 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 "port.h" +#include "serialportcomponent.h" + +#include "ecnode.h" +#include "itemdocument.h" +#include "libraryitem.h" +#include "pin.h" +#include "resistance.h" + +#include <kdebug.h> +#include <klocale.h> +#include <qpainter.h> + +#include <cmath> +#include <termios.h> + +Item* SerialPortComponent::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new SerialPortComponent( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* SerialPortComponent::libraryItem() +{ + return new LibraryItem( + "ec/serial_port", + i18n("Serial Port"), + i18n("Connections"), + "ic1.png", + LibraryItem::lit_component, + SerialPortComponent::construct + ); +} + +SerialPortComponent::SerialPortComponent( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "serial_port" ) +{ + m_name = i18n("Serial Port"); + m_desc = i18n("Interface to a serial port. The pins are:<br>" + "<ul>" + "<li><b>CD</b> - Carrier Detect (control; output)</li>" + "<li><b>RD</b> - Received Data (data; output)</li>" + "<li><b>TD</b> - Transmitted Data (data; input)</li>" + "<li><b>DTR</b> - Data Terminal Ready (control; input)</li>" + "<li><b>GND</b> - Signal Ground (ground)</li>" + "<li><b>DSR</b> - Data Set Ready (control; input)</li>" + "<li><b>RTS</b> - Request to Send (control; input)</li>" + "<li><b>CTS</b> - Clear to Send (control; output)</li>" + "<li><b>RI</b> - Ring Indicator (control; output)</li>" + "</ul>"); + + QPointArray pa( 4 ); + pa[0] = QPoint( -32, -48 ); + pa[1] = QPoint( 32, -40 ); + pa[2] = QPoint( 32, 40 ); + pa[3] = QPoint( -32, 48 ); + + setItemPoints( pa ); + + m_pSerialPort = new SerialPort(); + + ECNode * pin = 0; + + // Works + pin = createPin( -40, 32, 0, "CD" ); + addDisplayText( "CD", QRect( -28, 24, 28, 16 ), "CD", true, Qt::AlignLeft | Qt::AlignVCenter ); + m_pCD = createLogicOut( pin, false ); + + // Doesn't work +// pin = createPin( -40, 16, 0, "RD" ); + addDisplayText( "RD", QRect( -28, 8, 28, 16 ), "RD", true, Qt::AlignLeft | Qt::AlignVCenter ); +// m_pRD = createLogicOut( pin, false ); + + // Works + pin = createPin( -40, 0, 0, "TD" ); + addDisplayText( "TD", QRect( -28, -8, 28, 16 ), "TD", true, Qt::AlignLeft | Qt::AlignVCenter ); + m_pTD = createLogicIn( pin); + m_pTD->setCallback( this, (CallbackPtr)(&SerialPortComponent::tdCallback) ); + + // Works + pin = createPin( -40, -16, 0, "DTR" ); + addDisplayText( "DTR", QRect( -28, -24, 28, 16 ), "DTR", true, Qt::AlignLeft | Qt::AlignVCenter ); + m_pDTR = createLogicIn( pin ); + m_pDTR->setCallback( this, (CallbackPtr)(&SerialPortComponent::dtrCallback) ); + + // N/A + pin = createPin( -40, -32, 0, "GND" ); + addDisplayText( "GND", QRect( -28, -40, 28, 16 ), "GND", true, Qt::AlignLeft | Qt::AlignVCenter ); + pin->pin()->setGroundType( Pin::gt_always ); + + // Doesn't work +// pin = createPin( 40, 24, 180, "DSR" ); + addDisplayText( "DSR", QRect( 0, 16, 28, 16 ), "DSR", true, Qt::AlignRight | Qt::AlignVCenter ); +// m_pDSR = createLogicIn( pin ); +// m_pDSR->setCallback( this, (CallbackPtr)(&SerialPortComponent::dsrCallback) ); + + // Doesn't work +// pin = createPin( 40, 8, 180, "RTS" ); + addDisplayText( "RTS", QRect( 0, 0, 28, 16 ), "RTS", true, Qt::AlignRight | Qt::AlignVCenter ); +// m_pRTS = createLogicIn( pin ); +// m_pRTS->setCallback( this, (CallbackPtr)(&SerialPortComponent::rtsCallback) ); + + // Works + pin = createPin( 40, -8, 180, "CTS" ); + addDisplayText( "CTS", QRect( 0, -16, 28, 16 ), "CTS", true, Qt::AlignRight | Qt::AlignVCenter ); + m_pCTS = createLogicOut( pin, false ); + + // Works + pin = createPin( 40, -24, 180, "RI" ); + addDisplayText( "RI", QRect( 0, -32, 28, 16 ), "RI", true, Qt::AlignRight | Qt::AlignVCenter ); + m_pRI = createLogicOut( pin, false ); + + Variant * v = createProperty( "port", Variant::Type::Combo ); + v->setAllowed( SerialPort::ports( Port::ExistsAndRW ) ); + v->setCaption( i18n("Port") ); + +// v = createProperty( "baudRate", Variant::Type::Select ); +// v->setAllowed( QStringList::split( ",", "B0,B50,B75,B110,B134,B150,B200,B300,B600,B1200,B1800,B2400,B4800,B9600,B19200,B38400" ) ); +// v->setCaption( i18n("Baud rate") ); +// v->setValue("B9600"); +} + + +SerialPortComponent::~SerialPortComponent() +{ + delete m_pSerialPort; +} + + +void SerialPortComponent::dataChanged() +{ +#if 0 + QString baudString = dataString("baudRate"); + unsigned baudRate = 0; + + if ( baudString == "B0" ) + baudRate = B0; + else if ( baudString == "B50" ) + baudRate = B50; + else if ( baudString == "B75" ) + baudRate = B75; + else if ( baudString == "B110" ) + baudRate = B110; + else if ( baudString == "B134" ) + baudRate = B134; + else if ( baudString == "B150" ) + baudRate = B150; + else if ( baudString == "B200" ) + baudRate = B200; + else if ( baudString == "B300" ) + baudRate = B300; + else if ( baudString == "B600" ) + baudRate = B600; + else if ( baudString == "B1200" ) + baudRate = B1200; + else if ( baudString == "B1800" ) + baudRate = B1800; + else if ( baudString == "B2400" ) + baudRate = B2400; + else if ( baudString == "B4800" ) + baudRate = B4800; + else if ( baudString == "B9600" ) + baudRate = B9600; + else if ( baudString == "B19200" ) + baudRate = B19200; + else if ( baudString == "B38400" ) + baudRate = B38400; + else + { + kdError() << k_funcinfo << "Unknown baud rate = \""<<baudString<<"\""<<endl; + return; + } + + initPort( dataString("port"), baudRate ); +#endif + + initPort( dataString("port"), B200 ); +} + + +void SerialPortComponent::initPort( const QString & port, unsigned baudRate ) +{ + if ( port.isEmpty() ) + { + m_pSerialPort->closePort(); + return; + } + + if ( ! m_pSerialPort->openPort( port, baudRate ) ) + { + p_itemDocument->canvas()->setMessage( i18n("Could not open port %1").arg( port ) ); + return; + } +} + + +void SerialPortComponent::stepNonLogic() +{ + m_pCD->setHigh( m_pSerialPort->pinState( SerialPort::CD ) ); +// m_pRD->setHigh( m_pSerialPort->pinState( SerialPort::RD ) ); + m_pCTS->setHigh( m_pSerialPort->pinState( SerialPort::CTS ) ); + m_pRI->setHigh( m_pSerialPort->pinState( SerialPort::RI ) ); +} + + +void SerialPortComponent::tdCallback( bool isHigh ) +{ + m_pSerialPort->setPinState( SerialPort::TD, isHigh ); +} + + +void SerialPortComponent::dtrCallback( bool isHigh ) +{ + m_pSerialPort->setPinState( SerialPort::DTR, isHigh ); +} + + +void SerialPortComponent::dsrCallback( bool isHigh ) +{ + m_pSerialPort->setPinState( SerialPort::DSR, isHigh ); +} + + +void SerialPortComponent::rtsCallback( bool isHigh ) +{ + m_pSerialPort->setPinState( SerialPort::RTS, isHigh ); +} + + +void SerialPortComponent::drawShape( QPainter & p ) +{ + drawPortShape( p ); +} diff --git a/src/electronics/components/serialportcomponent.h b/src/electronics/components/serialportcomponent.h new file mode 100644 index 0000000..4f9bc9a --- /dev/null +++ b/src/electronics/components/serialportcomponent.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef SERIALPORTCOMPONENT_H +#define SERIALPORTCOMPONENT_H + +#include "logic.h" +#include "component.h" + +class SerialPort; + +/** +@author David Saxton +*/ +class SerialPortComponent : public CallbackClass, public Component +{ + public: + SerialPortComponent( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~SerialPortComponent(); + + virtual bool canFlip() const { return true; } + static Item * construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem * libraryItem(); + + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + + protected: + /** + * @param baudRate as defined in <bits/termios.h> + */ + void initPort( const QString & port, unsigned baudRate ); + virtual void dataChanged(); + virtual void drawShape( QPainter & p ); + + void tdCallback( bool isHigh ); + void dtrCallback( bool isHigh ); + void dsrCallback( bool isHigh ); + void rtsCallback( bool isHigh ); + + LogicIn * m_pTD; + LogicIn * m_pDTR; +// LogicIn * m_pDSR; +// LogicIn * m_pRTS; + + LogicOut * m_pCD; +// LogicOut * m_pRD; + LogicOut * m_pCTS; + LogicOut * m_pRI; + + SerialPort * m_pSerialPort; +}; + +#endif diff --git a/src/electronics/components/toggleswitch.cpp b/src/electronics/components/toggleswitch.cpp new file mode 100644 index 0000000..4efe9ab --- /dev/null +++ b/src/electronics/components/toggleswitch.cpp @@ -0,0 +1,407 @@ +/*************************************************************************** + * Copyright (C) 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 "toggleswitch.h" + +#include "canvasitemparts.h" +#include "ecnode.h" +#include "libraryitem.h" +#include "switch.h" + +#include <klocale.h> +#include <qpainter.h> + +//BEGIN class ECDPDT +Item* ECDPDT::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECDPDT( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECDPDT::libraryItem() +{ + return new LibraryItem( + QString("ec/dpdt_toggle"), + i18n("DPDT"), + i18n("Switches"), + "dpdt.png", + LibraryItem::lit_component, + ECDPDT::construct ); +} + + +ECDPDT::ECDPDT( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "dpdt_toggle" ) +{ + m_name = i18n("DPDT Toggle"); + m_desc = i18n("Double-Pole Double-Throw switch."); + setSize( -16, -32, 32, 64 ); + + addButton( "button", QRect( -16, 32, 32, 20 ), "", true ); + + createProperty( "button_text", Variant::Type::String ); + property("button_text")->setCaption( i18n("Button Text") ); + + Variant * v = createProperty( "bounce", Variant::Type::Bool ); + v->setCaption("Bounce"); + v->setAdvanced(true); + v->setValue(false); + + v = createProperty( "bounce_period", Variant::Type::Double ); + v->setCaption("Bounce Period"); + v->setAdvanced(true); + v->setUnit("s"); + v->setValue(5e-3); + + init4PinRight( -24, -8, 8, 24 ); + + init2PinLeft( -16, 16 ); + + m_switch1 = createSwitch( m_pNNode[0], m_pPNode[0], false ); + m_switch2 = createSwitch( m_pNNode[0], m_pPNode[1], true ); + m_switch3 = createSwitch( m_pNNode[1], m_pPNode[2], false ); + m_switch4 = createSwitch( m_pNNode[1], m_pPNode[3], true ); + pressed = false; +} + + +ECDPDT::~ECDPDT() +{ +} + + +void ECDPDT::dataChanged() +{ + button("button")->setText( dataString("button_text") ); + + bool bounce = dataBool("bounce"); + int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3); + + m_switch1->setBounce( bounce, bouncePeriod_ms ); + m_switch2->setBounce( bounce, bouncePeriod_ms ); + m_switch3->setBounce( bounce, bouncePeriod_ms ); + m_switch4->setBounce( bounce, bouncePeriod_ms ); +} + + +void ECDPDT::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()-16; + int _y = (int)y()-32; + const int radius = 2; + + p.drawEllipse( _x, _y+15, 2*radius, 2*radius ); + p.drawEllipse( _x, _y+47, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+7, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+23, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+39, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+55, 2*radius, 2*radius ); + + const int dy = pressed ? 6 : -6; + + p.drawLine( _x+2*radius, _y+16, _x+width()-2*radius+2, _y+16+dy ); + p.drawLine( _x+2*radius, _y+48, _x+width()-2*radius+2, _y+48+dy ); + + deinitPainter(p); +} + +void ECDPDT::buttonStateChanged( const QString &, bool state ) +{ + pressed = state; + m_switch1->setState( state ? Switch::Open : Switch::Closed ); + m_switch2->setState( state ? Switch::Closed : Switch::Open ); + m_switch3->setState( state ? Switch::Open : Switch::Closed ); + m_switch4->setState( state ? Switch::Closed : Switch::Open ); +} +//END class ECDPDT + + +//BEGIN class ECDPST +Item* ECDPST::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECDPST( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECDPST::libraryItem() +{ + return new LibraryItem( + QString("ec/dpst_toggle"), + i18n("DPST"), + i18n("Switches"), + "dpst.png", + LibraryItem::lit_component, + ECDPST::construct ); +} + +ECDPST::ECDPST( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "dpst_toggle" ) +{ + m_name = i18n("DPST Toggle"); + m_desc = i18n("Double-Pole Single-Throw switch."); + setSize( -16, -16, 32, 32 ); + + addButton( "button", QRect( -16, 16, 32, 20 ), "", true ); + + createProperty( "button_text", Variant::Type::String ); + property("button_text")->setCaption( i18n("Button Text") ); + + Variant * v = createProperty( "bounce", Variant::Type::Bool ); + v->setCaption("Bounce"); + v->setAdvanced(true); + v->setValue(false); + + v = createProperty( "bounce_period", Variant::Type::Double ); + v->setCaption("Bounce Period"); + v->setAdvanced(true); + v->setUnit("s"); + v->setValue(5e-3); + + init2PinLeft( -8, 8 ); + init2PinRight( -8, 8 ); + + m_switch1 = createSwitch( m_pPNode[0], m_pNNode[0], true ); + m_switch2 = createSwitch( m_pPNode[1], m_pNNode[1], true ); + pressed = false; +} + + +ECDPST::~ECDPST() +{ +} + + +void ECDPST::dataChanged() +{ + button("button")->setText( dataString("button_text") ); + + bool bounce = dataBool("bounce"); + int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3); + + m_switch1->setBounce( bounce, bouncePeriod_ms ); + m_switch2->setBounce( bounce, bouncePeriod_ms ); +} + + +void ECDPST::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()-16; + int _y = (int)y()-16; + const int radius = 2; + + p.drawEllipse( _x, _y+6, 2*radius, 2*radius ); + p.drawEllipse( _x, _y+22, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+6, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+22, 2*radius, 2*radius ); + + const int dy = pressed ? 6 : 0; + + p.drawLine( _x+2*radius,_y+7,_x+width()-2*radius,_y+1+dy ); + p.drawLine( _x+2*radius,_y+24,_x+width()-2*radius,_y+18+dy ); + + deinitPainter(p); +} + +void ECDPST::buttonStateChanged( const QString &, bool state ) +{ + m_switch1->setState( state ? Switch::Closed : Switch::Open ); + m_switch2->setState( state ? Switch::Closed : Switch::Open ); + pressed = state; +} +//END class ECDPST + + +//BEGIN class ECSPDT +Item* ECSPDT::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECSPDT( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECSPDT::libraryItem() +{ + return new LibraryItem( + QString("ec/spdt_toggle"), + i18n("SPDT"), + i18n("Switches"), + "spdt.png", + LibraryItem::lit_component, + ECSPDT::construct ); +} + + +ECSPDT::ECSPDT( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "spdt_toggle" ) +{ + m_name = i18n("SPDT Toggle"); + m_desc = i18n("Single-Pole Double-Throw switch."); + setSize( -16, -16, 32, 32 ); + + addButton( "button", QRect( -16, 16, width(), 20 ), "", true ); + + createProperty( "button_text", Variant::Type::String ); + property("button_text")->setCaption( i18n("Button Text") ); + + Variant * v = createProperty( "bounce", Variant::Type::Bool ); + v->setCaption("Bounce"); + v->setAdvanced(true); + v->setValue(false); + + v = createProperty( "bounce_period", Variant::Type::Double ); + v->setCaption("Bounce Period"); + v->setAdvanced(true); + v->setUnit("s"); + v->setValue(5e-3); + + init1PinLeft( 0 ); + init2PinRight( -8, 8 ); + + m_switch1 = createSwitch( m_pNNode[0], m_pPNode[0], false ); + m_switch2 = createSwitch( m_pNNode[0], m_pPNode[1], true ); + + pressed = false; +} + + +ECSPDT::~ECSPDT() +{ +} + + +void ECSPDT::dataChanged() +{ + button("button")->setText( dataString("button_text") ); + + bool bounce = dataBool("bounce"); + int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3); + + m_switch1->setBounce( bounce, bouncePeriod_ms ); + m_switch2->setBounce( bounce, bouncePeriod_ms ); +} + + +void ECSPDT::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()-16; + int _y = (int)y()-16; + const int radius = 2; + + p.drawEllipse( _x, _y+15, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+6, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+22, 2*radius, 2*radius ); + + const int dy = pressed ? 21 : 10; + p.drawLine( _x+2*radius, _y+16, _x+width()-2*radius+2, _y+dy ); + + deinitPainter(p); +} + +void ECSPDT::buttonStateChanged( const QString &, bool state ) +{ + pressed = state; + m_switch1->setState( state ? Switch::Open : Switch::Closed ); + m_switch2->setState( state ? Switch::Closed : Switch::Open ); +} +//END class ECSPDT + + +//BEGIN class ECSPST +Item* ECSPST::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECSPST( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECSPST::libraryItem() +{ + return new LibraryItem( + QString("ec/spst_toggle"), + i18n("SPST"), + i18n("Switches"), + "spst.png", + LibraryItem::lit_component, + ECSPST::construct + ); +} + + +ECSPST::ECSPST( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "spst_toggle" ) +{ + m_name = i18n("SPST Toggle"); + m_desc = i18n("Single-Pole Single-Throw switch."); + setSize( -16, -8, 32, 16 ); + pressed = false; + + addButton( "button", QRect( -16, 8, width(), 20 ), "", true ); + + createProperty( "button_text", Variant::Type::String ); + property("button_text")->setCaption( i18n("Button Text") ); + + Variant * v = createProperty( "bounce", Variant::Type::Bool ); + v->setCaption("Bounce"); + v->setAdvanced(true); + v->setValue(false); + + v = createProperty( "bounce_period", Variant::Type::Double ); + v->setCaption("Bounce Period"); + v->setAdvanced(true); + v->setUnit("s"); + v->setValue(5e-3); + + button("button")->setState(pressed); + + init1PinLeft(); + init1PinRight(); + + m_switch = createSwitch( m_pNNode[0], m_pPNode[0], !pressed ); +} + + +ECSPST::~ECSPST() +{ +} + + +void ECSPST::dataChanged() +{ + button("button")->setText( dataString("button_text") ); + + bool bounce = dataBool("bounce"); + int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3); + m_switch->setBounce( bounce, bouncePeriod_ms ); +} + + +void ECSPST::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()-16; + int _y = (int)y()-8; + const int radius = 2; + + p.drawEllipse( _x, _y+7, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+7, 2*radius, 2*radius ); + const int dy = pressed ? 0 : -6; + p.drawLine( _x+2*radius, _y+8, _x+width()-2*radius, _y+8+dy ); + + deinitPainter(p); +} + +void ECSPST::buttonStateChanged( const QString &, bool state ) +{ + pressed = state; + m_switch->setState( state ? Switch::Closed : Switch::Open ); +} +//END class ECSPST + diff --git a/src/electronics/components/toggleswitch.h b/src/electronics/components/toggleswitch.h new file mode 100644 index 0000000..80fd064 --- /dev/null +++ b/src/electronics/components/toggleswitch.h @@ -0,0 +1,116 @@ +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef TOGGLESWITCH_H +#define TOGGLESWITCH_H + +#include "component.h" + +/** +@short Double Pole Double Throw +@author David Saxton +*/ +class ECDPDT : public Component +{ +public: + ECDPDT( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECDPDT(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual void dataChanged(); + virtual bool canFlip() const { return true; } + +private: + virtual void drawShape( QPainter &p ); + Switch *m_switch1; + Switch *m_switch2; + Switch *m_switch3; + Switch *m_switch4; + bool pressed; +}; + + +/** +@short Double Pole Single Throw +@author David Saxton +*/ +class ECDPST : public Component +{ +public: + ECDPST( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECDPST(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual void dataChanged(); + virtual bool canFlip() const { return true; } + +private: + virtual void drawShape( QPainter &p ); + Switch *m_switch1; + Switch *m_switch2; + bool pressed; +}; + + +/** +@short Single Pole Double Throw +@author David Saxton +*/ +class ECSPDT : public Component +{ +public: + ECSPDT( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECSPDT(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual void dataChanged(); + virtual bool canFlip() const { return true; } + +private: + virtual void drawShape( QPainter &p ); + Switch *m_switch1; + Switch *m_switch2; + bool pressed; +}; + + +/** +@short Single-Pole Single-Throw Switch +@author David Saxton +*/ +class ECSPST : public Component +{ +public: + ECSPST( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECSPST(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual void dataChanged(); + virtual bool canFlip() const { return true; } + +private: + virtual void drawShape( QPainter &p ); + Switch *m_switch; + bool pressed; +}; + +#endif |