xytronic_simulator_gui.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. #!/usr/bin/env python3
  2. """
  3. # Xytronic LF-1600
  4. # Open Source firmware
  5. # Simulator graphical user interface
  6. #
  7. # Copyright (c) 2018 Michael Buesch <m@bues.ch>
  8. #
  9. # This program is free software; you can redistribute it and/or modify
  10. # it under the terms of the GNU General Public License as published by
  11. # the Free Software Foundation; either version 2 of the License, or
  12. # (at your option) any later version.
  13. #
  14. # This program is distributed in the hope that it will be useful,
  15. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. # GNU General Public License for more details.
  18. #
  19. # You should have received a copy of the GNU General Public License along
  20. # with this program; if not, write to the Free Software Foundation, Inc.,
  21. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  22. """
  23. import pyxytronic
  24. from xytronic_simulator import Simulator, IronTempSimulator, IronCurrentSimulator
  25. import sys
  26. from copy import copy
  27. import multiprocessing
  28. import time
  29. import queue
  30. from PyQt5.QtCore import *
  31. from PyQt5.QtGui import *
  32. from PyQt5.QtWidgets import *
  33. from PyQt5.QtChart import *
  34. class Measurements(object):
  35. dbg_currentRealR = 0.0
  36. dbg_currentUsedR = 0.0
  37. dbg_currentRState = 0
  38. dbg_currentY = 0.0
  39. dbg_tempR = 0.0
  40. dbg_tempY1 = 0.0
  41. dbg_tempY2 = 0.0
  42. dbg_measCurr = 0
  43. dbg_filtCurr = 0
  44. dbg_measTemp = 0
  45. dbg_boostMode = 0
  46. dbg_pidTempE = 0.0
  47. dbg_pidTempP = 0.0
  48. dbg_pidTempI = 0.0
  49. dbg_pidTempD = 0.0
  50. dbg_pidTempPrevE = 0.0
  51. dbg_pidCurrE = 0.0
  52. dbg_pidCurrP = 0.0
  53. dbg_pidCurrI = 0.0
  54. dbg_pidCurrD = 0.0
  55. dbg_pidCurrPrevE = 0.0
  56. class SimulatorProcess(multiprocessing.Process):
  57. def __init__(self, *args, **kwargs):
  58. super().__init__(*args, **kwargs, daemon=False)
  59. def __oneLoop(self):
  60. self.__sim.run()
  61. # time.sleep(0.0005)
  62. def __updateValues(self, temp):
  63. self.__sim.setting_set("temp_setpoint_active", 0)
  64. self.__sim.setting_set("temp_setpoint", temp)
  65. def setValues(self, temp=350.0):
  66. self.__commands.put(("temp", temp))
  67. def __buildMeasurements(self):
  68. meas = Measurements()
  69. meas.dbg_currentRealR = self.__sim.dbg_currentRealR
  70. meas.dbg_currentUsedR = self.__sim.dbg_currentUsedR
  71. meas.dbg_currentRState = self.__sim.dbg_currentRState
  72. meas.dbg_currentY = self.__sim.dbg_currentY
  73. meas.dbg_tempR = self.__sim.dbg_tempR
  74. meas.dbg_tempY1 = self.__sim.dbg_tempY1
  75. meas.dbg_tempY2 = self.__sim.dbg_tempY2
  76. meas.dbg_measCurr = self.__sim.dbg_measCurr
  77. meas.dbg_filtCurr = self.__sim.dbg_filtCurr
  78. meas.dbg_measTemp = self.__sim.dbg_measTemp
  79. meas.dbg_boostMode = self.__sim.dbg_boostMode
  80. meas.dbg_pidTempE = self.__sim.dbg_pidTempE
  81. meas.dbg_pidTempP = self.__sim.dbg_pidTempP
  82. meas.dbg_pidTempI = self.__sim.dbg_pidTempI
  83. meas.dbg_pidTempD = self.__sim.dbg_pidTempD
  84. meas.dbg_pidTempPrevE = self.__sim.dbg_pidTempPrevE
  85. meas.dbg_pidCurrE = self.__sim.dbg_pidCurrE
  86. meas.dbg_pidCurrP = self.__sim.dbg_pidCurrP
  87. meas.dbg_pidCurrI = self.__sim.dbg_pidCurrI
  88. meas.dbg_pidCurrD = self.__sim.dbg_pidCurrD
  89. meas.dbg_pidCurrPrevE = self.__sim.dbg_pidCurrPrevE
  90. self.__responses.put(("meas", meas))
  91. def requestMeasurements(self):
  92. self.__commands.put(("reqMeas", None))
  93. def getResponses(self):
  94. try:
  95. while True:
  96. ident, args = self.__responses.get(False)
  97. yield ident, args
  98. except queue.Empty as e:
  99. pass
  100. def start(self):
  101. self.__commands = multiprocessing.Queue()
  102. self.__responses = multiprocessing.Queue()
  103. self.setValues()
  104. super().start()
  105. def run(self):
  106. print("Starting simulator process.")
  107. pyxytronic.simulator_init()
  108. try:
  109. self.__sim = Simulator()
  110. self.__simTemp = IronTempSimulator(self.__sim)
  111. self.__simCurr = IronCurrentSimulator(self.__sim)
  112. run = True
  113. while run:
  114. while True:
  115. try:
  116. (cmd, args) = self.__commands.get(False)
  117. if cmd == "stop":
  118. run = False
  119. if cmd == "reqMeas":
  120. self.__buildMeasurements()
  121. if cmd == "temp":
  122. self.__updateValues(temp=args)
  123. except queue.Empty as e:
  124. break
  125. self.__oneLoop()
  126. finally:
  127. pyxytronic.simulator_exit()
  128. print("Exiting simulator process.")
  129. def shutdown(self):
  130. if self.is_alive():
  131. self.__commands.put(("stop", None))
  132. self.join()
  133. class Chart(QChart):
  134. def __init__(self, *args, **kwargs):
  135. super().__init__(*args, **kwargs)
  136. class MainChart(Chart):
  137. def __init__(self, *args, **kwargs):
  138. super().__init__(*args, **kwargs)
  139. self.lineSeries = {}
  140. self.timeAxis = None
  141. self.tempAxis = None
  142. self.currentAxis = None
  143. self.adcAxis = None
  144. self.stateAxis = None
  145. def rebuildChart(self,
  146. enaLineCurrentRealR,
  147. enaLineCurrentUsedR,
  148. enaLineCurrentRState,
  149. enaLineCurrentY,
  150. enaLineTempR,
  151. enaLineTempY1,
  152. enaLineTempY2,
  153. enaLineMeasCurr,
  154. enaLineFiltCurr,
  155. enaLineMeasTemp,
  156. enaLineBoostMode):
  157. self.removeAllSeries()
  158. if self.timeAxis is None:
  159. self.timeAxis = QValueAxis()
  160. self.addAxis(self.timeAxis, Qt.AlignBottom)
  161. self.timeAxis.setRange(0, 100)
  162. self.timeAxis.setLabelFormat("%d s")
  163. self.timeAxis.setTickCount(10)
  164. if self.currentAxis is None:
  165. self.currentAxis = QValueAxis()
  166. self.addAxis(self.currentAxis, Qt.AlignLeft)
  167. self.currentAxis.setLabelFormat("%.1f A")
  168. self.currentAxis.setRange(0, 5)
  169. if self.tempAxis is None:
  170. self.tempAxis = QValueAxis()
  171. self.addAxis(self.tempAxis, Qt.AlignLeft)
  172. self.tempAxis.setLabelFormat("%d *C")
  173. self.tempAxis.setRange(0, 600)
  174. if self.adcAxis is None:
  175. self.adcAxis = QValueAxis()
  176. self.addAxis(self.adcAxis, Qt.AlignRight)
  177. self.adcAxis.setLabelFormat("0x%X")
  178. self.adcAxis.setRange(0, 0x3FF)
  179. if self.stateAxis is None:
  180. self.stateAxis = QValueAxis()
  181. self.addAxis(self.stateAxis, Qt.AlignRight)
  182. self.stateAxis.setTickCount(3)
  183. self.stateAxis.setLabelFormat("%d")
  184. self.stateAxis.setRange(0, 2)
  185. self.lineSeries = {}
  186. for name, description, ena, axis in (
  187. ("crr", "Current real R (A)", enaLineCurrentRealR, self.currentAxis),
  188. ("cur", "Current used R (A)", enaLineCurrentUsedR, self.currentAxis),
  189. ("crs", "Current R state", enaLineCurrentRState, self.stateAxis),
  190. ("cy", "Current Y (A)", enaLineCurrentY, self.currentAxis),
  191. ("tr", "Temp R (*C)", enaLineTempR, self.tempAxis),
  192. ("ty1", "Temp Y1 (*C)", enaLineTempY1, self.tempAxis),
  193. ("ty2", "Temp Y2 (A)", enaLineTempY2, self.currentAxis),
  194. ("mc", "Current ADC (hex)", enaLineMeasCurr, self.adcAxis),
  195. ("fc", "Filtered current ADC (hex)", enaLineFiltCurr, self.adcAxis),
  196. ("mt", "Temp ADC (hex)", enaLineMeasTemp, self.adcAxis),
  197. ("bm", "Boost mode", enaLineBoostMode, self.stateAxis)):
  198. if ena:
  199. line = QLineSeries()
  200. line.setName(description)
  201. self.addSeries(line)
  202. line.attachAxis(self.timeAxis)
  203. line.attachAxis(axis)
  204. self.lineSeries[name] = line
  205. def updateChart(self, measurements, chartXCount):
  206. for chartLine, value in (
  207. (self.lineSeries.get("crr"), measurements.dbg_currentRealR),
  208. (self.lineSeries.get("cur"), measurements.dbg_currentUsedR),
  209. (self.lineSeries.get("crs"), measurements.dbg_currentRState),
  210. (self.lineSeries.get("cy"), measurements.dbg_currentY),
  211. (self.lineSeries.get("tr"), measurements.dbg_tempR),
  212. (self.lineSeries.get("ty1"), measurements.dbg_tempY1),
  213. (self.lineSeries.get("ty2"), measurements.dbg_tempY2),
  214. (self.lineSeries.get("mc"), measurements.dbg_measCurr),
  215. (self.lineSeries.get("fc"), measurements.dbg_filtCurr),
  216. (self.lineSeries.get("mt"), measurements.dbg_measTemp),
  217. (self.lineSeries.get("bm"), measurements.dbg_boostMode)):
  218. if chartLine is None:
  219. continue
  220. chartLine.append(chartXCount - 1, value)
  221. if chartXCount > 100:
  222. chartLine.remove(0)
  223. if chartXCount > 100:
  224. self.timeAxis.setRange(chartXCount - 100,
  225. chartXCount)
  226. class PidChart(Chart):
  227. def __init__(self, *args, **kwargs):
  228. super().__init__(*args, **kwargs)
  229. self.lineSeries = {}
  230. self.timeAxis = None
  231. self.valueAxis = None
  232. def rebuildChart(self,
  233. enaLinePidCE,
  234. enaLinePidCP,
  235. enaLinePidCI,
  236. enaLinePidCD,
  237. enaLinePidCPE,
  238. enaLinePidTE,
  239. enaLinePidTP,
  240. enaLinePidTI,
  241. enaLinePidTD,
  242. enaLinePidTPE):
  243. self.removeAllSeries()
  244. if self.timeAxis is None:
  245. self.timeAxis = QValueAxis()
  246. self.addAxis(self.timeAxis, Qt.AlignBottom)
  247. self.timeAxis.setRange(0, 100)
  248. self.timeAxis.setLabelFormat("%d s")
  249. self.timeAxis.setTickCount(10)
  250. if self.valueAxis is None:
  251. self.valueAxis = QValueAxis()
  252. self.addAxis(self.valueAxis, Qt.AlignLeft)
  253. self.valueAxis.setLabelFormat("%.2f")
  254. self.valueAxis.setRange(-100, 100)
  255. self.lineSeries = {}
  256. for name, description, ena, axis in (
  257. ("ce", "PID current e", enaLinePidCE, self.valueAxis),
  258. ("cp", "PID current p", enaLinePidCP, self.valueAxis),
  259. ("ci", "PID current i", enaLinePidCI, self.valueAxis),
  260. ("cd", "PID current d", enaLinePidCD, self.valueAxis),
  261. ("cpe", "PID current prev. e", enaLinePidCPE, self.valueAxis),
  262. ("te", "PID temp e", enaLinePidTE, self.valueAxis),
  263. ("tp", "PID temp p", enaLinePidTP, self.valueAxis),
  264. ("ti", "PID temp i", enaLinePidTI, self.valueAxis),
  265. ("td", "PID temp d", enaLinePidTD, self.valueAxis),
  266. ("tpe", "PID temp prev. e", enaLinePidTPE, self.valueAxis)):
  267. if ena:
  268. line = QLineSeries()
  269. line.setName(description)
  270. self.addSeries(line)
  271. line.attachAxis(self.timeAxis)
  272. line.attachAxis(axis)
  273. self.lineSeries[name] = line
  274. def updateChart(self, measurements, chartXCount):
  275. for chartLine, value in (
  276. (self.lineSeries.get("ce"), measurements.dbg_pidCurrE),
  277. (self.lineSeries.get("cp"), measurements.dbg_pidCurrP),
  278. (self.lineSeries.get("ci"), measurements.dbg_pidCurrI),
  279. (self.lineSeries.get("cd"), measurements.dbg_pidCurrD),
  280. (self.lineSeries.get("cpe"), measurements.dbg_pidCurrPrevE),
  281. (self.lineSeries.get("te"), measurements.dbg_pidTempE),
  282. (self.lineSeries.get("tp"), measurements.dbg_pidTempP),
  283. (self.lineSeries.get("ti"), measurements.dbg_pidTempI),
  284. (self.lineSeries.get("td"), measurements.dbg_pidTempD),
  285. (self.lineSeries.get("tpe"), measurements.dbg_pidTempPrevE)):
  286. if chartLine is None:
  287. continue
  288. chartLine.append(chartXCount - 1, value)
  289. if chartXCount > 100:
  290. chartLine.remove(0)
  291. if chartXCount > 100:
  292. self.timeAxis.setRange(chartXCount - 100,
  293. chartXCount)
  294. class ChartView(QChartView):
  295. def __init__(self, *args, **kwargs):
  296. super().__init__(*args, **kwargs)
  297. self.setRenderHint(QPainter.Antialiasing)
  298. class MainWidget(QWidget):
  299. def __init__(self, parent=None):
  300. QWidget.__init__(self, parent)
  301. self.setLayout(QGridLayout())
  302. self.simProc = None
  303. chartVBox = QVBoxLayout()
  304. self.mainChart = MainChart()
  305. self.mainChartView = ChartView(self.mainChart, self)
  306. chartVBox.addWidget(self.mainChartView)
  307. self.pidChart = PidChart()
  308. self.pidChartView = ChartView(self.pidChart, self)
  309. chartVBox.addWidget(self.pidChartView)
  310. self.layout().addLayout(chartVBox, 0, 0, 2, 1)
  311. self.measGroup = QGroupBox(self)
  312. self.measGroup.setLayout(QGridLayout())
  313. self.enaLineCurrentRealR = QCheckBox("Current real R", self)
  314. self.measGroup.layout().addWidget(self.enaLineCurrentRealR, 0, 0)
  315. self.enaLineCurrentUsedR = QCheckBox("Current used R", self)
  316. self.measGroup.layout().addWidget(self.enaLineCurrentUsedR, 1, 0)
  317. self.enaLineCurrentRState = QCheckBox("Current R state", self)
  318. self.measGroup.layout().addWidget(self.enaLineCurrentRState, 2, 0)
  319. self.enaLineCurrentY = QCheckBox("Current-Y", self)
  320. self.measGroup.layout().addWidget(self.enaLineCurrentY, 3, 0)
  321. self.enaLinePidCE = QCheckBox("Current PID e", self)
  322. self.measGroup.layout().addWidget(self.enaLinePidCE, 4, 0)
  323. self.enaLinePidCP = QCheckBox("Current PID p", self)
  324. self.measGroup.layout().addWidget(self.enaLinePidCP, 5, 0)
  325. self.enaLinePidCI = QCheckBox("Current PID i", self)
  326. self.measGroup.layout().addWidget(self.enaLinePidCI, 6, 0)
  327. self.enaLinePidCD = QCheckBox("Current PID d", self)
  328. self.measGroup.layout().addWidget(self.enaLinePidCD, 7, 0)
  329. self.enaLinePidCPE = QCheckBox("Current PID prev-e", self)
  330. self.measGroup.layout().addWidget(self.enaLinePidCPE, 8, 0)
  331. self.enaLineTempR = QCheckBox("Temp R", self)
  332. self.enaLineTempR.setCheckState(Qt.Checked)
  333. self.measGroup.layout().addWidget(self.enaLineTempR, 0, 1)
  334. self.enaLineTempY1 = QCheckBox("Temp Y1", self)
  335. self.enaLineTempY1.setCheckState(Qt.Checked)
  336. self.measGroup.layout().addWidget(self.enaLineTempY1, 1, 1)
  337. self.enaLineTempY2 = QCheckBox("Temp Y2", self)
  338. self.measGroup.layout().addWidget(self.enaLineTempY2, 2, 1)
  339. self.enaLinePidTE = QCheckBox("Temp PID e", self)
  340. self.enaLinePidTE.setCheckState(Qt.Checked)
  341. self.measGroup.layout().addWidget(self.enaLinePidTE, 3, 1)
  342. self.enaLinePidTP = QCheckBox("Temp PID p", self)
  343. self.enaLinePidTP.setCheckState(Qt.Checked)
  344. self.measGroup.layout().addWidget(self.enaLinePidTP, 4, 1)
  345. self.enaLinePidTI = QCheckBox("Temp PID i", self)
  346. self.enaLinePidTI.setCheckState(Qt.Checked)
  347. self.measGroup.layout().addWidget(self.enaLinePidTI, 5, 1)
  348. self.enaLinePidTD = QCheckBox("Temp PID d", self)
  349. self.enaLinePidTD.setCheckState(Qt.Checked)
  350. self.measGroup.layout().addWidget(self.enaLinePidTD, 6, 1)
  351. self.enaLinePidTPE = QCheckBox("Temp PID prev-e", self)
  352. self.measGroup.layout().addWidget(self.enaLinePidTPE, 7, 1)
  353. self.enaLineMeasCurr = QCheckBox("Current ADC", self)
  354. self.measGroup.layout().addWidget(self.enaLineMeasCurr, 0, 2)
  355. self.enaLineFiltCurr = QCheckBox("Filtered current ADC", self)
  356. self.measGroup.layout().addWidget(self.enaLineFiltCurr, 1, 2)
  357. self.enaLineMeasTemp = QCheckBox("Temp ADC", self)
  358. self.measGroup.layout().addWidget(self.enaLineMeasTemp, 2, 2)
  359. self.enaLineBoostMode = QCheckBox("Boost mode", self)
  360. self.measGroup.layout().addWidget(self.enaLineBoostMode, 3, 2)
  361. self.layout().addWidget(self.measGroup, 0, 1)
  362. self.controlsGroup = QGroupBox(self)
  363. self.controlsGroup.setLayout(QGridLayout())
  364. self.resetButton = QPushButton("Reset", self)
  365. self.controlsGroup.layout().addWidget(self.resetButton, 0, 0, 1, 2)
  366. label = QLabel("Temp sp:", self)
  367. self.controlsGroup.layout().addWidget(label, 1, 0)
  368. self.tempSp = QSlider(Qt.Horizontal, self)
  369. self.tempSp.setRange(-50, 550)
  370. self.tempSp.setValue(350)
  371. self.controlsGroup.layout().addWidget(self.tempSp, 1, 1)
  372. self.controlsGroup.layout().setRowStretch(99, 1)
  373. self.layout().addWidget(self.controlsGroup, 1, 1)
  374. self.chartTimer = QTimer(self)
  375. self.chartTimer.timeout.connect(self.__chartUpdate)
  376. self.chartTimer.setSingleShot(False)
  377. self.chartTimer.setTimerType(Qt.PreciseTimer)
  378. self.chartTimer.start(100)
  379. self.resetButton.released.connect(self.__handleReset)
  380. self.enaLineCurrentRealR.stateChanged.connect(self.__handleChartChange)
  381. self.enaLineCurrentUsedR.stateChanged.connect(self.__handleChartChange)
  382. self.enaLineCurrentRState.stateChanged.connect(self.__handleChartChange)
  383. self.enaLineCurrentY.stateChanged.connect(self.__handleChartChange)
  384. self.enaLinePidCE.stateChanged.connect(self.__handleChartChange)
  385. self.enaLinePidCP.stateChanged.connect(self.__handleChartChange)
  386. self.enaLinePidCI.stateChanged.connect(self.__handleChartChange)
  387. self.enaLinePidCD.stateChanged.connect(self.__handleChartChange)
  388. self.enaLinePidCPE.stateChanged.connect(self.__handleChartChange)
  389. self.enaLineTempR.stateChanged.connect(self.__handleChartChange)
  390. self.enaLineTempY1.stateChanged.connect(self.__handleChartChange)
  391. self.enaLineTempY2.stateChanged.connect(self.__handleChartChange)
  392. self.enaLinePidTE.stateChanged.connect(self.__handleChartChange)
  393. self.enaLinePidTP.stateChanged.connect(self.__handleChartChange)
  394. self.enaLinePidTI.stateChanged.connect(self.__handleChartChange)
  395. self.enaLinePidTD.stateChanged.connect(self.__handleChartChange)
  396. self.enaLinePidTPE.stateChanged.connect(self.__handleChartChange)
  397. self.enaLineMeasCurr.stateChanged.connect(self.__handleChartChange)
  398. self.enaLineFiltCurr.stateChanged.connect(self.__handleChartChange)
  399. self.enaLineMeasTemp.stateChanged.connect(self.__handleChartChange)
  400. self.enaLineBoostMode.stateChanged.connect(self.__handleChartChange)
  401. self.tempSp.valueChanged.connect(self.__handleValueChange)
  402. self.__handleReset()
  403. def __handleReset(self):
  404. self.__handleChartChange()
  405. if self.simProc:
  406. self.simProc.shutdown()
  407. self.simProc = SimulatorProcess()
  408. self.simProc.start()
  409. self.__handleValueChange()
  410. def __handleChartChange(self):
  411. self.mainChart.rebuildChart(
  412. enaLineCurrentRealR=(self.enaLineCurrentRealR.checkState() == Qt.Checked),
  413. enaLineCurrentUsedR=(self.enaLineCurrentUsedR.checkState() == Qt.Checked),
  414. enaLineCurrentRState=(self.enaLineCurrentRState.checkState() == Qt.Checked),
  415. enaLineCurrentY=(self.enaLineCurrentY.checkState() == Qt.Checked),
  416. enaLineTempR=(self.enaLineTempR.checkState() == Qt.Checked),
  417. enaLineTempY1=(self.enaLineTempY1.checkState() == Qt.Checked),
  418. enaLineTempY2=(self.enaLineTempY2.checkState() == Qt.Checked),
  419. enaLineMeasCurr=(self.enaLineMeasCurr.checkState() == Qt.Checked),
  420. enaLineFiltCurr=(self.enaLineFiltCurr.checkState() == Qt.Checked),
  421. enaLineMeasTemp=(self.enaLineMeasTemp.checkState() == Qt.Checked),
  422. enaLineBoostMode=(self.enaLineBoostMode.checkState() == Qt.Checked),
  423. )
  424. self.pidChart.rebuildChart(
  425. enaLinePidCE=(self.enaLinePidCE.checkState() == Qt.Checked),
  426. enaLinePidCP=(self.enaLinePidCP.checkState() == Qt.Checked),
  427. enaLinePidCI=(self.enaLinePidCI.checkState() == Qt.Checked),
  428. enaLinePidCD=(self.enaLinePidCD.checkState() == Qt.Checked),
  429. enaLinePidCPE=(self.enaLinePidCPE.checkState() == Qt.Checked),
  430. enaLinePidTE=(self.enaLinePidTE.checkState() == Qt.Checked),
  431. enaLinePidTP=(self.enaLinePidTP.checkState() == Qt.Checked),
  432. enaLinePidTI=(self.enaLinePidTI.checkState() == Qt.Checked),
  433. enaLinePidTD=(self.enaLinePidTD.checkState() == Qt.Checked),
  434. enaLinePidTPE=(self.enaLinePidTPE.checkState() == Qt.Checked),
  435. )
  436. self.chartXCount = 0
  437. def __handleValueChange(self):
  438. temp = float(self.tempSp.value())
  439. self.simProc.setValues(temp=temp)
  440. def __chartUpdate(self):
  441. for ident, args in self.simProc.getResponses():
  442. if ident == "meas":
  443. self.chartXCount += 1
  444. self.mainChart.updateChart(measurements=args,
  445. chartXCount=self.chartXCount)
  446. self.pidChart.updateChart(measurements=args,
  447. chartXCount=self.chartXCount)
  448. self.simProc.requestMeasurements()
  449. class MainWindow(QMainWindow):
  450. def __init__(self, parent=None):
  451. QMainWindow.__init__(self, parent)
  452. self.setWindowTitle("xytronic-lf simulator")
  453. self.mainWidget = MainWidget(self)
  454. self.setCentralWidget(self.mainWidget)
  455. self.resize(1500, 700)
  456. def closeEvent(self, ev):
  457. self.mainWidget.simProc.shutdown()
  458. def main():
  459. qapp = QApplication(sys.argv)
  460. mainwnd = MainWindow()
  461. mainwnd.show()
  462. return qapp.exec_()
  463. if __name__ == "__main__":
  464. sys.exit(main())