ControlWidget.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. """
  2. This module defines the Initial view of the gui
  3. """
  4. from PyQt4 import QtGui, QtCore
  5. import logging
  6. from . import kcgwidget as kcgw
  7. from .kcgwidget import error
  8. from .backend import board
  9. from .backend.board import available_boards
  10. from .groupedelements import Checkboxes, Buttons, Elements
  11. from . import backendinterface as bif
  12. from .loghandler import LogArea
  13. from . import storage
  14. from .. import config
  15. import traceback
  16. tr = kcgw.tr
  17. # 888 88888888888888888b.
  18. # 888 888 888 "Y88b
  19. # 888 888 888 888
  20. # 888 8888888 888 888
  21. # 888 888 888 888
  22. # 888 888 888 888
  23. # 888 888 888 .d88P
  24. # 8888888888888888888888888P"
  25. class LED(QtGui.QWidget):
  26. """
  27. Produces a graphical LED
  28. """
  29. def __init__(self, parent=None, status=1, height=10, width=10):
  30. """
  31. Initialize a LED
  32. :param parent: (QWidget) parent of this widget
  33. :param status: (int) (0=out, 1=off, 2=orange, 3=on) initial status of this LED
  34. :param height: (int) height of the LED
  35. :param width: (int) width of the LED
  36. :return: -
  37. """
  38. QtGui.QWidget.__init__(self, parent)
  39. colorRGB=(255, 0, 0)
  40. self.width = width
  41. self.height = height
  42. self.color = QtGui.QColor(colorRGB[0], colorRGB[1], colorRGB[2])
  43. self.center = QtCore.QPoint(width, height)
  44. self.setMinimumSize(2 * width, 2 * height)
  45. self.setMaximumSize(2 * width, 2 * height)
  46. if status == 3:
  47. self.set_on()
  48. elif status == 1:
  49. self.set_off()
  50. elif status == 0:
  51. self.set_out()
  52. elif status == 2:
  53. self.set_tri()
  54. self.status = status
  55. def paintEvent(self, event):
  56. paint = QtGui.QPainter()
  57. paint.begin(self)
  58. paint.setRenderHint(QtGui.QPainter.Antialiasing)
  59. # draw a grey 'socket' for the LED
  60. paint.setPen(QtGui.QColor(160, 160, 160))
  61. paint.setBrush(QtGui.QColor(180, 180, 180))
  62. paint.drawEllipse(self.center, self.width, self.height)
  63. # draw the body of the LED
  64. paint.setBrush(self.color)
  65. paint.drawEllipse(self.center, self.width*0.85, self.height*0.85)
  66. def set_on(self):
  67. """
  68. Set the LED to "on" state
  69. :return: -
  70. """
  71. self.color = QtGui.QColor(0, 255, 0)
  72. self.update()
  73. self.status = 3
  74. def set_off(self):
  75. """
  76. Set the LED to "off" state
  77. :return: -
  78. """
  79. self.color = QtGui.QColor(255, 0, 0)
  80. self.update()
  81. self.status = 1
  82. def set_out(self):
  83. """
  84. Set the LED to "OUT" state (that is like an LED without power)
  85. :return: -
  86. """
  87. self.color = QtGui.QColor(150, 150, 150)
  88. self.update()
  89. self.status = 0
  90. def set_tri(self):
  91. """
  92. Set the LED to "TRI" state (that is led is orange)
  93. :return: -
  94. """
  95. self.color = QtGui.QColor(255, 255, 0)
  96. self.update()
  97. self.status = 2
  98. def set_status(self, status):
  99. """
  100. Set the status of the led
  101. :param status: status (in 0, 1, 2, 3)
  102. """
  103. if status == 0:
  104. self.set_out()
  105. elif status == 1:
  106. self.set_off()
  107. elif status == 2:
  108. self.set_tri()
  109. elif status == 3:
  110. self.set_on()
  111. # .d8888b. 888 888 888 88888888888888888b.
  112. # d88P Y88b888 888 888 888 888 "Y88b
  113. # Y88b. 888 888 888 888 888 888
  114. # "Y888b. 888888 8888b. 888888888 888.d8888b 888 8888888 888 888
  115. # "Y88b.888 "88b888 888 88888K 888 888 888 888
  116. # "888888 .d888888888 888 888"Y8888b.888 888 888 888
  117. # Y88b d88PY88b. 888 888Y88b. Y88b 888 X88888 888 888 .d88P
  118. # "Y8888P" "Y888"Y888888 "Y888 "Y88888 88888P'8888888888888888888888888P"
  119. class StatusLED(QtGui.QWidget):
  120. """
  121. Create a Status LED with Label next to it
  122. """
  123. def __init__(self, text, status=None):
  124. """
  125. Initialise StatusLED
  126. :param text: label text next to the LED
  127. :param status: initial status of the LED
  128. :return: -
  129. """
  130. super(StatusLED, self).__init__()
  131. self.layout = QtGui.QHBoxLayout()
  132. self.label = QtGui.QLabel(text)
  133. self.led = LED(status=status, width=9, height=9)
  134. self.layout.addWidget(self.led)
  135. self.layout.addWidget(self.label)
  136. self.setLayout(self.layout)
  137. def set_on(self):
  138. """
  139. See set_on of LED Class
  140. """
  141. self.led.set_on()
  142. def set_off(self):
  143. """
  144. See set_off of LED Class
  145. """
  146. self.led.set_off()
  147. def set_out(self):
  148. """
  149. See set_out of LED Class
  150. """
  151. self.led.set_out()
  152. def set_tri(self):
  153. """
  154. See set_tri of LED Class
  155. """
  156. self.led.set_tri()
  157. def set_status(self, status):
  158. """
  159. See set_status of LED Class
  160. :param status: the status to set the led to
  161. """
  162. self.led.set_status(status)
  163. # 888888b. 888 .d8888b. 888 888
  164. # 888 "88b 888d88P Y88b 888 888
  165. # 888 .88P 888888 888 888 888
  166. # 8888888K. .d88b. 8888b. 888d888 .d88888888 .d88b. 88888b. 888888888d888 .d88b. 888
  167. # 888 "Y88bd88""88b "88b888P" d88" 888888 d88""88b888 "88b888 888P" d88""88b888
  168. # 888 888888 888.d888888888 888 888888 888888 888888 888888 888 888 888888
  169. # 888 d88PY88..88P888 888888 Y88b 888Y88b d88PY88..88P888 888Y88b. 888 Y88..88P888
  170. # 8888888P" "Y88P" "Y888888888 "Y88888 "Y8888P" "Y88P" 888 888 "Y888888 "Y88P" 888
  171. class BoardControl(kcgw.KCGWidgets):
  172. """
  173. The main view of the gui for each board at startup
  174. """
  175. def __init__(self, board_id, single=False):
  176. super(BoardControl, self).__init__()
  177. self.board_id = board_id
  178. self.layout = QtGui.QVBoxLayout()
  179. self.setLayout(self.layout)
  180. if not single:
  181. self.header_layout = QtGui.QHBoxLayout()
  182. left_line = QtGui.QFrame()
  183. left_line.setFrameShape(QtGui.QFrame.HLine)
  184. left_line.setFrameShadow(QtGui.QFrame.Sunken)
  185. right_line = QtGui.QFrame()
  186. right_line.setFrameShape(QtGui.QFrame.HLine)
  187. right_line.setFrameShadow(QtGui.QFrame.Sunken)
  188. self.header_layout.addWidget(left_line)
  189. header_label = self.createLabel("Board: {}".format(available_boards.get_board_name_from_id(board_id)))
  190. header_label.setFixedWidth(header_label.sizeHint().width())
  191. self.header_layout.addWidget(header_label)
  192. self.header_layout.addWidget(right_line)
  193. self.layout.addLayout(self.header_layout)
  194. self.mainControlLayout = QtGui.QHBoxLayout()
  195. self.subControlLayout = QtGui.QGridLayout()#QtGui.QHBoxLayout()
  196. self.subControlWidget = QtGui.QWidget()
  197. self.subControlWidget.setLayout(self.subControlLayout)
  198. self.statusLayout = QtGui.QHBoxLayout()
  199. self.layout.addLayout(self.mainControlLayout)
  200. self.layout.addWidget(self.subControlWidget)
  201. self.layout.addLayout(self.statusLayout)
  202. # ----------[ LED Status ]---------------
  203. self.pipeline_led = StatusLED(tr("Label", "DataFlow Pipeline"))
  204. self.master_control_led = StatusLED(tr("Label", "Master Control"))
  205. #self.data_check_led = StatusLED(tr("Label", "Data Check"))
  206. self.pll_ld_led = StatusLED(tr("Label", "PLL Lock"))
  207. self.statusLayout.addWidget(self.pipeline_led)
  208. self.statusLayout.addWidget(self.master_control_led)
  209. #self.statusLayout.addWidget(self.data_check_led)
  210. self.statusLayout.addWidget(self.pll_ld_led)
  211. # -----------[ Buttons ]--------------
  212. from functools import partial
  213. conf = board.get_board_config(board_id)
  214. if conf.get('board_version') > 10:
  215. logging.critical('Board Offline - GUI not working! - restart with active board')
  216. self.mainControlLayout.addWidget(self.createLabel('Board Offline - GUI not working! - restart with active board'))
  217. else:
  218. self.all_in_one_button = self.createButton(text=tr("Button", "Prepare Board"), connect=self.all_in_one,
  219. tooltip=tr("Tooltip", "Start, Calibrate, Synchronize and set Defaults\nCtrl+A"))
  220. self.toggleButton = self.createButton(text="", connect=self.toggle_sub_control)
  221. self.toggleButton.setIcon(QtGui.QIcon(config.icon_path("chevron-bottom.svg")))
  222. self.toggleButton.setFixedWidth(50)
  223. # self.all_in_one_button.setShortcut("Ctrl+A")
  224. # self.all_in_one_button.setObjectName("all_in_one")
  225. self.skip_init_button = self.createButton(text=tr("Button", "Skip Initialisation"), connect=self.skip_init,
  226. tooltip=tr("Tooltip", "Skip Initialisation and read values from board.\n"
  227. "NOTE: ONLY DO THIS IF BOARD WAS CALIBRATED AND SYNCHRONIZED BEFORE"))
  228. self.set_default_button = self.createButton(text=tr("Button", "Set Defaults"), connect=lambda x: bif.bk_write_values(board_id=board_id, defaults=True))
  229. self.soft_reset_button = self.createButton(text=tr("Button", "Soft Reset"), connect=lambda x: bif.bk_soft_reset(board_id=board_id))
  230. #self.off_button = self.createButton(text=tr("Button", "Board Off"), connect=lambda x: bif.bk_stop_board(board_id=board_id))
  231. #self.off_button.setObjectName("off")
  232. self.check_status_button = self.createButton(text=tr("Button", "Check Status"), connect=lambda x: bif._bif_status_readout(board_id=board_id))
  233. seqlist = conf.get_sequence_list()
  234. columnctr=0
  235. linectr = 0
  236. seqcolum = -1
  237. try:
  238. for item in seqlist:
  239. buttontemp = self.createButton(text=tr("Button", conf.get_sequence_comment(item)), connect=partial(bif.bk_run_sequence, board_id=board_id, name=item))
  240. Buttons.addButton(item, buttontemp)
  241. Elements.addItem('no_board_{}'.format(board_id),[buttontemp])
  242. #self.subControlLayout.addWidget(buttontemp)
  243. if 'PLL_sequence' in item:
  244. if seqcolum == -1:
  245. seqcolum = columnctr
  246. columnctr += 1
  247. self.subControlLayout.addWidget(buttontemp, linectr, seqcolum)
  248. linectr += 1
  249. else:
  250. self.subControlLayout.addWidget(buttontemp, 0,columnctr)
  251. columnctr += 1
  252. self.subControlLayout.addWidget(self.set_default_button, 0, columnctr)
  253. except Exception as e:
  254. traceback.print_exc()
  255. Buttons.addButton(['set_defaults_{}'.format(board_id), 'after_start_{}'.format(board_id)], self.set_default_button)
  256. Elements.addItem('no_board_{}'.format(board_id),
  257. [
  258. self.set_default_button,
  259. self.soft_reset_button,
  260. #self.off_button,
  261. self.all_in_one_button
  262. ])
  263. self.mainControlLayout.addWidget(self.all_in_one_button)
  264. self.mainControlLayout.addWidget(self.toggleButton)
  265. self.mainControlLayout.addWidget(self.skip_init_button)
  266. self.mainControlLayout.addWidget(self.soft_reset_button)
  267. #self.mainControlLayout.addWidget(self.off_button)
  268. self.statusLayout.addWidget(self.check_status_button)
  269. # register the led updater function (used in backendinterface.bk_status_readout)
  270. storage.get_board_specific_storage(board_id).update_LED = self.on_check
  271. self.geo = self.saveGeometry()
  272. self.subControlWidget.hide()
  273. def toggle_sub_control(self):
  274. """
  275. Show or hide the subcontrol buttons
  276. """
  277. self.subControlWidget.setHidden(not self.subControlWidget.isHidden())
  278. if self.subControlWidget.isHidden():
  279. self.toggleButton.setIcon(QtGui.QIcon(config.icon_path("chevron-bottom.svg")))
  280. else:
  281. self.toggleButton.setIcon(QtGui.QIcon(config.icon_path("chevron-top.svg")))
  282. self.parent().adjustSize()
  283. def all_in_one(self):
  284. """
  285. Function that gets called when the Prepare Board Button is pressed.
  286. It Starts the board, syncs it and sets defaults.
  287. This is accomplished via the Sequences module
  288. :return: -
  289. """
  290. seq = board.get_board_config(self.board_id).get_init_order()
  291. for item in seq:
  292. if item == 'startup_sequence':
  293. if board.is_active(board_id):
  294. logging.info('Board already powered on - skip startup_sequence')
  295. continue
  296. bif.bk_run_sequence(self.board_id, item)
  297. popup = kcgw.PopupDialog("Do not forget to turn on the T/H switches!",
  298. title='Reminder', okonly=True)
  299. popup.exec_()
  300. popup.deleteLater()
  301. popup.get_return_value()
  302. board.get_board_config(self.board_id).set_startup()
  303. def skip_init(self):
  304. """
  305. Skip board initialisation progress and read data from board. This will adjust the values in the gui to those
  306. on the board (for every value that is stored on the board)
  307. """
  308. board.get_board_config(self.board_id).read_from_board()
  309. board.get_board_status(self.board_id).calibrated = True
  310. board.get_board_status(self.board_id).synced = True
  311. board.get_board_status(self.board_id).defaults_set = True
  312. bif.bk_status_readout()
  313. logging.info("Initialisation skipped, configuration and status was read from KAPTURE.")
  314. def on_check(self):
  315. """
  316. This function is the handler for the status leds on the ControlWidget View.
  317. Parses the registers and sets the colors of the leds according.
  318. :return: -
  319. """
  320. try:
  321. status = bif.bk_get_status(self.board_id)
  322. except IndexError:
  323. error(0x002, "Pci returned not enough registers to update LEDs.")
  324. return
  325. for led, st in list(status.items()):
  326. try:
  327. getattr(self, led.lower()+"_led").set_status(st)
  328. except:
  329. pass
  330. # .d8888b. 888 888888 888d8b 888 888
  331. # d88P Y88b 888 888888 o 888Y8P 888 888
  332. # 888 888 888 888888 d8b 888 888 888
  333. # 888 .d88b. 88888b. 888888888d888 .d88b. 888888 d888b 888888 .d88888 .d88b. .d88b. 888888
  334. # 888 d88""88b888 "88b888 888P" d88""88b888888d88888b888888d88" 888d88P"88bd8P Y8b888
  335. # 888 888888 888888 888888 888 888 88888888888P Y88888888888 888888 88888888888888
  336. # Y88b d88PY88..88P888 888Y88b. 888 Y88..88P8888888P Y8888888Y88b 888Y88b 888Y8b. Y88b.
  337. # "Y8888P" "Y88P" 888 888 "Y888888 "Y88P" 888888P Y888888 "Y88888 "Y88888 "Y8888 "Y888
  338. # 888
  339. # Y8b d88P
  340. # "Y88P"
  341. class ControlWidget(kcgw.KCGWidgets):
  342. """
  343. Main Widget that is shown at start of gui.
  344. """
  345. def __init__(self):
  346. super(ControlWidget, self).__init__()
  347. self.overlayout = QtGui.QVBoxLayout()
  348. self.setLayout(self.overlayout)
  349. self.splitter = QtGui.QSplitter(QtCore.Qt.Vertical)
  350. self.overlayout.addWidget(self.splitter)
  351. self.log_area = LogArea()
  352. self.log_area.setReadOnly(True)
  353. self.log_area.init_logging()
  354. self.log_area.setKeywords([
  355. "Activating Board",
  356. "Started Board Calibration",
  357. "Synchronize PLLs",
  358. "Setting default Values",
  359. "Updating Values"
  360. ])
  361. self.board_control_list = {i: BoardControl(i, not available_boards.multi_board) for i in available_boards}
  362. self.board_widget = QtGui.QWidget()
  363. self.board_widget_layout = QtGui.QVBoxLayout()
  364. self.board_widget.setLayout(self.board_widget_layout)
  365. for bc in list(self.board_control_list.values()):
  366. self.board_widget_layout.addWidget(bc)
  367. self.board_widget_layout.addStretch(1)
  368. if available_boards.multi_board:
  369. self.scroll_widget = QtGui.QScrollArea()
  370. # self.scroll_widget.setMaximumWidth(1.1 * self.board_control_list.values()[0].minimumSizeHint().width())
  371. self.scroll_widget.setWidgetResizable(True)
  372. self.scroll_widget.setWidget(self.board_widget)
  373. self.scroll_widget_container = QtGui.QWidget()
  374. self.scroll_widget_layout = QtGui.QHBoxLayout()
  375. self.scroll_widget_layout.addWidget(self.scroll_widget)
  376. self.scroll_widget_layout.setAlignment(QtCore.Qt.AlignLeft)
  377. self.scroll_widget_container.setLayout(self.scroll_widget_layout)
  378. self.splitter.addWidget(self.scroll_widget_container)
  379. else:
  380. self.splitter.addWidget(self.board_widget)
  381. # self.log_area = QtGui.QTextEdit()
  382. self.splitter.addWidget(self.log_area)
  383. # self.setTabOrder(self.soft_reset_button, self.check_status_button)
  384. # self.setTabOrder(self.check_status_button, self.off_button)
  385. # ------------------[ Logging ]----------------------
  386. # log_handler = LogHandler(self.log_area)
  387. # self.logger = logging.getLogger()
  388. # self.logger.addHandler(log_handler)
  389. # self.logger.setLevel(config.log_level)
  390. # logging.logger = self.logger
  391. # logging.logger.addHandler(log_handler)