backendinterface.py 57 KB

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