backendinterface.py 61 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517
  1. """
  2. This is the interface to the backend.
  3. It is used to make the backend easily interchangable.
  4. All Functions that interface directly with the backend are prefixed with bk\_
  5. Functions only used internal in this module will be prefixed _bif_
  6. """
  7. import logging
  8. import time
  9. from datetime import datetime as dt
  10. import os
  11. import copy
  12. from PyQt4 import QtGui, QtCore
  13. import numpy as np
  14. from backend import board
  15. from backend.board import available_boards
  16. from backend import io
  17. from backend import dataset
  18. from groupedelements import Buttons, Elements, live_plot_windows
  19. import storage
  20. from .. import config
  21. import kcgwidget as kcgw
  22. from kcgwidget import error
  23. from callbacks import callbacks
  24. from log import log
  25. from globals import glob as global_objects
  26. tr = kcgw.tr
  27. livePlotData = None
  28. def initStatus(st):
  29. """
  30. Initialize Status variables. These variables are used to transfer status variables over different modules.
  31. :param st: variable to use (most likely a DummyStorage instance)
  32. :return: -
  33. """
  34. st.continuous_read = False
  35. st.calibrated = False
  36. st.synced = False
  37. st.defaults_set = False
  38. st.status_text = tr("sw", "Ready")
  39. st.time_scan = False
  40. st.wait_on_trigger = False
  41. st.last_file = None
  42. st.board_connected = True
  43. st.continuous_interval = 1000
  44. # -----------[ Backend Interface ]----------------------
  45. def _bif_enable_wait_cursor():
  46. """
  47. Show the "Wait Cursor"
  48. """
  49. QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor))
  50. def _bif_disable_wait_cursor():
  51. """
  52. Show the normal Cursor
  53. """
  54. QtGui.QApplication.restoreOverrideCursor()
  55. def _bif_continuous_read_is_enabled(board_id, popup_title_text=None):
  56. """
  57. Checks if continuous read is enabled and if yes shows a popup dialog to ask if it shall be disabled
  58. :param board_id: id of the board do manipulate
  59. :param popup_title_text: Text to display in the popup that asks to disable continuous read
  60. :return: bool (True if continuous read is enabled and not disabled in popup else False)
  61. """
  62. if board.get_board_status(board_id).continuous_read:
  63. if not available_boards.multi_board:
  64. popup = PopupDialog(tr("Dialog", "Continuous read is currently active!\nStop continuous read and proceed?"),
  65. title=popup_title_text)
  66. else:
  67. popup = PopupDialog(tr("Dialog", "Board {board_id}\nContinuous read is currently active!\nStop continuous read and proceed?").format(board_id=board_id),
  68. title=popup_title_text)
  69. popup.exec_()
  70. popup.deleteLater()
  71. if popup.get_return_value() is False:
  72. return False
  73. else:
  74. _bif_set_continuous_read_inactive(board_id)
  75. Elements.setChecked("continuousread_"+str(board_id), False)
  76. return True
  77. else:
  78. return False
  79. def bk_status_readout():
  80. """
  81. Read Status for every connected board
  82. """
  83. if not available_boards.has_boards:
  84. return
  85. for brd in available_boards.board_ids:
  86. _bif_status_readout(brd)
  87. def _bif_status_readout(board_id):
  88. """
  89. Read Status from board and update variables
  90. as well as enable and disable corresponding Buttons
  91. :return: -
  92. """
  93. # part_TODO: NOTE: Problem with this is that certain buttons will be greyed out until other buttons are pressed
  94. # part_TODO: even if only the gui is restarted and the board is in the same state
  95. if kcgw.testing:
  96. return
  97. if board.is_active(board_id):
  98. Buttons.setEnabled("after_start_{}".format(board_id), True)
  99. Buttons.setEnabled("start_board_{}".format(board_id), False)
  100. Buttons.setEnabled("continuous_read_{}".format(board_id), True)
  101. # MenuItems.setEnabled("continuous_read", True)
  102. else:
  103. board.get_board_status(board_id).calibrated = False
  104. board.get_board_status(board_id).synced = False
  105. board.get_board_status(board_id).defaults_set = False
  106. Buttons.setEnabled("after_start_{}".format(board_id), False)
  107. Buttons.setEnabled("continuous_read_{}".format(board_id), False)
  108. Buttons.setEnabled("synchronize_{}".format(board_id), board.get_board_status(board_id).calibrated)
  109. Buttons.setEnabled("set_defaults_{}".format(board_id), board.get_board_status(board_id).synced)
  110. Buttons.setEnabled("acquire_{}".format(board_id), board.get_board_status(board_id).synced)
  111. Buttons.setEnabled("acquireTrigger_{}".format(board_id), board.get_board_status(board_id).synced)
  112. Elements.setEnabled("timing_{}".format(board_id), board.get_board_status(board_id).synced)
  113. storage.get_board_specific_storage(board_id).update_LED()
  114. backup_readout = bk_status_readout
  115. class PopupDialog(QtGui.QDialog):
  116. """
  117. Simple Class to show a popup dialog.
  118. """
  119. def __init__(self, text, title=None, parent=None):
  120. QtGui.QDialog.__init__(self, parent)
  121. self.text = text
  122. self.setWindowTitle(title if title else tr("Dialog", "User action required"))
  123. self.return_value = False
  124. size = QtCore.QSize(200, 200)
  125. # self.setMaximumSize(size)
  126. self.setMinimumSize(size)
  127. box = QtGui.QVBoxLayout()
  128. self.text_label = QtGui.QLabel(self.text)
  129. self.text_label.setAlignment(QtCore.Qt.AlignCenter)
  130. box.addWidget(self.text_label)
  131. self.okay_btn = QtGui.QPushButton(tr("Button", "Ok"))
  132. self.okay_btn.setStyleSheet("padding: 15px;")
  133. self.okay_btn.clicked.connect(self.on_okay)
  134. box.addWidget(self.okay_btn)
  135. box.addSpacerItem(QtGui.QSpacerItem(1, 20))
  136. self.cancel_btn = QtGui.QPushButton(tr("Button", "Cancel"))
  137. self.cancel_btn.setStyleSheet("padding: 15px;")
  138. self.cancel_btn.clicked.connect(self.on_cancel)
  139. box.addWidget(self.cancel_btn)
  140. self.setLayout(box)
  141. def on_okay(self):
  142. """
  143. Handler for the press of the ok button
  144. """
  145. self.return_value = True
  146. self.close()
  147. def on_cancel(self):
  148. """
  149. Handler for the press of the cancel button
  150. :return:
  151. """
  152. self.close()
  153. def get_return_value(self):
  154. """
  155. Get True if the Window was closed with OK else False
  156. :return: True if OK else False
  157. """
  158. return self.return_value
  159. def bk_start_board(board_id):
  160. """
  161. Start the Board.
  162. This will set initial Registers to power up the Board.
  163. :param board_id: id of the board do manipulate
  164. :return: -
  165. """
  166. _bif_enable_wait_cursor()
  167. log(board_id=board_id, additional="Starting Board - following values are probably default values")
  168. sequence = board.startup_sequence(board_id)
  169. number = sequence.next()
  170. if _bif_continuous_read_is_enabled(board_id, tr("Button", "Start Board")):
  171. _bif_disable_wait_cursor()
  172. return False
  173. try:
  174. if board.is_active(board_id):
  175. _bif_disable_wait_cursor()
  176. bk_status_readout()
  177. return
  178. logging.info("Activating Board")
  179. sequence.next()
  180. time.sleep(1.0)
  181. dialog1 = PopupDialog(tr("Button", "Switch On the power supply --> FIRST <-- (on board {0})".format(board_id)))
  182. dialog1.exec_()
  183. dialog1.deleteLater()
  184. if not dialog1.get_return_value():
  185. logging.error("Starting procedure canceled")
  186. _bif_disable_wait_cursor()
  187. return False
  188. logging.info("Switch ON T/Hs")
  189. sequence.next()
  190. time.sleep(0.1)
  191. dialog2 = PopupDialog(tr("Dialog", "Switch On the power supply --> SECOND <-- (on board {0})".format(board_id)))
  192. dialog2.exec_()
  193. dialog2.deleteLater()
  194. if not dialog2.get_return_value():
  195. logging.info("Starting procedure canceled")
  196. _bif_disable_wait_cursor()
  197. return False
  198. logging.info("Switch ON ADCs")
  199. sequence.next()
  200. time.sleep(0.1)
  201. sequence.next()
  202. time.sleep(1.0)
  203. for step in sequence:
  204. time.sleep(0.1)
  205. logging.info("Board started successfully!")
  206. except board.BoardError as e:
  207. logging.error("Starting board failed: {}".format(str(e)))
  208. bk_update_config(board_id, 'header', bk_get_config(board_id, 'header'))
  209. _bif_disable_wait_cursor()
  210. bk_status_readout()
  211. class _bif_ProgressBar(QtGui.QProgressBar):
  212. """
  213. Simple Progressbar class.
  214. """
  215. def __init__(self, min, max, text):
  216. super(_bif_ProgressBar, self).__init__()
  217. self.setRange(min, max)
  218. self.setMaximumHeight(18)
  219. # kcgw.statusbar.clearMessage()
  220. self.label = QtGui.QLabel(text)
  221. global_objects.get_global('statusbar').insertWidget(0, self.label)
  222. global_objects.get_global('statusbar').insertWidget(1, self)
  223. self.setValue(0)
  224. QtGui.qApp.processEvents()
  225. def remove(self, timeout=None):
  226. """
  227. Remove this instance of a progressbar
  228. :param timeout: the time from calling this function to wanishing of the progressbar
  229. :return: -
  230. """
  231. def remove_progressbar():
  232. global_objects.get_global('statusbar').removeWidget(self)
  233. global_objects.get_global('statusbar').removeWidget(self.label)
  234. # kcgw.statusbar.showMessage(board.status.status_text)
  235. self.destroy()
  236. if timeout:
  237. QtCore.QTimer.singleShot(timeout, remove_progressbar)
  238. else:
  239. remove_progressbar()
  240. # thread = None
  241. # cal = None
  242. def bk_calibrate(board_id, do_the_rest=None):
  243. """
  244. Send commands to the board that will enable it to calibrate itself.
  245. This function checks if a read command is still running. BUT: It does not check if
  246. the board is acquiring or something like this.
  247. So Another instance of KCG can still be acquiring or calibrating at the same time. This can be dangerous.
  248. :param board_id: id of the board do manipulate
  249. :param do_the_rest: function to call after calibration. This is used when "Prepare Board" is pressed.
  250. :return: -
  251. """
  252. log(board_id=board_id, additional="Calibrate")
  253. thread = storage.get_board_specific_storage(board_id).setdefault('CalibrateThread', storage.ThreadStorage())
  254. if thread.running:
  255. logging.info("Calibration already running")
  256. return
  257. _bif_enable_wait_cursor()
  258. if _bif_continuous_read_is_enabled(board_id, tr("Button", "Calibrate Board")):
  259. _bif_disable_wait_cursor()
  260. return
  261. sequence = board.calibration_sequence(board_id)
  262. number = sequence.next()
  263. progressbar = _bif_ProgressBar(0, number, tr("sw", "Calibrating"))
  264. class Calibrate(QtCore.QObject):
  265. """
  266. Class to use as thread class. NOTE: this is not used at the moment.
  267. """
  268. update_progressbar_signal = QtCore.pyqtSignal(int)
  269. finished = QtCore.pyqtSignal()
  270. def calibrate(self):
  271. """
  272. The method that is called inside the thread and that does the calibration
  273. :return:
  274. """
  275. try:
  276. logging.info('Started Board Calibration')
  277. for idx, step in enumerate(sequence):
  278. time.sleep(0.5)
  279. self.update_progressbar_signal.emit(idx)
  280. board.get_board_status(board_id).calibrated = True
  281. except board.BoardError as e:
  282. logging.error("Calibration failed: {}".format(str(e)))
  283. # self.do_status_readout()
  284. self.finished.emit()
  285. return
  286. logging.info("Board Calibration successful!")
  287. self.finished.emit()
  288. def thread_quit():
  289. """
  290. Method to handle the end of the calibration thread
  291. :return:
  292. """
  293. thread.stop()
  294. bk_status_readout()
  295. progressbar.remove(0)
  296. _bif_disable_wait_cursor()
  297. if do_the_rest: # execute sync and set defaults (this is set if prepare board was pressed)
  298. do_the_rest(board_id)
  299. cal = Calibrate()
  300. thread.register(cal)
  301. thread.connect('update_progressbar_signal', progressbar.setValue)
  302. thread.connect('finished', thread_quit)
  303. thread.start('calibrate')
  304. def bk_sync_board(board_id):
  305. """
  306. Sends commands to the board to sync with triggers.
  307. :param board_id: id of the board do manipulate
  308. :return: -
  309. """
  310. _bif_enable_wait_cursor()
  311. log(board_id=board_id, additional="Synchronize")
  312. if _bif_continuous_read_is_enabled(board_id, tr("Dialog", "Synchronize Board")):
  313. _bif_disable_wait_cursor()
  314. return
  315. progressbar = _bif_ProgressBar(0, 100, tr("sw", "Synchronizing"))
  316. sequence = board.synchronisation_sequence(board_id)
  317. try:
  318. sequence.next() # skip number
  319. logging.info("Synchronize PLLs")
  320. sequence.next()
  321. for i in range(1, 101):
  322. time.sleep(0.01)
  323. progressbar.setValue(i)
  324. sequence.next()
  325. except board.BoardError as e:
  326. logging.error("Synchronization failed: {}".format(str(e)))
  327. progressbar.remove(0)
  328. _bif_disable_wait_cursor()
  329. bk_status_readout()
  330. return
  331. progressbar.remove(0)
  332. logging.info("Board synchronization successful!")
  333. # self.set_defaults_button.setEnabled(True)
  334. board.get_board_status(board_id).synced = True
  335. _bif_disable_wait_cursor()
  336. bk_status_readout()
  337. def bk_write_values(board_id, defaults=False):
  338. """
  339. Write values to board.
  340. :param board_id: id of the board do manipulate
  341. :param defaults: (bool) if True Writes default values
  342. :return: -
  343. """
  344. _bif_enable_wait_cursor()
  345. if defaults:
  346. log(board_id=board_id, additional="Set Default Values")
  347. else:
  348. log(board_id=board_id, additional="Update Values on board")
  349. if _bif_continuous_read_is_enabled(board_id, tr("Dialog", "Update Values on Board")):
  350. _bif_disable_wait_cursor()
  351. return
  352. sequence = board.write_value_sequence(board_id)
  353. number = sequence.next()
  354. if defaults:
  355. board.get_board_config(board_id)._set_defaults()
  356. progressbar = _bif_ProgressBar(0, number, tr("sw", "Setting Defaults"))
  357. logging.info("Setting default Values")
  358. else:
  359. progressbar = _bif_ProgressBar(0, number, tr("sw", "Updating Values on Board"))
  360. logging.info("Updating Values")
  361. try:
  362. for idx, step in enumerate(sequence):
  363. time.sleep(0.1)
  364. progressbar.setValue(idx)
  365. except board.BoardError as e:
  366. logging.error("Updating Values failed: {}".format(str(e)))
  367. progressbar.remove(0)
  368. _bif_disable_wait_cursor()
  369. bk_status_readout()
  370. return
  371. board.get_board_status(board_id).defaults_set = True
  372. progressbar.remove(0)
  373. if defaults:
  374. logging.info("Default values set successfully!")
  375. else:
  376. logging.info("Updated values successfully!")
  377. _bif_disable_wait_cursor()
  378. bk_status_readout()
  379. board.get_board_config(board_id).notify_all_observers()
  380. def bk_stop_board(board_id):
  381. """
  382. Stops the board and shuts it down
  383. :param board_id: id of the board do manipulate
  384. :return: -
  385. """
  386. _bif_enable_wait_cursor()
  387. log(board_id=board_id, additional="Stop Board")
  388. if _bif_continuous_read_is_enabled(board_id, tr("Dialog", "Soft Reset Board")):
  389. _bif_disable_wait_cursor()
  390. return
  391. try:
  392. logging.info("Switching Off Board {}".format(board_id))
  393. board.pci.write(board_id, '0x9040')
  394. board.pci.stop_dma(board_id)
  395. board.stop_board(board_id)
  396. time.sleep(0.5)
  397. except board.BoardError as e:
  398. logging.error("Sequence failed: {}".format(str(e)))
  399. _bif_disable_wait_cursor()
  400. bk_status_readout()
  401. return
  402. logging.info("Board switched off successfully!")
  403. Buttons.setEnabled("after_start_{}".format(board_id), False)
  404. Buttons.setEnabled("start_board_{}".format(board_id), True)
  405. board.get_board_status(board_id).calibrated = False
  406. _bif_disable_wait_cursor()
  407. bk_status_readout()
  408. def bk_soft_reset(board_id):
  409. """
  410. Perform a soft reset.
  411. :param board_id: id of the board do manipulate
  412. :return:
  413. """
  414. _bif_enable_wait_cursor()
  415. log(board_id=board_id, additional="Soft Reset")
  416. if _bif_continuous_read_is_enabled(board_id, tr("Dialog", "Soft Reset Board")):
  417. _bif_disable_wait_cursor()
  418. return
  419. try:
  420. logging.info("Soft-Resetting Board {}...".format(board_id))
  421. board.soft_reset(board_id)
  422. except board.BoardError as e:
  423. logging.error("Sequence failed: {}".format(str(e)))
  424. _bif_disable_wait_cursor()
  425. bk_status_readout()
  426. return
  427. _bif_disable_wait_cursor()
  428. bk_status_readout()
  429. board.get_board_config(board_id).update('header', True) # reset header (might be reset by soft reset)
  430. logging.info("Soft-Reset successful.")
  431. def bk_update_config(board_id, key, value, silent=False):
  432. """
  433. Interface to the update command of the BoardConfiguration class.
  434. :param board_id: id of the board do manipulate
  435. :param key: Key to update
  436. :param value: Value to set for key
  437. :param silent: (bool) if True do not inform observers on update
  438. :return: -
  439. """
  440. try:
  441. if silent:
  442. board.get_board_config(board_id).updateSilent(key, value)
  443. else:
  444. board.get_board_config(board_id).update(key, value)
  445. except board.BoardError as e:
  446. logging.error("Setting value of {} failed: {}".format(key, str(e)))
  447. def bk_get_config(board_id, key):
  448. """
  449. Interface to the get command of the BoardConfiguration class.
  450. :param board_id: id of the board do manipulate
  451. :param key: Key to get the value for
  452. :return: value stored for key
  453. """
  454. return board.get_board_config(board_id).get(key)
  455. def bk_get_board_status(board_id, status_variable):
  456. """
  457. Interface to the status class for each board.
  458. :param board_id: id of the board do manipulate
  459. :param status_variable: Key to get the value for
  460. :return: value stored for key
  461. """
  462. return getattr(board.get_board_status(board_id), status_variable, None)
  463. def bk_get_status(board_id):
  464. """
  465. Interface to the get_status of the board
  466. NOTE: This is not get_board_status
  467. :return: status dictionary
  468. """
  469. return board.get_status(board_id)
  470. def bk_get_board_config(board_id):
  471. """
  472. Get the board config instance
  473. :param board_id: the id of the board
  474. :return: the config instance
  475. """
  476. return board.get_board_config(board_id)
  477. def bk_change_num_of_orbits(board_id, value, silent=False):
  478. """
  479. Send new number of orbits to board and update in config
  480. :param board_id: id of the board do manipulate
  481. :param value: the value to send
  482. :param silent: (bool) if True do not inform observers on update
  483. :return: -
  484. """
  485. bk_update_config(board_id, "orbits_observe", value, silent=silent)
  486. def bk_change_num_of_skipped_orbits(board_id, value, silent=False):
  487. """
  488. Send new number of orbits to skip to board and update in config
  489. :param board_id: id of the board do manipulate
  490. :param value: the value to send
  491. :param silent: (bool) if True do not inform observers on update
  492. :return: -
  493. """
  494. bk_update_config(board_id, "orbits_skip", value, silent=silent)
  495. def bk_change_count(board_id, value, silent=False):
  496. """
  497. Change the number of acquisitions you want to make.
  498. :param board_id: id of the board do manipulate
  499. :param value: (int) Number of acquisitions
  500. :param silent: (bool) if True do not inform observers on update
  501. :return: -
  502. """
  503. bk_update_config(board_id, "acquisition_count", value, silent=silent)
  504. def bk_change_wait(board_id, value, silent=False):
  505. """
  506. Change the time between acquisitions.
  507. :param board_id: id of the board do manipulate
  508. :param value: (bool) Time in seconds
  509. :param silent: (bool) if True do not inform observers on update
  510. :return: -
  511. """
  512. bk_update_config(board_id, "orbits_wait_time", value, silent=silent)
  513. def bk_change_build_spectrograms(board_id, value, silent=False):
  514. """
  515. Change if spectrograms are built or not)
  516. :param board_id: id of the board do manipulate
  517. :param value: (bool) True or False built or not
  518. :param silent: (bool) if True do not inform observers on update
  519. :return:
  520. """
  521. bk_update_config(board_id, "build_spectrograms", value, silent=silent)
  522. def bk_change_pilot_bunch(board_id, value, silent=False):
  523. """
  524. Change if pilot bunch is simulated
  525. :param board_id: id of the board do manipulate
  526. :param value: (bool) True or False to simulate or not
  527. :param silent: (bool) if True do not inform observers on update
  528. :return:
  529. """
  530. bk_update_config(board_id, "pilot_bunch", value, silent=silent)
  531. def _bif_iterate_spectrograms(board_id, path):
  532. """
  533. BROKEN (DOES NOT GET ANY DATA)
  534. Built Spectrograms line by line
  535. :param board_id: id of the board do manipulate
  536. :param path: where to built the spectrogram
  537. :return: -
  538. """
  539. return # because it is broken
  540. if not os.path.isdir(str(path)):
  541. return
  542. # how does this get data? dataset.data does not exist
  543. transform = dataset.data.fft(1, frm=0, to=-1)
  544. for i in range(config.bunches_per_turn - 1):
  545. filename = os.path.join(storage.storage.save_location, storage.storage.subdirname, str(path), "%i.hsp" % i)
  546. write_header = False
  547. if not os.path.isfile(filename):
  548. write_header = True
  549. f = open(filename, 'ab')
  550. if write_header:
  551. f.write("#hsp\n") # heb spectrogram magic number
  552. f.write("#"+str(board.get_board_config(board_id).get("orbits_skip")))
  553. f.write("\n")
  554. line = transform[i, :]
  555. f.write('{:0.3f} '.format(time.time()))
  556. for e in line:
  557. f.write("%s " % np.absolute(e))
  558. f.write("\n")
  559. f.close()
  560. def _bif_read_data_and_save(board_id):
  561. """
  562. Tell the pci command to start acquisition and save data
  563. Also generates the filename from settings
  564. :param board_id: id of the board do manipulate
  565. :return:
  566. """
  567. now = time.time()
  568. if not os.path.isdir(str(storage.storage.save_location + '/' + storage.storage.subdirname)):
  569. os.makedirs(str(storage.storage.save_location + '/' + storage.storage.subdirname))
  570. filename = storage.storage.save_location + '/' + storage.storage.subdirname+'/{:0.3f}.out'.format(now)
  571. board.get_board_status(board_id).last_file = filename
  572. try:
  573. simulate = board.get_board_config(board_id).get("pilot_bunch")
  574. try:
  575. board.acquire_data(board_id, filename, simulate=simulate)
  576. if not os.path.isfile(filename):
  577. error(0x001, "No File Created")
  578. except IndexError:
  579. error(0x002, "Unexpected output of pci for number of orbits to observe. Returning")
  580. return
  581. _bif_read_and_update_data_from_file(board_id, filename)
  582. except board.BoardError as e:
  583. logging.error("Reading failed: {}".format(str(e)))
  584. def _bif_read_and_update_data_from_file(board_id, filename):
  585. """
  586. Proxy function for _bif_read_and_update to call with correct read_func
  587. :param board_id: id of the board do manipulate
  588. :param filename: filename to read data from
  589. :return: -
  590. """
  591. _bif_read_and_update(board_id, io.read_from_file, str(filename))
  592. def _bif_read_and_update_data_from_string(board_id, raw_data):
  593. """
  594. Proxy function for _bif_read_and_update to call with correct read_func
  595. :param board_id: id of the board do manipulate
  596. :param raw_data: Data as string
  597. :return: -
  598. """
  599. _bif_read_and_update(board_id, io.read_from_string, raw_data)
  600. def _bif_read_and_update(board_id, read_func, *args):
  601. """
  602. Function to read data from file or string (depending on read_func) and update plots etc.
  603. :param board_id: id of the board do manipulate
  604. :param read_func: function to use to read data
  605. :param args: filename or raw_data (see _bif_read_and_update_from_{filename, string}
  606. :return: -
  607. """
  608. _bif_enable_wait_cursor()
  609. header = board.get_board_config(board_id).get('header')
  610. # TODO: force_read: meaning ignore cache and read new -> in the old gui this was a commandline option
  611. # TODO: cache_data: meaning cache already processed numpy data -> in the old gui this was a commandline option
  612. if live_plot_windows.hasWindows(board_id):
  613. data = read_func(*args, force=False, header=header, cache=False)
  614. if not io.is_data_consistent(data):
  615. callbacks.async_callback('update_consistency', False)
  616. global_objects.get_global('statusbar').showMessage(tr("Dialog", "Data is inconsistent!"))
  617. if read_func == io.read_from_string:
  618. logging.info("Data is inconsistent")
  619. else:
  620. logging.info("Data is inconsistent - file: " + args[0])
  621. else:
  622. callbacks.async_callback('update_consistency', True)
  623. global_objects.get_global('statusbar').showMessage(tr("Dialog", ""))
  624. for plotwin in live_plot_windows.getWindows(board_id):
  625. plotwin.plot_live(data=data)
  626. QtGui.qApp.processEvents()
  627. else:
  628. callbacks.async_callback('update_consistency', None)
  629. _bif_disable_wait_cursor()
  630. def bk_acquire(board_id):
  631. """
  632. Toggle Acqisition
  633. :param board_id: id of the board do manipulate
  634. :return:
  635. """
  636. if not bk_get_config(board_id, 'use_trigger'):
  637. if board.get_board_status(board_id).acquisition == True:
  638. log(board_id=board_id, additional="Manually Stopped Acquisition\nPerformed Acquisitions: " + str(storage.storage.current_acquisition))
  639. _bif_stop_acquisition(board_id)
  640. else:
  641. _bif_start_acquisition(board_id)
  642. else:
  643. bk_toggle_wait_on_trigger(board_id)
  644. def _bif_stop_acquisition(board_id):
  645. """
  646. Stop acquisition
  647. This does stop the timer started by _bif_start_acquisition()
  648. :param board_id: id of the board do manipulate
  649. :return: -
  650. """
  651. board.get_board_status(board_id).acquisition = False
  652. storage.get_board_specific_storage(board_id).acquisition_progressbar.remove(0)
  653. storage.get_board_specific_storage(board_id).acquisition_timer.stop()
  654. # for elem in Elements.getElements("acquireTrigger_{}".format(board_id)):
  655. # if isinstance(elem, QtGui.QShortcut) or isinstance(elem, QtGui.QCheckBox):
  656. # continue
  657. # elem.setIcon(QtGui.QIcon(config.install_path + config.startIcon))
  658. # elem.setText(tr("Button", "Start Acquisition"))
  659. Elements.setEnabled('acquire_{}'.format(board_id), True)
  660. callbacks.callback('acquisition_stopped', board_id)
  661. def _bif_start_acquisition(board_id):
  662. """
  663. Start acquisition.
  664. This will start a timer to automatically acquire data.
  665. :param board_id: id of the board do manipulate
  666. :return: -
  667. """
  668. log(board_id=board_id, additional="Started Acquisition")
  669. board.get_board_status(board_id).acquisition = True
  670. Elements.setEnabled('acquire_{}'.format(board_id), False)
  671. # for elem in Elements.getElements("acquireTrigger_{}".format(board_id)):
  672. # if isinstance(elem, QtGui.QShortcut) or isinstance(elem, QtGui.QCheckBox):
  673. # continue
  674. # elem.setIcon(QtGui.QIcon(config.install_path + config.stopIcon))
  675. # elem.setText(tr("Button", "Stop Acquisition"))
  676. callbacks.callback('acquisition_started', board_id)
  677. storage.get_board_specific_storage(board_id).acquisition_timer = QtCore.QTimer()
  678. num_acquisitions = board.get_board_config(board_id).get("acquisition_count")
  679. storage.get_board_specific_storage(board_id).acquisition_progressbar = \
  680. _bif_ProgressBar(0, num_acquisitions, tr("sw", "Acquiring with board ")+str(board_id))
  681. # storage.storage.acquisition_progressbar = acquisition_progressbar
  682. # We increase already once because we do a single acquisition before the
  683. # timer is started, otherwise we have to wait until the timer fires the
  684. # first time.
  685. try:
  686. if isinstance(storage.storage.current_acquisition, dict):
  687. storage.storage.current_acquisition[board_id] = 1
  688. else:
  689. storage.storage.current_acquisition = {board_id: 1}
  690. except storage.StorageError:
  691. storage.storage.current_acquisition = {board_id: 1}
  692. _bif_read_data_and_save(board_id)
  693. if board.get_board_config(board_id).get("build_spectrograms"):
  694. spectrogram_dir = storage.storage.save_location + '/' + storage.storage.subdirname+"/spectrograms_{:0.3f}".format(time.time())
  695. os.makedirs(spectrogram_dir)
  696. _bif_iterate_spectrograms(board_id, spectrogram_dir) # TODO: not here?
  697. storage.get_board_specific_storage(board_id).acquisition_progressbar.setValue(storage.storage.current_acquisition[board_id])
  698. def on_timeout():
  699. '''Handler for the timeout of the acquisition timer. This does the acquisition'''
  700. if storage.storage.current_acquisition[board_id] < num_acquisitions:
  701. storage.storage.current_acquisition[board_id] += 1
  702. storage.get_board_specific_storage(board_id).acquisition_progressbar.setValue(storage.storage.current_acquisition[board_id])
  703. _bif_read_data_and_save(board_id)
  704. if board.get_board_config(board_id).get("build_spectrograms"):
  705. _bif_iterate_spectrograms(board_id, spectrogram_dir) # TODO: not here ?
  706. else:
  707. log(board_id=board_id, additional="Stopped Acquisition")
  708. _bif_stop_acquisition(board_id)
  709. storage.get_board_specific_storage(board_id).acquisition_progressbar.remove(0)
  710. storage.get_board_specific_storage(board_id).acquisition_timer.timeout.connect(on_timeout)
  711. storage.get_board_specific_storage(board_id).acquisition_timer.start(board.get_board_config(board_id).get('orbits_wait_time') * 1000)
  712. def bk_single_read(board_id):
  713. """
  714. Perform a single read of data
  715. :param board_id: id of the board do manipulate
  716. :return:
  717. """
  718. Elements.setEnabled("acquire_{}".format(board_id), False)
  719. _bif_read_data_and_save(board_id)
  720. log(board_id=board_id, additional="Single Read\nFilename: "+board.get_board_status(board_id).last_file.split('/')[-1])
  721. Elements.setEnabled("acquire_{}".format(board_id), True)
  722. def _bif_set_continuous_read_active(board_id):
  723. """
  724. Enable continuous read
  725. :param board_id: id of the board do manipulate
  726. :return: -
  727. """
  728. Elements.setEnabled("acquire_{}".format(board_id), False)
  729. Elements.setEnabled("acquireTrigger_{}".format(board_id), False)
  730. Elements.setEnabled("continuous_read_{}".format(board_id), True)
  731. board.get_board_status(board_id).continuous_read = True
  732. def _bif_set_continuous_read_inactive(board_id):
  733. """
  734. Disable continuous read
  735. :param board_id: id of the board do manipulate
  736. :return: -
  737. """
  738. if board.get_board_status(board_id).continuous_read:
  739. board.get_board_status(board_id).continuous_read = False
  740. storage.get_board_specific_storage(board_id).continuous_read_timer.stop()
  741. Elements.setEnabled('acquire_{}'.format(board_id), True)
  742. Elements.setEnabled('acquireTrigger_{}'.format(board_id), True)
  743. def bk_continuous_read(board_id, interval=100):
  744. """
  745. Toggle continuous read
  746. :param board_id: id of the board do manipulate
  747. :param interval: Time between two consecutive reads.
  748. :return: -
  749. """
  750. if not board.get_board_status(board_id).continuous_read:
  751. _bif_set_continuous_read_active(board_id)
  752. _bif_continuous_read(board_id, interval)
  753. else:
  754. _bif_set_continuous_read_inactive(board_id)
  755. def _bif_continuous_read(board_id, interval=None):
  756. """
  757. Perform continuous read based on a timer.
  758. :param interval:
  759. :return:
  760. """
  761. if interval is not None:
  762. # TODO: ueberall checken, dass der board specific storage verwendet wird
  763. storage.get_board_specific_storage(board_id).continuous_interval = interval
  764. storage.get_board_specific_storage(board_id).continuous_read_timer = QtCore.QTimer()
  765. logging.info("Start continuous read")
  766. def continuous_read_step():
  767. if board.get_board_status(board_id).continuous_read:
  768. _bif_read_data(board_id)
  769. storage.get_board_specific_storage(board_id).continuous_read_timer.singleShot(storage.storage.continuous_interval, continuous_read_step)
  770. storage.get_board_specific_storage(board_id).continuous_read_timer.singleShot(storage.storage.continuous_interval, continuous_read_step)
  771. def _bif_read_data(board_id):
  772. """
  773. Reads data acquired by board.
  774. :param board_id: id of the board do manipulate
  775. :return:
  776. """
  777. try:
  778. if board.get_board_config(board_id).get('pilot_bunch'):
  779. board.start_pilot_bunch_emulator(board_id)
  780. board.start_acquisition(board_id)
  781. try:
  782. board.wait_for_revolutions(board_id)
  783. except IndexError:
  784. error(0x002, "Unexpected output of pci for number of orbits to observe. Returning")
  785. return
  786. board.stop_acquisition(board_id)
  787. board.enable_transfer(board_id)
  788. data_raw = board.pci.read_data_to_variable(board_id)
  789. _bif_read_and_update_data_from_string(board_id, data_raw)
  790. except board.BoardError as e:
  791. logging.error("Reading failed for board {}: {}".format(str(board_id), str(e)))
  792. def bk_board_connected(board_id):
  793. """
  794. Interface to the board to check if it is connected.
  795. :param board_id: id of the board do manipulate
  796. :return: -
  797. """
  798. if not available_boards.has_boards:
  799. return False
  800. else:
  801. return board_id in available_boards.board_ids
  802. def bk_get_temperature(board_id):
  803. """
  804. Get Temperature from board and format it
  805. :param board_id: id of the board do manipulate
  806. :return: -
  807. """
  808. fpga_temp_raw_hex = board.pci.read(board_id, 1, '0x9110')[0]
  809. fpga_temp_raw_hex = fpga_temp_raw_hex[-3:]
  810. fpga_temp_raw_bin = '{0:012b}'.format(int(fpga_temp_raw_hex, 16))
  811. fpga_temp_encoded = board.get_dec_from_bits(fpga_temp_raw_bin, 9, 0)
  812. fpga_temp_celsius = '{0:2.2f}'.format(((fpga_temp_encoded * 503.975) / 1024) - 273.15)
  813. return fpga_temp_celsius
  814. backup_get_temp = bk_get_temperature
  815. def bk_time_scan(board_id, c_frm, c_to, f_frm, f_to, ts_pbar, plot_func, orbits_observe=None, orbits_skip=None, bucket_to_use=None, threshold_counts=None):
  816. """
  817. Toggle Timescan.
  818. :param board_id: id of the board do manipulate
  819. :param c_frm: (int) From value for Coarse scan
  820. :param c_to: (int) To value for Coarse scan
  821. :param f_frm: (int) From value for Fine scan
  822. :param f_to: (int) To value for fine scan
  823. :param ts_pbar: Handle to the Timescan Progressbar
  824. :param plot_func: Function to plot when timescan ended.
  825. :param orbits_observe: Number of orbits to observe for the timescan (original values will be restored after timescan)
  826. :param orbits_skip: Number of orbits to skipfor the timescan (original values will be restored after timescan)
  827. :return: -
  828. """
  829. if board.get_board_status(board_id).time_scan:
  830. _bif_stop_time_scan(board_id, ts_pbar)
  831. else:
  832. _bif_start_time_scan(board_id, c_frm, c_to, f_frm, f_to, ts_pbar, plot_func, orbits_observe, orbits_skip, bucket_to_use, threshold_counts)
  833. def _bif_stop_time_scan(board_id, ts_pbar):
  834. """
  835. Stop the timescan. This stops the timer.
  836. :param board_id: id of the board do manipulate
  837. :param ts_pbar: Timescan Progressbar handle
  838. :return: -
  839. """
  840. Elements.getElements("start_time_scan_{}".format(board_id))[0].setText(tr("Button", "Start time scan"))
  841. board.get_board_status(board_id).time_scan = False
  842. board.get_board_config(board_id).set_delay(storage.storage.th_old[board_id])
  843. board.get_board_config(board_id).set_chip_delay(
  844. [0, 1, 2, 3],
  845. [
  846. storage.storage.chip_1_old[board_id],
  847. storage.storage.chip_2_old[board_id],
  848. storage.storage.chip_3_old[board_id],
  849. storage.storage.chip_4_old[board_id]
  850. ]
  851. )
  852. ts_pbar.reset()
  853. # tst = None # Ugly but necessary for the thread not to be killed when function ends (which is almost immediately after start)
  854. # thread_ts = None
  855. def _bif_start_time_scan(board_id, c_frm, c_to, f_frm, f_to, timescan_progressbar, plot_func, orbits_observe, orbits_skip, bucket_to_use=None, threshold_counts=None):
  856. """
  857. Start the timscan. This starts the timer
  858. :param board_id: id of the board do manipulate
  859. :param c_frm: From value for coarse scan
  860. :param c_to: To value for coarse scan
  861. :param f_frm: From value for fine scan
  862. :param f_to: To value for fine scan
  863. :param timescan_progressbar: Handle for the timescan progressbar
  864. :param plot_func: Function to use to plot the data
  865. :param orbits_observe: Number of orbits to observe for the timescan (original values will be restored after timescan)
  866. :param orbits_skip: Number of orbits to skip for the timescan (original values will be restored after timescan)
  867. :param bucket_to_use: Number of the bucket whos data will be used to calculate the average signal at each timescan step (if None all bunches will be used)
  868. :param threshold_counts: Skip buckets with adc counts between 2048 +- threshold_counts
  869. :return: -
  870. """
  871. thread = storage.get_board_specific_storage(board_id).setdefault("TimeScanThread", storage.ThreadStorage())
  872. # if thread_ts is not None:
  873. # logging.info("Time scan already running")
  874. # return
  875. if thread.running:
  876. logging.info("Time scan already running")
  877. return
  878. board.get_board_status(board_id).time_scan = True
  879. Elements.getElements("start_time_scan_{}".format(board_id))[0].setText(tr("Button", "Stop time scan"))
  880. if c_frm > c_to:
  881. logging.info('Coarse Scan Interval is invalid: (%i > %i)' % (c_frm, c_to))
  882. return
  883. if f_frm > f_to:
  884. logging.info('Fine Scan Interval is invalid: (%i > %i)' % (f_frm, f_to))
  885. return
  886. # the following could be made nicer with the use of setdefault and the use of get_board_specific_storage
  887. if not hasattr(storage.storage, 'th_old'):
  888. storage.storage.th_old = {}
  889. storage.storage.chip_1_old = {}
  890. storage.storage.chip_2_old = {}
  891. storage.storage.chip_3_old = {}
  892. storage.storage.chip_4_old = {}
  893. storage.storage.th_old[board_id] = board.get_board_config(board_id).get('th_delay')
  894. storage.storage.chip_1_old[board_id] = board.get_board_config(board_id).get('chip_1_delay')
  895. storage.storage.chip_2_old[board_id] = board.get_board_config(board_id).get('chip_2_delay')
  896. storage.storage.chip_3_old[board_id] = board.get_board_config(board_id).get('chip_3_delay')
  897. storage.storage.chip_4_old[board_id] = board.get_board_config(board_id).get('chip_4_delay')
  898. minimum = [None, None, None, None]
  899. maximum = np.zeros((4, 3))
  900. heatmap = np.zeros((4, (f_to - f_frm + 1), (c_to - c_frm + 1)))
  901. timescan_progressbar.setRange(1, ((f_to - f_frm) + 1) * ((c_to - c_frm) + 1))
  902. class thread_time_scan(QtCore.QObject):
  903. '''Timescan Thread class'''
  904. pbarSignal = QtCore.pyqtSignal(int)
  905. stopSignal = QtCore.pyqtSignal()
  906. finished = QtCore.pyqtSignal()
  907. def __init__(self, c_frm, c_to, f_frm, f_to, timescan_progressbar, bucket_to_use, threshold_counts):
  908. super(thread_time_scan, self).__init__()
  909. self.c_frm = c_frm
  910. self.c_to = c_to
  911. self.f_frm = f_frm
  912. self.f_to = f_to
  913. self.timescan_progressbar = timescan_progressbar
  914. self.bucket_to_use = bucket_to_use
  915. self.threshold_counts = threshold_counts
  916. def time_scan(self):
  917. '''Method to run in the thread that does the timescan'''
  918. Elements.setEnabled('acquire_{}'.format(board_id), False, exclude=Elements.getElements('start_time_scan_{}'.format(board_id)))
  919. if orbits_observe:
  920. if not hasattr(storage.storage, 'orbits_observe_before_timescan'):
  921. storage.storage.orbits_observe_before_timescan = {}
  922. storage.storage.orbits_observe_before_timescan[board_id] = board.get_board_config(board_id).get("orbits_observe") # save old values to restore after timescan
  923. board.get_board_config(board_id).update("orbits_observe", orbits_observe)
  924. bk_change_num_of_orbits(board_id, orbits_observe)
  925. if orbits_skip is not None:
  926. if not hasattr(storage.storage, 'orbits_skip_before_timescan'):
  927. storage.storage.orbits_skip_before_timescan = {}
  928. storage.storage.orbits_skip_before_timescan[board_id] = board.get_board_config(board_id).get("orbits_skip")
  929. board.get_board_config(board_id).update("orbits_skip", orbits_skip)
  930. bk_change_num_of_skipped_orbits(board_id, orbits_skip)
  931. c_step = 0
  932. for coarse in range(self.c_frm, self.c_to + 1):
  933. try:
  934. board.get_board_config(board_id).set_delay(coarse)
  935. except board.BoardError as e:
  936. self.stopSignal.emit()
  937. self.finished.emit()
  938. return
  939. f_step = 0
  940. for fine in range(self.f_frm, self.f_to + 1):
  941. board.get_board_config(board_id).set_chip_delay([0, 1, 2, 3], [fine, fine, fine, fine])
  942. try:
  943. if bk_get_config(board_id, 'pilot_bunch') is True:
  944. board.start_pilot_bunch_emulator(board_id)
  945. board.start_acquisition(board_id)
  946. try:
  947. board.wait_for_revolutions(board_id) # Wait before asking for data
  948. except IndexError:
  949. error(0x002, "Unexpected output of pci for number of orbits to observe. Stopping Timescan")
  950. self.stopSignal.emit()
  951. return
  952. board.stop_acquisition(board_id)
  953. board.enable_transfer(board_id)
  954. # -----------[ IMPORTANT ]---------------------
  955. if not kcgw.testing:
  956. data_raw = board.pci.read_data_to_variable(board_id)
  957. board.flush_dma(board_id)
  958. # ----------------------------------------------
  959. else:
  960. f_name = "{InsertPathToPreAcquiredTimscanDataHere}" + str(
  961. coarse) + "_" + str(fine) + ".str"
  962. f = open(f_name, 'r')
  963. data_raw = f.read()
  964. # The PCI software not only prints the desired data but also some additional information.
  965. # This information has to be removed here.
  966. # To do so we split the output string from PCI at "Writting" (Note: Writting is correct as
  967. # this is a typo in the PCI driver)
  968. data = io.read_from_string(data_raw, force=True, cache=False)
  969. except board.BoardError as e:
  970. self.stopSignal.emit()
  971. self.finished.emit()
  972. return
  973. for adc in range(4):
  974. if self.bucket_to_use is None:
  975. if self.threshold_counts is not None:
  976. indexes = np.where(np.logical_or(data.array[:, adc] > 2048+self.threshold_counts, data.array[:, adc] < 2048-self.threshold_counts))[0]
  977. if indexes.shape[0] == 0:
  978. buckets = data.array[:, adc]
  979. else:
  980. buckets = data.array[indexes, adc]
  981. else:
  982. buckets = data.array[:, adc]
  983. else:
  984. buckets = data.array[self.bucket_to_use::config.bunches_per_turn, adc]
  985. heatmap[adc, f_step, c_step] = float(buckets.sum()) / buckets.shape[0]
  986. # Uncomment this to change back to the old (non functional) method of maxima determination
  987. # if heatmap[adc, f_step, c_step] > maximum[adc, 0]:
  988. # maximum[adc, 0] = heatmap[adc, f_step, c_step]
  989. # maximum[adc, 1] = coarse
  990. # maximum[adc, 2] = fine
  991. # if minimum[adc] is None or minimum[adc] > heatmap[adc, f_step, c_step]:
  992. # minimum[adc] = heatmap[adc, f_step, c_step]
  993. self.pbarSignal.emit(((c_step * (f_to - f_frm + 1)) + f_step) + 1)
  994. #GUI is blocked in our tight loop. Give it an opportunity to handle events
  995. # QtGui.QApplication.processEvents() # remove this if moved to thread again
  996. if board.get_board_status(board_id).time_scan is False:
  997. # Time Scan Stop is already performed by button press. Nothing else to do but leave
  998. self.finished.emit()
  999. return
  1000. f_step += 1
  1001. c_step += 1
  1002. self.finished.emit()
  1003. def finished(timescan_progressbar):
  1004. '''Method to handle the end of the thread'''
  1005. thread.stop()
  1006. _bif_stop_time_scan(board_id, timescan_progressbar)
  1007. Elements.setEnabled('acquire_{}'.format(board_id), True, exclude=Elements.getElements('start_time_scan_{}'.format(board_id)))
  1008. if orbits_observe:
  1009. board.get_board_config(board_id).update("orbits_observe", storage.storage.orbits_observe_before_timescan[board_id]) # restore values
  1010. bk_change_num_of_orbits(board_id, storage.storage.orbits_observe_before_timescan[board_id])
  1011. if orbits_skip:
  1012. board.get_board_config(board_id).update("orbits_skip", storage.storage.orbits_skip_before_timescan[board_id])
  1013. bk_change_num_of_skipped_orbits(board_id, storage.storage.orbits_skip_before_timescan[board_id])
  1014. board.get_board_config(board_id).set_delay(storage.storage.th_old[board_id])
  1015. board.get_board_config(board_id).set_chip_delay(
  1016. [0, 1, 2, 3],
  1017. [
  1018. storage.storage.chip_1_old[board_id],
  1019. storage.storage.chip_2_old[board_id],
  1020. storage.storage.chip_3_old[board_id],
  1021. storage.storage.chip_4_old[board_id]
  1022. ]
  1023. )
  1024. # maximum = []
  1025. for adc, a in enumerate(heatmap):
  1026. f, c = np.unravel_index(np.argmax(a), a.shape)
  1027. maximum[adc] = [a[f, c], c+c_frm, f+f_frm]
  1028. m = [np.min(heatmap[heatmap != 0]), np.max(heatmap)] # this gives the same levels for all 4 adcs
  1029. plot_func(heatmap, levels=m, ranges=[c_frm,c_to,f_frm,f_to], newTitle=str(tr("sw", "Coarserange:{c_f}-{c_t} ; Finerange:{f_f}-{f_t}")).format(
  1030. c_f=c_frm,
  1031. c_t=c_to,
  1032. f_f=f_frm,
  1033. f_t=f_to),
  1034. maxima=maximum
  1035. )
  1036. now = time.time()
  1037. if not os.path.isdir(str(storage.storage.save_location + '/' + storage.storage.subdirname + '/timescan')):
  1038. os.makedirs((storage.storage.save_location + '/' + storage.storage.subdirname + '/timescan'))
  1039. filename = storage.storage.save_location + '/' + storage.storage.subdirname + '/timescan/timescan_{:0.3f}.out'.format(
  1040. now)
  1041. f = open(filename, 'wr')
  1042. for adc in range(4):
  1043. f.write("#ADC_%s\n" % adc)
  1044. for coarse, curr_cor in enumerate(np.transpose(heatmap[adc])):
  1045. for fine, value in enumerate(curr_cor):
  1046. f.write("%i;%i;%f\n" % ((coarse + c_frm), (fine + f_frm), value))
  1047. f.write('\n')
  1048. f.close()
  1049. f = open(filename + '.gnuplot', 'wr')
  1050. f.write('set datafile separator ";"\n')
  1051. f.write('set multiplot layout 2,2\n')
  1052. f.write('unset key\n')
  1053. for i in range(4):
  1054. f.write('set label 1 "ADC_%i" at graph 0.7,0.95 font ",8"\n' % (i + 1))
  1055. f.write('plot "%s" every :::%i::%i using 3 with lines\n' % (filename, i, i))
  1056. f.write('unset multiplot\n')
  1057. f.close()
  1058. return
  1059. tst = thread_time_scan(c_frm, c_to, f_frm, f_to, timescan_progressbar, bucket_to_use, threshold_counts)
  1060. thread.register(tst)
  1061. thread.connect('pbarSignal', timescan_progressbar.setValue)
  1062. thread.connect('finished', lambda: finished(timescan_progressbar))
  1063. thread.connect('stopSignal', lambda: _bif_stop_time_scan(board_id, timescan_progressbar))
  1064. thread.start('time_scan')
  1065. def bk_check_for_board(board_id):
  1066. """
  1067. Check if board is connected
  1068. Also overrides the bk_status_readout function with a function that does nothing (suppresses read attempts that
  1069. generate errors - if no board is connected, there is nothing to read from)
  1070. Also overrides the bk_get_temperature function as of the same reasons
  1071. :param board_id: id of the board do manipulate
  1072. :return: -
  1073. """
  1074. # global bk_status_readout, bk_get_temperature
  1075. board_status = bk_board_connected(board_id)
  1076. if board_status:
  1077. if not hasattr(board.get_board_status(board_id), 'board_connected') or \
  1078. not board.get_board_status(board_id).board_connected:
  1079. globals()['bk_status_readout'] = backup_readout
  1080. globals()['bk_get_temperature'] = backup_get_temp
  1081. board.get_board_status(board_id).board_connected = True
  1082. else:
  1083. Elements.setEnabled('no_board_{}'.format(board_id), False)
  1084. def do_nothing():
  1085. pass
  1086. def no_temp(board_id):
  1087. return "-"
  1088. globals()['bk_status_readout'] = do_nothing
  1089. globals()['bk_get_temperature'] = no_temp
  1090. board.get_board_status(board_id).board_connected = False
  1091. if board_status == False:
  1092. board.get_board_status(board_id).status_text = tr("sw", "Board {} not connected".format(board_id))
  1093. elif board_status == None:
  1094. board.get_board_status(board_id).status_text = tr("sw", "Software Interface not found")
  1095. def bk_toggle_wait_on_trigger(board_id, num_of_acquisitions=None, skip=None, timeout=None, method=None):
  1096. """
  1097. Toggle waiting for trigger signal to acquire
  1098. :param board_id: id of the board do manipulate
  1099. :param num_of_acquisitions: number of acquisitions to wait for
  1100. :param skip: how much trigger signals to skip between acquisitions
  1101. :param timeout: the timeout for the pci to wait for date
  1102. :param method: wait method to use
  1103. 1 for wait in pci command and 2 for waiting until register is set that KAPTURE has read data
  1104. NOTE: this also means that method 1 enables simultaneous read and write to dma and method 2 does write and
  1105. read sequentially
  1106. :return:
  1107. """
  1108. thread = storage.get_board_specific_storage(board_id).setdefault('TriggerThread', storage.ThreadStorage())
  1109. if thread.running:
  1110. Elements.getElements("acquireTrigger_{}".format(board_id))[0].setText(tr("Button", "Stopping Acquisition"))
  1111. # FIXME: Button not updated otherwise:
  1112. QtGui.qApp.processEvents()
  1113. log(board_id=board_id, additional="Stop wait on trigger on board {}".format(board_id))
  1114. thread.quit()
  1115. thread.stop()
  1116. # for elem in Elements.getElements("acquire_{}".format(board_id)):
  1117. # if isinstance(elem, QtGui.QShortcut):
  1118. # continue
  1119. # elem.setText(tr("Button", "Stopping Acquisition"))
  1120. # elem.setEnabled(False)
  1121. else:
  1122. log(board_id=board_id, additional="Start wait on trigger on board {}".format(board_id))
  1123. # for elem in Elements.getElements("acquireTrigger_{}".format(board_id)):
  1124. # if isinstance(elem, QtGui.QShortcut):
  1125. # continue
  1126. # elem.setIcon(QtGui.QIcon(config.install_path + config.stopIcon))
  1127. # elem.setText(tr("Button", "Stop Acquisition"))
  1128. Elements.setEnabled('acquire_{}'.format(board_id), False)
  1129. callbacks.callback('acquisition_started', board_id)
  1130. _bif_start_wait_on_trigger(board_id, num_of_acquisitions, skip, timeout, method)
  1131. def _bif_start_wait_on_trigger(board_id, num_of_acquisitions=None, skip=None, timeout=None, method=None):
  1132. """
  1133. Start waiting on external acquisition trigger. This starts the timer
  1134. :param board_id: id of the board do manipulate
  1135. :param num_of_acquisitions: number of acquisitions to do
  1136. :param count_label: Handle for the countlabel
  1137. :param method: wait method to use
  1138. 1 for wait in pci command and 2 for waiting until register is set that KAPTURE has read data
  1139. NOTE: this also means that method 1 enables simultaneous read and write to dma and method 2 does write and
  1140. read sequentially
  1141. :return: -
  1142. """
  1143. # FIXme: This is a work around, for method 2 to work everytime a standard single read needs to be perform before acquisition is started
  1144. board.acquire_data(board_id, '/dev/null')
  1145. #with workaround no flush dema need, because it is done at end of board.acquire_data() anyway.
  1146. #board.flush_dma(board_id) # TODO: really at begining and end of function necessary?
  1147. thread = storage.get_board_specific_storage(board_id).setdefault('TriggerThread', storage.ThreadStorage())
  1148. if thread.running:
  1149. logging.info("Wait already running on board {}".format(board_id))
  1150. return
  1151. log(board_id=board_id, additional="Start wait on trigger")
  1152. board.get_board_status(board_id).wait_on_trigger = True
  1153. if not os.path.isdir(str(storage.storage.save_location + '/' + storage.storage.subdirname)):
  1154. os.makedirs(str(storage.storage.save_location + '/' + storage.storage.subdirname))
  1155. if not num_of_acquisitions:
  1156. num_of_acquisitions = bk_get_config(board_id, 'acquisition_count')
  1157. if not skip:
  1158. skip = bk_get_config(board_id, 'trigger_skip')
  1159. if not timeout:
  1160. timeout = bk_get_config(board_id, 'trigger_timeout')
  1161. if not method:
  1162. method = bk_get_config(board_id, 'trigger_method')
  1163. storage.get_board_specific_storage(board_id).trigger_progressbar = \
  1164. _bif_ProgressBar(0, num_of_acquisitions, tr("sw", "Acquiring with board ")+str(board_id))
  1165. board.pci.write(board_id, hex(num_of_acquisitions), "9024")
  1166. time.sleep(0.1)
  1167. board.pci.write(board_id, hex(skip), "902C")
  1168. # time.sleep(0.1)
  1169. # board.pci.write(board_id, 'ff0', hex_mask='ff0') # TODO: This writes t/h 3/4 but enable_transfer etc do not
  1170. # This seems to sometimes lead to segfaults of python it self. An Idea to prevent this
  1171. # is to use copy.deepcopy in __init__. But there is no reason to think that that causes the problem. In fact
  1172. # I don't have an idea why it crashes.
  1173. # A possible reason could the os.rename be (or even the board.safe_call as that saves data to the disk) But I think
  1174. # this is rather unlikely
  1175. # ~~NOTE~~: the thread of calibration also triggered segfaults sometimes. But this seems to be miraculously solved.
  1176. # Something that is likely to cause the problem is the log.debug in board.safe_call
  1177. # Logging (using the logging module) is directly connected to the main thread and could cause problems
  1178. class thread_wait_on_signal(QtCore.QObject):
  1179. '''Class to run the wait on signal functionality in a thread'''
  1180. countUpdate = QtCore.pyqtSignal(int)
  1181. stopSignal = QtCore.pyqtSignal()
  1182. finished = QtCore.pyqtSignal()
  1183. liveplot = QtCore.pyqtSignal(int, str) # This has to be changed if board_id is no integer
  1184. def __init__(self):
  1185. super(thread_wait_on_signal, self).__init__()
  1186. self.noa = None
  1187. self.path = None
  1188. self.timeout = None
  1189. self._quit = False
  1190. def init(self, num_of_acquisitions, path, timeout):
  1191. '''initialise a new run'''
  1192. self.noa = num_of_acquisitions
  1193. self.path = path
  1194. self.timeout = timeout
  1195. self._quit = False
  1196. # Elements.setEnabled('acquireTrigger_{}'.format(board_id), False) # exclude=Elements.getElements('wait_on_trigger_{}'.format(board_id)))
  1197. def wait_rw_simul(self): # Method 1
  1198. '''Wait simultaniously (with the pci command) for a trigger signal'''
  1199. board.pci.write(board_id, 'ff0', hex_mask='ff0') # TODO: This writes t/h 3/4 but enable_transfer etc do not
  1200. for num_of_acq in xrange(self.noa):
  1201. # def step():
  1202. if self._quit:
  1203. break
  1204. filename = self.path +'/{:0.3f}.out'.format(time.time())
  1205. board.pci.read_data_to_file(board_id, filename=filename, timeout=(self.timeout*1000000))
  1206. # rename with correct timestamp - last modified time
  1207. self.countUpdate.emit(num_of_acq + 1)
  1208. # file operations
  1209. if not os.path.isfile(filename):
  1210. error(0x001, "No File Created")
  1211. continue
  1212. newfile = '{path}/trigger_{num:05}_{htime}_{unixtime}.out'.format(
  1213. num=num_of_acq,
  1214. htime=dt.fromtimestamp(os.path.getmtime(filename)).strftime('%Y-%m-%dT%Hh%Mm%Ss%f'),
  1215. unixtime=int(os.path.getmtime(filename)),
  1216. path=self.path
  1217. )
  1218. os.rename(filename, newfile)
  1219. if os.path.getsize(newfile) > 0:
  1220. self.liveplot.emit(board_id, newfile)
  1221. else:
  1222. logging.info("Acquired 0b, possible trigger timeout.")
  1223. self.finished.emit()
  1224. def wait_rw_seq(self): # Method 2
  1225. '''Wait sequentially (in the gui) for a trigger signal'''
  1226. for num_of_acq in xrange(self.noa):
  1227. board.pci.write(board_id, '00bf0', hex_mask='CF0') # enable readout
  1228. pre_acq_num = board.pci.read(board_id, 1, '9034')[0]
  1229. time_a = time.time()
  1230. timeout = False
  1231. while pre_acq_num == board.pci.read(board_id, 1, '9034')[0]:
  1232. if time.time() - time_a > self.timeout:
  1233. timeout = True
  1234. break
  1235. if self._quit:
  1236. self.finished.emit()
  1237. return
  1238. if not timeout:
  1239. board.pci.write(board_id, '000f0', hex_mask='8F0') # disable readout
  1240. board.pci.write(board_id, '007f0', hex_mask='CF0') # enable transfer
  1241. filename = self.path +'/{:0.3f}.out'.format(time.time())
  1242. board.pci.read_data_to_file(board_id, filename=filename, timeout=(self.timeout*1000000))
  1243. # board.pci.write(board_id, '000f0', hex_mask='4F0') # disable transfer
  1244. self.countUpdate.emit(copy.deepcopy(num_of_acq+1))
  1245. if self._quit: # is this really the correct position? file is taken but not renamed!
  1246. self.finished.emit()
  1247. break
  1248. if not os.path.isfile(filename):
  1249. error(0x001, "No File Created")
  1250. continue
  1251. newfile = '{path}/trigger_{num:05}_{htime}_{unixtime}.out'.format(
  1252. num=num_of_acq,
  1253. htime=dt.fromtimestamp(os.path.getmtime(filename)).strftime('%Y-%m-%dT%Hh%Mm%Ss%f'),
  1254. unixtime=int(os.path.getmtime(filename)),
  1255. path=self.path
  1256. )
  1257. os.rename(filename, newfile)
  1258. self.liveplot.emit(board_id, newfile)
  1259. else:
  1260. logging.info("Trigger timeout.")
  1261. self.finished.emit()
  1262. def quit(self):
  1263. '''quit this thread'''
  1264. self._quit = True
  1265. def __del__(self):
  1266. print 'quite'
  1267. board.pci.write(board_id, '0', '9024')
  1268. time.sleep(0.1)
  1269. board.pci.write(board_id, '0', '902C')
  1270. time.sleep(0.1)
  1271. board.pci.write(board_id, '3f0', hex_mask='ff0') # TODO: This writes t/h 3/4 but enable_transfer etc do not
  1272. board.flush_dma(board_id)
  1273. def finished():
  1274. '''Handle the end of the thread'''
  1275. board.pci.write(board_id, '0', '9024')
  1276. time.sleep(0.1)
  1277. board.pci.write(board_id, '0', '902C')
  1278. time.sleep(0.1)
  1279. board.pci.write(board_id, '3f0', hex_mask='ff0') # TODO: This writes t/h 3/4 but enable_transfer etc do not
  1280. board.flush_dma(board_id)
  1281. thread.stop()
  1282. board.get_board_status(board_id).wait_on_trigger = False
  1283. storage.get_board_specific_storage(board_id).trigger_progressbar.remove(0)
  1284. log(board_id=board_id, additional="Stop wait on trigger")
  1285. Elements.setEnabled('acquire_{}'.format(board_id), True)
  1286. callbacks.callback('acquisition_stopped', board_id)
  1287. # for elem in Elements.getElements("acquire_{}".format(board_id)):
  1288. # if isinstance(elem, QtGui.QShortcut):
  1289. # continue
  1290. # elem.setIcon(QtGui.QIcon(config.install_path + config.startIcon))
  1291. # elem.setText(tr("Button", "Start Acquisition"))
  1292. # elem.setEnabled(True)
  1293. return
  1294. # twt = thread_wait_on_signal(num_of_acquisitions, storage.storage.save_location + '/' + storage.storage.subdirname,
  1295. # timeout)
  1296. if not thread.is_registered():
  1297. twt = thread_wait_on_signal()
  1298. thread.register(twt)
  1299. else:
  1300. thread.disconnect('countUpdate', 'finished', 'liveplot')
  1301. thread.init(num_of_acquisitions, storage.storage.save_location + '/' + storage.storage.subdirname, timeout)
  1302. # reconnect signals to make sure the correct versions of methods are called
  1303. thread.connect('countUpdate', storage.get_board_specific_storage(board_id).trigger_progressbar.setValue)
  1304. thread.connect('finished', finished)
  1305. thread.connect('liveplot', _bif_read_and_update_data_from_file)
  1306. if method == 1:
  1307. thread.start('wait_rw_simul')
  1308. elif method == 2:
  1309. thread.start('wait_rw_seq')
  1310. else:
  1311. raise ValueError("Wrong method")