summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRahul P2023-06-13 18:21:12 +0530
committerGitHub2023-06-13 18:21:12 +0530
commit3436aa4615dcc1310db8dc8a85f36418db641fb4 (patch)
treee9cf9d33ed2c137f3ac463c7b272e27fe23be75d /src
parent172debd60ec1bae09c6b9c9180a388628e819909 (diff)
parent9a5f3dabc357277b384c51ccf047f5580772f454 (diff)
downloadeSim-3436aa4615dcc1310db8dc8a85f36418db641fb4.tar.gz
eSim-3436aa4615dcc1310db8dc8a85f36418db641fb4.tar.bz2
eSim-3436aa4615dcc1310db8dc8a85f36418db641fb4.zip
Merge branch 'master' into sky130-dev
Diffstat (limited to 'src')
-rw-r--r--src/frontEnd/Application.py143
-rwxr-xr-xsrc/frontEnd/DockArea.py188
-rw-r--r--src/frontEnd/TerminalUi.py143
-rw-r--r--src/frontEnd/TerminalUi.ui163
-rwxr-xr-xsrc/kicadtoNgspice/Convert.py154
-rwxr-xr-xsrc/kicadtoNgspice/DeviceModel.py136
-rw-r--r--src/kicadtoNgspice/KicadtoNgspice.py138
-rw-r--r--src/kicadtoNgspice/Microcontroller.py283
-rw-r--r--src/kicadtoNgspice/Model.py224
-rw-r--r--src/kicadtoNgspice/Processing.py2
-rw-r--r--src/kicadtoNgspice/TrackWidget.py2
-rw-r--r--src/ngspiceSimulation/NgspiceWidget.py199
12 files changed, 1357 insertions, 418 deletions
diff --git a/src/frontEnd/Application.py b/src/frontEnd/Application.py
index 795b5bf9..96be7ca4 100644
--- a/src/frontEnd/Application.py
+++ b/src/frontEnd/Application.py
@@ -12,12 +12,15 @@
# AUTHOR: Fahim Khan, fahim.elex@gmail.com
# MAINTAINED: Rahul Paknikar, rahulp@iitb.ac.in
# Sumanto Kar, sumantokar@iitb.ac.in
+# Pranav P, pranavsdreams@gmail.com
# ORGANIZATION: eSim Team at FOSSEE, IIT Bombay
# CREATED: Tuesday 24 February 2015
-# REVISION: Tuesday 13 September 2022
+# REVISION: Wednesday 07 June 2023
# =========================================================================
import os
+import sys
+import shutil
import traceback
if os.name == 'nt':
@@ -28,20 +31,16 @@ else:
init_path = '../../'
from PyQt5 import QtGui, QtCore, QtWidgets
+from PyQt5.Qt import QSize
from configuration.Appconfig import Appconfig
+from frontEnd import ProjectExplorer
+from frontEnd import Workspace
+from frontEnd import DockArea
from projManagement.openProject import OpenProjectInfo
from projManagement.newProject import NewProjectInfo
from projManagement.Kicad import Kicad
from projManagement.Validation import Validation
from projManagement import Worker
-from frontEnd import ProjectExplorer
-from frontEnd import Workspace
-from frontEnd import DockArea
-from PyQt5.Qt import QSize
-import shutil
-import time
-import sys
-import psutil
# Its our main window of application.
@@ -49,6 +48,7 @@ import psutil
class Application(QtWidgets.QMainWindow):
"""This class initializes all objects used in this file."""
global project_name
+ simulationEndSignal = QtCore.pyqtSignal(QtCore.QProcess.ExitStatus, int)
def __init__(self, *args):
"""Initialize main Application window."""
@@ -59,6 +59,9 @@ class Application(QtWidgets.QMainWindow):
# Flag for mode of operation. Default is set to offline mode.
self.online_flag = False
+ # Set slot for simulation end signal to plot simulation data
+ self.simulationEndSignal.connect(self.plotSimulationData)
+
# Creating require Object
self.obj_workspace = Workspace.Workspace()
self.obj_Mainview = MainView()
@@ -551,109 +554,59 @@ class Application(QtWidgets.QMainWindow):
print("Current Project is : ", self.obj_appconfig.current_project)
self.obj_Mainview.obj_dockarea.usermanual()
- def checkIfProcessRunning(self, processName):
- '''
- Check if there is any running process
- that contains the given name processName.
- '''
- # Iterate over the all the running process
- for proc in psutil.process_iter():
+ @QtCore.pyqtSlot(QtCore.QProcess.ExitStatus, int)
+ def plotSimulationData(self, exitCode, exitStatus):
+ """Enables interaction for new simulation and
+ displays the plotter dock where graphs can be plotted.
+ """
+ self.ngspice.setEnabled(True)
+ self.conversion.setEnabled(True)
+ self.closeproj.setEnabled(True)
+ self.wrkspce.setEnabled(True)
+
+ if exitStatus == QtCore.QProcess.NormalExit and exitCode == 0:
try:
- # Check if process name contains the given name string.
- if processName.lower() in proc.name().lower():
- return True
- except (psutil.NoSuchProcess,
- psutil.AccessDenied, psutil.ZombieProcess):
- pass
- return False
+ self.obj_Mainview.obj_dockarea.plottingEditor()
+ except Exception as e:
+ self.msg = QtWidgets.QErrorMessage()
+ self.msg.setModal(True)
+ self.msg.setWindowTitle("Error Message")
+ self.msg.showMessage(
+ 'Data could not be plotted. Please try again.'
+ )
+ self.msg.exec_()
+ print("Exception Message:", str(e), traceback.format_exc())
+ self.obj_appconfig.print_error('Exception Message : '
+ + str(e))
def open_ngspice(self):
"""This Function execute ngspice on current project."""
- self.projDir = self.obj_appconfig.current_project["ProjectName"]
+ projDir = self.obj_appconfig.current_project["ProjectName"]
- if self.projDir is not None:
+ if projDir is not None:
+ projName = os.path.basename(projDir)
+ ngspiceNetlist = os.path.join(projDir, projName + ".cir.out")
- # Edited by Sumanto Kar 25/08/2021
- if self.obj_Mainview.obj_dockarea.ngspiceEditor(
- self.projDir) is False:
+ if not os.path.isfile(ngspiceNetlist):
print(
"Netlist file (*.cir.out) not found."
)
-
self.msg = QtWidgets.QErrorMessage()
self.msg.setModal(True)
self.msg.setWindowTitle("Error Message")
self.msg.showMessage(
- 'Netlist file (*.cir.out) not found.'
+ 'Netlist (*.cir.out) not found.'
)
self.msg.exec_()
return
- currTime = time.time()
- count = 0
- while True:
- try:
- # if os.name == 'nt':
- # proc = 'mintty'
- # else:
- # proc = 'xterm'
-
- # Edited by Sumanto Kar 25/08/2021
- if os.name != 'nt' and \
- self.checkIfProcessRunning('xterm') is False:
- self.msg = QtWidgets.QErrorMessage()
- self.msg.setModal(True)
- self.msg.setWindowTitle("Warning Message")
- self.msg.showMessage(
- 'Simulation was interrupted/failed. '
- 'Please close all the Ngspice windows '
- 'and then rerun the simulation.'
- )
- self.msg.exec_()
- return
+ self.obj_Mainview.obj_dockarea.ngspiceEditor(
+ projName, ngspiceNetlist, self.simulationEndSignal)
- st = os.stat(os.path.join(self.projDir, "plot_data_i.txt"))
- if st.st_mtime >= currTime:
- break
- except Exception:
- pass
- time.sleep(1)
-
- # Fail Safe ===>
- count += 1
- if count >= 10:
- print(
- "Ngspice taking too long for simulation. "
- "Check netlist file (*.cir.out) "
- "to change simulation parameters."
- )
-
- self.msg = QtWidgets.QErrorMessage()
- self.msg.setModal(True)
- self.msg.setWindowTitle("Warning Message")
- self.msg.showMessage(
- 'Ngspice taking too long for simulation. '
- 'Check netlist file (*.cir.out) '
- 'to change simulation parameters.'
- )
- self.msg.exec_()
-
- return
-
- # Calling Python Plotting
- try:
- self.obj_Mainview.obj_dockarea.plottingEditor()
- except Exception as e:
- self.msg = QtWidgets.QErrorMessage()
- self.msg.setModal(True)
- self.msg.setWindowTitle("Error Message")
- self.msg.showMessage(
- 'Error while opening python plotting Editor.'
- ' Please look at console for more details.'
- )
- self.msg.exec_()
- print("Exception Message:", str(e), traceback.format_exc())
- self.obj_appconfig.print_error('Exception Message : ' + str(e))
+ self.ngspice.setEnabled(False)
+ self.conversion.setEnabled(False)
+ self.closeproj.setEnabled(False)
+ self.wrkspce.setEnabled(False)
else:
self.msg = QtWidgets.QErrorMessage()
@@ -756,7 +709,7 @@ class Application(QtWidgets.QMainWindow):
# Creating a command for Ngspice to Modelica converter
self.cmd1 = "
python3 ../ngspicetoModelica/NgspicetoModelica.py "\
- +self.ngspiceNetlist
+ + self.ngspiceNetlist
self.obj_workThread1 = Worker.WorkerThread(self.cmd1)
self.obj_workThread1.start()
if self.obj_validation.validateTool("OMEdit"):
diff --git a/src/frontEnd/DockArea.py b/src/frontEnd/DockArea.py
index 461240b9..7037dcfd 100755
--- a/src/frontEnd/DockArea.py
+++ b/src/frontEnd/DockArea.py
@@ -89,6 +89,7 @@ class DockArea(QtWidgets.QMainWindow):
"""This function create widget for interactive PythonPlotting."""
self.projDir = self.obj_appconfig.current_project["ProjectName"]
self.projName = os.path.basename(self.projDir)
+ dockName = f'Plotting-{self.projName}-'
# self.project = os.path.join(self.projDir, self.projName)
global count
@@ -99,66 +100,65 @@ class DockArea(QtWidgets.QMainWindow):
# Adding to main Layout
self.plottingWidget.setLayout(self.plottingLayout)
- dock['Plotting-' + str(count)
- ] = QtWidgets.QDockWidget('Plotting-' + str(count))
- dock['Plotting-' + str(count)].setWidget(self.plottingWidget)
+ dock[dockName + str(count)
+ ] = QtWidgets.QDockWidget(dockName
+ + str(count))
+ dock[dockName + str(count)] \
+ .setWidget(self.plottingWidget)
self.addDockWidget(QtCore.Qt.TopDockWidgetArea,
- dock['Plotting-' + str(count)])
- self.tabifyDockWidget(dock['Welcome'], dock['Plotting-' + str(count)])
+ dock[dockName + str(count)])
+ self.tabifyDockWidget(dock['Welcome'],
+ dock[dockName + str(count)])
- dock['Plotting-' + str(count)].setVisible(True)
- dock['Plotting-' + str(count)].setFocus()
- dock['Plotting-' + str(count)].raise_()
+ dock[dockName + str(count)].setVisible(True)
+ dock[dockName + str(count)].setFocus()
+ dock[dockName + str(count)].raise_()
temp = self.obj_appconfig.current_project['ProjectName']
if temp:
self.obj_appconfig.dock_dict[temp].append(
- dock['Plotting-' + str(count)]
+ dock[dockName + str(count)]
)
count = count + 1
- def ngspiceEditor(self, projDir):
+ def ngspiceEditor(self, projName, netlist, simEndSignal):
""" This function creates widget for Ngspice window."""
- self.projDir = projDir
- self.projName = os.path.basename(self.projDir)
- self.ngspiceNetlist = os.path.join(
- self.projDir, self.projName + ".cir.out")
-
- # Edited by Sumanto Kar 25/08/2021
- if os.path.isfile(self.ngspiceNetlist) is False:
- return False
-
global count
self.ngspiceWidget = QtWidgets.QWidget()
self.ngspiceLayout = QtWidgets.QVBoxLayout()
self.ngspiceLayout.addWidget(
- NgspiceWidget(self.ngspiceNetlist, self.projDir)
+ NgspiceWidget(netlist, simEndSignal)
)
# Adding to main Layout
self.ngspiceWidget.setLayout(self.ngspiceLayout)
- dock['NgSpice-' + str(count)
- ] = QtWidgets.QDockWidget('NgSpice-' + str(count))
- dock['NgSpice-' + str(count)].setWidget(self.ngspiceWidget)
+ dockName = f'Simulation-{projName}-'
+ dock[dockName + str(count)
+ ] = QtWidgets.QDockWidget(dockName
+ + str(count))
+ dock[dockName + str(count)] \
+ .setWidget(self.ngspiceWidget)
self.addDockWidget(QtCore.Qt.TopDockWidgetArea,
- dock['NgSpice-' + str(count)])
- self.tabifyDockWidget(dock['Welcome'], dock['NgSpice-' + str(count)])
+ dock[dockName + str(count)])
+ self.tabifyDockWidget(dock['Welcome'],
+ dock[dockName
+ + str(count)])
# CSS
- dock['NgSpice-' + str(count)].setStyleSheet(" \
+ dock[dockName + str(count)].setStyleSheet(" \
.QWidget { border-radius: 15px; border: 1px solid gray; padding: 0px;\
width: 200px; height: 150px; } \
")
- dock['NgSpice-' + str(count)].setVisible(True)
- dock['NgSpice-' + str(count)].setFocus()
- dock['NgSpice-' + str(count)].raise_()
+ dock[dockName + str(count)].setVisible(True)
+ dock[dockName + str(count)].setFocus()
+ dock[dockName + str(count)].raise_()
temp = self.obj_appconfig.current_project['ProjectName']
if temp:
self.obj_appconfig.dock_dict[temp].append(
- dock['NgSpice-' + str(count)]
+ dock[dockName + str(count)]
)
count = count + 1
@@ -166,6 +166,11 @@ class DockArea(QtWidgets.QMainWindow):
"""This function defines UI for model editor."""
print("in model editor")
global count
+
+ projDir = self.obj_appconfig.current_project["ProjectName"]
+ projName = os.path.basename(projDir)
+ dockName = f'Model Editor-{projName}-'
+
self.modelwidget = QtWidgets.QWidget()
self.modellayout = QtWidgets.QVBoxLayout()
@@ -174,23 +179,25 @@ class DockArea(QtWidgets.QMainWindow):
# Adding to main Layout
self.modelwidget.setLayout(self.modellayout)
- dock['Model Editor-' +
- str(count)] = QtWidgets.QDockWidget('Model Editor-' + str(count))
- dock['Model Editor-' + str(count)].setWidget(self.modelwidget)
+ dock[dockName +
+ str(count)] = QtWidgets.QDockWidget(dockName
+ + str(count))
+ dock[dockName + str(count)] \
+ .setWidget(self.modelwidget)
self.addDockWidget(QtCore.Qt.TopDockWidgetArea,
- dock['Model Editor-' + str(count)])
+ dock[dockName + str(count)])
self.tabifyDockWidget(dock['Welcome'],
- dock['Model Editor-' + str(count)])
+ dock[dockName + str(count)])
# CSS
- dock['Model Editor-' + str(count)].setStyleSheet(" \
+ dock[dockName + str(count)].setStyleSheet(" \
.QWidget { border-radius: 15px; border: 1px solid gray; \
padding: 5px; width: 200px; height: 150px; } \
")
- dock['Model Editor-' + str(count)].setVisible(True)
- dock['Model Editor-' + str(count)].setFocus()
- dock['Model Editor-' + str(count)].raise_()
+ dock[dockName + str(count)].setVisible(True)
+ dock[dockName + str(count)].setFocus()
+ dock[dockName + str(count)].raise_()
count = count + 1
@@ -199,91 +206,109 @@ class DockArea(QtWidgets.QMainWindow):
This function is creating Editor UI for Kicad to Ngspice conversion.
"""
global count
+
+ projDir = self.obj_appconfig.current_project["ProjectName"]
+ projName = os.path.basename(projDir)
+ dockName = f'Netlist-{projName}-'
+
self.kicadToNgspiceWidget = QtWidgets.QWidget()
self.kicadToNgspiceLayout = QtWidgets.QVBoxLayout()
self.kicadToNgspiceLayout.addWidget(MainWindow(clarg1, clarg2))
self.kicadToNgspiceWidget.setLayout(self.kicadToNgspiceLayout)
- dock['kicadToNgspice-' + str(count)] = \
- QtWidgets.QDockWidget('kicadToNgspice-' + str(count))
- dock['kicadToNgspice-' +
+ dock[dockName + str(count)] = \
+ QtWidgets.QDockWidget(dockName + str(count))
+ dock[dockName +
str(count)].setWidget(self.kicadToNgspiceWidget)
self.addDockWidget(QtCore.Qt.TopDockWidgetArea,
- dock['kicadToNgspice-' + str(count)])
+ dock[dockName + str(count)])
self.tabifyDockWidget(dock['Welcome'],
- dock['kicadToNgspice-' + str(count)])
+ dock[dockName + str(count)])
# CSS
- dock['kicadToNgspice-' + str(count)].setStyleSheet(" \
+ dock[dockName + str(count)].setStyleSheet(" \
.QWidget { border-radius: 15px; border: 1px solid gray;\
padding: 5px; width: 200px; height: 150px; } \
")
- dock['kicadToNgspice-' + str(count)].setVisible(True)
- dock['kicadToNgspice-' + str(count)].setFocus()
- dock['kicadToNgspice-' + str(count)].raise_()
- dock['kicadToNgspice-' + str(count)].activateWindow()
+ dock[dockName + str(count)].setVisible(True)
+ dock[dockName + str(count)].setFocus()
+ dock[dockName + str(count)].raise_()
+ dock[dockName + str(count)].activateWindow()
temp = self.obj_appconfig.current_project['ProjectName']
if temp:
self.obj_appconfig.dock_dict[temp].append(
- dock['kicadToNgspice-' + str(count)]
+ dock[dockName + str(count)]
)
count = count + 1
def subcircuiteditor(self):
"""This function creates a widget for different subcircuit options."""
global count
+
+ projDir = self.obj_appconfig.current_project["ProjectName"]
+ projName = os.path.basename(projDir)
+ dockName = f'Subcircuit-{projName}-'
+
self.subcktWidget = QtWidgets.QWidget()
self.subcktLayout = QtWidgets.QVBoxLayout()
self.subcktLayout.addWidget(Subcircuit(self))
self.subcktWidget.setLayout(self.subcktLayout)
- dock['Subcircuit-' +
- str(count)] = QtWidgets.QDockWidget('Subcircuit-' + str(count))
- dock['Subcircuit-' + str(count)].setWidget(self.subcktWidget)
+ dock[dockName +
+ str(count)] = QtWidgets.QDockWidget(dockName
+ + str(count))
+ dock[dockName + str(count)] \
+ .setWidget(self.subcktWidget)
self.addDockWidget(QtCore.Qt.TopDockWidgetArea,
- dock['Subcircuit-' + str(count)])
+ dock[dockName + str(count)])
self.tabifyDockWidget(dock['Welcome'],
- dock['Subcircuit-' + str(count)])
+ dock[dockName + str(count)])
# CSS
- dock['Subcircuit-' + str(count)].setStyleSheet(" \
+ dock[dockName + str(count)].setStyleSheet(" \
.QWidget { border-radius: 15px; border: 1px solid gray;\
padding: 5px; width: 200px; height: 150px; } \
")
- dock['Subcircuit-' + str(count)].setVisible(True)
- dock['Subcircuit-' + str(count)].setFocus()
- dock['Subcircuit-' + str(count)].raise_()
+ dock[dockName + str(count)].setVisible(True)
+ dock[dockName + str(count)].setFocus()
+ dock[dockName + str(count)].raise_()
count = count + 1
def makerchip(self):
"""This function creates a widget for different subcircuit options."""
global count
+
+ projDir = self.obj_appconfig.current_project["ProjectName"]
+ projName = os.path.basename(projDir)
+ dockName = f'Makerchip-{projName}-'
+
self.makerWidget = QtWidgets.QWidget()
self.makerLayout = QtWidgets.QVBoxLayout()
self.makerLayout.addWidget(makerchip(self))
self.makerWidget.setLayout(self.makerLayout)
- dock['Makerchip-' +
- str(count)] = QtWidgets.QDockWidget('Makerchip-' + str(count))
- dock['Makerchip-' + str(count)].setWidget(self.makerWidget)
+ dock[dockName +
+ str(count)] = QtWidgets.QDockWidget(dockName
+ + str(count))
+ dock[dockName + str(count)].setWidget(self.makerWidget)
self.addDockWidget(QtCore.Qt.TopDockWidgetArea,
- dock['Makerchip-' + str(count)])
+ dock[dockName + str(count)])
self.tabifyDockWidget(dock['Welcome'],
- dock['Makerchip-' + str(count)])
+ dock[dockName + str(count)])
# CSS
- dock['Makerchip-' + str(count)].setStyleSheet(" \
+ dock[dockName + str(count)].setStyleSheet(" \
.QWidget { border-radius: 15px; border: 1px solid gray;\
padding: 5px; width: 200px; height: 150px; } \
")
- dock['Makerchip-' + str(count)].setVisible(True)
- dock['Makerchip-' + str(count)].setFocus()
- dock['Makerchip-' + str(count)].raise_()
+ dock[dockName + str(count)].setVisible(True)
+ dock[dockName + str(count)].setFocus()
+ dock[dockName + str(count)].raise_()
count = count + 1
@@ -318,31 +343,38 @@ class DockArea(QtWidgets.QMainWindow):
def modelicaEditor(self, projDir):
"""This function sets up the UI for ngspice to modelica conversion."""
global count
+
+ projName = os.path.basename(projDir)
+ dockName = f'Modelica-{projName}-'
+
self.modelicaWidget = QtWidgets.QWidget()
self.modelicaLayout = QtWidgets.QVBoxLayout()
self.modelicaLayout.addWidget(OpenModelicaEditor(projDir))
self.modelicaWidget.setLayout(self.modelicaLayout)
- dock['Modelica-' + str(count)
- ] = QtWidgets.QDockWidget('Modelica-' + str(count))
- dock['Modelica-' + str(count)].setWidget(self.modelicaWidget)
+ dock[dockName + str(count)
+ ] = QtWidgets.QDockWidget(dockName + str(count))
+ dock[dockName + str(count)] \
+ .setWidget(self.modelicaWidget)
self.addDockWidget(QtCore.Qt.TopDockWidgetArea,
- dock['Modelica-' + str(count)])
- self.tabifyDockWidget(dock['Welcome'], dock['Modelica-' + str(count)])
+ dock[dockName
+ + str(count)])
+ self.tabifyDockWidget(dock['Welcome'], dock[dockName
+ + str(count)])
- dock['Modelica-' + str(count)].setVisible(True)
- dock['Modelica-' + str(count)].setFocus()
- dock['Modelica-' + str(count)].raise_()
+ dock[dockName + str(count)].setVisible(True)
+ dock[dockName + str(count)].setFocus()
+ dock[dockName + str(count)].raise_()
# CSS
- dock['Modelica-' + str(count)].setStyleSheet(" \
+ dock[dockName + str(count)].setStyleSheet(" \
.QWidget { border-radius: 15px; border: 1px solid gray;\
padding: 5px; width: 200px; height: 150px; } \
")
temp = self.obj_appconfig.current_project['ProjectName']
if temp:
self.obj_appconfig.dock_dict[temp].append(
- dock['Modelica-' + str(count)]
+ dock[dockName + str(count)]
)
count = count + 1
diff --git a/src/frontEnd/TerminalUi.py b/src/frontEnd/TerminalUi.py
new file mode 100644
index 00000000..4c53548f
--- /dev/null
+++ b/src/frontEnd/TerminalUi.py
@@ -0,0 +1,143 @@
+from PyQt5 import QtCore, QtGui, QtWidgets, uic
+import os
+
+
+class TerminalUi(QtWidgets.QMainWindow):
+ """This is a class that represents the GUI required to provide
+ details regarding the ngspice simulation. This GUI consists of
+ a progress bar, a console window which displays the log of the
+ simulation and button required for re-simulation and cancellation
+ of the simulation"""
+ def __init__(self, qProcess, args):
+ """The constructor of the TerminalUi class
+ param: qProcess: a PyQt QProcess that runs ngspice
+ type: qProcess: :class:`QtCore.QProcess`
+ param: args: arguments to be passed on to the ngspice call
+ type: args: list
+ """
+ super(TerminalUi, self).__init__()
+
+ # Other variables
+ self.darkColor = True
+ self.qProcess = qProcess
+ self.args = args
+ self.iconDir = "../../images"
+
+ # Load the ui file
+ uic.loadUi("TerminalUi.ui", self)
+
+ # Define Our Widgets
+ self.progressBar = self.findChild(
+ QtWidgets.QProgressBar,
+ "progressBar"
+ )
+ self.simulationConsole = self.findChild(
+ QtWidgets.QTextEdit,
+ "simulationConsole"
+ )
+
+ self.lightDarkModeButton = self.findChild(
+ QtWidgets.QPushButton,
+ "lightDarkModeButton"
+ )
+ self.cancelSimulationButton = self.findChild(
+ QtWidgets.QPushButton,
+ "cancelSimulationButton"
+ )
+ self.cancelSimulationButton.setEnabled(True)
+
+ self.redoSimulationButton = self.findChild(
+ QtWidgets.QPushButton,
+ "redoSimulationButton"
+ )
+ self.redoSimulationButton.setEnabled(False)
+
+ # Add functionalities to Widgets
+ self.lightDarkModeButton.setIcon(
+ QtGui.QIcon(
+ os.path.join(
+ self.iconDir,
+ 'light_mode.png'
+ )
+ )
+ )
+ self.lightDarkModeButton.clicked.connect(self.changeColor)
+ self.cancelSimulationButton.clicked.connect(self.cancelSimulation)
+ self.redoSimulationButton.clicked.connect(self.redoSimulation)
+
+ self.simulationCancelled = False
+ self.show()
+
+ def cancelSimulation(self):
+ """This function cancels the ongoing ngspice simulation.
+ """
+ self.cancelSimulationButton.setEnabled(False)
+ self.redoSimulationButton.setEnabled(True)
+
+ if (self.qProcess.state() == QtCore.QProcess.NotRunning):
+ return
+
+ self.simulationCancelled = True
+ self.qProcess.kill()
+
+ # To show progressBar completed
+ self.progressBar.setMaximum(100)
+ self.progressBar.setProperty("value", 100)
+
+ cancelFormat = '<span style="color:#FF8624; font-size:26px;">{}</span>'
+ self.simulationConsole.append(
+ cancelFormat.format("Simulation Cancelled!"))
+ self.simulationConsole.verticalScrollBar().setValue(
+ self.simulationConsole.verticalScrollBar().maximum()
+ )
+
+ def redoSimulation(self):
+ """This function reruns the ngspice simulation
+ """
+ self.cancelSimulationButton.setEnabled(True)
+ self.redoSimulationButton.setEnabled(False)
+
+ if (self.qProcess.state() != QtCore.QProcess.NotRunning):
+ return
+
+ # To make the progressbar running
+ self.progressBar.setMaximum(0)
+ self.progressBar.setProperty("value", -1)
+
+ self.simulationConsole.setText("")
+ self.simulationCancelled = False
+
+ self.qProcess.start('ngspice', self.args)
+
+ def changeColor(self):
+ """Toggles the :class:`Ui_Form` console between dark mode
+ and light mode
+ """
+ if self.darkColor is True:
+ self.simulationConsole.setStyleSheet("QTextEdit {\n \
+ background-color: white;\n \
+ color: black;\n \
+ }")
+ self.lightDarkModeButton.setIcon(
+ QtGui.QIcon(
+ os.path.join(
+ self.iconDir,
+ "dark_mode.png"
+ )
+ )
+ )
+ self.darkColor = False
+ else:
+ self.simulationConsole.setStyleSheet("QTextEdit {\n \
+ background-color: rgb(36, 31, 49);\n \
+ color: white;\n \
+ }")
+ self.lightDarkModeButton.setIcon(
+ QtGui.QIcon(
+ os.path.join(
+ self.iconDir,
+ "light_mode.png"
+ )
+ )
+ )
+ self.darkColor = True
diff --git a/src/frontEnd/TerminalUi.ui b/src/frontEnd/TerminalUi.ui
new file mode 100644
index 00000000..9039984d
--- /dev/null
+++ b/src/frontEnd/TerminalUi.ui
@@ -0,0 +1,163 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>TerminalUi</class>
+ <widget class="QWidget" name="TerminalUi">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>1244</width>
+ <height>644</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <widget class="QWidget" name="verticalLayoutWidget">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>10</y>
+ <width>1131</width>
+ <height>471</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetDefaultConstraint</enum>
+ </property>
+ <property name="leftMargin">
+ <number>15</number>
+ </property>
+ <property name="topMargin">
+ <number>15</number>
+ </property>
+ <property name="rightMargin">
+ <number>15</number>
+ </property>
+ <property name="bottomMargin">
+ <number>15</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QProgressBar" name="progressBar">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>35</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">QProgressBar::chunk {
+ background-color: rgb(54,158,225);
+}</string>
+ </property>
+ <property name="maximum">
+ <number>0</number>
+ </property>
+ <property name="value">
+ <number>-1</number>
+ </property>
+ <property name="format">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="redoSimulationButton">
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>35</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Resimulate</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="cancelSimulationButton">
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>35</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Cancel Simulation</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="lightDarkModeButton">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>35</width>
+ <height>35</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QTextEdit" name="simulationConsole">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>400</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">QTextEdit {
+ background-color: rgb(36, 31, 49);
+ color: white;
+}</string>
+ </property>
+ <property name="html">
+ <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::NoTextInteraction</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/kicadtoNgspice/Convert.py b/src/kicadtoNgspice/Convert.py
index 566182e0..66f8a7c0 100755
--- a/src/kicadtoNgspice/Convert.py
+++ b/src/kicadtoNgspice/Convert.py
@@ -1,9 +1,11 @@
-from PyQt5 import QtWidgets
import os
import shutil
-from . import TrackWidget
from xml.etree import ElementTree as ET
+from PyQt5 import QtWidgets
+
+from . import TrackWidget
+
class Convert:
"""
@@ -67,9 +69,8 @@ class Convert:
theta_val = str(self.entry_var[self.end].text()) if len(
str(self.entry_var[self.end].text())) > 0 else '0'
self.addline = self.addline.partition(
- '(')[0] + "(" + vo_val + " " + va_val + " " +\
- freq_val + " " + td_val + " " +\
- theta_val + ")"
+ '(')[0] + "(" + vo_val + " " + va_val + " " + \
+ freq_val + " " + td_val + " " + theta_val + ")"
self.sourcelistvalue.append([self.index, self.addline])
except BaseException:
print(
@@ -102,8 +103,8 @@ class Convert:
str(self.entry_var[self.end].text())) > 0 else '0'
self.addline = self.addline.partition(
- '(')[0] + "(" + v1_val + " " + v2_val + " " +\
- td_val + " " + tr_val + " " + tf_val + " " +\
+ '(')[0] + "(" + v1_val + " " + v2_val + " " + \
+ td_val + " " + tr_val + " " + tf_val + " " + \
pw_val + " " + tp_val + ")"
self.sourcelistvalue.append([self.index, self.addline])
except BaseException:
@@ -183,8 +184,8 @@ class Convert:
str(self.entry_var[self.end].text())) > 0 else '0'
self.addline = self.addline.partition(
- '(')[0] + "(" + v1_val + " " + v2_val + " " +\
- td1_val + " " + tau1_val + " " + td2_val +\
+ '(')[0] + "(" + v1_val + " " + v2_val + " " + \
+ td1_val + " " + tau1_val + " " + td2_val + \
" " + tau2_val + ")"
self.sourcelistvalue.append([self.index, self.addline])
except BaseException:
@@ -403,18 +404,21 @@ class Convert:
if num_turns2 == "":
num_turns2 = "620"
addmodelLine = ".model " + \
- line[3] + \
- "_primary lcouple (num_turns= " + num_turns + ")"
+ line[3] + \
+ "_primary lcouple (num_turns= " + \
+ num_turns + ")"
modelParamValue.append(
[line[0], addmodelLine, "*primary lcouple"])
addmodelLine = ".model " + \
- line[3] + "_iron_core core (" + bh_array + \
- " area = " + area + " length =" + length + ")"
+ line[3] + "_iron_core core (" + bh_array + \
+ " area = " + area + " length =" + length + \
+ ")"
modelParamValue.append(
[line[0], addmodelLine, "*iron core"])
addmodelLine = ".model " + \
- line[3] + \
- "_secondary lcouple (num_turns =" + num_turns2 + ")"
+ line[3] + \
+ "_secondary lcouple (num_turns =" + \
+ num_turns2 + ")"
modelParamValue.append(
[line[0], addmodelLine, "*secondary lcouple"])
except Exception as e:
@@ -456,8 +460,8 @@ class Convert:
default = 0
# Checking if value is iterable.its for vector
if (
- not isinstance(value, str) and
- hasattr(value, '__iter__')
+ not isinstance(value, str) and
+ hasattr(value, '__iter__')
):
addmodelLine += param + "=["
for lineVar in value:
@@ -500,6 +504,122 @@ class Convert:
return schematicInfo
+ def addMicrocontrollerParameter(self, schematicInfo):
+ """
+ This function adds the Microcontroller Model details to schematicInfo
+ """
+
+ # Create object of TrackWidget
+ self.obj_track = TrackWidget.TrackWidget()
+
+ # List to store model line
+ addmodelLine = []
+ modelParamValue = []
+
+ for line in self.obj_track.microcontrollerTrack:
+ # print "Model Track :",line
+ try:
+ start = line[7]
+ # end = line[8]
+ addmodelLine = ".model " + line[3] + " " + line[2] + "("
+ z = 0
+ for key, value in line[9].items():
+ # Checking for default value and accordingly assign
+ # param and default.
+ if ':' in key:
+ key = key.split(':')
+ param = key[0]
+ default = key[1]
+ else:
+ param = key
+ default = 0
+ # Checking if value is iterable.its for vector
+ if (
+ not isinstance(value, str) and
+ hasattr(value, '__iter__')
+ ):
+ addmodelLine += param + "=["
+ for lineVar in value:
+ if str(
+ self.obj_track.microcontroller_var
+ [lineVar].text()) == "":
+ paramVal = default
+ else:
+ paramVal = str(
+ self.obj_track.microcontroller_var
+ [lineVar].text())
+ # Checks For 5th Parameter(Hex File Path)
+ if z == 4:
+ chosen_file_path = paramVal
+ star_file_path = chosen_file_path
+ star_count = 0
+ for c in chosen_file_path:
+ # If character is uppercase
+ if c.isupper():
+ c_in = chosen_file_path.index(c)
+ c_in += star_count
+ # Adding asterisks(*) to the path
+ # around the character
+ star_file_path = \
+ star_file_path[
+ :c_in] + "*" + star_file_path[
+ c_in] + "**" + star_file_path[
+ c_in + 1:]
+ star_count += 3
+
+ paramVal = "\"" + star_file_path + "\""
+
+ addmodelLine += paramVal + " "
+ z = z + 1
+ addmodelLine += "] "
+ else:
+ if str(
+ self.obj_track.microcontroller_var
+ [value].text()) == "":
+ paramVal = default
+ else:
+ paramVal = str(
+ self.obj_track.microcontroller_var
+ [value].text())
+ # Checks For 5th Parameter(Hex File Path)
+ if z == 4:
+ chosen_file_path = paramVal
+ star_file_path = chosen_file_path
+ star_count = 0
+ for c in chosen_file_path:
+ # If character is uppercase
+ if c.isupper():
+ c_in = chosen_file_path.index(c)
+ c_in += star_count
+ # Adding asterisks(*) to the path around
+ # the character
+ star_file_path = \
+ star_file_path[:c_in] + "*" + \
+ star_file_path[c_in] + "**" + \
+ star_file_path[c_in + 1:]
+ star_count += 3
+
+ paramVal = "\"" + star_file_path + "\""
+ z = z + 1
+ addmodelLine += param + "=" + paramVal + " "
+
+ addmodelLine += ") "
+ modelParamValue.append([line[0], addmodelLine, line[4]])
+ except Exception as e:
+ print("Caught an exception in microcontroller ", line[1])
+ print("Exception Message : ", str(e))
+
+ # Adding it to schematic
+ for item in modelParamValue:
+ if ".ic" in item[1]:
+ schematicInfo.insert(0, item[1])
+ schematicInfo.insert(0, item[2])
+ else:
+ schematicInfo.append(item[2]) # Adding Comment
+ schematicInfo.append(item[1]) # Adding model line
+
+ return schematicInfo
+
def addDeviceLibrary(self, schematicInfo, kicadFile):
"""
This function add the library details to schematicInfo
diff --git a/src/kicadtoNgspice/DeviceModel.py b/src/kicadtoNgspice/DeviceModel.py
index 7fb9776e..ccbe8986 100755
--- a/src/kicadtoNgspice/DeviceModel.py
+++ b/src/kicadtoNgspice/DeviceModel.py
@@ -15,6 +15,8 @@ class DeviceModel(QtWidgets.QWidget):
- d DIODE
- j JFET
- m MOSFET
+ - s SWITCH
+ - tx single lossy transmission line
- Other 2 functions same as the ones in subCircuit
- trackLibrary
- trackLibraryWithoutButton
@@ -436,6 +438,131 @@ class DeviceModel(QtWidgets.QWidget):
self.grid.addWidget(jfetbox)
# Adding Device Details #
+ # Increment row and widget count
+ self.row = self.row + 1
+ self.devicemodel_dict_end[words[0]] = self.count
+ self.count = self.count + 1
+
+ elif eachline[0] == 's':
+ # print("Device Model Switch:", words[0])
+ self.devicemodel_dict_beg[words[0]] = self.count
+ switchbox = QtWidgets.QGroupBox()
+ switchgrid = QtWidgets.QGridLayout()
+ switchbox.setTitle(
+ "Add library for Switch " +
+ words[0] +
+ " : " +
+ words[5])
+ self.entry_var[self.count] = QtWidgets.QLineEdit()
+ self.entry_var[self.count].setText("")
+ # global path_name
+ try:
+ for child in root:
+ if child.tag == words[0]:
+ # print("DEVICE MODEL MATCHING---", \
+ # child.tag, words[0])
+ try:
+ if child[0].text \
+ and os.path.exists(child[0].text):
+ path_name = child[0].text
+ self.entry_var[self.count] \
+ .setText(child[0].text)
+ else:
+ self.entry_var[self.count].setText("")
+ except BaseException as e:
+ print("Error when set text of device " +
+ "model switch :", str(e))
+ except BaseException:
+ pass
+
+ switchgrid.addWidget(self.entry_var[self.count], self.row, 1)
+ self.addbtn = QtWidgets.QPushButton("Add")
+ self.addbtn.setObjectName("%d" % self.count)
+ self.addbtn.clicked.connect(self.trackLibrary)
+ self.deviceDetail[self.count] = words[0]
+
+ if self.entry_var[self.count].text() == "":
+ pass
+ else:
+ self.trackLibraryWithoutButton(self.count, path_name)
+
+ switchgrid.addWidget(self.addbtn, self.row, 2)
+ switchbox.setLayout(switchgrid)
+
+ # CSS
+ switchbox.setStyleSheet(" \
+ QGroupBox { border: 1px solid gray; border-radius: \
+ 9px; margin-top: 0.5em; } \
+ QGroupBox::title { subcontrol-origin: margin; left:\
+ 10px; padding: 0 3px 0 3px; } \
+ ")
+
+ self.grid.addWidget(switchbox)
+
+ # Adding Device Details #
+
+ # Increment row and widget count
+ self.row = self.row + 1
+ self.devicemodel_dict_end[words[0]] = self.count
+ self.count = self.count + 1
+
+ elif eachline[0] == 'ytxl':
+ # print("Device Model ymod:", words[0])
+ self.devicemodel_dict_beg[words[0]] = self.count
+ ymodbox = QtWidgets.QGroupBox()
+ ymodgrid = QtWidgets.QGridLayout()
+ ymodbox.setTitle(
+ "Add library for ymod " +
+ words[0] +
+ " : " +
+ words[4])
+ self.entry_var[self.count] = QtWidgets.QLineEdit()
+ self.entry_var[self.count].setText("")
+ # global path_name
+ try:
+ for child in root:
+ if child.tag == words[0]:
+ # print("DEVICE MODEL MATCHING---", \
+ # child.tag, words[0])
+ try:
+ if child[0].text \
+ and os.path.exists(child[0].text):
+ path_name = child[0].text
+ self.entry_var[self.count] \
+ .setText(child[0].text)
+ else:
+ self.entry_var[self.count].setText("")
+ except BaseException as e:
+ print("Error when set text of device " +
+ "model ymod :", str(e))
+ except BaseException:
+ pass
+
+ ymodgrid.addWidget(self.entry_var[self.count], self.row, 1)
+ self.addbtn = QtWidgets.QPushButton("Add")
+ self.addbtn.setObjectName("%d" % self.count)
+ self.addbtn.clicked.connect(self.trackLibrary)
+ self.deviceDetail[self.count] = words[0]
+
+ if self.entry_var[self.count].text() == "":
+ pass
+ else:
+ self.trackLibraryWithoutButton(self.count, path_name)
+
+ ymodgrid.addWidget(self.addbtn, self.row, 2)
+ ymodbox.setLayout(ymodgrid)
+
+ # CSS
+ ymodbox.setStyleSheet(" \
+ QGroupBox { border: 1px solid gray; border-radius: \
+ 9px; margin-top: 0.5em; } \
+ QGroupBox::title { subcontrol-origin: margin; left:\
+ 10px; padding: 0 3px 0 3px; } \
+ ")
+
+ self.grid.addWidget(ymodbox)
+
+ # Adding Device Details #
# Increment row and widget count
self.row = self.row + 1
@@ -443,6 +570,7 @@ class DeviceModel(QtWidgets.QWidget):
self.count = self.count + 1
elif eachline[0] == 'm':
+
self.devicemodel_dict_beg[words[0]] = self.count
mosfetbox = QtWidgets.QGroupBox()
mosfetgrid = QtWidgets.QGridLayout()
@@ -452,7 +580,7 @@ class DeviceModel(QtWidgets.QWidget):
"Add library for MOSFET " +
words[0] +
" : " +
- words[5])
+ words[4])
self.entry_var[self.count] = QtWidgets.QLineEdit()
self.entry_var[self.count].setText("")
self.entry_var[self.count].setReadOnly(True)
@@ -512,12 +640,12 @@ class DeviceModel(QtWidgets.QWidget):
# print("DEVICE MODEL MATCHING---", \
# child.tag, words[0])
while i <= end:
- self.entry_var[i].setText(child[i-beg].text)
+ self.entry_var[i].setText(child[i - beg].text)
if (i - beg) == 0:
if os.path.exists(child[0].text):
self.entry_var[i] \
- .setText(child[i-beg].text)
- path_name = child[i-beg].text
+ .setText(child[i - beg].text)
+ path_name = child[i - beg].text
else:
self.entry_var[i].setText("")
i = i + 1
diff --git a/src/kicadtoNgspice/KicadtoNgspice.py b/src/kicadtoNgspice/KicadtoNgspice.py
index 231efd52..e018143f 100644
--- a/src/kicadtoNgspice/KicadtoNgspice.py
+++ b/src/kicadtoNgspice/KicadtoNgspice.py
@@ -13,21 +13,24 @@
# MODIFIED: Rahul Paknikar, rahulp@iitb.ac.in
# ORGANIZATION: eSim Team at FOSSEE, IIT Bombay
# CREATED: Wednesday 04 March 2015
-# REVISION: Sunday 18 September 2022
+# REVISION: Tuesday 25 April 2023
# =========================================================================
-import sys
import os
+import sys
+from xml.etree import ElementTree as ET
+
from PyQt5 import QtWidgets
-from .Processing import PrcocessNetlist
+
from . import Analysis
-from . import Source
-from . import Model
+from . import Convert
from . import DeviceModel
+from . import Model
+from . import Microcontroller
+from . import Source
from . import SubcircuitTab
-from . import Convert
from . import TrackWidget
-from xml.etree import ElementTree as ET
+from .Processing import PrcocessNetlist
class MainWindow(QtWidgets.QWidget):
@@ -93,10 +96,11 @@ class MainWindow(QtWidgets.QWidget):
schematicInfo, sourcelist)
# List storing model detail
- global modelList, outputOption,\
- unknownModelList, multipleModelList, plotText
+ global modelList, outputOption, unknownModelList, multipleModelList, \
+ plotText, microcontrollerList
modelList = []
+ microcontrollerList = []
outputOption = []
plotText = []
(
@@ -109,8 +113,10 @@ class MainWindow(QtWidgets.QWidget):
) = obj_proc.convertICintoBasicBlocks(
schematicInfo, outputOption, modelList, plotText
)
- # print("=======================================")
- # print("Model available in the Schematic :", modelList)
+ for line in modelList:
+ if line[6] == "Nghdl":
+ microcontrollerList.append(line)
+ modelList.remove(line)
"""
- Checking if any unknown model is used in schematic which is not
@@ -124,7 +130,7 @@ class MainWindow(QtWidgets.QWidget):
self.msg.setModal(True)
self.msg.setWindowTitle("Unknown Models")
self.content = "Your schematic contain unknown model " + \
- ', '.join(unknownModelList)
+ ', '.join(unknownModelList)
self.msg.showMessage(self.content)
self.msg.exec_()
@@ -134,7 +140,7 @@ class MainWindow(QtWidgets.QWidget):
self.msg.setWindowTitle("Multiple Models")
self.mcontent = "Look like you have duplicate model in \
modelParamXML directory " + \
- ', '.join(multipleModelList[0])
+ ', '.join(multipleModelList[0])
self.msg.showMessage(self.mcontent)
self.msg.exec_()
@@ -179,6 +185,9 @@ class MainWindow(QtWidgets.QWidget):
- Subcircuits => obj_subcircuitTab
=> SubcircuitTab.SubcircuitTab(`schematicInfo`,`path_to_projFile`)
+ - Microcontrollers => obj_microcontroller
+ => Model.Model(schematicInfo, microcontrollerList, self.clarg1)
+
- Finally pass each of these objects, to widgets
- convertWindow > mainLayout > tabWidgets > AnalysisTab, SourceTab ...
"""
@@ -213,6 +222,12 @@ class MainWindow(QtWidgets.QWidget):
schematicInfo, self.clarg1)
self.subcircuitTab.setWidget(obj_subcircuitTab)
self.subcircuitTab.setWidgetResizable(True)
+ global obj_microcontroller
+ self.microcontrollerTab = QtWidgets.QScrollArea()
+ obj_microcontroller = Microcontroller.\
+ Microcontroller(schematicInfo, microcontrollerList, self.clarg1)
+ self.microcontrollerTab.setWidget(obj_microcontroller)
+ self.microcontrollerTab.setWidgetResizable(True)
self.tabWidget = QtWidgets.QTabWidget()
# self.tabWidget.TabShape(QtWidgets.QTabWidget.Rounded)
@@ -221,6 +236,7 @@ class MainWindow(QtWidgets.QWidget):
self.tabWidget.addTab(self.modelTab, "Ngspice Model")
self.tabWidget.addTab(self.deviceModelTab, "Device Modeling")
self.tabWidget.addTab(self.subcircuitTab, "Subcircuits")
+ self.tabWidget.addTab(self.microcontrollerTab, "Microcontroller")
self.mainLayout = QtWidgets.QVBoxLayout()
self.mainLayout.addWidget(self.tabWidget)
# self.mainLayout.addStretch(1)
@@ -247,9 +263,9 @@ class MainWindow(QtWidgets.QWidget):
try:
fr = open(
- os.path.join(
- projpath, project_name + "_Previous_Values.xml"), 'r'
- )
+ os.path.join(
+ projpath, project_name + "_Previous_Values.xml"), 'r'
+ )
temp_tree = ET.parse(fr)
temp_root = temp_tree.getroot()
except BaseException:
@@ -552,7 +568,8 @@ class MainWindow(QtWidgets.QWidget):
for grand_child in child:
if i <= end:
grand_child.text = \
- str(obj_model.obj_trac.model_entry_var[i].text())
+ str(obj_model.obj_trac.model_entry_var[
+ i].text())
i = i + 1
tmp_check = 1
@@ -568,16 +585,16 @@ class MainWindow(QtWidgets.QWidget):
ET.SubElement(
attr_ui, "field" + str(i + 1), name=item
).text = str(
- obj_model.obj_trac.model_entry_var[i].text()
- )
+ obj_model.obj_trac.model_entry_var[i].text()
+ )
i = i + 1
else:
ET.SubElement(
attr_ui, "field" + str(i + 1), name=value
).text = str(
- obj_model.obj_trac.model_entry_var[i].text()
- )
+ obj_model.obj_trac.model_entry_var[i].text()
+ )
i = i + 1
# Writing Device Model values
@@ -596,7 +613,7 @@ class MainWindow(QtWidgets.QWidget):
while it <= end:
ET.SubElement(attr_var, "field").text = \
- str(obj_devicemodel.entry_var[it].text())
+ str(obj_devicemodel.entry_var[it].text())
it = it + 1
# Writing Subcircuit values
@@ -615,9 +632,70 @@ class MainWindow(QtWidgets.QWidget):
while it <= end:
ET.SubElement(attr_var, "field").text = \
- str(obj_subcircuitTab.entry_var[it].text())
+ str(obj_subcircuitTab.entry_var[it].text())
it = it + 1
+ # Writing for Microcontroller
+ if check == 0:
+ attr_microcontroller = ET.SubElement(attr_parent,
+ "microcontroller")
+ if check == 1:
+ for child in attr_parent:
+ if child.tag == "microcontroller":
+ attr_microcontroller = child
+ i = 0
+
+ # tmp_check is a variable to check for duplicates in the xml file
+ tmp_check = 0
+ # tmp_i is the iterator in case duplicates are there;
+ # then in that case we need to replace only the child node and
+ # not create a new parent node
+
+ for line in microcontrollerList:
+ tmp_check = 0
+ for rand_itr in obj_microcontroller.obj_trac.microcontrollerTrack:
+ if rand_itr[2] == line[2] and rand_itr[3] == line[3]:
+ start = rand_itr[7]
+ end = rand_itr[8]
+
+ i = start
+ for child in attr_microcontroller:
+ if child.text == line[2] and child.tag == line[3]:
+ for grand_child in child:
+ if i <= end:
+ grand_child.text = \
+ str(
+ obj_microcontroller.
+ obj_trac.microcontroller_var[i].text())
+ i = i + 1
+ tmp_check = 1
+
+ if tmp_check == 0:
+ attr_ui = ET.SubElement(attr_microcontroller, line[3],
+ name="type")
+ attr_ui.text = line[2]
+ for key, value in line[7].items():
+ if (
+ hasattr(value, '__iter__') and
+ i <= end and not isinstance(value, str)
+ ):
+ for item in value:
+ ET.SubElement(
+ attr_ui, "field" + str(i + 1), name=item
+ ).text = str(
+ obj_microcontroller.
+ obj_trac.microcontroller_var[i].text()
+ )
+ i = i + 1
+ else:
+ ET.SubElement(
+ attr_ui, "field" + str(i + 1), name=value
+ ).text = str(
+ obj_microcontroller.obj_trac.microcontroller_var[
+ i].text()
+ )
+ i = i + 1
+
# xml written to previous value file for the project
tree = ET.ElementTree(attr_parent)
tree.write(fw)
@@ -650,6 +728,12 @@ class MainWindow(QtWidgets.QWidget):
print("=========================================================")
print("Netlist After Adding Ngspice Model :", store_schematicInfo)
+ store_schematicInfo = self.obj_convert.addMicrocontrollerParameter(
+ store_schematicInfo)
+ print("=========================================================")
+ print("Netlist After Adding Microcontroller Model :",
+ store_schematicInfo)
+
# Adding Device Library to SchematicInfo
store_schematicInfo = self.obj_convert.addDeviceLibrary(
store_schematicInfo, self.kicadFile)
@@ -761,14 +845,14 @@ class MainWindow(QtWidgets.QWidget):
words = eachline.split()
option = words[0]
if (option == '.ac' or option == '.dc' or option ==
- '.disto' or option == '.noise' or
- option == '.op' or option == '.pz' or option ==
- '.sens' or option == '.tf' or
+ '.disto' or option == '.noise' or
+ option == '.op' or option == '.pz' or option ==
+ '.sens' or option == '.tf' or
option == '.tran'):
analysisOption.append(eachline + '\n')
elif (option == '.save' or option == '.print' or option ==
- '.plot' or option == '.four'):
+ '.plot' or option == '.four'):
eachline = eachline.strip('.')
outputOption.append(eachline + '\n')
elif (option == '.nodeset' or option == '.ic'):
diff --git a/src/kicadtoNgspice/Microcontroller.py b/src/kicadtoNgspice/Microcontroller.py
new file mode 100644
index 00000000..a9360147
--- /dev/null
+++ b/src/kicadtoNgspice/Microcontroller.py
@@ -0,0 +1,283 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+import os
+import random
+from configparser import ConfigParser
+from xml.etree import ElementTree as ET
+
+from PyQt5 import QtWidgets, QtCore
+
+from . import TrackWidget
+
+
+# Created By Vatsal Patel on 01/07/2022
+
+class Microcontroller(QtWidgets.QWidget):
+ """
+ - This class creates Model Tab of KicadtoNgspice window.
+ The widgets are created dynamically in the Model Tab.
+ """
+
+ def addHex(self):
+ """
+ This function is use to keep track of all Device Model widget
+ """
+ if os.name == 'nt':
+ self.home = os.path.join('library', 'config')
+ else:
+ self.home = os.path.expanduser('~')
+
+ self.parser = ConfigParser()
+ self.parser.read(os.path.join(
+ self.home, os.path.join('.nghdl', 'config.ini')))
+ self.nghdl_home = self.parser.get('NGHDL', 'NGHDL_HOME')
+
+ self.hexfile = QtCore.QDir.toNativeSeparators(
+ QtWidgets.QFileDialog.getOpenFileName(
+ self, "Open Hex Directory", os.path.expanduser('~'),
+ "HEX files (*.hex);;Text files (*.txt)"
+ )[0]
+ )
+
+ if not self.hexfile:
+ """If no path is selected by user function returns"""
+ return
+
+ chosen_file_path = os.path.abspath(self.hexfile)
+ btn = self.sender()
+
+ # If path is selected the clicked button is stored in btn variable and
+ # checked from list of buttons to add the file path to correct
+ # QLineEdit
+
+ if btn in self.hex_btns:
+ if "Add Hex File" in self.sender().text():
+ self.obj_trac.microcontroller_var[
+ 4 + (5 * self.hex_btns.index(btn))].setText(
+ chosen_file_path)
+
+ def __init__(
+ self,
+ schematicInfo,
+ modelList,
+ clarg1,
+ ):
+
+ QtWidgets.QWidget.__init__(self)
+
+ # Processing for getting previous values
+
+ kicadFile = clarg1
+ (projpath, filename) = os.path.split(kicadFile)
+ project_name = os.path.basename(projpath)
+ check = 1
+ try:
+ f = open(
+ os.path.join(projpath, project_name + "_Previous_Values.xml"),
+ "r",
+ )
+ tree = ET.parse(f)
+ parent_root = tree.getroot()
+ for parent in parent_root:
+ if parent.tag == "microcontroller":
+ self.root = parent
+ except BaseException:
+
+ check = 0
+ print("Microcontroller Previous Values XML is Empty")
+
+ # Creating track widget object
+
+ self.obj_trac = TrackWidget.TrackWidget()
+
+ # for increasing row and counting/tracking line edit widget
+
+ self.nextrow = 0
+ self.nextcount = 0
+
+ # for storing line edit details position details
+
+ self.start = 0
+ self.end = 0
+ self.entry_var = []
+ self.hex_btns = []
+ self.text = ""
+
+ # Creating GUI dynamically for Model tab
+
+ self.grid = QtWidgets.QGridLayout()
+ self.setLayout(self.grid)
+
+ for line in modelList:
+ # print "ModelList Item:",line
+ # Adding title label for model
+ # Key: Tag name,Value:Entry widget number
+
+ tag_dict = {}
+ modelbox = QtWidgets.QGroupBox()
+ modelgrid = QtWidgets.QGridLayout()
+ modelbox.setTitle(line[5])
+ self.start = self.nextcount
+
+ # line[7] is parameter dictionary holding parameter tags.
+
+ i = 0
+ for (key, value) in line[7].items():
+ # Check if value is iterable
+
+ if not isinstance(value, str) and hasattr(value, "__iter__"):
+
+ # For tag having vector value
+
+ temp_tag = []
+ for item in value:
+
+ paramLabel = QtWidgets.QLabel(item)
+ modelgrid.addWidget(paramLabel, self.nextrow, 0)
+ self.obj_trac.microcontroller_var[
+ self.nextcount
+ ] = QtWidgets.QLineEdit()
+ self.obj_trac.microcontroller_var[
+ self.nextcount] = QtWidgets.QLineEdit()
+ self.obj_trac.microcontroller_var[
+ self.nextcount].setText("")
+
+ if "Enter Instance ID (Between 0-99)" in value:
+ self.obj_trac.microcontroller_var[
+ self.nextcount].hide()
+ self.obj_trac.microcontroller_var[
+ self.nextcount].setText(
+ str(random.randint(0, 99)))
+ else:
+ modelgrid.addWidget(paramLabel, self.nextrow, 0)
+
+ if "Path of your .hex file" in value:
+ self.obj_trac.microcontroller_var[
+ self.nextcount].setReadOnly(True)
+ addbtn = QtWidgets.QPushButton("Add Hex File")
+ addbtn.setObjectName("%d" % self.nextcount)
+ addbtn.clicked.connect(self.addHex)
+ modelgrid.addWidget(addbtn, self.nextrow, 2)
+ modelbox.setLayout(modelgrid)
+ self.hex_btns.append(addbtn)
+ try:
+ for child in root:
+ if (
+ child.text == line[2]
+ and child.tag == line[3]
+ ):
+ self.obj_trac.microcontroller_var[
+ self.nextcount].setText(child[i].text)
+ i = i + 1
+ except BaseException:
+ print("Passes previous values")
+
+ modelgrid.addWidget(
+ self.obj_trac.microcontroller_var[self.nextcount],
+ self.nextrow,
+ 1, )
+
+ temp_tag.append(self.nextcount)
+ self.nextcount = self.nextcount + 1
+ self.nextrow = self.nextrow + 1
+
+ tag_dict[key] = temp_tag
+
+ else:
+
+ paramLabel = QtWidgets.QLabel(value)
+ self.obj_trac.microcontroller_var[
+ self.nextcount
+ ] = QtWidgets.QLineEdit()
+ self.obj_trac.microcontroller_var[
+ self.nextcount] = QtWidgets.QLineEdit()
+ self.obj_trac.microcontroller_var[self.nextcount].setText(
+ "")
+
+ if "Enter Instance ID (Between 0-99)" in value:
+ self.obj_trac.microcontroller_var[
+ self.nextcount].hide()
+ self.obj_trac.microcontroller_var[
+ self.nextcount].setText(str(random.randint(0, 99)))
+ else:
+ modelgrid.addWidget(paramLabel, self.nextrow, 0)
+
+ if "Path of your .hex file" in value:
+ self.obj_trac.microcontroller_var[
+ self.nextcount].setReadOnly(True)
+ addbtn = QtWidgets.QPushButton("Add Hex File")
+ addbtn.setObjectName("%d" % self.nextcount)
+ addbtn.clicked.connect(self.addHex)
+ modelgrid.addWidget(addbtn, self.nextrow, 2)
+ modelbox.setLayout(modelgrid)
+ self.hex_btns.append(addbtn)
+
+ # CSS
+
+ modelbox.setStyleSheet(
+ " \
+ QGroupBox { border: 1px solid gray; border-radius:\
+ 9px; margin-top: 0.5em; } \
+ QGroupBox::title { subcontrol-origin: margin; left:\
+ 10px; padding: 0 3px 0 3px; } \
+ "
+ )
+ self.grid.addWidget(modelbox)
+
+ try:
+ for child in root:
+ if child.text == line[2] and child.tag == line[3]:
+ self.obj_trac.microcontroller_var[
+ self.nextcount].setText(child[i].text)
+ i = i + 1
+
+ except BaseException:
+ print("Passes previous values")
+
+ modelgrid.addWidget(
+ self.obj_trac.microcontroller_var[self.nextcount],
+ self.nextrow,
+ 1, )
+
+ tag_dict[key] = self.nextcount
+ self.nextcount = self.nextcount + 1
+ self.nextrow = self.nextrow + 1
+
+ self.end = self.nextcount - 1
+ modelbox.setLayout(modelgrid)
+
+ # CSS
+
+ modelbox.setStyleSheet(
+ " \
+ QGroupBox { border: 1px solid gray; border-radius: \
+ 9px; margin-top: 0.5em; } \
+ QGroupBox::title { subcontrol-origin: margin; left:\
+ 10px; padding: 0 3px 0 3px; } \
+ "
+ )
+
+ self.grid.addWidget(modelbox)
+
+ # This keeps the track of Microcontroller Tab Widget
+
+ lst = [
+ line[0],
+ line[1],
+ line[2],
+ line[3],
+ line[4],
+ line[5],
+ line[6],
+ self.start,
+ self.end,
+ tag_dict,
+ ]
+ check = 0
+ for itr in self.obj_trac.microcontrollerTrack:
+ if itr == lst:
+ check = 1
+ if check == 0:
+ self.obj_trac.microcontrollerTrack.append(lst)
+
+ self.show()
diff --git a/src/kicadtoNgspice/Model.py b/src/kicadtoNgspice/Model.py
index 75c0eaf5..55a988c0 100644
--- a/src/kicadtoNgspice/Model.py
+++ b/src/kicadtoNgspice/Model.py
@@ -1,69 +1,27 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
-from PyQt5 import QtWidgets, QtCore
-from . import TrackWidget
-from xml.etree import ElementTree as ET
import os
+from xml.etree import ElementTree as ET
+from PyQt5 import QtWidgets
+from . import TrackWidget
-class Model(QtWidgets.QWidget):
+class Model(QtWidgets.QWidget):
"""
- This class creates Model Tab of KicadtoNgspice window.
The widgets are created dynamically in the Model Tab.
"""
-
- # by Sumanto and Jay
- def addHex(self):
- """
- This function is use to keep track of all Device Model widget
- """
-
- # print("Calling Track Device Model Library funtion")
-
- init_path = "../../../"
- if os.name == "nt":
- init_path = ""
-
- self.hexfile = QtCore.QDir.toNativeSeparators(
- QtWidgets.QFileDialog.getOpenFileName(
- self, "Open Hex Directory", init_path + "home", "*.hex"
- )[0]
- )
- self.text = open(self.hexfile).read()
-
- # By Sumanto and Jay
- def uploadHex(self):
- """
- This function is use to keep track of all Device Model widget
- """
-
- # print("Calling Track Device Model Library funtion")
-
- path1 = os.path.expanduser("~")
- path2 = "/ngspice-nghdl/src/xspice/icm/ghdl"
- init_path = path1 + path2
- if os.name == "nt":
- init_path = ""
-
- self.hexloc = QtWidgets.QFileDialog.getExistingDirectory(
- self, "Open Hex Directory", init_path
- )
- self.file = open(self.hexloc + "/hex.txt", "w")
- self.file.write(self.text)
- self.file.close()
-
def __init__(
- self,
- schematicInfo,
- modelList,
- clarg1,
+ self,
+ schematicInfo,
+ modelList,
+ clarg1,
):
QtWidgets.QWidget.__init__(self)
# Processing for getting previous values
-
kicadFile = clarg1
(projpath, filename) = os.path.split(kicadFile)
project_name = os.path.basename(projpath)
@@ -79,33 +37,27 @@ class Model(QtWidgets.QWidget):
if child.tag == "model":
root = child
except BaseException:
-
check = 0
- print("Model Previous Values XML is Empty")
# Creating track widget object
-
self.obj_trac = TrackWidget.TrackWidget()
# for increasing row and counting/tracking line edit widget
-
self.nextrow = 0
self.nextcount = 0
# for storing line edit details position details
-
self.start = 0
self.end = 0
- self.entry_var = {}
+ self.entry_var = []
+ self.hex_btns = []
self.text = ""
# Creating GUI dynamically for Model tab
-
self.grid = QtWidgets.QGridLayout()
self.setLayout(self.grid)
for line in modelList:
-
# print "ModelList Item:",line
# Adding title label for model
# Key: Tag name,Value:Entry widget number
@@ -115,99 +67,79 @@ class Model(QtWidgets.QWidget):
modelgrid = QtWidgets.QGridLayout()
modelbox.setTitle(line[5])
self.start = self.nextcount
+ self.model_name = line[2]
# line[7] is parameter dictionary holding parameter tags.
-
i = 0
for (key, value) in line[7].items():
+ print(value)
+ print(key)
# Check if value is iterable
-
if not isinstance(value, str) and hasattr(value, "__iter__"):
-
# For tag having vector value
-
temp_tag = []
for item in value:
+
paramLabel = QtWidgets.QLabel(item)
modelgrid.addWidget(paramLabel, self.nextrow, 0)
self.obj_trac.model_entry_var[
self.nextcount
] = QtWidgets.QLineEdit()
- modelgrid.addWidget(
- self.obj_trac.model_entry_var[self.nextcount],
- self.nextrow,
- 1,
- )
+
+ self.obj_trac.model_entry_var[
+ self.nextcount] = QtWidgets.QLineEdit()
+ self.obj_trac.model_entry_var[self.nextcount].setText(
+ "")
try:
for child in root:
if (
- child.text == line[2]
- and child.tag == line[3]
+ child.text == line[2]
+ and child.tag == line[3]
):
self.obj_trac.model_entry_var
[self.nextcount].setText(child[i].text)
+ self.entry_var[self.count].setText(
+ child[0].text)
i = i + 1
except BaseException:
pass
+ modelgrid.addWidget(self.entry_var[self.nextcount],
+ self.nextrow, 1)
+
+ modelgrid.addWidget(
+ self.obj_trac.model_entry_var[self.nextcount],
+ self.nextrow,
+ 1, )
temp_tag.append(self.nextcount)
self.nextcount = self.nextcount + 1
self.nextrow = self.nextrow + 1
- if "upload_hex_file:1" in tag_dict:
- self.addbtn = QtWidgets.QPushButton("Add Hex File")
- self.addbtn.setObjectName("%d" % self.nextcount)
- self.addbtn.clicked.connect(self.addHex)
- modelgrid.addWidget(self.addbtn, self.nextrow, 2)
- modelbox.setLayout(modelgrid)
-
- # CSS
-
- modelbox.setStyleSheet(
- " \
- QGroupBox { border: 1px solid gray; border-radius:\
- 9px; margin-top: 0.5em; } \
- QGroupBox::title {subcontrol-origin: margin; left:\
- 10px; padding: 0 3px 0 3px; } \
- "
- )
-
- self.grid.addWidget(modelbox)
- self.addbtn = QtWidgets.QPushButton(
- "Upload Hex File"
- )
- self.addbtn.setObjectName("%d" % self.nextcount)
- self.addbtn.clicked.connect(self.uploadHex)
- modelgrid.addWidget(self.addbtn, self.nextrow, 3)
- modelbox.setLayout(modelgrid)
-
- # CSS
-
- modelbox.setStyleSheet(
- " \
- QGroupBox { border: 1px solid gray; border-radius:\
- 9px; margin-top: 0.5em; } \
- QGroupBox::title {subcontrol-origin: margin; left:\
- 10px; padding: 0 3px 0 3px; } \
- "
- )
-
- self.grid.addWidget(modelbox)
tag_dict[key] = temp_tag
- else:
+ else:
paramLabel = QtWidgets.QLabel(value)
modelgrid.addWidget(paramLabel, self.nextrow, 0)
self.obj_trac.model_entry_var[
self.nextcount
] = QtWidgets.QLineEdit()
- modelgrid.addWidget(
- self.obj_trac.model_entry_var[self.nextcount],
- self.nextrow,
- 1,
+
+ self.obj_trac.model_entry_var[
+ self.nextcount] = QtWidgets.QLineEdit()
+ self.obj_trac.model_entry_var[self.nextcount].setText("")
+
+ # CSS
+ modelbox.setStyleSheet(
+ " \
+ QGroupBox { border: 1px solid gray; border-radius:\
+ 9px; margin-top: 0.5em; } \
+ QGroupBox::title { subcontrol-origin: margin; left:\
+ 10px; padding: 0 3px 0 3px; } \
+ "
)
+ self.grid.addWidget(modelbox)
try:
for child in root:
@@ -215,56 +147,27 @@ class Model(QtWidgets.QWidget):
self.obj_trac.model_entry_var[
self.nextcount
].setText(child[i].text)
+ self.entry_var[self.count].setText(
+ child[0].text)
i = i + 1
except BaseException:
pass
+ modelgrid.addWidget(self.entry_var[self.nextcount],
+ self.nextrow, 1)
+ modelgrid.addWidget(
+ self.obj_trac.model_entry_var[self.nextcount],
+ self.nextrow,
+ 1, )
+
tag_dict[key] = self.nextcount
self.nextcount = self.nextcount + 1
self.nextrow = self.nextrow + 1
- if "upload_hex_file:1" in tag_dict:
- self.addbtn = QtWidgets.QPushButton("Add Hex File")
- self.addbtn.setObjectName("%d" % self.nextcount)
- self.addbtn.clicked.connect(self.addHex)
- modelgrid.addWidget(self.addbtn, self.nextrow, 2)
- modelbox.setLayout(modelgrid)
-
- # CSS
-
- modelbox.setStyleSheet(
- " \
- QGroupBox { border: 1px solid gray; border-radius:\
- 9px; margin-top: 0.5em; } \
- QGroupBox::title { subcontrol-origin: margin; left:\
- 10px; padding: 0 3px 0 3px; } \
- "
- )
-
- self.grid.addWidget(modelbox)
- self.addbtn = QtWidgets.QPushButton("Upload Hex File")
- self.addbtn.setObjectName("%d" % self.nextcount)
- self.addbtn.clicked.connect(self.uploadHex)
- modelgrid.addWidget(self.addbtn, self.nextrow, 3)
- modelbox.setLayout(modelgrid)
-
- # CSS
-
- modelbox.setStyleSheet(
- " \
- QGroupBox { border: 1px solid gray; border-radius:\
- 9px; margin-top: 0.5em; } \
- QGroupBox::title { subcontrol-origin: margin; left:\
- 10px; padding: 0 3px 0 3px; } \
- "
- )
-
- self.grid.addWidget(modelbox)
self.end = self.nextcount - 1
modelbox.setLayout(modelgrid)
# CSS
-
modelbox.setStyleSheet(
" \
QGroupBox { border: 1px solid gray; border-radius: \
@@ -277,7 +180,6 @@ class Model(QtWidgets.QWidget):
self.grid.addWidget(modelbox)
# This keeps the track of Model Tab Widget
-
lst = [
line[0],
line[1],
@@ -298,3 +200,21 @@ class Model(QtWidgets.QWidget):
self.obj_trac.modelTrack.append(lst)
self.show()
+
+ def add_hex_btn(self, modelgrid, modelbox):
+ self.addbtn = QtWidgets.QPushButton("Add Hex File")
+ self.addbtn.setObjectName("%d" % self.nextcount)
+ self.addbtn.clicked.connect(self.addHex)
+ modelgrid.addWidget(self.addbtn, self.nextrow, 2)
+ modelbox.setLayout(modelgrid)
+
+ # CSS
+ modelbox.setStyleSheet(
+ " \
+ QGroupBox { border: 1px solid gray; border-radius:\
+ 9px; margin-top: 0.5em; } \
+ QGroupBox::title { subcontrol-origin: margin; left:\
+ 10px; padding: 0 3px 0 3px; } \
+ "
+ )
+ self.grid.addWidget(modelbox)
diff --git a/src/kicadtoNgspice/Processing.py b/src/kicadtoNgspice/Processing.py
index a0b20ada..11c95965 100644
--- a/src/kicadtoNgspice/Processing.py
+++ b/src/kicadtoNgspice/Processing.py
@@ -408,7 +408,7 @@ class PrcocessNetlist:
# Insert comment at remove line
schematicInfo.insert(index, "* " + compline)
comment = "* Schematic Name:\
- " + compType + ", NgSpice Name: " + modelname
+ " + compType + ", Ngspice Name: " + modelname
# Here instead of adding compType(use for XML),
# added modelName(Unique Model Name)
modelList.append(
diff --git a/src/kicadtoNgspice/TrackWidget.py b/src/kicadtoNgspice/TrackWidget.py
index 3a8b0dac..9f1d07c2 100644
--- a/src/kicadtoNgspice/TrackWidget.py
+++ b/src/kicadtoNgspice/TrackWidget.py
@@ -24,7 +24,9 @@ class TrackWidget:
op_check = []
# Track widget for Model detail
modelTrack = []
+ microcontrollerTrack = []
model_entry_var = {}
+ microcontroller_var = {}
# Track Widget for Device Model detail
deviceModelTrack = {}
diff --git a/src/ngspiceSimulation/NgspiceWidget.py b/src/ngspiceSimulation/NgspiceWidget.py
index 8c63a22a..94368cdd 100644
--- a/src/ngspiceSimulation/NgspiceWidget.py
+++ b/src/ngspiceSimulation/NgspiceWidget.py
@@ -1,58 +1,169 @@
+import os
from PyQt5 import QtWidgets, QtCore
from configuration.Appconfig import Appconfig
-from configparser import ConfigParser
-import os
+from frontEnd import TerminalUi
# This Class creates NgSpice Window
class NgspiceWidget(QtWidgets.QWidget):
- def __init__(self, command, projPath):
+ def __init__(self, netlist, simEndSignal):
"""
- Creates constructor for NgspiceWidget class.
- - Checks whether OS is Linux or Windows and
- creates Ngspice window accordingly.
+ - Creates NgspiceWindow and runs the process
+ - Calls the logs the ngspice process, returns
+ it's simulation status and calls the plotter
+ - Checks whether it is Linux and runs gaw
+ :param netlist: The file .cir.out file that
+ contains the instructions.
+ :type netlist: str
+ :param simEndSignal: A signal that will be emitted to Application class
+ for enabling simulation interaction and plotting data if the
+ simulation is successful
+ :type simEndSignal: PyQt Signal
"""
QtWidgets.QWidget.__init__(self)
self.obj_appconfig = Appconfig()
+ self.projDir = self.obj_appconfig.current_project["ProjectName"]
+ self.args = ['-b', '-r', netlist.replace(".cir.out", ".raw"), netlist]
+ print("Argument to ngspice: ", self.args)
+
self.process = QtCore.QProcess(self)
- self.terminal = QtWidgets.QWidget(self)
+ self.terminalUi = TerminalUi.TerminalUi(self.process, self.args)
self.layout = QtWidgets.QVBoxLayout(self)
- self.layout.addWidget(self.terminal)
-
- print("Argument to ngspice command : ", command)
-
- if os.name == 'nt': # For Windows OS
- parser_nghdl = ConfigParser()
- parser_nghdl.read(
- os.path.join('library', 'config', '.nghdl', 'config.ini')
- )
-
- msys_home = parser_nghdl.get('COMPILER', 'MSYS_HOME')
-
- tempdir = os.getcwd()
- projPath = self.obj_appconfig.current_project["ProjectName"]
- os.chdir(projPath)
- self.command = 'cmd /c '+'"start /min ' + \
- msys_home + "/usr/bin/mintty.exe ngspice -p " + command + '"'
- self.process.start(self.command)
- os.chdir(tempdir)
-
- else: # For Linux OS
- self.command = "cd " + projPath + \
- ";ngspice -r " + command.replace(".cir.out", ".raw") + \
- " " + command
- # Creating argument for process
- self.args = ['-hold', '-e', self.command]
- self.process.start('xterm', self.args)
- self.obj_appconfig.process_obj.append(self.process)
- print(self.obj_appconfig.proc_dict)
- (
- self.obj_appconfig.proc_dict
- [self.obj_appconfig.current_project['ProjectName']].append(
- self.process.pid())
- )
- self.process = QtCore.QProcess(self)
- self.command = "gaw " + command.replace(".cir.out", ".raw")
- self.process.start('sh', ['-c', self.command])
- print(self.command)
+ self.layout.addWidget(self.terminalUi)
+
+ self.process.setWorkingDirectory(self.projDir)
+ self.process.setProcessChannelMode(QtCore.QProcess.MergedChannels)
+ self.process.readyRead.connect(self.readyReadAll)
+ self.process.finished.connect(
+ lambda exitCode, exitStatus:
+ self.finishSimulation(exitCode, exitStatus, simEndSignal, False)
+ )
+ self.process.errorOccurred.connect(
+ lambda: self.finishSimulation(None, None, simEndSignal, True))
+ self.process.start('ngspice', self.args)
+
+ self.obj_appconfig.process_obj.append(self.process)
+ print(self.obj_appconfig.proc_dict)
+ (
+ self.obj_appconfig.proc_dict
+ [self.obj_appconfig.current_project['ProjectName']].append(
+ self.process.pid())
+ )
+
+ if os.name != "nt": # Linux OS
+ self.gawProcess = QtCore.QProcess(self)
+ self.gawCommand = "gaw " + netlist.replace(".cir.out", ".raw")
+ self.gawProcess.start('sh', ['-c', self.gawCommand])
+ print(self.gawCommand)
+
+ @QtCore.pyqtSlot()
+ def readyReadAll(self):
+ """Outputs the ngspice process standard output and standard error
+ to :class:`TerminalUi.TerminalUi` console
+ """
+ self.terminalUi.simulationConsole.insertPlainText(
+ str(self.process.readAllStandardOutput().data(), encoding='utf-8')
+ )
+
+ stderror = str(self.process.readAllStandardError().data(),
+ encoding='utf-8')
+
+ # Suppressing the Ngspice PrinterOnly error that batch mode throws
+ stderror = '\n'.join([errLine for errLine in stderror.split('\n')
+ if ('PrinterOnly' not in errLine and
+ 'viewport for graphics' not in errLine)])
+
+ self.terminalUi.simulationConsole.insertPlainText(stderror)
+
+ def finishSimulation(self, exitCode, exitStatus,
+ simEndSignal, hasErrorOccurred):
+ """This function is intended to run when the Ngspice
+ simulation finishes. It singals to the function that generates
+ the plots and also writes in the appropriate status of the
+ simulation (Whether it was a success or not).
+
+ :param exitCode: The exit code signal of the QProcess
+ that runs ngspice
+ :type exitCode: int
+ :param exitStatus: The exit status signal of the
+ qprocess that runs ngspice
+ :type exitStatus: class:`QtCore.QProcess.ExitStatus`
+ :param simEndSignal: A signal passed from constructor
+ for enabling simulation interaction and plotting data if the
+ simulation is successful
+ :type simEndSignal: PyQt Signal
+ """
+
+ # Canceling simulation triggers both finished and
+ # errorOccurred signals...need to skip finished signal in this case.
+ if not hasErrorOccurred and self.terminalUi.simulationCancelled:
+ return
+
+ # Stop progressbar from running after simulation is completed
+ self.terminalUi.progressBar.setMaximum(100)
+ self.terminalUi.progressBar.setProperty("value", 100)
+ self.terminalUi.cancelSimulationButton.setEnabled(False)
+ self.terminalUi.redoSimulationButton.setEnabled(True)
+
+ if exitCode is None:
+ exitCode = self.process.exitCode()
+
+ errorType = self.process.error()
+ if errorType < 3: # 0, 1, 2 ==> failed to start, crashed, timedout
+ exitStatus = QtCore.QProcess.CrashExit
+ elif exitStatus is None:
+ exitStatus = self.process.exitStatus()
+
+ if self.terminalUi.simulationCancelled:
+ msg = QtWidgets.QMessageBox()
+ msg.setModal(True)
+ msg.setIcon(QtWidgets.QMessageBox.Warning)
+ msg.setWindowTitle("Warning Message")
+ msg.setText("Simulation was cancelled.")
+ msg.setStandardButtons(QtWidgets.QMessageBox.Ok)
+ msg.exec()
+
+ elif exitStatus == QtCore.QProcess.NormalExit and exitCode == 0 \
+ and errorType == QtCore.QProcess.UnknownError:
+ # Redo-simulation does not set correct exit status and code.
+ # So, need to check the error type ==>
+ # UnknownError along with NormalExit seems successful simulation
+
+ successFormat = '<span style="color:#00ff00; font-size:26px;">\
+ {} \
+ </span>'
+ self.terminalUi.simulationConsole.append(
+ successFormat.format("Simulation Completed Successfully!"))
+
+ else:
+ failedFormat = '<span style="color:#ff3333; font-size:26px;"> \
+ {} \
+ </span>'
+ self.terminalUi.simulationConsole.append(
+ failedFormat.format("Simulation Failed!"))
+
+ errMsg = 'Simulation '
+ if errorType == QtCore.QProcess.FailedToStart:
+ errMsg += 'failed to start. ' + \
+ 'Ensure that eSim is installed correctly.'
+ elif errorType == QtCore.QProcess.Crashed:
+ errMsg += 'crashed. Try again later.'
+ elif errorType == QtCore.QProcess.Timedout:
+ errMsg += ' has timed out. Try to reduce the ' + \
+ ' simulation time or the simulation step interval.'
+ else:
+ errMsg += ' could not complete. Try again later.'
+
+ msg = QtWidgets.QErrorMessage()
+ msg.setModal(True)
+ msg.setWindowTitle("Error Message")
+ msg.showMessage(errMsg)
+ msg.exec()
+
+ self.terminalUi.simulationConsole.verticalScrollBar().setValue(
+ self.terminalUi.simulationConsole.verticalScrollBar().maximum()
+ )
+
+ simEndSignal.emit(exitStatus, exitCode)