backendinterface.py 59 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488
  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 = 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('0x01', '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. for plotwin in live_plot_windows.getWindows(board_id):
  624. plotwin.plot_live(data=data)
  625. QtGui.qApp.processEvents()
  626. else:
  627. callbacks.async_callback('update_consistency', None)
  628. _bif_disable_wait_cursor()
  629. def bk_acquire(board_id):
  630. """
  631. Toggle Acqisition
  632. :param board_id: id of the board do manipulate
  633. :return:
  634. """
  635. if not bk_get_config(board_id, 'use_trigger'):
  636. if board.get_board_status(board_id).acquisition == True:
  637. log(board_id=board_id, additional="Manually Stopped Acquisition\nPerformed Acquisitions: " + str(storage.storage.current_acquisition))
  638. _bif_stop_acquisition(board_id)
  639. else:
  640. _bif_start_acquisition(board_id)
  641. else:
  642. bk_toggle_wait_on_trigger(board_id)
  643. def _bif_stop_acquisition(board_id):
  644. """
  645. Stop acquisition
  646. This does stop the timer started by _bif_start_acquisition()
  647. :param board_id: id of the board do manipulate
  648. :return: -
  649. """
  650. board.get_board_status(board_id).acquisition = False
  651. storage.get_board_specific_storage(board_id).acquisition_progressbar.remove(0)
  652. storage.get_board_specific_storage(board_id).acquisition_timer.stop()
  653. # for elem in Elements.getElements("acquireTrigger_{}".format(board_id)):
  654. # if isinstance(elem, QtGui.QShortcut) or isinstance(elem, QtGui.QCheckBox):
  655. # continue
  656. # elem.setIcon(QtGui.QIcon(config.install_path + config.startIcon))
  657. # elem.setText(tr("Button", "Start Acquisition"))
  658. Elements.setEnabled('acquire_{}'.format(board_id), True)
  659. callbacks.callback('acquisition_stopped', board_id)
  660. def _bif_start_acquisition(board_id):
  661. """
  662. Start acquisition.
  663. This will start a timer to automatically acquire data.
  664. :param board_id: id of the board do manipulate
  665. :return: -
  666. """
  667. log(board_id=board_id, additional="Started Acquisition")
  668. board.get_board_status(board_id).acquisition = True
  669. Elements.setEnabled('acquire_{}'.format(board_id), False)
  670. # for elem in Elements.getElements("acquireTrigger_{}".format(board_id)):
  671. # if isinstance(elem, QtGui.QShortcut) or isinstance(elem, QtGui.QCheckBox):
  672. # continue
  673. # elem.setIcon(QtGui.QIcon(config.install_path + config.stopIcon))
  674. # elem.setText(tr("Button", "Stop Acquisition"))
  675. callbacks.callback('acquisition_started', board_id)
  676. storage.get_board_specific_storage(board_id).acquisition_timer = QtCore.QTimer()
  677. num_acquisitions = board.get_board_config(board_id).get("acquisition_count")
  678. storage.get_board_specific_storage(board_id).acquisition_progressbar = \
  679. _bif_ProgressBar(0, num_acquisitions, tr("sw", "Acquiring with board ")+str(board_id))
  680. # storage.storage.acquisition_progressbar = acquisition_progressbar
  681. # We increase already once because we do a single acquisition before the
  682. # timer is started, otherwise we have to wait until the timer fires the
  683. # first time.
  684. try:
  685. if isinstance(storage.storage.current_acquisition, dict):
  686. storage.storage.current_acquisition[board_id] = 1
  687. else:
  688. storage.storage.current_acquisition = {board_id: 1}
  689. except storage.StorageError:
  690. storage.storage.current_acquisition = {board_id: 1}
  691. _bif_read_data_and_save(board_id)
  692. if board.get_board_config(board_id).get("build_spectrograms"):
  693. spectrogram_dir = storage.storage.save_location + '/' + storage.storage.subdirname+"/spectrograms_{:0.3f}".format(time.time())
  694. os.makedirs(spectrogram_dir)
  695. _bif_iterate_spectrograms(board_id, spectrogram_dir) # TODO: not here?
  696. storage.get_board_specific_storage(board_id).acquisition_progressbar.setValue(storage.storage.current_acquisition[board_id])
  697. def on_timeout():
  698. '''Handler for the timeout of the acquisition timer. This does the acquisition'''
  699. if storage.storage.current_acquisition[board_id] < num_acquisitions:
  700. storage.storage.current_acquisition[board_id] += 1
  701. storage.get_board_specific_storage(board_id).acquisition_progressbar.setValue(storage.storage.current_acquisition[board_id])
  702. _bif_read_data_and_save(board_id)
  703. if board.get_board_config(board_id).get("build_spectrograms"):
  704. _bif_iterate_spectrograms(board_id, spectrogram_dir) # TODO: not here ?
  705. else:
  706. log(board_id=board_id, additional="Stopped Acquisition")
  707. _bif_stop_acquisition(board_id)
  708. storage.get_board_specific_storage(board_id).acquisition_progressbar.remove(0)
  709. storage.get_board_specific_storage(board_id).acquisition_timer.timeout.connect(on_timeout)
  710. storage.get_board_specific_storage(board_id).acquisition_timer.start(board.get_board_config(board_id).get('orbits_wait_time') * 1000)
  711. def bk_single_read(board_id):
  712. """
  713. Perform a single read of data
  714. :param board_id: id of the board do manipulate
  715. :return:
  716. """
  717. Elements.setEnabled("acquire_{}".format(board_id), False)
  718. _bif_read_data_and_save(board_id)
  719. log(board_id=board_id, additional="Single Read\nFilename: "+board.get_board_status(board_id).last_file.split('/')[-1])
  720. Elements.setEnabled("acquire_{}".format(board_id), True)
  721. def _bif_set_continuous_read_active(board_id):
  722. """
  723. Enable continuous read
  724. :param board_id: id of the board do manipulate
  725. :return: -
  726. """
  727. Elements.setEnabled("acquire_{}".format(board_id), False)
  728. Elements.setEnabled("acquireTrigger_{}".format(board_id), False)
  729. Elements.setEnabled("continuous_read_{}".format(board_id), True)
  730. board.get_board_status(board_id).continuous_read = True
  731. def _bif_set_continuous_read_inactive(board_id):
  732. """
  733. Disable continuous read
  734. :param board_id: id of the board do manipulate
  735. :return: -
  736. """
  737. if board.get_board_status(board_id).continuous_read:
  738. board.get_board_status(board_id).continuous_read = False
  739. storage.get_board_specific_storage(board_id).continuous_read_timer.stop()
  740. Elements.setEnabled('acquire_{}'.format(board_id), True)
  741. Elements.setEnabled('acquireTrigger_{}'.format(board_id), True)
  742. def bk_continuous_read(board_id, interval=100):
  743. """
  744. Toggle continuous read
  745. :param board_id: id of the board do manipulate
  746. :param interval: Time between two consecutive reads.
  747. :return: -
  748. """
  749. if not board.get_board_status(board_id).continuous_read:
  750. _bif_set_continuous_read_active(board_id)
  751. _bif_continuous_read(board_id, interval)
  752. else:
  753. _bif_set_continuous_read_inactive(board_id)
  754. def _bif_continuous_read(board_id, interval=None):
  755. """
  756. Perform continuous read based on a timer.
  757. :param interval:
  758. :return:
  759. """
  760. if interval is not None:
  761. # TODO: ueberall checken, dass der board specific storage verwendet wird
  762. storage.get_board_specific_storage(board_id).continuous_interval = interval
  763. storage.get_board_specific_storage(board_id).continuous_read_timer = QtCore.QTimer()
  764. logging.info("Start continuous read")
  765. def continuous_read_step():
  766. if board.get_board_status(board_id).continuous_read:
  767. _bif_read_data(board_id)
  768. storage.get_board_specific_storage(board_id).continuous_read_timer.singleShot(storage.storage.continuous_interval, continuous_read_step)
  769. storage.get_board_specific_storage(board_id).continuous_read_timer.singleShot(storage.storage.continuous_interval, continuous_read_step)
  770. def _bif_read_data(board_id):
  771. """
  772. Reads data acquired by board.
  773. :param board_id: id of the board do manipulate
  774. :return:
  775. """
  776. try:
  777. if board.get_board_config(board_id).get('pilot_bunch'):
  778. board.start_pilot_bunch_emulator(board_id)
  779. board.start_acquisition(board_id)
  780. try:
  781. board.wait_for_revolutions(board_id)
  782. except IndexError:
  783. error(0x002, "Unexpected output of pci for number of orbits to observe. Returning")
  784. return
  785. board.stop_acquisition(board_id)
  786. board.enable_transfer(board_id)
  787. data_raw = board.pci.read_data_to_variable(board_id)
  788. _bif_read_and_update_data_from_string(board_id, data_raw)
  789. except board.BoardError as e:
  790. logging.error("Reading failed for board {}: {}".format(str(board_id), str(e)))
  791. def bk_board_connected(board_id):
  792. """
  793. Interface to the board to check if it is connected.
  794. :param board_id: id of the board do manipulate
  795. :return: -
  796. """
  797. if not available_boards.has_boards:
  798. return False
  799. else:
  800. return board_id in available_boards.board_ids
  801. def bk_get_temperature(board_id):
  802. """
  803. Get Temperature from board and format it
  804. :param board_id: id of the board do manipulate
  805. :return: -
  806. """
  807. fpga_temp_raw_hex = board.pci.read(board_id, 1, '0x9110')[0]
  808. fpga_temp_raw_hex = fpga_temp_raw_hex[-3:]
  809. fpga_temp_raw_bin = '{0:012b}'.format(int(fpga_temp_raw_hex, 16))
  810. fpga_temp_encoded = board.get_dec_from_bits(fpga_temp_raw_bin, 9, 0)
  811. fpga_temp_celsius = '{0:2.2f}'.format(((fpga_temp_encoded * 503.975) / 1024) - 273.15)
  812. return fpga_temp_celsius
  813. backup_get_temp = bk_get_temperature
  814. def bk_time_scan(board_id, c_frm, c_to, f_frm, f_to, ts_pbar, plot_func, orbits_observe=None, orbits_skip=None):
  815. """
  816. Toggle Timescan.
  817. :param board_id: id of the board do manipulate
  818. :param c_frm: (int) From value for Coarse scan
  819. :param c_to: (int) To value for Coarse scan
  820. :param f_frm: (int) From value for Fine scan
  821. :param f_to: (int) To value for fine scan
  822. :param ts_pbar: Handle to the Timescan Progressbar
  823. :param plot_func: Function to plot when timescan ended.
  824. :param orbits_observe: Number of orbits to observe for the timescan (original values will be restored after timescan)
  825. :param orbits_skip: Number of orbits to skipfor the timescan (original values will be restored after timescan)
  826. :return: -
  827. """
  828. if board.get_board_status(board_id).time_scan:
  829. _bif_stop_time_scan(board_id, ts_pbar)
  830. else:
  831. _bif_start_time_scan(board_id, c_frm, c_to, f_frm, f_to, ts_pbar, plot_func, orbits_observe, orbits_skip)
  832. def _bif_stop_time_scan(board_id, ts_pbar):
  833. """
  834. Stop the timescan. This stops the timer.
  835. :param board_id: id of the board do manipulate
  836. :param ts_pbar: Timescan Progressbar handle
  837. :return: -
  838. """
  839. Elements.getElements("start_time_scan_{}".format(board_id))[0].setText(tr("Button", "Start time scan"))
  840. board.get_board_status(board_id).time_scan = False
  841. board.get_board_config(board_id).set_delay(storage.storage.th_old[board_id])
  842. board.get_board_config(board_id).set_chip_delay(
  843. [0, 1, 2, 3],
  844. [
  845. storage.storage.chip_1_old[board_id],
  846. storage.storage.chip_2_old[board_id],
  847. storage.storage.chip_3_old[board_id],
  848. storage.storage.chip_4_old[board_id]
  849. ]
  850. )
  851. ts_pbar.reset()
  852. # tst = None # Ugly but necessary for the thread not to be killed when function ends (which is almost immediately after start)
  853. # thread_ts = None
  854. def _bif_start_time_scan(board_id, c_frm, c_to, f_frm, f_to, timescan_progressbar, plot_func, orbits_observe, orbits_skip):
  855. """
  856. Start the timscan. This starts the timer
  857. :param board_id: id of the board do manipulate
  858. :param c_frm: From value for coarse scan
  859. :param c_to: To value for coarse scan
  860. :param f_frm: From value for fine scan
  861. :param f_to: To value for fine scan
  862. :param timescan_progressbar: Handle for the timescanprogressbar
  863. :param plot_func: Function to use to plot the data
  864. :param orbits_observe: Number of orbits to observe for the timescan (original values will be restored after timescan)
  865. :param orbits_skip: Number of orbits to skipfor the timescan (original values will be restored after timescan)
  866. :return: -
  867. """
  868. thread = storage.get_board_specific_storage(board_id).setdefault("TimeScanThread", storage.ThreadStorage())
  869. # if thread_ts is not None:
  870. # logging.info("Time scan already running")
  871. # return
  872. if thread.running:
  873. logging.info("Time scan already running")
  874. return
  875. board.get_board_status(board_id).time_scan = True
  876. Elements.getElements("start_time_scan_{}".format(board_id))[0].setText(tr("Button", "Stop time scan"))
  877. if c_frm > c_to:
  878. logging.info('Coarse Scan Interval is invalid: (%i > %i)' % (c_frm, c_to))
  879. return
  880. if f_frm > f_to:
  881. logging.info('Fine Scan Interval is invalid: (%i > %i)' % (f_frm, f_to))
  882. return
  883. # the following could be made nicer with the use of setdefault and the use of get_board_specific_storage
  884. if not hasattr(storage.storage, 'th_old'):
  885. storage.storage.th_old = {}
  886. storage.storage.chip_1_old = {}
  887. storage.storage.chip_2_old = {}
  888. storage.storage.chip_3_old = {}
  889. storage.storage.chip_4_old = {}
  890. storage.storage.th_old[board_id] = board.get_board_config(board_id).get('th_delay')
  891. storage.storage.chip_1_old[board_id] = board.get_board_config(board_id).get('chip_1_delay')
  892. storage.storage.chip_2_old[board_id] = board.get_board_config(board_id).get('chip_2_delay')
  893. storage.storage.chip_3_old[board_id] = board.get_board_config(board_id).get('chip_3_delay')
  894. storage.storage.chip_4_old[board_id] = board.get_board_config(board_id).get('chip_4_delay')
  895. minimum = [None, None, None, None]
  896. maximum = np.zeros((4, 3))
  897. heatmap = np.zeros((4, (f_to - f_frm + 1), (c_to - c_frm + 1)))
  898. timescan_progressbar.setRange(1, ((f_to - f_frm) + 1) * ((c_to - c_frm) + 1))
  899. class thread_time_scan(QtCore.QObject):
  900. '''Timescan Thread class'''
  901. pbarSignal = QtCore.pyqtSignal(int)
  902. stopSignal = QtCore.pyqtSignal()
  903. finished = QtCore.pyqtSignal()
  904. def __init__(self, c_frm, c_to, f_frm, f_to, timescan_progressbar):
  905. super(thread_time_scan, self).__init__()
  906. self.c_frm = c_frm
  907. self.c_to = c_to
  908. self.f_frm = f_frm
  909. self.f_to = f_to
  910. self.timescan_progressbar = timescan_progressbar
  911. def time_scan(self):
  912. '''Method to run in the thread that does the timescan'''
  913. Elements.setEnabled('acquire_{}'.format(board_id), False, exclude=Elements.getElements('start_time_scan_{}'.format(board_id)))
  914. if orbits_observe:
  915. if not hasattr(storage.storage, 'orbits_observe_before_timescan'):
  916. storage.storage.orbits_observe_before_timescan = {}
  917. storage.storage.orbits_observe_before_timescan[board_id] = board.get_board_config(board_id).get("orbits_observe") # save old values to restore after timescan
  918. board.get_board_config(board_id).update("orbits_observe", orbits_observe)
  919. bk_change_num_of_orbits(board_id, orbits_observe)
  920. if orbits_skip:
  921. if not hasattr(storage.storage, 'orbits_skip_before_timescan'):
  922. storage.storage.orbits_skip_before_timescan = {}
  923. storage.storage.orbits_skip_before_timescan[board_id] = board.get_board_config(board_id).get("orbits_skip")
  924. board.get_board_config(board_id).update("orbits_skip", orbits_skip)
  925. bk_change_num_of_skipped_orbits(board_id, orbits_skip)
  926. c_step = 0
  927. for coarse in range(self.c_frm, self.c_to + 1):
  928. try:
  929. board.get_board_config(board_id).set_delay(coarse)
  930. except board.BoardError as e:
  931. self.stopSignal.emit()
  932. self.finished.emit()
  933. return
  934. f_step = 0
  935. for fine in range(self.f_frm, self.f_to + 1):
  936. board.get_board_config(board_id).set_chip_delay([0, 1, 2, 3], [fine, fine, fine, fine])
  937. try:
  938. if bk_get_config(board_id, 'pilot_bunch') is True:
  939. board.start_pilot_bunch_emulator(board_id)
  940. board.start_acquisition(board_id)
  941. try:
  942. board.wait_for_revolutions(board_id) # Wait before asking for data
  943. except IndexError:
  944. error(0x002, "Unexpected output of pci for number of orbits to observe. Stopping Timescan")
  945. self.stopSignal.emit()
  946. return
  947. board.stop_acquisition(board_id)
  948. board.enable_transfer(board_id)
  949. # -----------[ IMPORTANT ]---------------------
  950. if not kcgw.testing:
  951. data_raw = board.pci.read_data_to_variable(board_id)
  952. board.flush_dma(board_id)
  953. # ----------------------------------------------
  954. else:
  955. f_name = "/home/blaxxun/Documents/Hiwi/KaptureSimulator/timescan/" + str(
  956. coarse) + "_" + str(fine) + ".str"
  957. f = open(f_name, 'r')
  958. data_raw = f.read()
  959. # The PCI software not only prints the desired data but also some additional information.
  960. # This information has to be removed here.
  961. # To do so we split the output string from PCI at "Writting" (Note: Writting is correct as
  962. # this is a typo in the PCI driver)
  963. data = io.read_from_string(data_raw, force=True, cache=False)
  964. except board.BoardError as e:
  965. self.stopSignal.emit()
  966. self.finished.emit()
  967. return
  968. for adc in range(4):
  969. buckets = data.array[:, adc:adc + 1].reshape(-1)
  970. heatmap[adc, f_step, c_step] = float(buckets.sum()) / buckets.shape[0]
  971. if heatmap[adc, f_step, c_step] > maximum[adc, 0]:
  972. maximum[adc, 0] = heatmap[adc, f_step, c_step]
  973. maximum[adc, 1] = coarse
  974. maximum[adc, 2] = fine
  975. if minimum[adc] is None or minimum[adc] > heatmap[adc, f_step, c_step]:
  976. minimum[adc] = heatmap[adc, f_step, c_step]
  977. self.pbarSignal.emit(((c_step * (f_to - f_frm + 1)) + f_step) + 1)
  978. #GUI is blocked in our tight loop. Give it an opportunity to handle events
  979. # QtGui.QApplication.processEvents() # remove this if moved to thread again
  980. if board.get_board_status(board_id).time_scan is False:
  981. # Time Scan Stop is already performed by button press. Nothing else to do but leave
  982. self.finished.emit()
  983. return
  984. f_step += 1
  985. c_step += 1
  986. self.finished.emit()
  987. def finished(timescan_progressbar):
  988. '''Method to handle the end of the thread'''
  989. thread.stop()
  990. _bif_stop_time_scan(board_id, timescan_progressbar)
  991. Elements.setEnabled('acquire_{}'.format(board_id), True, exclude=Elements.getElements('start_time_scan_{}'.format(board_id)))
  992. if orbits_observe:
  993. board.get_board_config(board_id).update("orbits_observe", storage.storage.orbits_observe_before_timescan[board_id]) # restore values
  994. bk_change_num_of_orbits(board_id, storage.storage.orbits_observe_before_timescan[board_id])
  995. if orbits_skip:
  996. board.get_board_config(board_id).update("orbits_skip", storage.storage.orbits_skip_before_timescan[board_id])
  997. bk_change_num_of_skipped_orbits(board_id, storage.storage.orbits_skip_before_timescan[board_id])
  998. board.get_board_config(board_id).set_delay(storage.storage.th_old[board_id])
  999. board.get_board_config(board_id).set_chip_delay(
  1000. [0, 1, 2, 3],
  1001. [
  1002. storage.storage.chip_1_old[board_id],
  1003. storage.storage.chip_2_old[board_id],
  1004. storage.storage.chip_3_old[board_id],
  1005. storage.storage.chip_4_old[board_id]
  1006. ]
  1007. )
  1008. m = [np.min(heatmap[heatmap != 0]), np.max(heatmap)] # this gives the same levels for all 4 adcs
  1009. plot_func(heatmap, levels=m, newTitle=str(tr("sw", "Coarserange:{c_f}-{c_t} ; Finerange:{f_f}-{f_t}")).format(
  1010. c_f=c_frm,
  1011. c_t=c_to,
  1012. f_f=f_frm,
  1013. f_t=f_to),
  1014. maxima=maximum
  1015. )
  1016. now = time.time()
  1017. if not os.path.isdir(str(storage.storage.save_location + '/' + storage.storage.subdirname + '/timescan')):
  1018. os.makedirs((storage.storage.save_location + '/' + storage.storage.subdirname + '/timescan'))
  1019. filename = storage.storage.save_location + '/' + storage.storage.subdirname + '/timescan/timescan_{:0.3f}.out'.format(
  1020. now)
  1021. f = open(filename, 'wr')
  1022. for adc in range(4):
  1023. f.write("#ADC_%s\n" % adc)
  1024. for coarse, curr_cor in enumerate(np.transpose(heatmap[adc])):
  1025. for fine, value in enumerate(curr_cor):
  1026. f.write("%i;%i;%f\n" % ((coarse + c_frm), (fine + f_frm), value))
  1027. f.write('\n')
  1028. f.close()
  1029. f = open(filename + '.gnuplot', 'wr')
  1030. f.write('set datafile separator ";"\n')
  1031. f.write('set multiplot layout 2,2\n')
  1032. f.write('unset key\n')
  1033. for i in range(4):
  1034. f.write('set label 1 "ADC_%i" at graph 0.7,0.95 font ",8"\n' % (i + 1))
  1035. f.write('plot "%s" every :::%i::%i using 3 with lines\n' % (filename, i, i))
  1036. f.write('unset multiplot\n')
  1037. f.close()
  1038. return
  1039. tst = thread_time_scan(c_frm, c_to, f_frm, f_to, timescan_progressbar)
  1040. thread.register(tst)
  1041. thread.connect('pbarSignal', timescan_progressbar.setValue)
  1042. thread.connect('finished', lambda: finished(timescan_progressbar))
  1043. thread.connect('stopSignal', lambda: _bif_stop_time_scan(board_id, timescan_progressbar))
  1044. thread.start('time_scan')
  1045. def bk_check_for_board(board_id):
  1046. """
  1047. Check if board is connected
  1048. Also overrides the bk_status_readout function with a function that does nothing (suppresses read attempts that
  1049. generate errors - if no board is connected, there is nothing to read from)
  1050. Also overrides the bk_get_temperature function as of the same reasons
  1051. :param board_id: id of the board do manipulate
  1052. :return: -
  1053. """
  1054. # global bk_status_readout, bk_get_temperature
  1055. board_status = bk_board_connected(board_id)
  1056. if board_status:
  1057. if not hasattr(board.get_board_status(board_id), 'board_connected') or \
  1058. not board.get_board_status(board_id).board_connected:
  1059. globals()['bk_status_readout'] = backup_readout
  1060. globals()['bk_get_temperature'] = backup_get_temp
  1061. board.get_board_status(board_id).board_connected = True
  1062. else:
  1063. Elements.setEnabled('no_board_{}'.format(board_id), False)
  1064. def do_nothing():
  1065. pass
  1066. def no_temp(board_id):
  1067. return "-"
  1068. globals()['bk_status_readout'] = do_nothing
  1069. globals()['bk_get_temperature'] = no_temp
  1070. board.get_board_status(board_id).board_connected = False
  1071. if board_status == False:
  1072. board.get_board_status(board_id).status_text = tr("sw", "Board {} not connected".format(board_id))
  1073. elif board_status == None:
  1074. board.get_board_status(board_id).status_text = tr("sw", "Software Interface not found")
  1075. def bk_toggle_wait_on_trigger(board_id, num_of_acquisitions=None, skip=None, timeout=None, method=None):
  1076. """
  1077. Toggle waiting for trigger signal to acquire
  1078. :param board_id: id of the board do manipulate
  1079. :param num_of_acquisitions: number of acquisitions to wait for
  1080. :param skip: how much trigger signals to skip between acquisitions
  1081. :param timeout: the timeout for the pci to wait for date
  1082. :param method: wait method to use
  1083. 1 for wait in pci command and 2 for waiting until register is set that KAPTURE has read data
  1084. NOTE: this also means that method 1 enables simultaneous read and write to dma and method 2 does write and
  1085. read sequentially
  1086. :return:
  1087. """
  1088. thread = storage.get_board_specific_storage(board_id).setdefault('TriggerThread', storage.ThreadStorage())
  1089. if thread.running:
  1090. # Elements.getElements("acquireTrigger_{}".format(board_id))[0].setText(tr("Button", "Start Acquisition"))
  1091. log(board_id=board_id, additional="Stop wait on trigger on board {}".format(board_id))
  1092. thread.quit()
  1093. thread.stop()
  1094. # for elem in Elements.getElements("acquire_{}".format(board_id)):
  1095. # if isinstance(elem, QtGui.QShortcut):
  1096. # continue
  1097. # elem.setText(tr("Button", "Stopping Acquisition"))
  1098. # elem.setEnabled(False)
  1099. else:
  1100. log(board_id=board_id, additional="Start wait on trigger on board {}".format(board_id))
  1101. # for elem in Elements.getElements("acquireTrigger_{}".format(board_id)):
  1102. # if isinstance(elem, QtGui.QShortcut):
  1103. # continue
  1104. # elem.setIcon(QtGui.QIcon(config.install_path + config.stopIcon))
  1105. # elem.setText(tr("Button", "Stop Acquisition"))
  1106. Elements.setEnabled('acquire_{}'.format(board_id), False)
  1107. callbacks.callback('acquisition_started', board_id)
  1108. _bif_start_wait_on_trigger(board_id, num_of_acquisitions, skip, timeout, method)
  1109. def _bif_start_wait_on_trigger(board_id, num_of_acquisitions=None, skip=None, timeout=None, method=None):
  1110. """
  1111. Start waiting on external acquisition trigger. This starts the timer
  1112. :param board_id: id of the board do manipulate
  1113. :param num_of_acquisitions: number of acquisitions to do
  1114. :param count_label: Handle for the countlabel
  1115. :param method: wait method to use
  1116. 1 for wait in pci command and 2 for waiting until register is set that KAPTURE has read data
  1117. NOTE: this also means that method 1 enables simultaneous read and write to dma and method 2 does write and
  1118. read sequentially
  1119. :return: -
  1120. """
  1121. thread = storage.get_board_specific_storage(board_id).setdefault('TriggerThread', storage.ThreadStorage())
  1122. if thread.running:
  1123. logging.info("Wait already running on board {}".format(board_id))
  1124. return
  1125. log(board_id=board_id, additional="Start wait on trigger")
  1126. board.get_board_status(board_id).wait_on_trigger = True
  1127. if not os.path.isdir(str(storage.storage.save_location + '/' + storage.storage.subdirname)):
  1128. os.makedirs(str(storage.storage.save_location + '/' + storage.storage.subdirname))
  1129. if not num_of_acquisitions:
  1130. num_of_acquisitions = bk_get_config(board_id, 'acquisition_count')
  1131. if not skip:
  1132. skip = bk_get_config(board_id, 'trigger_skip')
  1133. if not timeout:
  1134. timeout = bk_get_config(board_id, 'trigger_timeout')
  1135. if not method:
  1136. method = bk_get_config(board_id, 'trigger_method')
  1137. storage.get_board_specific_storage(board_id).trigger_progressbar = \
  1138. _bif_ProgressBar(0, num_of_acquisitions, tr("sw", "Acquiring with board ")+str(board_id))
  1139. board.pci.write(board_id, hex(num_of_acquisitions), "9024")
  1140. time.sleep(0.1)
  1141. board.pci.write(board_id, hex(skip), "902C")
  1142. # time.sleep(0.1)
  1143. # board.pci.write(board_id, 'ff0', hex_mask='ff0') # TODO: This writes t/h 3/4 but enable_transfer etc do not
  1144. # This seems to sometimes lead to segfaults of python it self. An Idea to prevent this
  1145. # is to use copy.deepcopy in __init__. But there is no reason to think that that causes the problem. In fact
  1146. # I don't have an idea why it crashes.
  1147. # A possible reason could the os.rename be (or even the board.safe_call as that saves data to the disk) But I think
  1148. # this is rather unlikely
  1149. # ~~NOTE~~: the thread of calibration also triggered segfaults sometimes. But this seems to be miraculously solved.
  1150. # Something that is likely to cause the problem is the log.debug in board.safe_call
  1151. # Logging (using the logging module) is directly connected to the main thread and could cause problems
  1152. class thread_wait_on_signal(QtCore.QObject):
  1153. '''Class to run the wait on signal functionality in a thread'''
  1154. countUpdate = QtCore.pyqtSignal(int)
  1155. stopSignal = QtCore.pyqtSignal()
  1156. finished = QtCore.pyqtSignal()
  1157. liveplot = QtCore.pyqtSignal(int, str) # This has to be changed if board_id is no integer
  1158. def __init__(self):
  1159. super(thread_wait_on_signal, self).__init__()
  1160. self.noa = None
  1161. self.path = None
  1162. self.timeout = None
  1163. self._quit = False
  1164. def init(self, num_of_acquisitions, path, timeout):
  1165. '''initialise a new run'''
  1166. self.noa = num_of_acquisitions
  1167. self.path = path
  1168. self.timeout = timeout
  1169. self._quit = False
  1170. # Elements.setEnabled('acquireTrigger_{}'.format(board_id), False) # exclude=Elements.getElements('wait_on_trigger_{}'.format(board_id)))
  1171. def wait_rw_simul(self):
  1172. '''Wait simultaniously (with the pci command) for a trigger signal'''
  1173. board.pci.write(board_id, 'ff0', hex_mask='ff0') # TODO: This writes t/h 3/4 but enable_transfer etc do not
  1174. for num_of_acq in xrange(self.noa):
  1175. # def step():
  1176. filename = self.path +'/{:0.3f}.out'.format(time.time())
  1177. board.pci.read_data_to_file(board_id, filename=filename, timeout=(self.timeout*1000000))
  1178. # rename with correct timestamp - last modified time
  1179. self.countUpdate.emit(num_of_acq + 1)
  1180. if self._quit:
  1181. break
  1182. # file operations
  1183. if not os.path.isfile(filename):
  1184. error(0x001, "No File Created")
  1185. continue
  1186. newfile = '{path}/trigger_{num:05}_{htime}_{unixtime}.out'.format(
  1187. num=num_of_acq,
  1188. htime=dt.fromtimestamp(os.path.getmtime(filename)).strftime('%Y-%m-%dT%Hh%Mm%Ss%f'),
  1189. unixtime=int(os.path.getmtime(filename)),
  1190. path=self.path
  1191. )
  1192. os.rename(filename, newfile)
  1193. if os.path.getsize(newfile) > 0:
  1194. self.liveplot.emit(board_id, newfile)
  1195. else:
  1196. logging.info("Acquired 0b, possible trigger timeout.")
  1197. self.finished.emit()
  1198. def wait_rw_seq(self):
  1199. '''Wait sequentially (in the gui) for a trigger signal'''
  1200. for num_of_acq in xrange(self.noa):
  1201. board.pci.write(board_id, '00bf0', hex_mask='CF0') # enable readout
  1202. pre_acq_num = board.pci.read(board_id, 1, '9034')[0]
  1203. time_a = time.time()
  1204. timeout = False
  1205. while pre_acq_num == board.pci.read(board_id, 1, '9034')[0]:
  1206. if time.time() - time_a > self.timeout:
  1207. timeout = True
  1208. break
  1209. if self._quit:
  1210. self.finished.emit()
  1211. return
  1212. if not timeout:
  1213. board.pci.write(board_id, '000f0', hex_mask='8F0') # disable readout
  1214. board.pci.write(board_id, '007f0', hex_mask='CF0') # enable transfer
  1215. filename = self.path +'/{:0.3f}.out'.format(time.time())
  1216. board.pci.read_data_to_file(board_id, filename=filename, timeout=(self.timeout*1000000))
  1217. # board.pci.write(board_id, '000f0', hex_mask='4F0') # disable transfer
  1218. self.countUpdate.emit(copy.deepcopy(num_of_acq+1))
  1219. if self._quit:
  1220. break
  1221. if not os.path.isfile(filename):
  1222. error(0x001, "No File Created")
  1223. continue
  1224. newfile = '{path}/trigger_{num:05}_{htime}_{unixtime}.out'.format(
  1225. num=num_of_acq,
  1226. htime=dt.fromtimestamp(os.path.getmtime(filename)).strftime('%Y-%m-%dT%Hh%Mm%Ss%f'),
  1227. unixtime=int(os.path.getmtime(filename)),
  1228. path=self.path
  1229. )
  1230. os.rename(filename, newfile)
  1231. self.liveplot.emit(board_id, newfile)
  1232. else:
  1233. logging.info("Trigger timeout.")
  1234. self.finished.emit()
  1235. def quit(self):
  1236. '''quit this thread'''
  1237. self._quit = True
  1238. def __del__(self):
  1239. print 'quite'
  1240. board.pci.write(board_id, '0', '9024')
  1241. time.sleep(0.1)
  1242. board.pci.write(board_id, '0', '902C')
  1243. time.sleep(0.1)
  1244. board.pci.write(board_id, '3f0', hex_mask='ff0') # TODO: This writes t/h 3/4 but enable_transfer etc do not
  1245. def finished():
  1246. '''Handle the end of the thread'''
  1247. board.pci.write(board_id, '0', '9024')
  1248. time.sleep(0.1)
  1249. board.pci.write(board_id, '0', '902C')
  1250. time.sleep(0.1)
  1251. board.pci.write(board_id, '3f0', hex_mask='ff0') # TODO: This writes t/h 3/4 but enable_transfer etc do not
  1252. thread.stop()
  1253. board.get_board_status(board_id).wait = False
  1254. storage.get_board_specific_storage(board_id).trigger_progressbar.remove(0)
  1255. log(board_id=board_id, additional="Stop wait on trigger")
  1256. Elements.setEnabled('acquire_{}'.format(board_id), True)
  1257. callbacks.callback('acquisition_stopped', board_id)
  1258. # for elem in Elements.getElements("acquire_{}".format(board_id)):
  1259. # if isinstance(elem, QtGui.QShortcut):
  1260. # continue
  1261. # elem.setIcon(QtGui.QIcon(config.install_path + config.startIcon))
  1262. # elem.setText(tr("Button", "Start Acquisition"))
  1263. # elem.setEnabled(True)
  1264. return
  1265. # twt = thread_wait_on_signal(num_of_acquisitions, storage.storage.save_location + '/' + storage.storage.subdirname,
  1266. # timeout)
  1267. if not thread.is_registered():
  1268. twt = thread_wait_on_signal()
  1269. thread.register(twt)
  1270. else:
  1271. thread.disconnect('countUpdate', 'finished', 'liveplot')
  1272. thread.init(num_of_acquisitions, storage.storage.save_location + '/' + storage.storage.subdirname, timeout)
  1273. # reconnect signals to make sure the correct versions of methods are called
  1274. thread.connect('countUpdate', storage.get_board_specific_storage(board_id).trigger_progressbar.setValue)
  1275. thread.connect('finished', finished)
  1276. thread.connect('liveplot', _bif_read_and_update_data_from_file)
  1277. if method == 1:
  1278. thread.start('wait_rw_simul')
  1279. elif method == 2:
  1280. thread.start('wait_rw_seq')
  1281. else:
  1282. raise ValueError("Wrong method")