Advertisement
Guest User

Untitled

a guest
Jul 20th, 2017
483
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.15 KB | None | 0 0
  1. from PyQt5.QtCore import (Qt, QTime)
  2. from PyQt5.QtWidgets import (QGridLayout, QHBoxLayout, QLabel, QLineEdit,
  3. QMessageBox, QPushButton, QTextEdit, QVBoxLayout, QWidget, QGroupBox,
  4. QTimeEdit, QComboBox, QSpinBox, QCheckBox, QApplication)
  5.  
  6. import os
  7. import datetime
  8. import io
  9. import functools
  10. import serial
  11. import KPDR900_serial
  12. import logging
  13.  
  14. class defaults:
  15. PCtimeout = 5
  16. PCport = "COM1"
  17. PCbaud = 19200
  18. logfilename = "KPDR900_log.txt"
  19. downloadfilename = os.path.join("data",datetime.datetime.now().strftime("%Y%m%d%H%M") + ".csv")
  20.  
  21. class GUI(QWidget):
  22. def __init__(self, parent=None):
  23. super(GUI, self).__init__(parent)
  24.  
  25. self.ADC = QLabel('?')
  26. self.BRC = QLabel('?')
  27. self.FVC = QLabel('?')
  28. self.HVC = QLabel('?')
  29. self.SNC = QLabel('?')
  30. self.TIC = QLabel("?")
  31. self.DLT = QLabel("?")
  32. self.DLS = QLabel("?")
  33. self.DLC = QLabel("?")
  34. self.ALH = QLabel("?")
  35. self.ALL = QLabel("?")
  36. self.ACH = QLabel("?")
  37. self.ACL = QLabel("?")
  38. self.PCport = QLabel(defaults.PCport)
  39. self.PCbaud = QLabel(str(defaults.PCbaud))
  40. self.PCtimeout =QLabel(str(defaults.PCtimeout))
  41. self.serial = serial.Serial(port=self.PCport.text(),baudrate=int(self.PCbaud.text()),timeout=int(self.PCtimeout.text()))
  42. self.pdr = KPDR900_serial.KPDR900(self.serial,logfile=defaults.logfilename)
  43.  
  44. datalogger_box = self.make_datalogger_box()
  45. serial_box = self.make_serial_box()
  46. term_box = self.make_term_box()
  47. info_box = self.make_info_box()
  48.  
  49. self.termLog_text = io.StringIO()
  50. self.logger = logging.getLogger()
  51. assert len(self.logger.handlers) == 1
  52. self.logfileHandler = self.logger.handlers[0]
  53. self.logconsoleHandler = logging.StreamHandler(self.termLog_text)
  54. self.logger.addHandler(self.logconsoleHandler)
  55.  
  56. mainLayout = QGridLayout()
  57. mainLayout.addWidget(serial_box,0,0)
  58. mainLayout.addWidget(datalogger_box,0,1)
  59. mainLayout.addWidget(info_box,1,0)
  60. mainLayout.addWidget(term_box,1,1)
  61.  
  62. self.setLayout(mainLayout)
  63. self.setWindowTitle("KPDR900")
  64.  
  65. def make_datalogger_box(self):
  66. box = QGroupBox("DataLogger & Terminal Log")
  67. g = QGridLayout()
  68.  
  69. labelnames = ["Current","Timer (DLT)", "Source (DLS)", "Control (DLC)",
  70. "Download Filename", "Log Filename"]
  71. labelpos = [(0,1), (1,0), (2,0), (3,0), (4,0), (5,0)]
  72.  
  73. for i in range(len(labelnames)):
  74. g.addWidget(QLabel(labelnames[i]),*labelpos[i])
  75.  
  76. values = {self.DLT : (1,1), self.DLS : (2,1), self.DLC : (3,1)}
  77. for v,p in values.items():
  78. g.addWidget(v,*p)
  79.  
  80. #self.timerEdit = QLineEdit()
  81. #self.timerEdit.setInputMask("99:59:59")
  82. self.timerEdit = QTimeEdit()
  83. self.timerEdit.setMaximumTime(QTime(99,59,59)) # Maximum maximum is 24h =(
  84. self.timerEdit.setMinimumTime(QTime(0,0,0))
  85. self.timerEdit.setTime(QTime(0,0,30))
  86. self.timerEdit.setDisplayFormat("HH:mm:ss")
  87. self.sourceMenu = QComboBox()
  88. self.sourceMenu.addItems(["PR1","PR2","PR3"])
  89.  
  90. self.downloadfileLine = QLineEdit()
  91. self.downloadfileLine.setText(defaults.downloadfilename)
  92. self.logfileLine = QLineEdit()
  93. self.logfileLine.setText(defaults.logfilename)
  94. g.addWidget(self.timerEdit,1,2)
  95. g.addWidget(self.sourceMenu,2,2)
  96. g.addWidget(self.downloadfileLine,4,1,1,2)
  97. g.addWidget(self.logfileLine,5,1,1,2)
  98.  
  99. self.startButton = QPushButton("Start")
  100. self.stopButton = QPushButton("Stop")
  101. g.addWidget(self.startButton,3,2)
  102. g.addWidget(self.stopButton,3,3)
  103.  
  104. self.timerButton = QPushButton("Set")
  105. self.sourceButton = QPushButton("Set")
  106. self.downloadButton = QPushButton("Download")
  107. self.loggingCheck = QCheckBox("Logging Enabled")
  108. self.loggingCheck.setChecked(True)
  109. g.addWidget(self.timerButton,1,3)
  110. g.addWidget(self.sourceButton,2,3)
  111. g.addWidget(self.downloadButton,4,3)
  112. g.addWidget(self.loggingCheck,5,3)
  113.  
  114. # TODO: add callback functions to the various buttons.
  115. self.loggingCheck.stateChanged.connect(self.toggleLogging)
  116. self.logfileLine.editingFinished.connect(self.changeLog)
  117.  
  118. self.timerButton.clicked.connect(self.setTimer)
  119. self.sourceButton.clicked.connect(self.setSource)
  120.  
  121. self.startButton.clicked.connect(self.start)
  122. self.stopButton.clicked.connect(self.stop)
  123. self.downloadButton.clicked.connect(self.download)
  124.  
  125. box.setLayout(g)
  126. return box
  127.  
  128. def make_serial_box(self):
  129. box = QGroupBox("Serial")
  130. g = QGridLayout()
  131.  
  132. labels = {"PC Port" : (1,0), "PC Rate" : (2,0), "PC Timeout (s)" : (3,0),
  133. "KPDR900 Address" : (5,0), "KPDR900 Rate" : (6,0),
  134. "Current" : (0,1)}
  135.  
  136. for l,p in labels.items():
  137. g.addWidget(QLabel(l),*p)
  138.  
  139. values = {self.PCport : (1,1), self.PCbaud : (2,1), self.PCtimeout : (3,1),
  140. self.ADC : (5,1), self.BRC : (6,1)}
  141. for v,p in values.items():
  142. g.addWidget(v,*p)
  143.  
  144.  
  145. self.portLine = QLineEdit()
  146. self.portLine.setText(defaults.PCport)
  147. self.PCrateMenu = QComboBox()
  148. baud_rates = list(map(str,[2400,4800,9600,19200,115000]))
  149. self.PCrateMenu.addItems(baud_rates)
  150. self.PCrateMenu.setCurrentText(str(defaults.PCbaud))
  151. self.PCtimeoutLine = QLineEdit()
  152. self.PCtimeoutLine.setText(str(defaults.PCtimeout))
  153.  
  154. self.PDRrateMenu = QComboBox()
  155. self.PDRrateMenu.addItems(baud_rates)
  156. self.PDRrateMenu.setCurrentText(str(defaults.PCbaud))
  157. self.PDRaddrMenu = QSpinBox()
  158. self.PDRaddrMenu.setMinimum(0)
  159. self.PDRaddrMenu.setMaximum(253)
  160. self.PDRaddrMenu.setWrapping(True)
  161.  
  162. g.addWidget(self.portLine,1,2)
  163. g.addWidget(self.PCrateMenu,2,2)
  164. g.addWidget(self.PCtimeoutLine,3,2)
  165. g.addWidget(self.PDRaddrMenu,5,2)
  166. g.addWidget(self.PDRrateMenu,6,2)
  167.  
  168. self.PCportButton = QPushButton("Set")
  169. self.PCrateButton = QPushButton("Set")
  170. self.PCtimeoutButton = QPushButton("Set")
  171. self.PDRrateButton = QPushButton("Set")
  172. self.PDRaddrButton = QPushButton("Set")
  173. self.reconnectButton = QPushButton("Reconnect")
  174. self.flushButton = QPushButton("Flush")
  175.  
  176. g.addWidget(self.PCportButton,1,3)
  177. g.addWidget(self.PCrateButton,2,3)
  178. g.addWidget(self.PCtimeoutButton,3,3)
  179. g.addWidget(self.PDRrateButton,5,3)
  180. g.addWidget(self.PDRaddrButton,6,3)
  181. g.addWidget(self.reconnectButton,4,2)
  182. g.addWidget(self.flushButton,4,3)
  183.  
  184. self.PCportButton.clicked.connect(self.notimplemented)
  185. self.PCrateButton.clicked.connect(self.notimplemented)
  186. self.PCtimeoutButton.clicked.connect(self.notimplemented)
  187. self.PDRrateButton.clicked.connect(self.notimplemented)
  188. self.PDRaddrButton.clicked.connect(self.notimplemented)
  189. self.reconnectButton.clicked.connect(self.notimplemented)
  190. self.flushButton.clicked.connect(self.notimplemented)
  191.  
  192. # TODO: add callback functions to the various buttons.
  193.  
  194. box.setLayout(g)
  195. return box
  196.  
  197. def make_term_box(self):
  198. box = QGroupBox("Terminal")
  199. v = QVBoxLayout()
  200. h = QHBoxLayout()
  201.  
  202. self.termLog = QTextEdit()
  203. self.termLog.setReadOnly(True)
  204. self.commandLine = QLineEdit() # returnPressed() signal emitted on enterkey.
  205.  
  206. self.termButton = QPushButton("Enter")
  207. self.clearButton = QPushButton("Clear")
  208. h.addWidget(self.commandLine,Qt.AlignLeft)
  209. h.addWidget(self.termButton)
  210. h.addWidget(self.clearButton)
  211. h.addStretch()
  212.  
  213. v.addWidget(self.termLog,Qt.AlignTop)
  214. v.addLayout(h)
  215. v.addStretch()
  216. # TODO: add callback functions to the various buttons.
  217.  
  218. self.termButton.clicked.connect(self.termSubmit)
  219. self.commandLine.returnPressed.connect(self.termSubmit)
  220. self.clearButton.clicked.connect(self.termLog.clear)
  221.  
  222. box.setLayout(v)
  223. return box
  224.  
  225. def make_info_box(self):
  226. box = QGroupBox("Info")
  227. g = QGridLayout()
  228. h = QHBoxLayout()
  229.  
  230. labels = {"Firmware Version" : (0,0), "Hardware Version" : (1,0),
  231. "Serial Number" : (2,0), "Time On" : (3,0)}
  232.  
  233. for l,p in labels.items():
  234. g.addWidget(QLabel(l),*p)
  235.  
  236. values = {self.FVC : (0,1), self.HVC : (1,1), self.SNC : (2,1), self.TIC : (3,1)}
  237. for v,p in values.items():
  238. g.addWidget(v,*p)
  239.  
  240.  
  241. self.queryinfoButton = QPushButton("Query Info")
  242. self.queryallButton = QPushButton("Query All")
  243. self.helpButton = QPushButton("Help")
  244. h.addWidget(self.queryinfoButton)
  245. h.addWidget(self.queryallButton)
  246. h.addWidget(self.helpButton)
  247.  
  248. g.addLayout(h,4,0,1,2)
  249.  
  250. # TODO: add callback functions to the various buttons.
  251. self.queryinfoButton.clicked.connect(self.queryinfo)
  252. self.queryallButton.clicked.connect(self.queryall)
  253. self.helpButton.clicked.connect(self.notimplemented)
  254.  
  255. box.setLayout(g)
  256. return box
  257.  
  258. def write_serial(self,msg):
  259. #msg = self.commandLine.text()
  260. self.pdr.write(bytes(msg,"ASCII"))
  261. self.updatetermLog()
  262.  
  263. # I've been told this next line is an awful hack.
  264. # It tells Qt to run the event loop, so the write shows up
  265. # on the event log, you can move the mouse a bit...
  266. # we kind of have to wait for the KPDR900 to answer anwyays,
  267. # so it's not a problem.
  268. QApplication.instance().processEvents()
  269.  
  270. resp = self.pdr.read()
  271. self.updatetermLog()
  272.  
  273. return resp
  274.  
  275. def updatetermLog(self):
  276. # Snap scroll to bottom, but only if already at bottom.
  277. snap = False
  278. vsb = self.termLog.verticalScrollBar()
  279. if vsb.value() == vsb.maximum():
  280. snap = True
  281. self.termLog.setText(self.termLog_text.getvalue())
  282. if snap:
  283. vsb.setValue(vsb.maximum())
  284.  
  285. def termSubmit(self):
  286. msg = self.commandLine.text()
  287. self.write_serial(msg)
  288.  
  289. def query(self,item):
  290. val = str(self.write_serial("%s?" % item),'ASCII')
  291. getattr(self,item).setText(val.split("ACK")[1][:-3])
  292.  
  293. def queryinfo(self):
  294. for item in ["FVC","HVC","SNC","TIC"]:
  295. self.query(item)
  296.  
  297. def queryall(self):
  298. self.queryinfo()
  299. for item in ["ADC","BRC","DLT","DLS","DLC"]:#,"ALH","ALL","ACH","ACL"]: # Alarm+action not implemented
  300. self.query(item)
  301.  
  302. def notimplemented(self):
  303. logging.warning("Not implemented. Ask JF at jcaron@uh.edu.")
  304. self.updatetermLog()
  305.  
  306. def toggleLogging(self):
  307. if self.loggingCheck.isChecked():
  308. self.logger.addHandler(self.logfileHandler)
  309. else:
  310. self.logger.removeHandler(self.logfileHandler)
  311.  
  312. def changeLog(self):
  313. newfile = self.logfileLine.text()
  314. logging.info("Changing log file to %s" % newfile)
  315. self.updatetermLog()
  316. newhandler = logging.FileHandler(newfile)
  317. self.logger.addHandler(newhandler)
  318. self.logger.removeHandler(self.logfileHandler)
  319. self.logfileHandler = newhandler
  320. logging.info("Changed log file to %s" % newfile)
  321. self.updatetermLog()
  322.  
  323. def setTimer(self):
  324. newtime = self.timerEdit.time()
  325. value = newtime.toString("HH:mm:ss")
  326. resp = self.write_serial("DLT!%s" % value)
  327. if b'ACK' in resp:
  328. self.DLT.setText(value)
  329.  
  330. def setSource(self):
  331. #newsource = self.sourceMenu.currentData()
  332. #print(newsource)
  333. #value = newsource.toString()
  334. value = self.sourceMenu.currentText()
  335. resp = self.write_serial("DLS!%s" % value)
  336. if b'ACK' in resp:
  337. self.DLS.setText(value)
  338.  
  339. def start(self):
  340. resp = self.write_serial("DLC!START")
  341. if b'ACK' in resp:
  342. self.DLC.setText("START")
  343.  
  344. def stop(self):
  345. resp = self.write_serial("DLC!STOP")
  346. if b'ACK' in resp:
  347. self.DLC.setText("STOP")
  348.  
  349. def download(self):
  350. fname = self.downloadfileLine.text()
  351. resp = self.write_serial("DL?")
  352. datalines = resp.split(b'\r')
  353. with open(fname,"w") as of:
  354. if b'Torr' not in datalines[0]:
  355. logging.warning("Units not set to Torr, check log file and PDR device.")
  356. of.write("#time (HH:MM:SS), time (s), pressure (Torr)\n")
  357.  
  358. for dline in datalines[1:-1]:
  359. time_s, press_s = str(dline,'ASCII').split(";")
  360. h,m,s = map(int,time_s.split(':'))
  361. seconds_s = str(s + 60*(m + 60*h))
  362. theline = ",".join([time_s,seconds_s,press_s])
  363. of.write(theline+'\n')
  364.  
  365. if not datalines[-1].endswith(b';FF'):
  366. logging.warning("Last line did not end with ;FF, check log file.")
  367.  
  368.  
  369.  
  370. if __name__ == '__main__':
  371. import sys
  372.  
  373. from PyQt5.QtWidgets import QApplication
  374.  
  375. app = QApplication(sys.argv)
  376.  
  377. gui = GUI()
  378. gui.show()
  379.  
  380. sys.exit(app.exec_())
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement