TimingWidget.py 28 KB

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