TimingWidget.py 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  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. import h5py
  9. from ..base import kcgwidget as kcgw
  10. from ..base.backend import board
  11. from ..base.backend.board import available_boards
  12. from ..base import backendinterface as bif
  13. from ..base.groupedelements import Elements
  14. from ..base.globals import glob as global_objects
  15. from .. import config
  16. from ..base import storage
  17. from ..base.backend.CalibrationHandle import theCalibration
  18. tr = kcgw.tr
  19. import os
  20. __widget_id__ = None
  21. __timing_plot_widget_id__ = {}
  22. __timing_plot_widget__ = None
  23. BUNCHES_PER_TURN = config.bunches_per_turn
  24. # 88888888888d8b d8b 8888888b. 888
  25. # 888 Y8P Y8P 888 Y88b 888
  26. # 888 888 888 888
  27. # 888 88888888b.d88b. 88888888b. .d88b. 888 d88P 8888b. 888d888888888
  28. # 888 888888 "888 "88b888888 "88bd88P"88b8888888P" "88b888P" 888
  29. # 888 888888 888 888888888 888888 888888 .d888888888 888
  30. # 888 888888 888 888888888 888Y88b 888888 888 888888 Y88b.
  31. # 888 888888 888 888888888 888 "Y88888888 "Y888888888 "Y888
  32. # 888
  33. # Y8b d88P
  34. # "Y88P"
  35. class TimingPart(kcgw.KCGWidgets):
  36. """
  37. The actual timing settings window
  38. """
  39. def __init__(self, board_id, parent=None):
  40. """
  41. Initialise the timing settings window
  42. :param unique_id:
  43. :param parent:
  44. :return:
  45. """
  46. super(TimingPart, self).__init__()
  47. if __timing_plot_widget__:
  48. self.plotWidget = __timing_plot_widget__
  49. self.parent = parent
  50. self.board_id = board_id
  51. self.board_config = board.get_board_config(board_id)
  52. self.layout = QtGui.QGridLayout()
  53. self.outerLayout = QtGui.QVBoxLayout()
  54. self.outerLayout.addLayout(self.layout)
  55. self.setLayout(self.outerLayout)
  56. self.show_advanced = True
  57. # --------[ Create Labels and corresponding Fields ]---------
  58. def update_delay(which, spinbox):
  59. '''update the delays on the board'''
  60. val = getattr(self, spinbox).value()
  61. self.board_config.update(which, val)
  62. #if not self.show_advanced and "th" in which:
  63. # key = which[:-2] + "adc"
  64. # self.board_config.update(key, val)
  65. self.adc_number = self.board_config.get('adc_number')
  66. #board.get_board_config(board_id).set_delay(self.coarseInput.value())
  67. self.thdelayLabel = self.createLabel(tr("Label", "Total Delay"))
  68. #self.adc1thdelayLabel = self.createLabel(tr("Label", "2. ADC1 T/H Delay"))
  69. self.labelCoarseAdcDelay = self.createLabel("ADC")
  70. self.labelCoarseFpgaDelay = self.createLabel("FPGA")
  71. if self.adc_number > 4:
  72. self.thdelayLabel_2 = self.createLabel("T/H FMC2")
  73. self.labelCoarseAdcDelay_2 = self.createLabel("ADC FMC2")
  74. #self.labelCoarseFpgaDelay_2 = self.createLabel("FPGA FMC2")
  75. self.labelCascade = self.createLabel("Cascade")
  76. self.coarseLabel = self.createLabel(tr("Label", "330ps Coarse Delay"))
  77. self.coarseInputTh = self.createSpinbox(0, self.board_config.get('delay_330_max'), connect=lambda: update_delay("delay_330_th", "coarseInputTh"))
  78. self.coarseInputAdc = self.createSpinbox(0, self.board_config.get('delay_330_max'), connect=lambda: update_delay("delay_330_adc", "coarseInputAdc"))
  79. self.coarseInputFpga = self.createSpinbox(0, self.board_config.get('delay_330_max'), connect=lambda: update_delay("delay_330_fpga", "coarseInputFpga"))
  80. Elements.addItem(["timing_{}".format(self.board_id), "no_board_{}".format(self.board_id), "acquire_{}".format(self.board_id), "continuous_read_{}".format(board_id)],
  81. [
  82. #self.coarseInputFpga,
  83. #self.coarseInputAdc,
  84. self.coarseInputTh
  85. ]
  86. )
  87. #self.coarseInputAdc.setEnabled(False)
  88. #self.coarseInputFpga.setEnabled(False)
  89. if self.board_config.is_KAPTURE2():
  90. self.coarse2Label = self.createLabel(tr("Label", "25ps Coarse Delay"))
  91. self.coarse2InputTh = self.createSpinbox(0, self.board_config.get('delay_25_max'), connect=lambda: update_delay("delay_25_th", "coarse2InputTh"))
  92. self.coarse2InputAdc = self.createSpinbox(0, self.board_config.get('delay_25_max'), connect=lambda: update_delay("delay_25_adc", "coarse2InputAdc"))
  93. self.coarse2InputFpga = self.createSpinbox(0, self.board_config.get('delay_25_max'), connect=lambda: update_delay("delay_25_fpga", "coarse2InputFpga"))
  94. Elements.addItem(["timing_{}".format(self.board_id), "no_board_{}".format(self.board_id), "acquire_{}".format(self.board_id), "continuous_read_{}".format(board_id)],
  95. [
  96. #self.coarse2InputAdc,
  97. #self.coarse2InputFpga,
  98. self.coarse2InputTh
  99. ]
  100. )
  101. self.adc1CoarseInputSwitch = self.createCheckbox(tr("Label", "Enable advanced"), connect=self.toggleAdvanced)
  102. if self.adc_number > 4:
  103. #self.coarseLabel_2 = self.createLabel(tr("Label", "330ps FMC2"))
  104. self.coarseInputTh_2 = self.createSpinbox(0, self.board_config.get('delay_330_max'), connect=lambda: update_delay("delay_330_th_2", "coarseInputTh_2"))
  105. self.coarseInputAdc_2 = self.createSpinbox(0, self.board_config.get('delay_330_max'), connect=lambda: update_delay("delay_330_adc_2", "coarseInputAdc_2"))
  106. #self.coarseInputFpga_2 = self.createSpinbox(0, self.board_config.get('delay_330_max'), connect=lambda: update_delay("delay_330_fpga_2", "coarseInputFpga_2"))
  107. #self.coarse2Label = self.createLabel(tr("Label", "25ps FMC2"))
  108. self.coarse2InputTh_2 = self.createSpinbox(0, self.board_config.get('delay_25_max'), connect=lambda: update_delay("delay_25_th_2", "coarse2InputTh_2"))
  109. self.coarse2InputAdc_2 = self.createSpinbox(0, self.board_config.get('delay_25_max'), connect=lambda: update_delay("delay_25_adc_2", "coarse2InputAdc_2"))
  110. #self.coarse2InputFpga_2 = self.createSpinbox(0, self.board_config.get('delay_25_max'), connect=lambda: update_delay("delay_25_fpga_2", "coarse2InputFpga_2"))
  111. self.coarseInputCascade = self.createSpinbox(0, self.board_config.get('delay_cascade_max'), connect=lambda: update_delay("delay_cascade", "coarseInputCascade"))
  112. self.coarse2InputCascade = self.createSpinbox(0, self.board_config.get('delay_25_max'), connect=lambda: update_delay("delay_cascade_25", "coarse2InputCascade"))
  113. Elements.addItem(["timing_{}".format(self.board_id), "no_board_{}".format(self.board_id), "acquire_{}".format(self.board_id), "continuous_read_{}".format(board_id)],
  114. [
  115. #self.coarseInputFpga,
  116. #self.coarseInputAdc,
  117. #self.coarseInputTh_2,
  118. #self.coarse2InputAdc,
  119. #self.coarse2InputFpga,
  120. self.coarse2InputTh_2
  121. ]
  122. )
  123. self.fineLabel = self.createLabel(tr("Label", "Fine Delay"))
  124. self.fineAdcInput = []
  125. for i in range(self.adc_number):
  126. self.fineAdcInput.append(self.createSpinbox(0, 31, connect=self.on_adc_delay_changed))
  127. Elements.addItem(["timing_{}".format(self.board_id),
  128. "no_board_{}".format(self.board_id),
  129. "acquire_{}".format(self.board_id),
  130. "continuous_read_{}".format(board_id)], self.fineAdcInput)
  131. self.bunchShiftLabel = self.createLabel(tr("Label", "Bunch Shift"))
  132. self.bunchShiftInput = []
  133. for i in range(self.adc_number):
  134. self.bunchShiftInput.append(self.createSpinbox(-2, 2, connect=self.on_bunch_shift_changed))
  135. Elements.addItem(["timing_{}".format(self.board_id),
  136. "no_board_{}".format(self.board_id),
  137. "acquire_{}".format(self.board_id),
  138. "continuous_read_{}".format(board_id)], self.bunchShiftInput)
  139. #---------[ End ]---------
  140. def setValueSilent(value, spinbox, adc):
  141. '''set values silent to not trigger signals'''
  142. spinbox.blockSignals(True)
  143. if adc is None:
  144. spinbox.setValue(value)
  145. else:
  146. spinbox.setValue(value[adc])
  147. spinbox.blockSignals(False)
  148. #Bunch Shift values are encoded 0x0 - 0x4 in Hardware
  149. #but displayed as -2 to +2 in the GUI, so we need to offset
  150. #the received register value by -2 when receiving an update
  151. def setBunchShiftValuesSilent(values):
  152. for i, v in enumerate(values):
  153. self.bunchShiftInput[i].blockSignals(True)
  154. self.bunchShiftInput[i].setValue(v-2)
  155. self.bunchShiftInput[i].blockSignals(False)
  156. # --------[ Set observers ]------------
  157. def obs(who, what, adc=None):
  158. '''observe something'''
  159. board.get_board_config(board_id).observe(
  160. who,
  161. lambda value=None: setValueSilent(value=value, spinbox=who, adc=adc),
  162. what
  163. )
  164. for i, item in enumerate(self.fineAdcInput):
  165. obs(item, 'chip_delay', i)
  166. obs(self.coarseInputTh, 'delay_330_th')
  167. obs(self.coarseInputAdc, 'delay_330_adc')
  168. obs(self.coarseInputFpga, 'delay_330_fpga')
  169. if self.board_config.is_KAPTURE2():
  170. obs(self.coarse2InputTh, 'delay_25_th')
  171. obs(self.coarse2InputAdc, 'delay_25_adc')
  172. obs(self.coarse2InputFpga, 'delay_25_fpga')
  173. if self.adc_number > 4:
  174. obs(self.coarseInputTh_2, 'delay_330_th_2')
  175. obs(self.coarseInputAdc_2, 'delay_330_adc_2')
  176. #obs(self.coarseInputFpga_2, 'delay_330_fpga_2')
  177. obs(self.coarseInputCascade, 'delay_cascade')
  178. obs(self.coarse2InputTh_2, 'delay_25_th_2')
  179. obs(self.coarse2InputAdc_2, 'delay_25_adc_2')
  180. obs(self.coarse2InputCascade, 'delay_cascade_25')
  181. #obs(self.coarse2InputFpga_2, 'delay_25_fpga_2')
  182. #obs(self.adc1CoarseInput, 'adc_1_delay_individual')
  183. board.get_board_config(board_id).observe(
  184. self.bunchShiftInput,
  185. setBunchShiftValuesSilent,
  186. 'bunch_shift'
  187. )
  188. # -------[ Create outputs ]---------------
  189. self.totalLabel = self.createLabel(tr("Label", "Total Delay"))
  190. self.totalAdcBox = []
  191. for i in range(self.adc_number):
  192. self.totalAdcBox.append(self.createInput("", read_only=True))
  193. self.totalAdcBoxCalib = []
  194. for i in range(self.adc_number):
  195. self.totalAdcBoxCalib.append(self.createInput("", read_only=True))
  196. self.board_config.observe(self.totalAdcBox[0], self.delay_observer, 'chip_delay')
  197. self.board_config.observe(self.totalAdcBox[0], self.delay_observer, 'delay_330_th')
  198. if self.board_config.is_KAPTURE2():
  199. self.board_config.observe(self.totalAdcBox[0], self.delay_observer, 'delay_25_th')
  200. if self.adc_number > 4:
  201. self.board_config.observe(self.totalAdcBox[0], self.delay_observer, 'delay_330_th_2')
  202. self.board_config.observe(self.totalAdcBox[0], self.delay_observer, 'delay_25_th_2')
  203. #--------[ Fill Grid ]----------------
  204. self.layout.addWidget(self.thdelayLabel, 0, 1)
  205. self.layout.addWidget(self.labelCoarseAdcDelay, 0, 2)
  206. self.layout.addWidget(self.labelCoarseFpgaDelay, 0, 3)
  207. if self.board_config.is_KAPTURE2():
  208. self.layout.addWidget(self.adc1CoarseInputSwitch, 0, 8,1,2)
  209. if self.adc_number > 4:
  210. self.layout.addWidget(self.thdelayLabel_2, 0, 4)
  211. self.layout.addWidget(self.labelCoarseAdcDelay_2, 0, 5)
  212. #self.layout.addWidget(self.labelCoarseFpgaDelay_2, 0, 6)
  213. self.layout.addWidget(self.labelCascade, 0, 7)
  214. self.layout.addWidget(self.coarseLabel, 1, 0)
  215. self.layout.addWidget(self.coarseInputTh, 1, 1)
  216. self.layout.addWidget(self.coarseInputAdc, 1, 2)
  217. self.layout.addWidget(self.coarseInputFpga, 1, 3)
  218. #self.layout.addWidget(self.adc1thdelayLabel, 0, 2)
  219. #self.layout.addWidget(self.adc1CoarseInput, 1, 2)
  220. #self.layout.addWidget(self.adc1CoarseInputSwitch, 1, 3, 1, 2)
  221. self.layout.addItem(QtGui.QSpacerItem(10, 15), 2, 1)
  222. if self.board_config.is_KAPTURE2():
  223. self.layout.addWidget(self.coarse2Label, 3, 0)
  224. self.layout.addWidget(self.coarse2InputTh, 3, 1)
  225. self.layout.addWidget(self.coarse2InputAdc, 3, 2)
  226. self.layout.addWidget(self.coarse2InputFpga, 3, 3)
  227. if self.adc_number > 4:
  228. self.layout.addWidget(self.coarseInputTh_2, 1, 4)
  229. self.layout.addWidget(self.coarseInputAdc_2, 1, 5)
  230. #self.layout.addWidget(self.coarseInputFpga_2, 1, 6)
  231. self.layout.addWidget(self.coarseInputCascade, 1, 7)
  232. self.layout.addWidget(self.coarse2InputTh_2, 3, 4)
  233. self.layout.addWidget(self.coarse2InputAdc_2, 3, 5)
  234. #self.layout.addWidget(self.coarse2InputFpga_2, 3, 6)
  235. self.layout.addWidget(self.coarse2InputCascade, 3, 7)
  236. self.layout.addItem(QtGui.QSpacerItem(10, 15), 4, 1)
  237. # Leave some rows free for additional things (empty rows will not be shown)
  238. for i in range(self.adc_number):
  239. self.layout.addWidget(self.createLabel("ADC "+str(i+1)), 5, i+1)
  240. self.layout.addWidget(self.fineLabel, 6, 0)
  241. for i, item in enumerate(self.fineAdcInput):
  242. self.layout.addWidget(item, 6, i+1)
  243. self.layout.addWidget(self.bunchShiftLabel, 7, 0)
  244. for i, item in enumerate(self.bunchShiftInput):
  245. self.layout.addWidget(item, 7, i+1)
  246. self.layout.addItem(QtGui.QSpacerItem(10, 15), 7, 1)
  247. line = QtGui.QFrame()
  248. line.setFrameStyle(QtGui.QFrame.HLine)
  249. self.layout.addWidget(line, 8, 0, 1, 0)
  250. self.layout.addItem(QtGui.QSpacerItem(10, 15), 9, 1)
  251. self.layout.addWidget(self.totalLabel, 10, 0)
  252. for i, item in enumerate(self.totalAdcBox):
  253. self.layout.addWidget(item, 10, i+1)
  254. item.setFocusPolicy(QtCore.Qt.ClickFocus)
  255. self.layout.addWidget(self.createLabel('Calibrated (ps)'), 11, 0)
  256. for i, item in enumerate(self.totalAdcBoxCalib):
  257. self.layout.addWidget(item, 11, i+1)
  258. self.layout.addItem(QtGui.QSpacerItem(10, 15), 11, 1)
  259. self.board_config.notify_all_observers()
  260. self.toggleAdvanced()
  261. self.setWindowTitle(tr("Heading", "Timing"))
  262. def delay_observer(self, x):
  263. d330 = ['delay_330_th', 'delay_330_th']
  264. d25 = ['delay_25_th', 'delay_25_th']
  265. for i, item in enumerate(self.totalAdcBox):
  266. if self.board_config.is_KAPTURE2():
  267. string = '%i + %i + %i' % (self.board_config.get(d330[i//4]) * self.board_config.get('delay_330_factor'),
  268. self.board_config.get(d25[i//4]) * self.board_config.get('delay_25_factor'),
  269. (self.board_config.get('chip_delay')[i]) * self.board_config.get('chip_delay_factor'))
  270. if i < 4:
  271. string += "+ {:d}".format(self.board_config.get("delay_330_th_2") * self.board_config.get('delay_330_factor')
  272. + (self.board_config.get("delay_25_th_2")- self.board_config.get("default_25_th_2")) * self.board_config.get('delay_25_factor'))
  273. item.setText(string)
  274. val = self.board_config.get(d25[i//4]) * self.board_config.get('delay_25_factor')+self.board_config.get('chip_delay')[i] * self.board_config.get('chip_delay_factor')
  275. if val == self.board_config.get('delay_330_factor'):
  276. item.setStyleSheet("color: rgb(120, 80, 0);")
  277. elif val > self.board_config.get('delay_330_factor'):
  278. item.setStyleSheet("color: rgb(200, 80, 0);")
  279. else:
  280. item.setStyleSheet("color: rgb(0, 0, 0);")
  281. else:
  282. item.setText('%i + %i' % (self.board_config.get('delay_330_th') * self.board_config.get('delay_330_factor'),
  283. self.board_config.get('chip_delay')[i] * self.board_config.get('chip_delay_factor')))
  284. if self.board_config.is_KAPTURE2():
  285. for i, item in enumerate(self.totalAdcBoxCalib):
  286. value = theCalibration.calibrateX(i, self.board_config.get('delay_330_th'), self.board_config.get('delay_25_th'), self.board_config.get('chip_delay')[i], self.board_config.get("delay_25_th_2"))
  287. item.setText('{}'.format(np.round(value*1e12,1)))
  288. """
  289. if self.fileHandle is not None:
  290. for i, item in enumerate(self.totalAdcBoxCalib):
  291. item.setText('{:.1f}'.format(self.board_config.get(d330[i//4]) * self.xcalib['d330'][()] + self.xcalib[str(i)]['33'][int(self.board_config.get(d330[i//4]))] +
  292. self.board_config.get(d25[i//4]) * self.xcalib['d25'][()] + self.xcalib[str(i)]['25'][int(self.board_config.get(d25[i//4]))] +
  293. self.board_config.get('chip_delay')[i]* self.xcalib['d3'][()] + self.xcalib[str(i)]['3'][int(self.board_config.get('chip_delay')[i])] -
  294. float(self.fileHandle['x'][str(i)]['offset'][()])*1e12
  295. ))
  296. else:
  297. for i, item in enumerate(self.totalAdcBoxCalib):
  298. value = (self.board_config.get(d330[i//4]) * self.board_config.get('delay_330_factor')
  299. + self.board_config.get(d25[i//4]) * self.board_config.get('delay_25_factor')
  300. + (self.board_config.get('chip_delay')[i]) * self.board_config.get('chip_delay_factor'))
  301. if i>=4:
  302. value -= (self.board_config.get("delay_330_th_2") * self.board_config.get('delay_330_factor')
  303. + self.board_config.get("delay_25_th_2") * self.board_config.get('delay_25_factor'))
  304. item.setText(str(value))
  305. """
  306. def toggleAdvanced(self):
  307. if self.show_advanced:
  308. self.labelCoarseAdcDelay.setEnabled(False)
  309. self.labelCoarseFpgaDelay.setEnabled(False)
  310. self.coarseInputAdc.setEnabled(False)
  311. self.coarseInputFpga.setEnabled(False)
  312. if self.board_config.is_KAPTURE2():
  313. self.coarse2InputAdc.setEnabled(False)
  314. self.coarse2InputFpga.setEnabled(False)
  315. if self.adc_number > 4:
  316. self.labelCoarseAdcDelay_2.setEnabled(False)
  317. #self.labelCoarseFpgaDelay_2.setEnabled(False)
  318. self.labelCascade.setEnabled(False)
  319. self.coarseInputTh_2.setEnabled(False)
  320. self.coarseInputAdc_2.setEnabled(False)
  321. #self.coarseInputFpga_2.setEnabled(False)
  322. self.coarse2InputAdc_2.setEnabled(False)
  323. #self.coarse2InputFpga_2.setEnabled(False)
  324. self.coarseInputCascade.setEnabled(False)
  325. self.coarse2InputCascade.setEnabled(False)
  326. self.show_advanced = False
  327. else:
  328. self.labelCoarseAdcDelay.setEnabled(True)
  329. self.labelCoarseFpgaDelay.setEnabled(True)
  330. self.coarseInputAdc.setEnabled(True)
  331. self.coarseInputFpga.setEnabled(True)
  332. if self.board_config.is_KAPTURE2():
  333. self.coarse2InputAdc.setEnabled(True)
  334. self.coarse2InputFpga.setEnabled(True)
  335. if self.adc_number > 4:
  336. self.labelCoarseAdcDelay_2.setEnabled(True)
  337. #self.labelCoarseFpgaDelay_2.setEnabled(True)
  338. self.labelCascade.setEnabled(True)
  339. self.coarseInputTh_2.setEnabled(True)
  340. self.coarseInputAdc_2.setEnabled(True)
  341. #self.coarseInputFpga_2.setEnabled(True)
  342. self.coarse2InputAdc_2.setEnabled(True)
  343. #self.coarse2InputFpga_2.setEnabled(True)
  344. self.coarseInputCascade.setEnabled(True)
  345. self.coarse2InputCascade.setEnabled(True)
  346. self.show_advanced = True
  347. def toggleAdc1IndividualDelay(self):
  348. """
  349. Toggle to use an individual delay for adc1 or not
  350. :return: -
  351. """
  352. self.adc1CoarseInput.setEnabled(self.adc1CoarseInputSwitch.checkState())
  353. if not self.adc1CoarseInput.isEnabled():
  354. board.get_board_config(self.board_id).update('adc_1_delay_individual', -1) # Be careful this does no silent update
  355. def setValueSilent(self, element, value):
  356. """
  357. Set Values to inputs without notifying observers
  358. :param element: the input
  359. :param value: the value
  360. :return: -
  361. """
  362. element.blockSignals(True)
  363. element.setValue(value)
  364. element.blockSignals(False)
  365. def closeEvent(self, event):
  366. """
  367. Event handler when this window is closed
  368. """
  369. self.board_config.unobserve(self.totalAdcBox[0], 'chip_delay')
  370. if self.board_config.is_KAPTURE2():
  371. self.board_config.unobserve(self.totalAdcBox[0], 'delay_25_th')
  372. if self.adc_number > 4:
  373. self.board_config.unobserve(self.totalAdcBox[0], 'delay_330_th_2')
  374. self.board_config.unobserve(self.totalAdcBox[0], 'delay_25_th_2')
  375. self.board_config.unobserve(self.totalAdcBox[0], 'delay_330_th')
  376. for i, item in enumerate(self.fineAdcInput):
  377. self.board_config.unobserve(item, 'chip_delay')
  378. self.board_config.unobserve(self.bunchShiftInput, 'bunch_shift')
  379. self.board_config.unobserve(self.coarseInputTh, 'delay_330_th')
  380. self.board_config.unobserve(self.coarseInputAdc, 'delay_330_adc')
  381. self.board_config.unobserve(self.coarseInputFpga, 'delay_330_fpga')
  382. if self.board_config.is_KAPTURE2():
  383. self.board_config.unobserve(self.coarse2InputTh, 'delay_25_th')
  384. self.board_config.unobserve(self.coarse2InputAdc, 'delay_25_adc')
  385. self.board_config.unobserve(self.coarse2InputFpga, 'delay_25_fpga')
  386. if self.adc_number > 4:
  387. self.board_config.unobserve(self.coarseInputTh_2, 'delay_330_th_2')
  388. self.board_config.unobserve(self.coarseInputAdc_2, 'delay_330_adc_2')
  389. #self.board_config.unobserve(self.coarseInputFpga_2, 'delay_330_fpga_2')
  390. self.board_config.unobserve(self.coarseInputCascade, 'delay_cascade')
  391. self.board_config.unobserve(self.coarse2InputTh_2, 'delay_25_th_2')
  392. self.board_config.unobserve(self.coarse2InputAdc_2, 'delay_25_adc_2')
  393. self.board_config.unobserve(self.coarse2InputCascade, 'delay_cascade_25')
  394. #self.board_config.unobserve(self.coarse2InputFpga_2, 'delay_25_fpga_2')
  395. Elements.emptyGroup('timing_{}'.format(self.board_id))
  396. Elements.removeItem(None, self.fineAdcInput)
  397. Elements.removeItem(None, self.bunchShiftInput)
  398. Elements.removeItem(None, [
  399. self.coarseInputTh,
  400. self.coarseInputAdc,
  401. self.coarseInputFpga
  402. ]
  403. )
  404. if self.board_config.is_KAPTURE2():
  405. Elements.removeItem(None, [
  406. self.coarse2InputTh,
  407. self.coarse2InputAdc,
  408. self.coarse2InputFpga
  409. ]
  410. )
  411. if self.adc_number > 4:
  412. Elements.removeItem(None, [
  413. self.coarseInputTh_2,
  414. self.coarseInputAdc_2,
  415. #self.coarseInputFpga_2,
  416. self.coarse2InputTh_2,
  417. self.coarse2InputAdc_2,
  418. #self.coarse2InputFpga_2
  419. ]
  420. )
  421. super(TimingPart, self).closeEvent(event)
  422. def on_adc_delay_changed(self):
  423. """
  424. Handler that gets called when an adc delay gets changed
  425. """
  426. try:
  427. factors = []
  428. for item in self.fineAdcInput:
  429. factors.extend([item.value()])
  430. self.board_config.update('chip_delay', factors)
  431. except board.BoardError as e:
  432. logging.error("ADC fine delay failed: {}".format(str(e)))
  433. bif.bk_status_readout(self.board_id)
  434. return
  435. def on_bunch_shift_changed(self):
  436. """
  437. Handler that gets called when a bunch shift setting gets changed
  438. """
  439. try:
  440. factors = []
  441. for item in self.bunchShiftInput:
  442. #Bunch Shifts are encoded 0x0 - 0x4 in Hardware
  443. #but shown as -2 to +2 in GUI, so we need a +2 offset
  444. factors.extend([item.value()+2])
  445. self.board_config.update('bunch_shift', factors)
  446. except board.BoardError as e:
  447. logging.error("ADC bunch shift failed: {}".format(str(e)))
  448. bif.bk_status_readout(self.board_id)
  449. return
  450. # 888 d8b d8b 888 888d8b 888 888
  451. # 888 Y8P Y8P 888 o 888Y8P 888 888
  452. # 888 888 d8b 888 888 888
  453. # 88888888888888b.d88b. 88888888b. .d88b. 888 d888b 888888 .d88888 .d88b. .d88b. 888888
  454. # 888 888888 "888 "88b888888 "88bd88P"88b888d88888b888888d88" 888d88P"88bd8P Y8b888
  455. # 888 888888 888 888888888 888888 88888888P Y88888888888 888888 88888888888888
  456. # Y88b. 888888 888 888888888 888Y88b 8888888P Y8888888Y88b 888Y88b 888Y8b. Y88b.
  457. # "Y888888888 888 888888888 888 "Y88888888P Y888888 "Y88888 "Y88888 "Y8888 "Y888
  458. # 888 888
  459. # Y8b d88P Y8b d88P
  460. # "Y88P" "Y88P"
  461. class TimingWidget(kcgw.KCGWidgets):
  462. """
  463. This is the container that holds the tab widget which contains the timing widgets for each board
  464. """
  465. def __init__(self, unique_id, parent=None):
  466. super(TimingWidget, self).__init__()
  467. self.id = unique_id
  468. self.par = parent
  469. self.setWindowTitle("Timing")
  470. self.layout = QtGui.QHBoxLayout()
  471. self.setLayout(self.layout)
  472. self.widgets = {i: TimingPart(i, self) for i in available_boards} # has to set parent with self because
  473. # otherwise the window does not get resized correctly upon enabling timescan
  474. if available_boards.multi_board:
  475. self.tabWidget = QtGui.QTabWidget()
  476. self.layout.addWidget(self.tabWidget)
  477. for id, widget in self.widgets.items():
  478. self.tabWidget.addTab(widget, available_boards.get_board_name_from_id(id))
  479. else:
  480. self.single_board_widget = list(self.widgets.values())[0]
  481. self.layout.addWidget(self.single_board_widget)
  482. def adjustSizeForTimeScan(self):
  483. """
  484. Adjust the size of the widget to accomodate the time_scan part
  485. :return:
  486. """
  487. # self.parentWindow = self.parent().parent().parent().parent() # one up is stacked widget, second up is
  488. # tab widget, third up is timingWidget fourh up is KCGWSubWindow (the actual window)
  489. QtCore.QCoreApplication.processEvents()
  490. if self.parent().windowState() & QtCore.Qt.WindowMaximized:
  491. self.parent().setWindowState(QtCore.Qt.WindowMaximized)
  492. else:
  493. # self.parent().resize(self.minimumSizeHint().width() * 1.2, self.minimumSizeHint().height()*1.1)
  494. self.parent().adjustSize()
  495. def closeEvent(self, event):
  496. global __widget_id__
  497. __widget_id__ = None
  498. for widget in list(self.widgets.values()):
  499. widget.closeEvent(event)
  500. del self.par.widgets[self.id]
  501. super(TimingWidget, self).closeEvent(event)
  502. def addTimingWidget():
  503. """
  504. Add this widget to the gui.
  505. This function will actually open the subwindow.
  506. :return: -
  507. """
  508. global __widget_id__
  509. if __widget_id__:
  510. global_objects.get_global('area').widgets[__widget_id__].setFocus()
  511. else:
  512. nid = kcgw.idg.genid()
  513. __widget_id__ = nid
  514. w = TimingWidget(nid, global_objects.get_global('area'))
  515. global_objects.get_global('area').newWidget(w, tr("Heading", "Timing"), nid, widget_type=4, minSize=True) #TODO: proper type
  516. kcgw.register_widget(QtGui.QIcon(config.icon_path(config.timingIcon)), tr("Heading", "Timing"), addTimingWidget, "Ctrl+T")