TimingWidget.py 28 KB

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