board_config.py 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960
  1. """
  2. Configuration for each board
  3. """
  4. import os
  5. import sys
  6. import traceback
  7. if sys.version_info[:3] < (3,0):
  8. import ConfigParser as configparser
  9. else:
  10. import configparser
  11. import numpy as np
  12. import logging
  13. from PyQt4 import QtGui, QtCore
  14. from time import sleep
  15. from .communication import *
  16. from .... import config as kcg_config
  17. class BoardConfiguration(QtGui.QWidget):
  18. """
  19. The Main configuration class for boards.
  20. """
  21. callback_signal = QtCore.pyqtSignal(str, list)
  22. def __init__(self, identifier, config_file=None):
  23. from . import sequences
  24. super(BoardConfiguration, self).__init__()
  25. self.callback_signal.connect(self._notify_observers_receiver)
  26. self.identifier = identifier
  27. self._config = {}
  28. self._observers = {}
  29. self._observers_for_all = []
  30. self._observers_write = {}
  31. self._set_defaults()
  32. self._get_board_version()
  33. if self._config['board_version'] > 10:
  34. logging.critical('Unknown Board Version - gui not working! - restart with active board')
  35. print('Unknown Board Version - gui not working! - restart with active board')
  36. else:
  37. logging.info('Detected Board Version: {}'.format(self._config["board_version"]))
  38. print('Detected Board Version: {}'.format(self._config["board_version"]))
  39. self._sequences = sequences.read_sequence(self._config["board_version"])
  40. self.set_default_observers()
  41. if self.is_KAPTURE2():
  42. self.update('bunches_per_turn', kcg_config.bunches_per_turn)
  43. else:
  44. self._config['delay_330_factor'] = 150
  45. self._config['delay_330_max'] = 15
  46. self._config['chip_delay'] = [3,3,3,3]
  47. if config_file:
  48. self.load_config(config_file)
  49. #self.notify_all_observers(True)
  50. def _set_defaults(self):
  51. """
  52. Set default values
  53. """
  54. self._config = {
  55. 'board_version' : 7,
  56. 'lastDataSet': None,
  57. 'adc_number': 8,
  58. 'samplingrate': 1,
  59. 'bunches_per_turn': 184,
  60. 'header_byte_size': 32,
  61. 'chip_delay_max': 31,
  62. 'chip_delay' : [0,0,0,0,0,0,0,0],
  63. 'bunch_shift' : [2,2,2,2,2,2,2,2], #Offset by +2 to encode -2 to +2 range
  64. 'chip_delay_factor': 3,
  65. 'delay_330_max': 20, #technical 522 #be aware: changing this makes the Delay Calibration invalid!
  66. 'delay_330_factor': 330,
  67. 'delay_330_th': 0,
  68. 'delay_330_adc': 1,
  69. 'delay_330_fpga': 1,
  70. #-Kapture 2 only--------------------
  71. 'delay_25_max' : 23, #be aware: changing this makes the Delay Calibration invalid!
  72. 'delay_25_factor': 25,
  73. 'delay_25_th': 0,
  74. 'delay_25_adc': 10,
  75. 'delay_25_fpga': 0,
  76. #-Second FMC------------------
  77. 'delay_330_th_2': 0,
  78. 'delay_330_adc_2': 1,
  79. #'delay_330_fpga_2': 0,
  80. 'delay_25_th_2': 4,
  81. 'delay_25_adc_2': 10,
  82. #'delay_25_fpga_2': 0,
  83. 'default_25_th_2': 4,
  84. 'delay_cascade_max': 20,
  85. 'delay_cascade_factor': 330,
  86. 'delay_cascade': 0,
  87. 'delay_cascade_25': 14,
  88. #-Clock Division--------------
  89. 'clk_div': 6,
  90. 'clk_div_th': 6,
  91. 'clk_div_adc': 6,
  92. 'clk_div_fpga': 6,
  93. 'clk_div_cascade': 24,
  94. #-Kapture 1 only-------------------
  95. 'th_to_adc_cycles': 7,
  96. #'adc_1_delay_individual': -1,
  97. #----------------------------------
  98. 'turns_observe': 1000,
  99. 'turns_skip': 0,
  100. 'acquisition_count': 10,
  101. 'turns_wait_time': 15,
  102. 'trigger_skip': 0,
  103. 'trigger_timeout': 12,
  104. 'trigger_method': 1,
  105. 'use_trigger': False,
  106. 'build_spectrograms': False,
  107. 'pilot_bunch': True,
  108. 'header': True if kcg_config.save_header is True else False,
  109. #Kapture 2
  110. 'adc_offset': [0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000],
  111. 'adc_gain': [0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000]
  112. }
  113. def _get_board_version(self):
  114. try:
  115. self._config["board_version"] = int(pci.read(self.identifier, reg='0x9030')[0])
  116. if self._config["board_version"] == 6:
  117. self._config["board_version"] = 5
  118. elif self._config["board_version"] == 7:
  119. self._config["adc_number"] = 8
  120. except Exception as e:
  121. self._config["board_version"] = 0xDEAD
  122. def is_KAPTURE2(self):
  123. return self._config["board_version"] >4
  124. ##########################################################################
  125. # .d8888b.
  126. # d88P Y88b
  127. # Y88b.
  128. # "Y888b. .d88b. .d88888888 888 .d88b. 88888b. .d8888b .d88b.
  129. # "Y88b.d8P Y8bd88" 888888 888d8P Y8b888 "88bd88P" d8P Y8b
  130. # "88888888888888 888888 88888888888888 888888 88888888
  131. # Y88b d88PY8b. Y88b 888Y88b 888Y8b. 888 888Y88b. Y8b.
  132. # "Y8888P" "Y8888 "Y88888 "Y88888 "Y8888 888 888 "Y8888P "Y8888
  133. # 888
  134. # 888
  135. # 888
  136. #
  137. def get_sequence_list(self):
  138. if self._sequences =={}:
  139. return "No Sequences"
  140. return self._sequences["sequence_names"]
  141. def get_init_order(self):
  142. if self._sequences =={}:
  143. return "No Sequences"
  144. return self._sequences["initialization_sequence_order"]
  145. def get_sequence_comment(self, sequence_name):
  146. if self._sequences =={}:
  147. return "No Sequences"
  148. return self._sequences[sequence_name]["Comment"]
  149. def get_sequence_status(self, sequence_name):
  150. if self._sequences =={}:
  151. return "No Sequences"
  152. return self._sequences[sequence_name]["status_val"]
  153. def run_sequence(self, name, progressbar=None):
  154. if self._sequences == {}:
  155. return False
  156. from . import sequences
  157. return sequences.run_sequence(self.identifier, self._sequences[name]["sequence"], progressbar)
  158. ##########################################################################
  159. ##########################################################################
  160. def load_config(self, filename):
  161. """
  162. Load a config from a file
  163. :param filename: the configuration file
  164. :return:
  165. """
  166. if filename:
  167. config = configparser.RawConfigParser()
  168. if not config.read(str(filename)):
  169. return False
  170. for key in list(self._config.keys()):
  171. try:
  172. if type(self._config[key]) == int:
  173. self._config[key] = config.getint('Config', key)
  174. elif type(self._config[key]) == bool:
  175. self._config[key] = config.getboolean('Config', key)
  176. logging.vinfo("Read '%s' for '%s' from '%s'"%(str(self._config[key]), key, str(filename)))
  177. except configparser.NoOptionError as e:
  178. pass
  179. except configparser.NoSectionError as e:
  180. pass
  181. return True
  182. else:
  183. return False
  184. def save_config(self, filename):
  185. """
  186. Save the current configuration to a file
  187. :param filename: the file to write to
  188. """
  189. if filename:
  190. # with open(filename, 'w') as f:
  191. try:
  192. f = open(filename, 'w')
  193. cp = configparser.RawConfigParser()
  194. cp.add_section('Config')
  195. for key in list(self._config.keys()):
  196. cp.set('Config', key, self._config[key])
  197. f.write('#\n'
  198. '# KCG (KAPTURE Control Gui) Configuration file\n'
  199. '#\n'
  200. '# (c) Karlsruhe Institute of Technology, 2015\n'
  201. '# All rights reserved.\n'
  202. '#\n'
  203. '# Applicable Gui Version(s): 1.0 - 1.0.2\n'
  204. '#\n'
  205. '# Saved at: ' + time.asctime() + '\n'
  206. '#\n\n')
  207. cp.write(f)
  208. except (IOError, TypeError):
  209. return False
  210. return True
  211. else:
  212. return False
  213. def get(self, key):
  214. """
  215. Get the configuration value for key
  216. :param key: the key to get the value for
  217. :return: the value of the configuration for key
  218. """
  219. if not key in self._config:
  220. raise NoSuchKeyError(key+" is not registered in BoardConfiguration for board "+str(self.identifier))
  221. return self._config.get(key, None)
  222. def dump(self):
  223. """
  224. Dump all configuration values
  225. :return: all configuration values as list
  226. """
  227. s = ""
  228. for key in list(self._config.keys()):
  229. s += key + ": " + str(self.get(key)) + ", "
  230. return s[:-1]
  231. ##########################################################################
  232. # .d88888b. 888
  233. # d88P" "Y88b888
  234. # 888 888888
  235. # 888 88888888b. .d8888b .d88b. 888d888888 888 .d88b. 888d888.d8888b
  236. # 888 888888 "88b88K d8P Y8b888P" 888 888d8P Y8b888P" 88K
  237. # 888 888888 888"Y8888b.88888888888 Y88 88P88888888888 "Y8888b.
  238. # Y88b. .d88P888 d88P X88Y8b. 888 Y8bd8P Y8b. 888 X88
  239. # "Y88888P" 88888P" 88888P' "Y8888 888 Y88P "Y8888 888 88888P'
  240. def set_default_observers(self):
  241. """
  242. Set observers that are always used
  243. """
  244. #def obsprint(x,y):
  245. # print(x, y)
  246. #self.observe_all(obsprint)
  247. self.observe_write(self._update_header, 'header')
  248. self.observe_write(self._update_pilot_bunch, 'pilot_bunch')
  249. self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x9020'), 'turns_observe')
  250. self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x9028'), 'turns_skip')
  251. if self._config['board_version'] > 4: # everything for KAPTURE 2
  252. self.observe_write(lambda x: pci.write(self.identifier, hex(x-2), '0x90E0'), 'bunches_per_turn')
  253. self.observe_write(self._set_adc_gain, 'adc_gain')
  254. self.observe_write(self._set_adc_offset, 'adc_offset')
  255. #Attention: the th delays are inverted! Means: due to the internal setup by increasing the value the sampling
  256. #would be earlier. This is not intuitive therefore the gui inverts the value by using the delay_max as offset.
  257. #Setup Long delay 330ps. Value needs to be shifted to the left because first bit is used to set halfstep
  258. self.observe_write(lambda x: pci.write(self.identifier, hex((x+5)<<1), '0x9090'), 'delay_330_adc')
  259. self.observe_write(lambda x: pci.write(self.identifier, hex((self._config['delay_330_max']-x+5)<<1), '0x90B0'), 'delay_330_th')
  260. self.observe_write(lambda x: pci.write(self.identifier, hex((x+5)<<1), '0x90C0'), 'delay_330_fpga')
  261. self.observe_write(lambda x: pci.write(self.identifier, hex((x+5)<<1), '0x90D0'), 'delay_cascade')
  262. #Setup short Delay 25ps.
  263. self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x9094'), 'delay_25_adc')
  264. self.observe_write(lambda x: pci.write(self.identifier, hex(self._config['delay_25_max']-x), '0x90B4'), 'delay_25_th')
  265. #self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x90C4'), 'delay_25_fpga')
  266. #Setup Clock Div
  267. self.observe_write(self._set_clk_div_all , 'clk_div') #one to set it all - normaly they should be all the same
  268. self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x9098'), 'clk_div_adc')
  269. self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x90B8'), 'clk_div_th')
  270. self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x90C8'), 'clk_div_fpga')
  271. self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x90D8'), 'clk_div_cascade')
  272. self.observe_write(self._set_chip_delay, 'chip_delay')
  273. self.observe_write(self._set_samplingrate, 'samplingrate')
  274. self.observe_write(self._set_bunch_shift, 'bunch_shift')
  275. if self._config['adc_number'] > 4:
  276. #Setup Long delay 330ps. Value needs to be shifted to the left because first bit is used vor halfstep
  277. self.observe_write(lambda x: pci.write(self.identifier, hex((x+5)<<1), '0x90A0'), 'delay_330_adc_2')
  278. self.observe_write(lambda x: pci.write(self.identifier, hex((self._config['delay_330_max']-x+5)<<1), '0x90A8'), 'delay_330_th_2')
  279. #Setup short Delay 25ps
  280. self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x90A4'), 'delay_25_adc_2')
  281. self.observe_write(lambda x: pci.write(self.identifier, hex(self._config['delay_25_max']-x), '0x90AC'), 'delay_25_th_2')
  282. else:
  283. self.observe_write(self._set_fpga_delay, 'delay_330_fpga')
  284. self.observe_write(self._set_chip_delay, 'chip_delay')
  285. self.observe_write(self._set_th_delay, 'delay_330_th')
  286. self.observe_write(self._set_adc_delay, 'delay_330_adc')
  287. def notify_all_observers(self, write=False):
  288. """
  289. Notify all observers not only the ones that are affected by a change
  290. """
  291. for key, value in list(self._config.items()):
  292. self._notify_observers(key, value, write)
  293. # observers = self._observers.get(key, None)
  294. # if observers:
  295. # for (who, callback) in observers:
  296. # callback(self.get(key))
  297. def update(self, key, value, entry=None, write=True):
  298. """
  299. Update the value for key in the configuration
  300. :param key: the key to update
  301. :param value: the value to set the configuration for key to
  302. :param entry: if key is array to select the array index.
  303. """
  304. if entry is not None:
  305. self._config[key][entry] = value
  306. else:
  307. self._config[key] = value
  308. self._notify_observers(key, self._config[key], write)
  309. def updateSilent(self, key, value, entry=None):
  310. """
  311. Update the configuration without notifying observers
  312. :param key: the key to updae
  313. :param value: the value to set the configuration of key to
  314. :param entry: if key is array to select the array index.
  315. """
  316. if entry is not None:
  317. self._config[key][entry] = value
  318. else:
  319. self._config[key] = value
  320. def observe(self, who, callback, key):
  321. """
  322. Register an observer. (A callback that is called when the according configuration value changes)
  323. :param who: who is observing
  324. :param callback: the callback to call on change of the configuration value
  325. :param key: the key to observe
  326. """
  327. if key not in list(self._config.keys()):
  328. raise ObserverError(str("Key '%s' is unknown." % key))
  329. if self._observers.get(key, None) is None:
  330. self._observers[key] = []
  331. self._observers[key].append([who, callback])
  332. def observe_all(self, callback):
  333. """
  334. Register a observer that is called when any key changes
  335. :param callback: the callback to register
  336. """
  337. if callback not in self._observers_for_all:
  338. self._observers_for_all.append(callback)
  339. else:
  340. raise ObserverError("Observer already registered")
  341. def observe_write(self, callback, key):
  342. """
  343. Register an observer that writes the value for Key on the Board
  344. :param callback: the callback to call on change of the configuration value
  345. :param key: the key to observe
  346. """
  347. if key not in list(self._config.keys()):
  348. raise ObserverError(str("Key '%s' is unknown." % key))
  349. if self._observers_write.get(key, None) is None:
  350. self._observers_write[key] = []
  351. self._observers_write[key].append(callback)
  352. def unobserve(self, who, key=None):
  353. """
  354. Remove an observer
  355. :param who: the observing entity
  356. :param key: the key to remove it from
  357. """
  358. if key is not None:
  359. observers = np.array(self._observers.get(key, None))
  360. if observers is None:
  361. return
  362. if who not in observers[:, 0]:
  363. return
  364. for i, _obs in enumerate(self._observers[key]):
  365. if _obs[0] is who:
  366. del self._observers[key][i]
  367. if not self._observers[key]:
  368. del self._observers[key]
  369. return
  370. for _key in list(self._observers.keys()):
  371. for i, _obs in enumerate(self._observers[_key]):
  372. if _obs[0] is who:
  373. del self._observers[_key][i]
  374. if not self._observers[_key]:
  375. del self._observers[_key]
  376. def unobserve_all_observer(self, callback):
  377. """
  378. Unobserve an observer that observes all keys.
  379. :param callback: the callback to unobserve
  380. """
  381. if callback in self._observers_for_all:
  382. del self._observers_for_all[self._observers_for_all.index(callback)]
  383. def _notify_observers_receiver(self, key, args):
  384. """
  385. The pyqt signal slot for notifications of observers
  386. :param key: the key that changed
  387. :param value: the new value
  388. """
  389. observers = self._observers.get(str(key), None)
  390. value = args[0]
  391. write = args[1]
  392. if observers is not None:
  393. for (who, callback) in observers:
  394. try:
  395. callback(value)
  396. except Exception as e:
  397. log.error('Observer Callback error: {}'.format(e))
  398. print(traceback.format_exc())
  399. for cb in self._observers_for_all:
  400. try:
  401. cb(key, value)
  402. except:
  403. pass
  404. if write:
  405. observers = self._observers_write.get(str(key), None)
  406. if observers is not None:
  407. for callback in observers:
  408. try:
  409. #log.debug('write ' + key , args)
  410. callback(value)
  411. except Exception as e:
  412. log.error('Observer Callback error: {}'.format(e))
  413. print(traceback.format_exc())
  414. time.sleep(0.025)
  415. def _notify_observers(self, key, value, write=True):
  416. """
  417. Notify observers. This emits a pyqt signal to make it thread save
  418. :param key: the key that changed
  419. :param value: the new value
  420. """
  421. #print("_notify_observers", key, value, write)
  422. self.callback_signal.emit(key, [value, write])
  423. def make_uint(self, value, maximum, name=None):
  424. """
  425. Convert a value to an uint
  426. :param value: the value
  427. :param maximum: the maximum of the returned value
  428. :param name: the name of this value
  429. :return: the converted value
  430. """
  431. if value is None:
  432. raise ValueError(str("%s Value is invalid (None)" % name))
  433. val = None
  434. try:
  435. val = int(value)
  436. except ValueError:
  437. raise ValueError(str("%s Value is not a valid number" % name))
  438. if maximum is not None:
  439. if val > maximum:
  440. raise ValueError(str("%s Value is too large (>%i)" % (name, maximum)))
  441. if val < 0:
  442. raise ValueError(str("%s Values below 0 are not allowed" % name))
  443. return val
  444. def _set_clk_div_all(self, value):
  445. self.update('clk_div_adc', value)
  446. self.update('clk_div_th', value)
  447. self.update('clk_div_fpga', value)
  448. self.update('clk_div_cascade', value)
  449. def _set_chip_delay(self, values):
  450. """
  451. Set the chip_delays on the board
  452. :param values: the value to set the delays to
  453. """
  454. _values = []
  455. for value in values[:4]:
  456. _values.append(self.make_uint(value, self.get('chip_delay_max'), 'ADC_Value'))
  457. #print("ADC1: ", values, _values)
  458. reg_value = ''
  459. mask = ''
  460. # Chip Delays are stored as 'ADC_4 ADC_3 ADC_2 ADC_1' in the register.
  461. # Therefore, we need to traverse the factors array in reverse order
  462. for value in _values: #reversed(_values): # not for Kapture 2
  463. if value is not None:
  464. reg_value += '{0:02x}'.format(value)
  465. mask += 'ff'
  466. else:
  467. reg_value += '00'
  468. mask += '00'
  469. if self._config['adc_number'] > 4:
  470. pci.write(self.identifier, reg_value, '0x9084', hex_mask=mask)
  471. else:
  472. pci.write(self.identifier, reg_value, '0x9080', hex_mask=mask)
  473. s = "Setting ADC Delays:"
  474. for (adc, value) in enumerate(_values):
  475. s += ' ADC_%i Fine Delay: %i,' % (adc, value)
  476. s = s[:-1] # cut away the last dangling ','
  477. logging.vinfo(s)
  478. if self._config['adc_number'] > 4:
  479. _values = []
  480. for value in values[4:]:
  481. _values.append(self.make_uint(value, self.get('chip_delay_max'), 'ADC_Value'))
  482. #print("ADC 2", values, _values)
  483. reg_value = ''
  484. mask = ''
  485. # Chip Delays are stored as 'ADC_4 ADC_3 ADC_2 ADC_1' in the register.
  486. # Therefore, we need to traverse the factors array in reverse order
  487. for value in _values: #reversed(_values): # not for Kapture 2
  488. if value is not None:
  489. reg_value += '{0:02x}'.format(value)
  490. mask += 'ff'
  491. else:
  492. reg_value += '00'
  493. mask += '00'
  494. pci.write(self.identifier, reg_value, '0x9080', hex_mask=mask)
  495. s = "Setting ADC Delays:"
  496. for (adc, value) in enumerate(_values):
  497. s += ' ADC_%i Fine Delay: %i,' % (adc+4, value)
  498. s = s[:-1] # cut away the last dangling ','
  499. logging.vinfo(s)
  500. def _set_bunch_shift(self, values):
  501. #print("Setting bunch shifts: ", values)
  502. #Banks are flipped!
  503. #0x9320: 5,6,7,8
  504. #0x9330: 1,2,3,4
  505. bank1 = values[4:8]
  506. bank2 = values[0:4]
  507. adcs = bank1 + bank2
  508. base_reg = 0x9320
  509. for i, val in enumerate(adcs):
  510. reg = hex(base_reg+(i*4))
  511. set = "0x{0:08x}".format(val)
  512. logging.vinfo("Setting %s to %s"%(reg,set))
  513. pci.write(self.identifier, set, reg)
  514. def _update_header(self, state):
  515. """
  516. Set the flag to write Header to files when acquiring.
  517. :param state: True to enabling header and False to disable
  518. :return: -
  519. """
  520. try:
  521. control = pci.read(self.identifier, 1, '0x9040')[0]
  522. control_bits = '{0:032b}'.format(int(control, 16))
  523. if state:
  524. control_bits = control_bits[:3] + '1' + control_bits[4:]
  525. else:
  526. control_bits = control_bits[:3] + '0' + control_bits[4:]
  527. dec_val_bits = int(control_bits, 2)
  528. pci.write(self.identifier, hex(dec_val_bits), '0x9040')
  529. except BoardError as e:
  530. reason = str(e) if str(e) != '' else "Unknown"
  531. logging.error("Error in Board Communication, was unable to write value to board "+reason)
  532. def _update_pilot_bunch(self, state):
  533. """
  534. Set the flag to write Header to files when acquiring.
  535. :param state: True to enabling header and False to disable
  536. :return: -
  537. """
  538. try:
  539. control = pci.read(self.identifier, 1, '0x9040')[0]
  540. control_bits = '{0:032b}'.format(int(control, 16))
  541. if state:
  542. control_bits = control_bits[:1] + '1' + control_bits[2:]
  543. else:
  544. control_bits = control_bits[:1] + '0' + control_bits[2:]
  545. dec_val_bits = int(control_bits, 2)
  546. pci.write(self.identifier, hex(dec_val_bits), '0x9040')
  547. except BoardError as e:
  548. reason = str(e) if str(e) != '' else "Unknown"
  549. logging.error("Error in Board Communication, was unable to write value to board "+reason)
  550. def _set_adc_gain(self, x):
  551. #Bits 1 and 2 of register 9044 control which SPI channels to select.
  552. #SPI_1 will route to ADC-Element 1 (Channel 1 and 2), and SPI_2
  553. #will route to ADC-Element 2 (Channel 3 and 4).
  554. #Bits 16 and 17 of register 9044 control which FMCs to route the
  555. #SPI commands to. If both bits are 1, then the SPI commands get routed
  556. #to both FMCs at the same time.
  557. #Bit 16 is FMC1 and Bit 17 is FMC2
  558. #pci.read response is returned as a list. Since we expect only one
  559. #value, we access index [0]
  560. initial_mux_config = pci.read(self.identifier, reg='9044')[0]
  561. #Note:
  562. #Due to the way the hardware is internally structured, things are
  563. #a bit confusing as to which value is supposed to go where ...
  564. #If in the future, this addressing and ordering gets cleaned,
  565. #you should be able to safely remove the following reodering
  566. if len(x) > 4 and len(x) < 9:
  567. idx = [4,5,6,7,2,3,0,1]
  568. x = x[idx]
  569. else:
  570. a = np.array([0,0,0,0])
  571. idx = [2,3,0,1]
  572. x = x[idx]
  573. x = np.concatenate((a,x), axis=None)
  574. #Select SPI1 and FMC1
  575. pci.write(self.identifier, '0x10002', '0x9044')
  576. pci.write(self.identifier, '46{:04x}'.format(int(x[0])), '0x9064')
  577. pci.write(self.identifier, '56{:04x}'.format(int(x[1])), '0x9064')
  578. #Select SPI2 and FMC1
  579. pci.write(self.identifier, '0x10004', '0x9044')
  580. pci.write(self.identifier, '46{:04x}'.format(int(x[2])), '0x9064')
  581. pci.write(self.identifier, '56{:04x}'.format(int(x[3])), '0x9064')
  582. #Select SPI0 and FMC2
  583. pci.write(self.identifier, '0x20002', '0x9044')
  584. pci.write(self.identifier, '46{:04x}'.format(int(x[4])), '0x9064')
  585. pci.write(self.identifier, '56{:04x}'.format(int(x[5])), '0x9064')
  586. #Select SPI2 and FMC2
  587. pci.write(self.identifier, '0x20004', '0x9044')
  588. pci.write(self.identifier, '46{:04x}'.format(int(x[6])), '0x9064')
  589. pci.write(self.identifier, '56{:04x}'.format(int(x[7])), '0x9064')
  590. if len(x) > 8:
  591. logging.vinfo("Gain update not defined for more than 8 adc")
  592. #Restore the initial MUX Configuration
  593. pci.write(self.identifier, initial_mux_config, '0x9044')
  594. def _set_adc_offset(self, x):
  595. #Bits 1 and 2 of register 9044 control which SPI channels to select.
  596. #SPI_1 will route to ADC-Element 1 (Channel 1 and 2), and SPI_2
  597. #will route to ADC-Element 2 (Channel 3 and 4).
  598. #Bits 16 and 17 of register 9044 control which FMCs to route the
  599. #SPI commands to. If both bits are 1, then the SPI commands get routed
  600. #to both FMCs at the same time.
  601. #pci.read response is returned as a list. Since we expect only one
  602. #value, we access index [0]
  603. initial_mux_config = pci.read(self.identifier, reg='9044', decimal=True)[0]
  604. #Note:
  605. #Due to the way the hardware is internally structured, things are
  606. #a bit confusing as to which value is supposed to go where ...
  607. #If in the future, this addressing and ordering gets cleaned,
  608. #you should be able to safely remove the following reodering
  609. if len(x) > 4 and len(x) < 9:
  610. idx = [4,5,6,7,2,3,0,1]
  611. x = x[idx]
  612. else:
  613. a = np.array([0,0,0,0])
  614. idx = [2,3,0,1]
  615. x = x[idx]
  616. x = np.concatenate((a,x), axis=None)
  617. #Select SPI1 and FMC1
  618. pci.write(self.identifier, '0x10002', '0x9044')
  619. pci.write(self.identifier, '44{:04x}'.format(int(x[0])), '0x9064')
  620. pci.write(self.identifier, '54{:04x}'.format(int(x[1])), '0x9064')
  621. #Select SPI2 and FMC1
  622. pci.write(self.identifier, '0x10004', '0x9044')
  623. pci.write(self.identifier, '44{:04x}'.format(int(x[2])), '0x9064')
  624. pci.write(self.identifier, '54{:04x}'.format(int(x[3])), '0x9064')
  625. #Select SPI1 and FMC2
  626. pci.write(self.identifier, '0x20002', '0x9044')
  627. pci.write(self.identifier, '44{:04x}'.format(int(x[4])), '0x9064')
  628. pci.write(self.identifier, '54{:04x}'.format(int(x[5])), '0x9064')
  629. #Select SPI2 and FMC2
  630. pci.write(self.identifier, '0x20004', '0x9044')
  631. pci.write(self.identifier, '44{:04x}'.format(int(x[6])), '0x9064')
  632. pci.write(self.identifier, '54{:04x}'.format(int(x[7])), '0x9064')
  633. if len(x) > 8:
  634. logging.vinfo("Offset update not defined for more than 8 adc")
  635. #Restore the initial MUX Configuration
  636. pci.write(self.identifier, hex(initial_mux_config), '0x9044')
  637. def _set_samplingrate(self, rate):
  638. return
  639. if rate == 1:
  640. #500 MHz
  641. self.update('delay_25_adc', 10)
  642. self.update('delay_330_adc', 1)
  643. self.update('delay_25_adc_2', 10)
  644. self.update('delay_330_adc_2', 1)
  645. elif rate == 2:
  646. #1 GHz
  647. self.update('delay_25_adc', 10)
  648. self.update('delay_330_adc', 0)
  649. self.update('delay_25_adc_2', 10)
  650. self.update('delay_330_adc_2', 0)
  651. def set_startup(self):
  652. #print('board_config setting startup')
  653. #self.update('delay_330_th', 0)
  654. #sleep(0.1)
  655. #self.update('delay_25_th', 0)
  656. #sleep(0.1)
  657. self.update('delay_330_th_2', 0)
  658. sleep(0.1)
  659. self.update('delay_25_th_2', 3)
  660. sleep(0.1)
  661. self.update('delay_25_th_2', 4)
  662. sleep(0.1)
  663. self.update('chip_delay', [0,0,0,0, 0,0,0,0])
  664. sleep(0.1)
  665. #Bunch Shifts are offset by +2 to encode -2 to +2 as 0x0 to 0x4 in hardware
  666. self.update('bunch_shift', [2,2,2,2, 2,2,2,2])
  667. sleep(0.1)
  668. self.update('adc_gain', [0,0,0,0, 0,0,0,0])
  669. sleep(0.1)
  670. self.update('header', 1)
  671. sleep(0.1)
  672. self.update('pilot_bunch', 1)
  673. logging.vinfo('Startup Config Set')
  674. def read_from_board(self):
  675. """
  676. Read values from board and update them in the configuration (Mainly used for skip init functionality)
  677. """
  678. try:
  679. #settings = ['chip_1_delay','chip_2_delay','chip_3_delay','chip_4_delay']
  680. # --[ read fine/chip delays ]
  681. adc_number = self._config["adc_number"]
  682. val = pci.read(self.identifier, reg='9080')[0]
  683. if adc_number > 4:
  684. val = val + pci.read(self.identifier, reg='9084')[0]
  685. tmp = np.zeros(adc_number)
  686. for i in range(adc_number):
  687. selector = [3,2,1,0,7,6,5,4]
  688. tmp[selector[i]] = int(val[(adc_number-1-i)*2:(adc_number-i)*2], 16)
  689. self.update('chip_delay', tmp , write=False)
  690. # --[ read bunch shifts ] --
  691. #Banks are flipped!
  692. #0x9320: 5,6,7,8
  693. #0x9330: 1,2,3,4
  694. bunch_shifts = pci.read(self.identifier, reg='9330', amount=4, decimal=True)
  695. if adc_number > 4:
  696. bunch_shifts = bunch_shifts + pci.read(self.identifier, reg='9320', amount=4, decimal=True)
  697. self.update('bunch_shift', bunch_shifts, write=False)
  698. # --[ read and set th delay ]--
  699. val = pci.read(self.identifier, reg='90B0')[0]
  700. self.update('delay_330_th', self._config['delay_330_max'] - ((int(val, 16)>>1)-5), write=False)
  701. val = pci.read(self.identifier, reg='90B4')[0]
  702. self.update('delay_25_th', self._config['delay_25_max'] - int(val, 16), write=False)
  703. val = pci.read(self.identifier, reg='90B8')[0]
  704. self.update('clk_div_th', int(val, 16), write=False)
  705. # --[ read and set adc delay ]--
  706. val = pci.read(self.identifier, reg='9090')[0]
  707. self.update('delay_330_adc', (int(val, 16)>>1)-5, write=False)
  708. val = pci.read(self.identifier, reg='9094')[0]
  709. self.update('delay_25_adc', int(val, 16), write=False)
  710. val = pci.read(self.identifier, reg='9098')[0]
  711. self.update('clk_div_adc', int(val, 16), write=False)
  712. # --[ read and set fpga delay ]--
  713. val = pci.read(self.identifier, reg='90C0')[0]
  714. self.update('delay_330_fpga', (int(val, 16)>>1)-5, write=False)
  715. #val = pci.read(self.identifier, reg='90C4')[0]
  716. #self.update('delay_25_fpga', int(val, 16), write=False)
  717. val = pci.read(self.identifier, reg='90C8')[0]
  718. self.update('clk_div_fpga', int(val, 16), write=False)
  719. # --[ read and set number of turns to acquire ]--
  720. val = pci.read(self.identifier, reg='9020')[0]
  721. self.update('turns_observe', int(val, 16), write=False)
  722. # --[ read and set number of turns to skip ]--
  723. val = pci.read(self.identifier, reg='9028')[0]
  724. self.update('turns_skip', int(val, 16), write=False)
  725. # --[ read FMC 2 ] --
  726. # --[ FMC2 read and set th delay ]--
  727. val = pci.read(self.identifier, reg='90A8')[0]
  728. self.update('delay_330_th_2', ((int(val, 16)>>1)-5), write=False)
  729. val = pci.read(self.identifier, reg='90AC')[0]
  730. self.update('delay_25_th_2', int(val, 16), write=False)
  731. # --[ FCM 2 read and set adc delay ]--
  732. val = pci.read(self.identifier, reg='90A0')[0]
  733. self.update('delay_330_adc_2', ((int(val, 16)>>1)-5), write=False)
  734. val = pci.read(self.identifier, reg='90A4')[0]
  735. self.update('delay_25_adc_2', int(val, 16), write=False)
  736. # --[ read and update header ]--
  737. control = pci.read(self.identifier, 1, '0x9040')[0]
  738. control_bits = '{0:032b}'.format(int(control, 16))
  739. if control_bits[3] == '1':
  740. self.update('header', True, write=False)
  741. else:
  742. self.update('header', False, write=False)
  743. except IndexError:
  744. error(0x002, "Could not Read data from Board. Pci returned wrong amount of data.")
  745. # 888 d8P d8888 8888888b. 88888888888 888 888 8888888b. 8888888888 d888
  746. # 888 d8P d88888 888 Y88b 888 888 888 888 Y88b 888 d8888
  747. # 888 d8P d88P888 888 888 888 888 888 888 888 888 888
  748. # 888d88K d88P 888 888 d88P 888 888 888 888 d88P 8888888 888
  749. # 8888888b d88P 888 8888888P" 888 888 888 8888888P" 888 888
  750. # 888 Y88b d88P 888 888 888 888 888 888 T88b 888 888888 888
  751. # 888 Y88b d8888888888 888 888 Y88b. .d88P 888 T88b 888 888
  752. # 888 Y88b d88P 888 888 888 "Y88888P" 888 T88b 8888888888 8888888
  753. #
  754. #
  755. #
  756. def _set_fpga_delay(self, value):
  757. """
  758. observer function to set the fpga_delays on the board
  759. :param value: the value to set the delays to
  760. """
  761. time_factor = self.make_uint(value, self.get('delay_330_max'), 'FPGA_Delay')
  762. reg_value = "0x000501" + '{0:01x}'.format(time_factor) + "0"
  763. pci.write(self.identifier, reg_value, '0x9060')
  764. logging.vinfo("Set FPGA clock delay %i * %i --> %i picoseconds" % (time_factor, self.get('delay_330_factor'), time_factor*self.get('delay_330_factor')))
  765. #self.update('fpga_delay', value)
  766. def _set_th_delay(self, value):
  767. """
  768. Set the track and hold delay on the board
  769. :param value: the value to set the delay to
  770. """
  771. time_factor = self.make_uint(value, self.get('delay_330_max'), 'TH_Delay')
  772. reg_value = "0x000501" + '{0:01x}'.format(time_factor) + "3"
  773. pci.write(self.identifier, reg_value, '0x9060')
  774. logging.vinfo("Set T/H Signal delay %i * %i --> %i picoseconds" % (time_factor, self.get('delay_330_factor'), time_factor*self.get('delay_330_factor')))
  775. self.update('delay_330_adc', time_factor)
  776. def _set_adc_delay(self, value):
  777. """
  778. Set the adc delay for the given adc on the board
  779. :param value: the value to set the delay to
  780. """
  781. def write_delay(value, channel):
  782. '''write the delays to the board'''
  783. value = self.make_uint(value, self.get('delay_330_max'), 'ADC Delay')
  784. cmd = '00501' + '%01x' % value + str(channel+4)
  785. pci.write(self.identifier, cmd, reg='0x9060')
  786. time.sleep(0.005)
  787. delay = value + self.get('th_to_adc_cycles')
  788. if delay > self.get('delay_330_max'):
  789. delay -= self.get('delay_330_max') + 1
  790. if self._config['adc_number'] == 4:
  791. for adc in range(self._config['adc_number']):
  792. write_delay(delay, adc)
  793. s = "Setting ADC_%i delay %i * %i --> %i picoseconds" % ((adc+1), delay, self.get('delay_330_factor'), delay*self.get('delay_330_factor'))
  794. logging.vinfo(s)
  795. else:
  796. logging.vinfo("adc_delay update not defined for more than 4 adc")