timingWidget.py 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  1. """
  2. This Module Is the Timingsettings subWindow.
  3. """
  4. import logging
  5. from PyQt4 import QtGui, QtCore
  6. import pyqtgraph as pg
  7. import numpy as np
  8. from ..base import kcgwidget as kcgw
  9. from ..base.backend import board
  10. from ..base.backend.board import available_boards
  11. from ..base import backendinterface as bif
  12. from ..base.groupedelements import Elements
  13. from ..base.globals import glob as global_objects
  14. from .. import config
  15. tr = kcgw.tr
  16. __widget_id__ = None
  17. __timing_plot_widget_id__ = {}
  18. __timing_plot_widget__ = None
  19. class timingPlotWidget(kcgw.KCGWidgets):
  20. """
  21. The Timescan result plot subwindow.
  22. """
  23. def __init__(self, unique_id, board_id, parent=None):
  24. """
  25. Initialises the timing plot window
  26. :param unique_id: the id for this window
  27. :param parent: parent object
  28. :return: -
  29. """
  30. super(timingPlotWidget, self).__init__()
  31. self.id = unique_id
  32. self.par = parent
  33. self.board_id = board_id
  34. # ------[ Variable declaration ]------------
  35. self.plot_type = "colour" # The Plot Type for this window (Changeable in this window)
  36. self.x = None # Number of Ticks in the x-direction This is set by the gui programmatically
  37. self.y = None # Number of Ticks in the y-direction This is set by the gui programmatically
  38. self.data = None # Data to plot
  39. self.levels = None # Levels for colors
  40. self.inputsSet = False # If Inputs (Timing) are set
  41. # -------[ Create Plot Elements ]-----------
  42. self.adc1_plot_widget = pg.PlotWidget(title="ADC 1")
  43. self.adc2_plot_widget = pg.PlotWidget(title="ADC 2")
  44. self.adc3_plot_widget = pg.PlotWidget(title="ADC 3")
  45. self.adc4_plot_widget = pg.PlotWidget(title="ADC 4")
  46. # -------[ Create structure ]----------
  47. self.outerLayout = QtGui.QVBoxLayout() # Outermost layout of this window
  48. self.setLayout(self.outerLayout)
  49. self.headerLayout = QtGui.QHBoxLayout() # Layout for the header (including the switch to change plots)
  50. self.outerLayout.addLayout(self.headerLayout)
  51. self.layout = QtGui.QGridLayout() # Main Layout to hold the most elements in this window
  52. # ------[ Create Some Elements ]-----------
  53. self.position_label = self.createLabel("")
  54. self.position_label.setAlignment(QtCore.Qt.AlignCenter)
  55. self.plot_type_switcher = self.createSwitch(connect=self.switch)
  56. # ------[ Add Elements to various layouts ]--------------
  57. self.headerLayout.addWidget(self.position_label)
  58. self.headerLayout.addWidget(self.createLabel("Colour Plot"))
  59. self.headerLayout.addWidget(self.plot_type_switcher)
  60. self.headerLayout.addWidget(self.createLabel("Line Plot"))
  61. self.headerLayout.setAlignment(QtCore.Qt.AlignRight)
  62. self.layout.addWidget(self.adc1_plot_widget, 0, 0)
  63. self.layout.addWidget(self.adc2_plot_widget, 0, 1)
  64. self.layout.addWidget(self.adc3_plot_widget, 1, 0)
  65. self.layout.addWidget(self.adc4_plot_widget, 1, 1)
  66. self.outerLayout.addLayout(self.layout)
  67. self.setWindowTitle(tr("Heading", "Timescan Results")+" "+available_boards.get_board_name_from_id(board_id))
  68. # Initially show the colour plot
  69. self.colour_plot()
  70. def switch(self):
  71. """
  72. Switch Plot types
  73. :return: -
  74. """
  75. if self.plot_type == 'colour':
  76. self.remove_colour_plot()
  77. self.line_plot()
  78. self.plot()
  79. else:
  80. self.adc1_plot_widget.plotItem.clearPlots()
  81. self.adc2_plot_widget.plotItem.clearPlots()
  82. self.adc3_plot_widget.plotItem.clearPlots()
  83. self.adc4_plot_widget.plotItem.clearPlots()
  84. self.colour_plot()
  85. self.plot()
  86. def colour_plot(self):
  87. """
  88. Initialize Color Plot
  89. :return: -
  90. """
  91. self.plot_type = "colour"
  92. self.adc1 = pg.ImageItem()
  93. self.adc2 = pg.ImageItem()
  94. self.adc3 = pg.ImageItem()
  95. self.adc4 = pg.ImageItem()
  96. self.adc1.mouseClickEvent = lambda x: self.click("ADC 1", x)
  97. self.adc2.mouseClickEvent = lambda x: self.click("ADC 2", x)
  98. self.adc3.mouseClickEvent = lambda x: self.click("ADC 3", x)
  99. self.adc4.mouseClickEvent = lambda x: self.click("ADC 4", x)
  100. def tickStrings(values, scale, spacing):
  101. """
  102. Generate the strings for ticks
  103. """
  104. if len(values) > 20:
  105. return [str(i) for i in range(int(values[0]), int(values[-1]), 2)]
  106. else:
  107. return [str(int(i)) for i in values]
  108. # ----------[ Configure and add color plots for ADC1 ]----------
  109. for i in range(1, 5):
  110. getattr(self, "adc{}_plot_widget".format(i)).getPlotItem().setLabel("left", tr("Heading", "Coarse delay"))
  111. getattr(self, "adc{}_plot_widget".format(i)).getPlotItem().setLabel("bottom", tr("Heading", "Fine delay"))
  112. getattr(self, "adc{}_plot_widget".format(i)).plotItem.addItem(getattr(self, "adc"+str(i)))
  113. bax = getattr(self, "adc{}_plot_widget".format(i)).plotItem.getAxis('bottom')
  114. lax = getattr(self, "adc{}_plot_widget".format(i)).plotItem.getAxis('left')
  115. bax.setTickSpacing(levels=[(1, 2.5),])
  116. bax.tickStrings = tickStrings
  117. lax.setTickSpacing(levels=[(1, 1.5),])
  118. lax.tickStrings = tickStrings
  119. pos = np.array([0, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 1])
  120. color = np.array([[0, 0, 255, 255], [0, 255, 255, 255], [0, 255, 0, 255], [130, 255, 0, 255], [255, 255, 0, 255], [255, 180, 0, 255], [255, 100, 0, 255], [255, 0, 0, 255]])
  121. cmap = pg.ColorMap(pos, color)
  122. lut = cmap.getLookupTable(0.0, 1.0, 256)
  123. self.adc1.setLookupTable(lut)
  124. self.adc2.setLookupTable(lut)
  125. self.adc3.setLookupTable(lut)
  126. self.adc4.setLookupTable(lut)
  127. def remove_colour_plot(self):
  128. """
  129. Remove the color plot elements
  130. :return: -
  131. """
  132. self.adc1_plot_widget.plotItem.removeItem(self.adc1)
  133. self.adc2_plot_widget.plotItem.removeItem(self.adc2)
  134. self.adc3_plot_widget.plotItem.removeItem(self.adc3)
  135. self.adc4_plot_widget.plotItem.removeItem(self.adc4)
  136. def line_plot_axis_strings(self, values, scale, spacing):
  137. """
  138. Plot to format the strings for the line plot
  139. This is used to override the default tickStrings method of pyqtgraph.AxisItem
  140. :param values: See pyqtgraph.AxisItem.tickStrings
  141. :param scale: See pyqtgraph.AxisItem.tickStrings
  142. :param spacing: See pyqtgraph.AxisItem.tickStrings
  143. :return: See pyqtgraph.AxisItem.tickStrings
  144. """
  145. coarses = [i//(self.x) for i in values]
  146. fines = [i%(self.x) for i in values]
  147. return [str(int(c))+"\n"+str(int(f)) for c, f in zip(coarses, fines)]
  148. def spacing(self, minVal, maxVal, size):
  149. """
  150. Calculate spacing between ticks
  151. This is used to override the default tickSpacing method of pyqtgraph.AxisItem
  152. :param minVal: See pyqtgraph.AxisItem.tickSpacing
  153. :param maxVal: See pyqtgraph.AxisItem.tickSpacing
  154. :param size: See pyqtgraph.AxisItem.tickSpacing
  155. :return: See pyqtgraph.AxisItem.tickSpacing
  156. """
  157. if maxVal - minVal < 20.:
  158. return [(1, 0),]
  159. else:
  160. return [(round((maxVal-minVal)/20.), 0),]
  161. def y_axis_strings(self, values, scale, spacing):
  162. """
  163. Sets the strings for the y axis
  164. :param values:
  165. :param scale:
  166. :param spacing:
  167. :return:
  168. """
  169. return [str(int(v)) for v in values]
  170. def line_plot(self):
  171. """
  172. Initialise the Line Plot
  173. :return: -
  174. """
  175. self.plot_type = "line"
  176. for i in range(1, 5):
  177. getattr(self, "adc{}_plot_widget".format(i)).getPlotItem().setLabel("left", tr("Heading", "Intensity"))
  178. getattr(self, "adc{}_plot_widget".format(i)).getPlotItem().setLabel("bottom", tr("Heading", "Coarse over Fine"))
  179. bax = getattr(self, "adc{}_plot_widget".format(i)).plotItem.getAxis('bottom')
  180. lax = getattr(self, "adc{}_plot_widget".format(i)).plotItem.getAxis('left')
  181. bax.tickSpacing = self.spacing
  182. bax.tickStrings = self.line_plot_axis_strings
  183. lax.setTickSpacing()
  184. lax.tickStrings = self.y_axis_strings
  185. def setInputs(self, coarse_input, fine_inputs):
  186. """
  187. Register the Inputfields for timing in the timingsettings window
  188. :param coarse_input: (QSpinBox) Spinbox for coarse timing settings
  189. :param fine_inputs: (list) List of (QSpinBox)es for fine timing settings
  190. :return: -
  191. """
  192. self.c_input = coarse_input
  193. self.adc1_f_input = fine_inputs[0]
  194. self.adc2_f_input = fine_inputs[1]
  195. self.adc3_f_input = fine_inputs[2]
  196. self.adc4_f_input = fine_inputs[3]
  197. self.inputsSet = True
  198. def click(self, adc, event):
  199. """
  200. Handler for the click event in color plots
  201. :param adc: (str) The ADC plot that was clicked on
  202. :param event: (QEvent) the event
  203. :return: -
  204. """
  205. event.accept()
  206. pos = event.pos()
  207. self.position_label.setText(adc + " - " + str(int(pos.x())) + ":"+str(int(pos.y())))
  208. if not self.inputsSet:
  209. return
  210. self.c_input.setValue(int(pos.y()))
  211. if adc == "ADC 1":
  212. self.adc1_f_input.setValue(int(pos.x()))
  213. elif adc == "ADC 2":
  214. self.adc2_f_input.setValue(int(pos.x()))
  215. elif adc == "ADC 3":
  216. self.adc3_f_input.setValue(int(pos.x()))
  217. elif adc == "ADC 4":
  218. self.adc4_f_input.setValue(int(pos.x()))
  219. def plot(self, data=None, levels=None, newTitle=None, maxima=None):
  220. """
  221. Plot Data
  222. :param data: (numpy 4d array) data to plot
  223. :param levels: (tuple) Min and Max Values for color plot
  224. :param newTitle: (str) The title for the window
  225. :param maxima: (list) Maximum for each adc
  226. :return: -
  227. """
  228. # if self.data is not None and data is not None: # keine ahnung
  229. # return
  230. if self.data is None and data is None:
  231. return
  232. if data is not None:
  233. self.data = data # if called with no data a replot is performed (if data is set previously)
  234. if levels is not None:
  235. self.levels = levels
  236. self.x = self.data.shape[1]
  237. self.y = self.data.shape[2]
  238. if self.plot_type == 'colour':
  239. # self.colour_plot()
  240. self.adc1.setImage(self.data[0])
  241. self.adc2.setImage(self.data[1])
  242. self.adc3.setImage(self.data[2])
  243. self.adc4.setImage(self.data[3])
  244. if self.levels:
  245. self.adc1.setLevels(self.levels)
  246. self.adc2.setLevels(self.levels)
  247. self.adc3.setLevels(self.levels)
  248. self.adc4.setLevels(self.levels)
  249. if newTitle:
  250. self.setWindowTitle(tr("Heading", "Timescan Result:") + " " + newTitle + " " +
  251. available_boards.get_board_name_from_id(self.board_id))
  252. if maxima is not None:
  253. self.adc1_plot_widget.getPlotItem().setTitle(str(tr("Heading", "ADC 1: Maximum C:{c} F:{f}")).format(
  254. c=int(maxima[0, 1]), f=int(maxima[0, 2])))
  255. self.adc2_plot_widget.getPlotItem().setTitle(str(tr("Heading", "ADC 2: Maximum C:{c} F:{f}")).format(
  256. c=int(maxima[1, 1]), f=int(maxima[1, 2])))
  257. self.adc3_plot_widget.getPlotItem().setTitle(str(tr("Heading", "ADC 3: Maximum C:{c} F:{f}")).format(
  258. c=int(maxima[2, 1]), f=int(maxima[2, 2])))
  259. self.adc4_plot_widget.getPlotItem().setTitle(str(tr("Heading", "ADC 4: Maximum C:{c} F:{f}")).format(
  260. c=int(maxima[3, 1]), f=int(maxima[3, 2])))
  261. if self.plot_type == 'line':
  262. # self.line_plot()
  263. def reshape(data):
  264. ''' simply reshape the data'''
  265. return np.reshape(data, data.shape[0]*data.shape[1], order='F')
  266. self.adc1_plot_widget.plotItem.clear()
  267. self.adc2_plot_widget.plotItem.clear()
  268. self.adc3_plot_widget.plotItem.clear()
  269. self.adc4_plot_widget.plotItem.clear()
  270. self.adc1_plot_widget.plotItem.plot(reshape(self.data[0]))
  271. self.adc2_plot_widget.plotItem.plot(reshape(self.data[1]))
  272. self.adc3_plot_widget.plotItem.plot(reshape(self.data[2]))
  273. self.adc4_plot_widget.plotItem.plot(reshape(self.data[3]))
  274. # ---[ Show this window and set focus to it ]------
  275. self.parent().show()
  276. self.show()
  277. self.setFocus()
  278. def closeEvent(self, event):
  279. """
  280. Event handler for closing this window
  281. """
  282. global __timing_plot_widget_id__
  283. __timing_plot_widget_id__ = {}
  284. del self.par.widgets[self.id]
  285. class timingPart(kcgw.KCGWidgets):
  286. """
  287. The actual timing settings window
  288. """
  289. def __init__(self, board_id, parent=None):
  290. """
  291. Initialise the timing settings window
  292. :param unique_id:
  293. :param parent:
  294. :return:
  295. """
  296. super(timingPart, self).__init__()
  297. if __timing_plot_widget__:
  298. self.plotWidget = __timing_plot_widget__
  299. self.parent = parent
  300. self.board_id = board_id
  301. self.layout = QtGui.QGridLayout()
  302. self.outerLayout = QtGui.QVBoxLayout()
  303. self.outerLayout.addLayout(self.layout)
  304. self.setLayout(self.outerLayout)
  305. self.time_scan_enabled = False
  306. # --------[ Create TimeScan part ]----------
  307. # --------[ Create Elements ]-------------
  308. self.coarse_scan_range_label = self.createLabel(tr("Label", "Coarse scan"))
  309. self.fine_scan_range_label = self.createLabel(tr("Label", "Fine scan"))
  310. self.from_label = self.createLabel(tr("Label", "From"))
  311. self.to_label = self.createLabel(tr("Label", "To"))
  312. self.coarse_scan_min_spinbox = self.createSpinbox(0, bif.bk_get_config(board_id, 'th_delay_max'), start_value=0)
  313. self.coarse_scan_max_spinbox = self.createSpinbox(0, bif.bk_get_config(board_id, 'th_delay_max'), start_value=bif.bk_get_config(board_id, 'th_delay_max'))
  314. self.fine_scan_min_spinbox = self.createSpinbox(0, bif.bk_get_config(board_id, 'chip_delay_max'), start_value=0)
  315. self.fine_scan_max_spinbox = self.createSpinbox(0, bif.bk_get_config(board_id, 'chip_delay_max'), start_value=bif.bk_get_config(board_id, 'chip_delay_max'))
  316. self.orbits_observe_spinbox = self.createSpinbox(1, 10000000, start_value=100)
  317. self.orbits_skip_spinbox = self.createSpinbox(0, 100, start_value=2)
  318. self.time_scan_progressbar = QtGui.QProgressBar()
  319. self.time_scan_button = self.createButton(tr("Button", "Start time scan"), connect=self.time_scan)
  320. Elements.addButton("start_time_scan_{}".format(board_id), self.time_scan_button)
  321. self.timeScan = QtGui.QWidget()
  322. # --------[ Create and Fill Timescan layouts ]----------------
  323. self.timeScanVLayout = QtGui.QVBoxLayout()
  324. self.timeScanLayout = QtGui.QGridLayout()
  325. self.timeScanVLayout.addWidget(self.time_scan_progressbar)
  326. self.timeScanVLayout.addLayout(self.timeScanLayout)
  327. self.timeScan.setLayout(self.timeScanVLayout)
  328. self.timeScanLayout.addWidget(self.from_label, 0, 1)
  329. self.timeScanLayout.addWidget(self.to_label, 0, 2)
  330. self.timeScanLayout.addWidget(self.coarse_scan_range_label, 1, 0)
  331. self.timeScanLayout.addWidget(self.coarse_scan_min_spinbox, 1, 1)
  332. self.timeScanLayout.addWidget(self.coarse_scan_max_spinbox, 1, 2)
  333. self.timeScanLayout.addWidget(self.fine_scan_range_label, 2, 0)
  334. self.timeScanLayout.addWidget(self.fine_scan_min_spinbox, 2, 1)
  335. self.timeScanLayout.addWidget(self.fine_scan_max_spinbox, 2, 2)
  336. self.timeScanLayout.addWidget(self.createLabel("Orbits to Observe"), 3, 1)
  337. self.timeScanLayout.addWidget(self.orbits_observe_spinbox, 3, 2)
  338. self.timeScanLayout.addWidget(self.createLabel("Orbits to Skip"), 4, 1)
  339. self.timeScanLayout.addWidget(self.orbits_skip_spinbox, 4, 2)
  340. self.timeScanLayout.addWidget(self.time_scan_button, 5, 2)
  341. self.setTabOrder(self.fine_scan_max_spinbox, self.time_scan_button)
  342. # --------[ End Time Scan Part ]-------------
  343. # --------[ Create Labels and corresponding Fields ]---------
  344. def update_delay(which, spinbox):
  345. '''update the delays on the board'''
  346. board.get_board_config(board_id).update(which, getattr(self, spinbox).value())
  347. board.get_board_config(board_id).set_delay(self.coarseInput.value())
  348. self.thdelayLabel = self.createLabel(tr("Label", "T/H Delay"))
  349. self.adc1thdelayLabel = self.createLabel(tr("Label", "2. ADC1 T/H Delay"))
  350. self.coarseLabel = self.createLabel(tr("Label", "Coarse Delay"))
  351. self.coarseInput = self.createSpinbox(0, 15, connect=lambda: update_delay("th_delay", "coarseInput"))
  352. self.adc1CoarseInput = self.createSpinbox(0, 15, connect=lambda: update_delay("adc_1_delay_individual", "adc1CoarseInput"))
  353. self.adc1CoarseInput.setEnabled(False)
  354. self.adc1CoarseInputSwitch = self.createCheckbox(tr("Label", "Enable second ADC1 T/H Delay"), connect=self.toggleAdc1IndividualDelay)
  355. self.fineLabel = self.createLabel(tr("Label", "Fine Delay"))
  356. self.fineAdc1Input = self.createSpinbox(0, 31, connect=self.on_adc_delay_changed)
  357. self.fineAdc2Input = self.createSpinbox(0, 31, connect=self.on_adc_delay_changed)
  358. self.fineAdc3Input = self.createSpinbox(0, 31, connect=self.on_adc_delay_changed)
  359. self.fineAdc4Input = self.createSpinbox(0, 31, connect=self.on_adc_delay_changed)
  360. self.toggleTimeScanCheckbox = self.createCheckbox(tr("Button", "Time Scan"), tr("Tooltip", "Show time scan part"),
  361. connect=self.showTimeScan)
  362. #---------[ End ]---------
  363. Elements.addItem(["timing_{}".format(self.board_id), "no_board_{}".format(self.board_id)], [
  364. self.coarseInput,
  365. self.fineAdc1Input,
  366. self.fineAdc2Input,
  367. self.fineAdc3Input,
  368. self.fineAdc4Input,
  369. self.time_scan_button,
  370. self.adc1CoarseInputSwitch
  371. ])
  372. Elements.addItem('acquire_{}'.format(self.board_id), self.time_scan_button)
  373. def setValueSilent(value, spinbox):
  374. '''set values silent to not trigger signals'''
  375. spinbox.blockSignals(True)
  376. spinbox.setValue(value)
  377. spinbox.blockSignals(False)
  378. # --------[ Set observers ]------------
  379. def obs(who, what):
  380. '''observe something'''
  381. board.get_board_config(board_id).observe(
  382. who,
  383. lambda value=None: setValueSilent(value=value, spinbox=who),
  384. what
  385. )
  386. obs(self.fineAdc1Input, 'chip_1_delay')
  387. obs(self.fineAdc2Input, 'chip_2_delay')
  388. obs(self.fineAdc3Input, 'chip_3_delay')
  389. obs(self.fineAdc4Input, 'chip_4_delay')
  390. obs(self.coarseInput, 'th_delay')
  391. obs(self.adc1CoarseInput, 'adc_1_delay_individual')
  392. # -------[ Create outputs ]---------------
  393. self.totalLabel = self.createLabel(tr("Label", "Total Delay"))
  394. self.totalAdc1Box = self.createInput("", read_only=True)
  395. self.totalAdc2Box = self.createInput("", read_only=True)
  396. self.totalAdc3Box = self.createInput("", read_only=True)
  397. self.totalAdc4Box = self.createInput("", read_only=True)
  398. def observe_function(x, box):
  399. '''method to pass as callable to to the configuration as observer'''
  400. box.setText('%i + %i' % (board.get_board_config(board_id).get('th_delay')*
  401. board.get_board_config(board_id).get('th_delay_factor'),
  402. x*board.get_board_config(board_id).get('chip_delay_factor')))
  403. def observe_function_total(x, box, adc):
  404. '''method to pass as callable to to the configuration as observer'''
  405. box.setText('%i + %i' % (x *
  406. board.get_board_config(board_id).get('th_delay_factor'),
  407. board.get_board_config(board_id).get('chip_'+adc+'_delay') *
  408. board.get_board_config(board_id).get('chip_delay_factor')))
  409. # def adc1_observe_function_total(x, box):
  410. # adc1_individual = board.get_board_config(board_id).get("adc_1_delay_individual")
  411. # if adc1_individual == -1:
  412. # adc1_individual = 0
  413. # box.setText('%i + %i' % ((x+adc1_individual)*
  414. # board.get_board_config(board_id).get('th_delay_factor'),
  415. # board.get_board_config(board_id).get('chip_1_delay') *
  416. # board.get_board_config(board_id).get('chip_delay_factor')))
  417. board.get_board_config(board_id).observe(self.totalAdc1Box,
  418. lambda x: observe_function(x, self.totalAdc1Box), 'chip_1_delay')
  419. board.get_board_config(board_id).observe(self.totalAdc1Box,
  420. lambda x: observe_function_total(x, self.totalAdc1Box, '1'), 'th_delay')
  421. # board.get_board_config(board_id).observe(self.totalAdc1Box, lambda x: adc1_observe_function_total(x, self.totalAdc1Box), 'th_delay')
  422. # board.get_board_config(board_id).observe(self.totalAdc1Box, lambda x: adc1_observe_function_total(x, self.totalAdc1Box), 'adc_1_delay_individual')
  423. board.get_board_config(board_id).observe(self.totalAdc2Box,
  424. lambda x: observe_function(x, self.totalAdc2Box), 'chip_2_delay')
  425. board.get_board_config(board_id).observe(self.totalAdc2Box,
  426. lambda x: observe_function_total(x, self.totalAdc2Box, '2'), 'th_delay')
  427. board.get_board_config(board_id).observe(self.totalAdc3Box,
  428. lambda x: observe_function(x, self.totalAdc3Box), 'chip_3_delay')
  429. board.get_board_config(board_id).observe(self.totalAdc3Box,
  430. lambda x: observe_function_total(x, self.totalAdc3Box, '3'), 'th_delay')
  431. board.get_board_config(board_id).observe(self.totalAdc4Box,
  432. lambda x: observe_function(x, self.totalAdc4Box), 'chip_4_delay')
  433. board.get_board_config(board_id).observe(self.totalAdc4Box,
  434. lambda x: observe_function_total(x, self.totalAdc4Box, '4'), 'th_delay')
  435. #--------[ Fill Grid ]----------------
  436. self.layout.addWidget(self.thdelayLabel, 0, 1)
  437. self.layout.addWidget(self.coarseLabel, 1, 0)
  438. self.layout.addWidget(self.coarseInput, 1, 1)
  439. self.layout.addWidget(self.adc1thdelayLabel, 0, 2)
  440. self.layout.addWidget(self.adc1CoarseInput, 1, 2)
  441. self.layout.addWidget(self.adc1CoarseInputSwitch, 1, 3, 1, 2)
  442. self.layout.addItem(QtGui.QSpacerItem(10, 15), 2, 1)
  443. # Leave some rows free for additional things (empty rows will not be shown)
  444. for i in range(4):
  445. self.layout.addWidget(self.createLabel("ADC "+str(i+1)), 5, i+1)
  446. self.layout.addWidget(self.fineLabel, 6, 0)
  447. self.layout.addWidget(self.fineAdc1Input, 6, 1)
  448. self.layout.addWidget(self.fineAdc2Input, 6, 2)
  449. self.layout.addWidget(self.fineAdc3Input, 6, 3)
  450. self.layout.addWidget(self.fineAdc4Input, 6, 4)
  451. self.layout.addItem(QtGui.QSpacerItem(10, 15), 7, 1)
  452. line = QtGui.QFrame()
  453. line.setFrameStyle(QtGui.QFrame.HLine)
  454. self.layout.addWidget(line, 8, 0, 1, 5)
  455. self.layout.addItem(QtGui.QSpacerItem(10, 15), 9, 1)
  456. self.layout.addWidget(self.totalLabel, 10, 0)
  457. self.layout.addWidget(self.totalAdc1Box, 10, 1)
  458. self.layout.addWidget(self.totalAdc2Box, 10, 2)
  459. self.layout.addWidget(self.totalAdc3Box, 10, 3)
  460. self.layout.addWidget(self.totalAdc4Box, 10, 4)
  461. self.layout.addItem(QtGui.QSpacerItem(10, 15), 11, 1)
  462. self.layout.addWidget(self.toggleTimeScanCheckbox, 12, 0)
  463. # -------[ Add TimeScan ]---------
  464. self.outerLayout.addWidget(self.timeScan)
  465. self.timeScan.hide()
  466. self.outerLayout.addStretch(1)
  467. # -------[ End ]-----------
  468. # ------[ Exclude Total Delay Boxes from Tab Order ]--------
  469. self.totalAdc1Box.setFocusPolicy(QtCore.Qt.ClickFocus)
  470. self.totalAdc2Box.setFocusPolicy(QtCore.Qt.ClickFocus)
  471. self.totalAdc3Box.setFocusPolicy(QtCore.Qt.ClickFocus)
  472. self.totalAdc4Box.setFocusPolicy(QtCore.Qt.ClickFocus)
  473. self.setTabOrder(self.fineAdc4Input, self.toggleTimeScanCheckbox)
  474. self.setValues()
  475. self.setWindowTitle(tr("Heading", "Timing"))
  476. def toggleAdc1IndividualDelay(self):
  477. """
  478. Toggle to use an individual delay for adc1 or not
  479. :return: -
  480. """
  481. self.adc1CoarseInput.setEnabled(self.adc1CoarseInputSwitch.checkState())
  482. if not self.adc1CoarseInput.isEnabled():
  483. board.get_board_config(self.board_id).update('adc_1_delay_individual', -1) # Be careful this does no silent update
  484. def showTimeScan(self):
  485. """
  486. Show the time scan part of this window
  487. :return: -
  488. """
  489. if self.timeScan.isHidden():
  490. # self.outerLayout.addWidget(self.timeScan)
  491. self.timeScan.show()
  492. else:
  493. self.timeScan.hide()
  494. # self.outerLayout.removeWidget(self.timeScan)
  495. self.parent.adjustSizeForTimeScan()
  496. def time_scan(self):
  497. """
  498. Toggle timescan and create timingPlotWidget if it doesn't exist
  499. :return: -
  500. """
  501. global __timing_plot_widget_id__
  502. global __timing_plot_widget__
  503. if not (self.board_id in __timing_plot_widget_id__):
  504. nid = kcgw.idg.genid()
  505. __timing_plot_widget_id__[self.board_id] = nid
  506. self.plotWidget = timingPlotWidget(nid, self.board_id, global_objects.get_global('area'))
  507. __timing_plot_widget__ = self.plotWidget
  508. global_objects.get_global('area').newWidget(self.plotWidget, tr("Heading", "Timing result"), nid, widget_type=5)
  509. self.plotWidget.parent().hide()
  510. self.plotWidget.setInputs(self.coarseInput, [
  511. self.fineAdc1Input,
  512. self.fineAdc2Input,
  513. self.fineAdc3Input,
  514. self.fineAdc4Input
  515. ])
  516. bif.bk_time_scan(
  517. self.board_id,
  518. self.coarse_scan_min_spinbox.value(),
  519. self.coarse_scan_max_spinbox.value(),
  520. self.fine_scan_min_spinbox.value(),
  521. self.fine_scan_max_spinbox.value(),
  522. self.time_scan_progressbar,
  523. self.plotWidget.plot,
  524. orbits_observe = self.orbits_observe_spinbox.value(),
  525. orbits_skip = self.orbits_skip_spinbox.value()
  526. )
  527. def setValueSilent(self, element, value):
  528. """
  529. Set Values to inputs without notifying observers
  530. :param element: the input
  531. :param value: the value
  532. :return: -
  533. """
  534. element.blockSignals(True)
  535. element.setValue(value)
  536. element.blockSignals(False)
  537. def setValues(self):
  538. """
  539. Set Values to inputs (initially)
  540. :return: -
  541. """
  542. self.setValueSilent(self.fineAdc1Input, board.get_board_config(self.board_id).get('chip_1_delay'))
  543. self.setValueSilent(self.fineAdc2Input, board.get_board_config(self.board_id).get('chip_2_delay'))
  544. self.setValueSilent(self.fineAdc3Input, board.get_board_config(self.board_id).get('chip_3_delay'))
  545. self.setValueSilent(self.fineAdc4Input, board.get_board_config(self.board_id).get('chip_4_delay'))
  546. self.setValueSilent(self.coarseInput, board.get_board_config(self.board_id).get('th_delay'))
  547. if board.get_board_config(self.board_id).get('adc_1_delay_individual') != -1: # This may be nonsense Also: it is only possible to set adc1 higher than th_delay
  548. self.totalAdc1Box.setText('%i + %i' % ((board.get_board_config(self.board_id).get('th_delay')+board.get_board_config(self.board_id).get('adc_1_delay_individual'))
  549. * board.get_board_config(self.board_id).get('th_delay_factor'),
  550. board.get_board_config(self.board_id).get('chip_1_delay')*board.get_board_config(self.board_id).get('chip_delay_factor')))
  551. else:
  552. self.totalAdc1Box.setText('%i + %i' % (board.get_board_config(self.board_id).get('th_delay')* board.get_board_config(self.board_id).get('th_delay_factor'),
  553. board.get_board_config(self.board_id).get('chip_1_delay')*board.get_board_config(self.board_id).get('chip_delay_factor')))
  554. self.totalAdc2Box.setText('%i + %i' % (board.get_board_config(self.board_id).get('th_delay')* board.get_board_config(self.board_id).get('th_delay_factor'),
  555. board.get_board_config(self.board_id).get('chip_2_delay')*board.get_board_config(self.board_id).get('chip_delay_factor')))
  556. self.totalAdc3Box.setText('%i + %i' % (board.get_board_config(self.board_id).get('th_delay')* board.get_board_config(self.board_id).get('th_delay_factor'),
  557. board.get_board_config(self.board_id).get('chip_3_delay')*board.get_board_config(self.board_id).get('chip_delay_factor')))
  558. self.totalAdc4Box.setText('%i + %i' % (board.get_board_config(self.board_id).get('th_delay')* board.get_board_config(self.board_id).get('th_delay_factor'),
  559. board.get_board_config(self.board_id).get('chip_4_delay')*board.get_board_config(self.board_id).get('chip_delay_factor')))
  560. def closeEvent(self, event):
  561. """
  562. Event handler when this window is closed
  563. """
  564. Elements.emptyGroup('timing_{}'.format(self.board_id))
  565. board.get_board_config(self.board_id).unobserve(self.fineAdc1Input, 'chip_1_delay')
  566. board.get_board_config(self.board_id).unobserve(self.fineAdc2Input, 'chip_2_delay')
  567. board.get_board_config(self.board_id).unobserve(self.fineAdc3Input, 'chip_3_delay')
  568. board.get_board_config(self.board_id).unobserve(self.fineAdc4Input, 'chip_4_delay')
  569. board.get_board_config(self.board_id).unobserve(self.coarseInput, 'th_delay')
  570. board.get_board_config(self.board_id).unobserve(self.totalAdc1Box, 'chip_1_delay')
  571. board.get_board_config(self.board_id).unobserve(self.totalAdc2Box, 'chip_2_delay')
  572. board.get_board_config(self.board_id).unobserve(self.totalAdc3Box, 'chip_3_delay')
  573. board.get_board_config(self.board_id).unobserve(self.totalAdc4Box, 'chip_4_delay')
  574. board.get_board_config(self.board_id).unobserve(self.totalAdc1Box, 'th_delay')
  575. board.get_board_config(self.board_id).unobserve(self.totalAdc2Box, 'th_delay')
  576. board.get_board_config(self.board_id).unobserve(self.totalAdc3Box, 'th_delay')
  577. board.get_board_config(self.board_id).unobserve(self.totalAdc4Box, 'th_delay')
  578. board.get_board_config(self.board_id).unobserve(self.adc1CoarseInput, 'adc_1_delay_individual')
  579. Elements.removeItem('no_board_{}'.format(self.board_id),
  580. [
  581. self.fineAdc1Input,
  582. self.fineAdc2Input,
  583. self.fineAdc3Input,
  584. self.fineAdc4Input,
  585. self.coarseInput,
  586. self.time_scan_button,
  587. self.adc1CoarseInputSwitch
  588. ])
  589. Elements.removeItem("start_time_scan_{}".format(self.board_id), self.time_scan_button)
  590. Elements.removeItem(['acquire_{}'.format(self.board_id), "start_time_scan_{}".format(self.board_id)], self.time_scan_button)
  591. super(timingPart, self).closeEvent(event)
  592. def on_adc_delay_changed(self):
  593. """
  594. Handler that gets called when an adc delay gets changed
  595. """
  596. try:
  597. board.get_board_config(self.board_id).set_delay(self.coarseInput.value())
  598. factors = [self.fineAdc1Input.value(), self.fineAdc2Input.value(),
  599. self.fineAdc3Input.value(), self.fineAdc4Input.value()]
  600. board.get_board_config(self.board_id).set_chip_delay([0, 1, 2, 3], factors)
  601. except board.BoardError as e:
  602. logging.error("ADC fine delay failed: {}".format(str(e)))
  603. bif.bk_status_readout(self.board_id)
  604. return
  605. class timingWidget(kcgw.KCGWidgets):
  606. """
  607. This is the container that holds the tab widget which contains the timing widgets for each board
  608. """
  609. def __init__(self, unique_id, parent=None):
  610. super(timingWidget, self).__init__()
  611. self.id = unique_id
  612. self.par = parent
  613. self.setWindowTitle("Timing")
  614. self.layout = QtGui.QHBoxLayout()
  615. self.setLayout(self.layout)
  616. self.widgets = {i: timingPart(i, self) for i in available_boards} # has to set parent with self because
  617. # otherwise the window does not get resized correctly upon enabling timescan
  618. if available_boards.multi_board:
  619. self.tabWidget = QtGui.QTabWidget()
  620. self.layout.addWidget(self.tabWidget)
  621. for id, widget in self.widgets.iteritems():
  622. self.tabWidget.addTab(widget, available_boards.get_board_name_from_id(id))
  623. else:
  624. self.single_board_widget = self.widgets.values()[0]
  625. self.layout.addWidget(self.single_board_widget)
  626. def adjustSizeForTimeScan(self):
  627. """
  628. Adjust the size of the widget to accomodate the time_scan part
  629. :return:
  630. """
  631. # self.parentWindow = self.parent().parent().parent().parent() # one up is stacked widget, second up is
  632. # tab widget, third up is timingWidget fourh up is KCGWSubWindow (the actual window)
  633. QtCore.QCoreApplication.processEvents()
  634. if self.parent().windowState() & QtCore.Qt.WindowMaximized:
  635. self.parent().setWindowState(QtCore.Qt.WindowMaximized)
  636. else:
  637. # self.parent().resize(self.minimumSizeHint().width() * 1.2, self.minimumSizeHint().height()*1.1)
  638. self.parent().adjustSize()
  639. def closeEvent(self, event):
  640. global __widget_id__
  641. __widget_id__ = None
  642. for widget in self.widgets.values():
  643. widget.closeEvent(event)
  644. del self.par.widgets[self.id]
  645. super(timingWidget, self).closeEvent(event)
  646. def addTimingWidget():
  647. """
  648. Add this widget to the gui.
  649. This function will actually open the subwindow.
  650. :return: -
  651. """
  652. global __widget_id__
  653. if __widget_id__:
  654. global_objects.get_global('area').widgets[__widget_id__].setFocus()
  655. else:
  656. nid = kcgw.idg.genid()
  657. __widget_id__ = nid
  658. w = timingWidget(nid, global_objects.get_global('area'))
  659. global_objects.get_global('area').newWidget(w, tr("Heading", "Timing"), nid, widget_type=4, minSize=True) #TODO: proper type
  660. kcgw.register_widget(QtGui.QIcon(config.install_path + config.timingIcon), tr("Heading", "Timing"), addTimingWidget, "Ctrl+T")