mirror of
https://github.com/ra3xdh/qucs_s
synced 2025-03-28 21:13:26 +00:00

SPICE libraries referenced by SpiceLibComp are copied to the the subdirectory when creating a library from project.
264 lines
8.2 KiB
C++
264 lines
8.2 KiB
C++
/***************************************************************************
|
|
spicelibcomp.cpp
|
|
--------------
|
|
begin : Tue Mar 08 2016
|
|
copyright : (C) 2016 by Vadim Kuznetsov
|
|
email : ra3xdh@gmail.com
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* 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 "spicelibcomp.h"
|
|
#include "main.h"
|
|
#include "misc.h"
|
|
#include "node.h"
|
|
#include "extsimkernels/spicecompat.h"
|
|
|
|
#include <QTextStream>
|
|
#include <QFileInfo>
|
|
#include <QMutex>
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
|
|
SpiceLibComp::SpiceLibComp()
|
|
{
|
|
Type = isComponent; // both analog and digital
|
|
Description = QObject::tr("SPICE library device. You can attach symbol patterns to it.");
|
|
Simulator = spicecompat::simSpice;
|
|
|
|
QStringList patterns;
|
|
misc::getSymbolPatternsList(patterns);
|
|
QString p_str = "[auto";
|
|
if (!patterns.isEmpty()) p_str += "," + patterns.join(",");
|
|
p_str += "]";
|
|
Props.append(new Property("File", "", false, QObject::tr("SpiceLibrary file")));
|
|
Props.append(new Property("Device", "", false, QObject::tr("Subcircuit entry (.SUBCKT) name")));
|
|
Props.append(new Property("SymPattern", "auto", false, p_str));
|
|
Props.append(new Property("Params", "", false, QObject::tr("Extra parameters list")));
|
|
Props.append(new Property("PinAssign", "", false, QObject::tr("Pins assignment")));
|
|
|
|
Model = "SpLib";
|
|
Name = "X";
|
|
SpiceModel = "X";
|
|
|
|
// Do NOT call createSymbol() here. But create port to let it rotate.
|
|
Ports.append(new Port(0, 0, false));
|
|
}
|
|
|
|
// ---------------------------------------------------------------------
|
|
Component* SpiceLibComp::newOne()
|
|
{
|
|
SpiceLibComp *p = new SpiceLibComp();
|
|
p->Props.front()->Value = Props.front()->Value;
|
|
p->recreate(0);
|
|
return p;
|
|
}
|
|
|
|
// -------------------------------------------------------
|
|
Element* SpiceLibComp::info(QString& Name, char* &BitmapFile, bool getNewOne)
|
|
{
|
|
Name = QObject::tr("SPICE library device");
|
|
BitmapFile = (char *) "spicelibcomp";
|
|
|
|
if(getNewOne) {
|
|
SpiceLibComp *p = new SpiceLibComp();
|
|
p->recreate(0); // createSymbol() is NOT called in constructor !!!
|
|
return p;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------
|
|
// Makes the schematic symbol SpiceLibComp with the correct number
|
|
// of ports.
|
|
void SpiceLibComp::createSymbol()
|
|
{
|
|
int No;
|
|
QString FileName;
|
|
QString symname = misc::properAbsFileName(Props.at(2)->Value, containingSchematic);
|
|
if (QFileInfo::exists(symname)) {
|
|
FileName = symname;
|
|
} else {
|
|
FileName = QucsSettings.BinDir;
|
|
FileName += QStringLiteral("/../share/" QUCS_NAME "/symbols/%1.sym").arg(Props.at(2)->Value);
|
|
}
|
|
|
|
// Default symbol: LM358 in opamps.lib ---> opamps/LM358.sym
|
|
QString LibName = misc::properAbsFileName(Props.at(0)->Value, containingSchematic);
|
|
QString DefSym = LibName;
|
|
QFileInfo inf(LibName); // Remove extension
|
|
int l = inf.suffix().size();
|
|
DefSym.chop(l+1);
|
|
DefSym += "/" + Props.at(1)->Value + ".sym";
|
|
QString CommonSym = inf.canonicalPath() + "/" + inf.baseName() + "/" + inf.baseName() + ".sym";
|
|
|
|
tx = INT_MIN;
|
|
ty = INT_MIN;
|
|
if(loadSymbol(FileName) > 0) { // try to load SpiceLibComp symbol
|
|
removeUnusedPorts();
|
|
} else if(loadSymbol(DefSym) > 0) {
|
|
removeUnusedPorts();
|
|
} else if(loadSymbol(CommonSym) > 0) { // CommonSymbol for all library
|
|
removeUnusedPorts();
|
|
} else {
|
|
QStringList pins;
|
|
No = spicecompat::getPins(LibName,Props.at(1)->Value,pins);
|
|
Ports.clear();
|
|
remakeSymbol(No,pins); // no symbol was found -> create standard symbol
|
|
}
|
|
}
|
|
|
|
void SpiceLibComp::removeUnusedPorts()
|
|
{
|
|
if(tx == INT_MIN) tx = x1+4;
|
|
if(ty == INT_MIN) ty = y2+4;
|
|
// remove unused ports
|
|
QMutableListIterator<Port *> ip(Ports);
|
|
Port *pp;
|
|
while (ip.hasNext()) {
|
|
pp = ip.next();
|
|
if(!pp->avail) {
|
|
pp = ip.peekNext();
|
|
ip.remove();
|
|
}
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------
|
|
void SpiceLibComp::remakeSymbol(int No, QStringList &pin_names)
|
|
{
|
|
QString nam;
|
|
int h = 30*((No-1)/2) + 15;
|
|
Lines.append(new qucs::Line(-15, -h, 15, -h,QPen(Qt::darkBlue,2)));
|
|
Lines.append(new qucs::Line( 15, -h, 15, h,QPen(Qt::darkBlue,2)));
|
|
Lines.append(new qucs::Line(-15, h, 15, h,QPen(Qt::darkBlue,2)));
|
|
Lines.append(new qucs::Line(-15, -h,-15, h,QPen(Qt::darkBlue,2)));
|
|
Texts.append(new Text(-10, -6,"lib"));
|
|
|
|
int i=0, y = 15-h;
|
|
while(i<No) {
|
|
i++;
|
|
Lines.append(new qucs::Line(-30, y,-15, y,QPen(Qt::darkBlue,2)));
|
|
Ports.append(new Port(-30, y));
|
|
if (i<=pin_names.count()) nam = pin_names.at(i-1);
|
|
Texts.append(new Text(-25,y-14,nam));
|
|
|
|
if(i == No) break;
|
|
i++;
|
|
Lines.append(new qucs::Line( 15, y, 30, y,QPen(Qt::darkBlue,2)));
|
|
Ports.append(new Port( 30, y));
|
|
if (i<=pin_names.count()) nam = pin_names.at(i-1);
|
|
Texts.append(new Text( 19,y-14,nam));
|
|
y += 60;
|
|
}
|
|
|
|
x1 = -30; y1 = -h-2;
|
|
x2 = 30; y2 = h+2;
|
|
tx = x1+4;
|
|
ty = y2+4;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------
|
|
// Loads the symbol for the SpiceLibComp from the schematic file and
|
|
// returns the number of painting elements.
|
|
int SpiceLibComp::loadSymbol(const QString& DocName)
|
|
{
|
|
QString FileString;
|
|
QFile symfile(DocName);
|
|
if (symfile.open(QIODevice::ReadOnly)) {
|
|
QTextStream ts(&symfile);
|
|
FileString = ts.readAll();
|
|
symfile.close();
|
|
} else return -1;
|
|
|
|
QString Line;
|
|
QTextStream stream(&FileString, QIODevice::ReadOnly);
|
|
|
|
|
|
// read content *************************
|
|
while(!stream.atEnd()) {
|
|
Line = stream.readLine();
|
|
if(Line == "<Symbol>") break;
|
|
}
|
|
|
|
x1 = y1 = INT_MAX;
|
|
x2 = y2 = INT_MIN;
|
|
|
|
int z=0, Result;
|
|
while(!stream.atEnd()) {
|
|
Line = stream.readLine();
|
|
if(Line == "</Symbol>") {
|
|
x1 -= 4; // enlarge component boundings a little
|
|
x2 += 4;
|
|
y1 -= 4;
|
|
y2 += 4;
|
|
return z; // return number of ports
|
|
}
|
|
|
|
Line = Line.trimmed();
|
|
if(Line.at(0) != '<') return -5;
|
|
if(Line.at(Line.length()-1) != '>') return -6;
|
|
Line = Line.mid(1, Line.length()-2); // cut off start and end character
|
|
if (Line.startsWith(".ID")) continue; // Do not adjust properties for SpiceLibComp
|
|
Result = analyseLine(Line, 4);
|
|
if(Result < 0) return -7; // line format error
|
|
z += Result;
|
|
}
|
|
|
|
return -8; // field not closed
|
|
}
|
|
|
|
QString SpiceLibComp::spice_netlist(spicecompat::SpiceDialect dialect /* = spicecompat::SPICEDefault */)
|
|
{
|
|
Q_UNUSED(dialect);
|
|
|
|
QString s = QStringLiteral("X%1 ").arg(Name);
|
|
QString pins = getProperty("PinAssign")->Value;
|
|
QString sym = getProperty("SymPattern")->Value;
|
|
if (sym == "auto" || pins.isEmpty()) {
|
|
for (Port *p1 : Ports) {
|
|
s += " " + spicecompat::normalize_node_name(p1->Connection->Name);
|
|
}
|
|
} else {
|
|
QStringList pin_nums = pins.split(";");
|
|
for (int i = 0; i < pin_nums.count(); i++) {
|
|
int pn = pin_nums.at(i).toInt();
|
|
Port *pp = Ports.at(pn-1);
|
|
s += " " + spicecompat::normalize_node_name(pp->Connection->Name);
|
|
}
|
|
}
|
|
s += QStringLiteral(" %1 %2\n").arg(Props.at(1)->Value).arg(Props.at(3)->Value);
|
|
return s;
|
|
}
|
|
|
|
QString SpiceLibComp::cdl_netlist()
|
|
{
|
|
return spice_netlist(spicecompat::CDL);
|
|
}
|
|
|
|
QString SpiceLibComp::getSpiceLibrary()
|
|
{
|
|
if (isActive != COMP_IS_ACTIVE) return QString();
|
|
QString f = misc::properAbsFileName(Props.at(0)->Value, containingSchematic);
|
|
QString s = QStringLiteral(".INCLUDE \"%1\"\n").arg(f);
|
|
return s;
|
|
}
|
|
|
|
QStringList SpiceLibComp::getSpiceLibraryFiles()
|
|
{
|
|
QString f = misc::properAbsFileName(getProperty("File")->Value, containingSchematic);
|
|
QStringList files;
|
|
files.append(f);
|
|
return files;
|
|
}
|