My Project  0.0.16
QUCS Mapping
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
libcomp.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  libcomp.cpp
3  -------------
4  begin : Fri Jun 10 2005
5  copyright : (C) 2005 by Michael Margraf
6  email : michael.margraf@alumni.tu-berlin.de
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 
22 #include "libcomp.h"
23 #include "qucs.h"
24 #include "main.h"
25 #include "schematic.h"
26 
27 #include <qdir.h>
28 #include <qfileinfo.h>
29 #include <qregexp.h>
30 
31 #include <math.h>
32 #include <limits.h>
33 
34 extern QDir QucsWorkDir;
35 
36 
38 {
39  Type = isComponent; // both analog and digital
40  Description = QObject::tr("Component taken from Qucs library");
41 
42  Ports.append(new Port(0, 0)); // dummy port because of being device
43 
44  Model = "Lib";
45  Name = "X";
46 
47  Props.append(new Property("Lib", "", true,
48  QObject::tr("name of qucs library file")));
49  Props.append(new Property("Comp", "", true,
50  QObject::tr("name of component in library")));
51 }
52 
53 // ---------------------------------------------------------------------
55 {
56  LibComp *p = new LibComp();
57  p->Props.first()->Value = Props.first()->Value;
58  p->Props.next()->Value = Props.next()->Value;
59  p->recreate(0);
60  return p;
61 }
62 
63 // ---------------------------------------------------------------------
64 // Makes the schematic symbol subcircuit with the correct number
65 // of ports.
67 {
68  tx = INT_MIN;
69  ty = INT_MIN;
70  if(loadSymbol() > 0) {
71  if(tx == INT_MIN) tx = x1+4;
72  if(ty == INT_MIN) ty = y2+4;
73  }
74  else {
75  // only paint a rectangle
76  Lines.append(new Line(-15, -15, 15, -15, QPen(QPen::darkBlue,2)));
77  Lines.append(new Line( 15, -15, 15, 15, QPen(QPen::darkBlue,2)));
78  Lines.append(new Line(-15, 15, 15, 15, QPen(QPen::darkBlue,2)));
79  Lines.append(new Line(-15, -15,-15, 15, QPen(QPen::darkBlue,2)));
80 
81  x1 = -18; y1 = -18;
82  x2 = 18; y2 = 18;
83 
84  tx = x1+4;
85  ty = y2+4;
86  }
87 }
88 
89 // ---------------------------------------------------------------------
90 // Loads the section with name "Name" from library file into "Section".
91 int LibComp::loadSection(const QString& Name, QString& Section,
92  QStringList *Includes)
93 {
94  QDir Directory(QucsSettings.LibDir);
95  QFile file(Directory.absFilePath(Props.first()->Value + ".lib"));
96  if(!file.open(IO_ReadOnly))
97  return -1;
98 
99  QTextStream ReadWhole(&file);
100  Section = ReadWhole.read();
101  file.close();
102 
103 
104  if(Section.left(14) != "<Qucs Library ") // wrong file type ?
105  return -2;
106 
107  int Start, End = Section.find(' ', 14);
108  if(End < 15) return -3;
109  QString Line = Section.mid(14, End-14);
110  if(!checkVersion(Line)) // wrong version number ?
111  return -3;
112 
113  if(Name == "Symbol") {
114  Start = Section.find("\n<", 14); // if library has default symbol, take it
115  if(Start > 0)
116  if(Section.mid(Start+2, 14) == "DefaultSymbol>") {
117  Start += 16;
118  End = Section.find("\n</DefaultSymbol>", Start);
119  if(End < 0) return -9;
120  Section = Section.mid(Start, End-Start);
121  return 0;
122  }
123  }
124 
125  // search component
126  Line = "\n<Component " + Props.next()->Value + ">";
127  Start = Section.find(Line);
128  if(Start < 0) return -4; // component not found
129  Start = Section.find('\n', Start);
130  if(Start < 0) return -5; // file corrupt
131  Start++;
132  End = Section.find("\n</Component>", Start);
133  if(End < 0) return -6; // file corrupt
134  Section = Section.mid(Start, End-Start+1);
135 
136  // search model includes
137  if(Includes) {
138  int StartI, EndI;
139  StartI = Section.find("<"+Name+"Includes");
140  if(StartI >= 0) { // includes found
141  StartI = Section.find('"', StartI);
142  if(StartI < 0) return -10; // file corrupt
143  EndI = Section.find('>', StartI);
144  if(EndI < 0) return -11; // file corrupt
145  StartI++; EndI--;
146  QString inc = Section.mid(StartI, EndI-StartI);
147  QStringList f = QStringList::split(QRegExp("\"\\s+\""), inc);
148  for(QStringList::Iterator it = f.begin(); it != f.end(); ++it ) {
149  Includes->append(*it);
150  }
151  }
152  }
153 
154  // search model
155  Start = Section.find("<"+Name+">");
156  if(Start < 0) return -7; // symbol not found
157  Start = Section.find('\n', Start);
158  if(Start < 0) return -8; // file corrupt
159  while(Section.at(++Start) == ' ') ;
160  End = Section.find("</"+Name+">", Start);
161  if(End < 0) return -9; // file corrupt
162 
163  // snip actual model
164  Section = Section.mid(Start, End-Start);
165  return 0;
166 }
167 
168 // ---------------------------------------------------------------------
169 // Loads the symbol for the subcircuit from the schematic file and
170 // returns the number of painting elements.
171 int LibComp::loadSymbol()
172 {
173  int z, Result;
174  QString FileString, Line;
175  z = loadSection("Symbol", FileString);
176  if(z < 0) {
177  if(z != -7) return z;
178 
179  // If library component not defined as subcircuit, then load
180  // new component and transfer data to this component.
181  z = loadSection("Model", Line);
182  if(z < 0) return z;
183 
184  Component *pc = getComponentFromName(Line);
185  if(pc == 0) return -20;
186 
187  copyComponent(pc);
188 
189  pc->Arcs.setAutoDelete(false);
190  pc->Lines.setAutoDelete(false);
191  pc->Rects.setAutoDelete(false);
192  pc->Ellips.setAutoDelete(false);
193  pc->Ports.setAutoDelete(false);
194  pc->Texts.setAutoDelete(false);
195  pc->Props.setAutoDelete(false);
196  delete pc;
197 
198  return 1;
199  }
200 
201 
202  z = 0;
203  x1 = y1 = INT_MAX;
204  x2 = y2 = INT_MIN;
205 
206  QTextStream stream(&FileString, IO_ReadOnly);
207  while(!stream.atEnd()) {
208  Line = stream.readLine();
209  Line = Line.stripWhiteSpace();
210  if(Line.isEmpty()) continue;
211  if(Line.at(0) != '<') return -11;
212  if(Line.at(Line.length()-1) != '>') return -12;
213  Line = Line.mid(1, Line.length()-2); // cut off start and end character
214  Result = analyseLine(Line, 2);
215  if(Result < 0) return -13; // line format error
216  z += Result;
217  }
218 
219  x1 -= 4; x2 += 4; // enlarge component boundings a little
220  y1 -= 4; y2 += 4;
221  return z; // return number of ports
222 }
223 
224 // -------------------------------------------------------
226 {
227  QDir Directory(QucsSettings.LibDir);
228  QString FileName = Directory.absFilePath(Props.first()->Value);
229  return properAbsFileName(FileName);
230 }
231 
232 // -------------------------------------------------------
233 bool LibComp::createSubNetlist(QTextStream *stream, QStringList &FileList,
234  int type)
235 {
236  int r = -1;
237  QString FileString;
238  QStringList Includes;
239  if(type&1) {
240  r = loadSection("Model", FileString, &Includes);
241  } else if(type&2) {
242  r = loadSection("VHDLModel", FileString, &Includes);
243  } else if(type&4) {
244  r = loadSection("VerilogModel", FileString, &Includes);
245  }
246  if(r < 0) return false;
247 
248  // also include files
249  int error = 0;
250  for(QStringList::Iterator it = Includes.begin();
251  it != Includes.end(); ++it ) {
252  QString s = getSubcircuitFile()+"/"+*it;
253  if(FileList.findIndex(s) >= 0) continue;
254  FileList.append(s);
255 
256  // load file and stuff into stream
257  QFile file(s);
258  if(!file.open(IO_ReadOnly)) {
259  error++;
260  } else {
261  QByteArray FileContent = file.readAll();
262  file.close();
263  stream->writeRawBytes(FileContent.data(), FileContent.size());
264  }
265  }
266 
267  (*stream) << "\n" << FileString << "\n";
268  return error > 0 ? false : true;
269 }
270 
271 // -------------------------------------------------------
272 QString LibComp::createType()
273 {
274  QString Type = properFileName(Props.first()->Value);
275  return properName(Type + "_" + Props.next()->Value);
276 }
277 
278 // -------------------------------------------------------
280 {
281  QString s = "Sub:"+Name; // output as subcircuit
282 
283  // output all node names
284  for(Port *p1 = Ports.first(); p1 != 0; p1 = Ports.next())
285  s += " "+p1->Connection->Name; // node names
286 
287  // output property
288  s += " Type=\""+createType()+"\""; // type for subcircuit
289 
290  // output user defined parameters
291  for(Property *pp = Props.at(2); pp != 0; pp = Props.next())
292  s += " "+pp->Name+"=\""+pp->Value+"\"";
293 
294  return s + '\n';
295 }
296 
297 // -------------------------------------------------------
299 {
300  QString s = " Sub_" + createType() + " " + Name + " (";
301 
302  // output all node names
303  Port *pp = Ports.first();
304  if(pp) s += pp->Connection->Name;
305  for(pp = Ports.next(); pp != 0; pp = Ports.next())
306  s += ", "+pp->Connection->Name; // node names
307 
308  s += ");\n";
309  return s;
310 }
311 
312 // -------------------------------------------------------
313 QString LibComp::vhdlCode(int)
314 {
315  QString s = " " + Name + ": entity Sub_" + createType() + " port map (";
316 
317  // output all node names
318  Port *pp = Ports.first();
319  if(pp) s += pp->Connection->Name;
320  for(pp = Ports.next(); pp != 0; pp = Ports.next())
321  s += ", "+pp->Connection->Name; // node names
322 
323  s += ");\n";
324  return s;
325 }