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

320 lines
6.4 KiB

/***************************************************************************
* Copyright (C) 2003-2005 by David Saxton *
* david@bluehaze.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
***************************************************************************/
#include <vector>
#include "circuit.h"
#include "elementset.h"
#include "logic.h"
#include "matrix.h"
#include "simulator.h"
#include "src/core/ktlconfig.h"
LogicIn::LogicIn( LogicConfig config )
: Element::Element()
{
m_config = config;
m_pCallbackFunction = 0l;
m_numCNodes = 1;
m_bLastState = false;
m_pNextLogic = 0l;
setLogic(getConfig());
}
LogicIn::~LogicIn()
{
Simulator::self()->removeLogicInReferences(this);
}
void LogicIn::setCallback( CallbackClass * object, CallbackPtr func )
{
m_pCallbackFunction = func;
m_pCallbackObject = object;
}
void LogicIn::check()
{
if (!b_status)
return;
bool newState;
if (m_bLastState)
{
// Was high, will still be high unless voltage is less than falling trigger
newState = p_cnode[0]->v > m_config.fallingTrigger;
}
else
{
// Was low, will still be low unless voltage is more than rising trigger
newState = p_cnode[0]->v > m_config.risingTrigger;
}
if ( m_pCallbackFunction && (newState != m_bLastState) )
{
m_bLastState = newState;
(m_pCallbackObject->*m_pCallbackFunction)(newState);
}
m_bLastState = newState;
}
void LogicIn::setLogic( LogicConfig config )
{
m_config = config;
check();
}
void LogicIn::setElementSet( ElementSet *c )
{
if (c)
m_pNextLogic = 0l;
else
m_cnodeI[0] = 0.;
Element::setElementSet(c);
}
void LogicIn::add_initial_dc()
{
}
void LogicIn::updateCurrents()
{
}
LogicConfig LogicIn::getConfig()
{
LogicConfig c;
c.risingTrigger = KTLConfig::logicRisingTrigger();
c.fallingTrigger = KTLConfig::logicFallingTrigger();
c.output = KTLConfig::logicOutputHigh();
c.highImpedance = KTLConfig::logicOutputHighImpedance();
c.lowImpedance = KTLConfig::logicOutputLowImpedance();
return c;
}
LogicOut::LogicOut( LogicConfig config, bool _high )
: LogicIn(config)
{
m_bCanAddChanged = true;
m_bOutputHighConductanceConst = false;
m_bOutputLowConductanceConst = false;
m_bOutputHighVoltageConst = false;
m_pNextChanged[0] = m_pNextChanged[1] = 0l;
m_pSimulator = 0l;
m_bUseLogicChain = false;
b_state = false;
m_numCNodes = 1;
m_vHigh = m_gHigh = m_gLow = 0.0;
m_old_g_out = m_g_out = 0.0;
m_old_v_out = m_v_out = 0.0;
setHigh(_high);
// Although we already call this function in LogicIn's constructor, our
// virtual function will not have got called, so we have to call it again.
setLogic(getConfig());
}
LogicOut::~LogicOut()
{
if (!m_pSimulator)
m_pSimulator = Simulator::self();
// Note that although this function will get called in the destructor of
// LogicIn, we must call it here as well as it needs to be called before
// removeLogicOutReferences(this) is called.
m_pSimulator->removeLogicInReferences(this);
m_pSimulator->removeLogicOutReferences(this);
}
void LogicOut::setUseLogicChain( bool use )
{
if (!m_pSimulator)
m_pSimulator = Simulator::self();
m_bUseLogicChain = use;
if (use)
setElementSet(0l);
}
void LogicOut::setElementSet( ElementSet *c )
{
if (!m_pSimulator)
m_pSimulator = Simulator::self();
if (c)
{
m_bUseLogicChain = false;
m_pNextChanged[0] = m_pNextChanged[1] = 0l;
}
// NOTE Make sure that the next two lines are the same as those in setHigh and setLogic
m_g_out = b_state ? m_gHigh : m_gLow;
m_v_out = b_state ? m_vHigh : 0.0;
LogicIn::setElementSet(c);
}
void LogicOut::setOutputHighConductance( double g )
{
m_bOutputHighConductanceConst = true;
if ( g == m_gHigh )
return;
m_gHigh = g;
configChanged();
}
void LogicOut::setOutputLowConductance( double g )
{
m_bOutputLowConductanceConst = true;
if ( g == m_gLow )
return;
m_gLow = g;
configChanged();
}
void LogicOut::setOutputHighVoltage( double v )
{
m_bOutputHighVoltageConst = true;
if ( v == m_vHigh )
return;
m_vHigh = v;
configChanged();
}
void LogicOut::setLogic( LogicConfig config )
{
m_config = config;
if (!m_bOutputHighConductanceConst)
m_gHigh = 1.0/config.highImpedance;
if (!m_bOutputLowConductanceConst)
m_gLow = (config.lowImpedance == 0.0) ? 0.0 : 1.0/config.lowImpedance;
if (!m_bOutputHighVoltageConst)
m_vHigh = config.output;
configChanged();
}
void LogicOut::configChanged()
{
if (m_bUseLogicChain)
return;
if (p_eSet)
p_eSet->setCacheInvalidated();
// Re-add the DC stuff using the new values
m_old_g_out = m_g_out;
m_old_v_out = m_v_out;
// NOTE Make sure that the next two lines are the same as those in setElementSet and setHigh
m_g_out = b_state ? m_gHigh : m_gLow;
m_v_out = b_state ? m_vHigh : 0.0;
add_initial_dc();
m_old_g_out = 0.;
m_old_v_out = 0.;
check();
}
void LogicOut::add_map()
{
if (!b_status) return;
p_A->setUse( p_cnode[0]->n(), p_cnode[0]->n(), Map::et_variable, false );
}
void LogicOut::add_initial_dc()
{
if (!b_status)
return;
A_g( 0, 0 ) += m_g_out-m_old_g_out;
b_i( 0 ) += m_g_out*m_v_out-m_old_g_out*m_old_v_out;
}
void LogicOut::updateCurrents()
{
if (m_bUseLogicChain)
{
m_cnodeI[0] = 0.;
return;
}
if (!b_status) {
return;
}
m_cnodeI[0] = (p_cnode[0]->v-m_v_out)*m_g_out;
}
void LogicOut::setHigh( bool high )
{
if ( high == b_state )
return;
if (m_bUseLogicChain)
{
b_state = high;
for ( LogicIn * logic = this; logic; logic = logic->nextLogic() )
logic->setLastState(high);
if (m_bCanAddChanged)
{
m_pSimulator->addChangedLogic(this);
m_bCanAddChanged = false;
}
return;
}
m_old_g_out = m_g_out;
m_old_v_out = m_v_out;
// NOTE Make sure that the next two lines are the same as those in setElementSet and setLogic
m_g_out = high ? m_gHigh : m_gLow;
m_v_out = high ? m_vHigh : 0.0;
add_initial_dc();
m_old_g_out = 0.;
m_old_v_out = 0.;
b_state = high;
if ( p_eSet && p_eSet->circuit()->canAddChanged() )
{
m_pSimulator->addChangedCircuit( p_eSet->circuit() );
p_eSet->circuit()->setCanAddChanged(false);
}
}