board_config.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. """
  2. Configuration for each board
  3. """
  4. import ConfigParser
  5. import numpy as np
  6. import logging
  7. from PyQt4 import QtGui, QtCore
  8. from communication import *
  9. from .... import config as kcg_config
  10. class BoardConfiguration(QtGui.QWidget):
  11. """
  12. The Main configuration class for boards.
  13. """
  14. callback_signal = QtCore.pyqtSignal(str, list)
  15. def __init__(self, identifier, config_file=None):
  16. super(BoardConfiguration, self).__init__()
  17. self.callback_signal.connect(self._notify_observers_receiver)
  18. self.identifier = identifier
  19. self._config = {}
  20. self._observers = {}
  21. self._observers_for_all = []
  22. self._set_defaults()
  23. self.set_default_observers()
  24. if config_file:
  25. self.load_config(config_file)
  26. def _set_defaults(self):
  27. """
  28. Set default values
  29. """
  30. self._config ={
  31. 'fpga_delay_max': 15,
  32. 'fpga_delay': 0,
  33. 'fpga_delay_factor': 150,
  34. 'chip_delay_max': 31,
  35. 'chip_1_delay': 4,
  36. 'chip_2_delay': 4,
  37. 'chip_3_delay': 4,
  38. 'chip_4_delay': 4,
  39. 'chip_delay_factor': 3,
  40. 'th_delay_max': 15,
  41. 'th_delay': 3,
  42. 'th_delay_factor': 150,
  43. 'adc_delay_max': 15,
  44. 'adc_1_delay': 4,
  45. 'adc_2_delay': 4,
  46. 'adc_3_delay': 4,
  47. 'adc_4_delay': 4,
  48. 'adc_delay_factor': 150,
  49. 'th_to_adc_cycles': 7,
  50. 'adc_1_delay_individual': -1,
  51. 'orbits_observe': 100,
  52. 'orbits_skip': 2,
  53. 'acquisition_count': 10,
  54. 'orbits_wait_time': 15,
  55. 'trigger_skip': 0,
  56. 'trigger_timeout': 12,
  57. 'trigger_method': 1,
  58. 'use_trigger': False,
  59. 'build_spectrograms': False,
  60. 'pilot_bunch': False,
  61. 'header': True if kcg_config.save_header is True else False
  62. }
  63. def set_default_observers(self):
  64. """
  65. Set observers that are always used
  66. """
  67. self.observe(None, self.update_header, 'header')
  68. self.observe(None, lambda x: pci.write(self.identifier, hex(x), '0x9020'), 'orbits_observe')
  69. self.observe(None, lambda x: pci.write(self.identifier, hex(x), '0x9028'), 'orbits_skip')
  70. def notify_all_observers(self):
  71. """
  72. Notify all observers not only the ones that are affected by a change
  73. """
  74. for key, value in self._config.items():
  75. self._notify_observers(key, value)
  76. # observers = self._observers.get(key, None)
  77. # if observers:
  78. # for (who, callback) in observers:
  79. # callback(self.get(key))
  80. def load_config(self, filename):
  81. """
  82. Load a config from a file
  83. :param filename: the configuration file
  84. :return:
  85. """
  86. if filename:
  87. config = ConfigParser.RawConfigParser()
  88. if not config.read(str(filename)):
  89. return False
  90. for key in self._config.keys():
  91. try:
  92. if type(self._config[key]) == int:
  93. self._config[key] = config.getint('Config', key)
  94. elif type(self._config[key]) == bool:
  95. self._config[key] = config.getboolean('Config', key)
  96. logging.vinfo("Read '%s' for '%s' from '%s'"%(str(self._config[key]), key, str(filename)))
  97. except ConfigParser.NoOptionError as e:
  98. pass
  99. except ConfigParser.NoSectionError as e:
  100. pass
  101. return True
  102. else:
  103. return False
  104. def save_config(self, filename):
  105. """
  106. Save the current configuration to a file
  107. :param filename: the file to write to
  108. """
  109. if filename:
  110. # with open(filename, 'w') as f:
  111. try:
  112. f = open(filename, 'w')
  113. cp = ConfigParser.RawConfigParser()
  114. cp.add_section('Config')
  115. for key in self._config.keys():
  116. cp.set('Config', key, self._config[key])
  117. f.write('#\n'
  118. '# KCG (KAPTURE Control Gui) Configuration file\n'
  119. '#\n'
  120. '# (c) Karlsruhe Institute of Technology, 2015\n'
  121. '# All rights reserved.\n'
  122. '#\n'
  123. '# Applicable Gui Version(s): 1.0 - 1.0.2\n'
  124. '#\n'
  125. '# Saved at: ' + time.asctime() + '\n'
  126. '#\n\n')
  127. cp.write(f)
  128. except (IOError, TypeError):
  129. return False
  130. return True
  131. else:
  132. return False
  133. def get(self, key):
  134. """
  135. Get the configuration value for key
  136. :param key: the key to get the value for
  137. :return: the value of the configuration for key
  138. """
  139. if not key in self._config:
  140. raise NoSuchKeyError(key+" is not registered in BoardConfiguration for board "+str(self.identifier))
  141. return self._config.get(key, None)
  142. def dump(self):
  143. """
  144. Dump all configuration values
  145. :return: all configuration values as list
  146. """
  147. s = ""
  148. for key in self._config.keys():
  149. s += key + ": " + str(self.get(key)) + ", "
  150. return s[:-1]
  151. def update(self, key, value):
  152. """
  153. Update the value for key in the configuration
  154. :param key: the key to update
  155. :param value: the value to set the configuration for key to
  156. """
  157. self._config[key] = value
  158. self._notify_observers(key, value)
  159. def updateSilent(self, key, value):
  160. """
  161. Update the configuration without notifying observers
  162. :param key: the key to updae
  163. :param value: the value to set the configuration of key to
  164. """
  165. self._config[key] = value
  166. def observe(self, who, callback, key):
  167. """
  168. Register an observer. (A callback that is called when the according configuration value changes)
  169. :param who: who is observing
  170. :param callback: the callback to call on change of the configuration value
  171. :param key: the key to observe
  172. """
  173. if key not in self._config.keys():
  174. raise ObserverError(str("Key '%s' is unknown." % key))
  175. if self._observers.get(key, None) is None:
  176. self._observers[key] = []
  177. self._observers[key].append([who, callback])
  178. def observe_all(self, callback):
  179. """
  180. Register a observer that is called when any key changes
  181. :param callback: the callback to register
  182. """
  183. if callback not in self._observers_for_all:
  184. self._observers_for_all.append(callback)
  185. else:
  186. raise ObserverError("Observer already registered")
  187. def unobserve(self, who, key=None):
  188. """
  189. Remove an observer
  190. :param who: the observing entity
  191. :param key: the key to remove it from
  192. """
  193. if key is not None:
  194. observers = np.array(self._observers.get(key, None))
  195. if observers is None:
  196. return
  197. if who not in observers[:, 0]:
  198. return
  199. for i, _obs in enumerate(self._observers[key]):
  200. if _obs[0] is who:
  201. del self._observers[key][i]
  202. if not self._observers[key]:
  203. del self._observers[key]
  204. return
  205. for _key in self._observers.keys():
  206. for i, _obs in enumerate(self._observers[_key]):
  207. if _obs[0] is who:
  208. del self._observers[_key][i]
  209. if not self._observers[_key]:
  210. del self._observers[_key]
  211. def unobserve_all_observer(self, callback):
  212. """
  213. Unobserve an observer that observes all keys.
  214. :param callback: the callback to unobserve
  215. """
  216. if callback in self._observers_for_all:
  217. del self._observers_for_all[self._observers_for_all.index(callback)]
  218. def _notify_observers_receiver(self, key, value):
  219. """
  220. The pyqt signal slot for notifications of observers
  221. :param key: the key that changed
  222. :param value: the new value
  223. """
  224. observers = self._observers.get(str(key), None)
  225. value = value[0]
  226. if observers is None:
  227. return
  228. for (who, callback) in observers:
  229. callback(value)
  230. for cb in self._observers_for_all:
  231. cb(key, value)
  232. def _notify_observers(self, key, value):
  233. """
  234. Notify observers. This emits a pyqt signal to make it thread save
  235. :param key: the key that changed
  236. :param value: the new value
  237. """
  238. self.callback_signal.emit(key, [value])
  239. def make_uint(self, value, maximum, name=None):
  240. """
  241. Convert a value to an uint
  242. :param value: the value
  243. :param maximum: the maximum of the returned value
  244. :param name: the name of this value
  245. :return: the converted value
  246. """
  247. if value is None:
  248. raise ValueError(str("%s Value is invalid (None)" % name))
  249. val = None
  250. try:
  251. val = int(value)
  252. except ValueError:
  253. raise ValueError(str("%s Value is not a valid number" % name))
  254. if maximum is not None:
  255. if val > maximum:
  256. raise ValueError(str("%s Value is too large (>%i)" % (name, maximum)))
  257. if val < 0:
  258. raise ValueError(str("%s Values below 0 are not allowed" % name))
  259. return val
  260. def set_fpga_delay(self, value):
  261. """
  262. Set the fpga_delays on the board
  263. :param value: the value to set the delays to
  264. """
  265. time_factor = self.make_uint(value, self.get('fpga_delay_max'), 'FPGA_Delay')
  266. reg_value = "0x000501" + '{0:01x}'.format(time_factor) + "0"
  267. pci.write(self.identifier, reg_value, '0x9060')
  268. logging.vinfo("Set FPGA clock delay %i * %i --> %i picoseconds" % (time_factor, self.get('fpga_delay_factor'), time_factor*self.get('fpga_delay_factor')))
  269. self.update('fpga_delay', value)
  270. def set_chip_delay(self, adcs, values):
  271. """
  272. Set the chip_delays on the board
  273. :param adcs: the adcs to set the delays for
  274. :param values: the value to set the delays to
  275. """
  276. if not adcs or not values:
  277. logging.vinfo("Nothing to do for chip delay.")
  278. return
  279. _adcs = []
  280. for adc in adcs:
  281. _adcs.append(self.make_uint(adc, 3, 'ADC_'))
  282. _values = []
  283. for value in values:
  284. _values.append(self.make_uint(value, self.get('chip_delay_max'), 'ADC_Value'))
  285. a_v = zip(_adcs, _values)
  286. factors = [None, None, None, None]
  287. for (adc, value) in a_v:
  288. factors[adc] = value
  289. reg_value = ''
  290. mask = ''
  291. # Chip Delays are stored as 'ADC_4 ADC_3 ADC_2 ADC_1' in the register.
  292. # Therefore, we need to traverse the factors array in reverse order
  293. for value in reversed(factors):
  294. if value is not None:
  295. reg_value += '{0:02x}'.format(value)
  296. mask += 'ff'
  297. else:
  298. reg_value += '00'
  299. mask += '00'
  300. pci.write(self.identifier, reg_value, '0x9080', hex_mask=mask)
  301. s = "Setting ADC Delays:"
  302. for (adc, value) in a_v:
  303. s += ' ADC_%i Fine Delay: %i,' % (adc, value)
  304. s = s[:-1] # cut away the last dangling ','
  305. logging.vinfo(s)
  306. for (adc, value) in a_v:
  307. s = 'chip_%i_delay'%(adc+1)
  308. self.update(s, value)
  309. def set_th_delay(self, value):
  310. """
  311. Set the track and hold delay on the board
  312. :param value: the value to set the delay to
  313. """
  314. time_factor = self.make_uint(value, self.get('th_delay_max'), 'TH_Delay')
  315. reg_value = "0x000501" + '{0:01x}'.format(time_factor) + "3"
  316. pci.write(self.identifier, reg_value, '0x9060')
  317. logging.vinfo("Set T/H Signal delay %i * %i --> %i picoseconds" % (time_factor, self.get('th_delay_factor'), time_factor*self.get('th_delay_factor')))
  318. self.update('th_delay', value)
  319. def set_adc_delay(self, adc, value):
  320. """
  321. Set the adc delay for the given adc on the board
  322. :param adc: the adc to change the delay for
  323. :param value: the value to set the delay to
  324. """
  325. if adc is None or value is None:
  326. logging.vinfo("Nothing to do for ADC delay.")
  327. return
  328. _adc = self.make_uint(adc, 3, 'ADC Number')
  329. _val = self.make_uint(value, self.get('adc_delay_max'), 'ADC Delay')
  330. reg_value = "0x000501" + '{0:01x}'.format(_val) + "%i" % (_adc+4)
  331. pci.write(self.identifier, reg_value, '0x9060')
  332. s = "Setting ADC_%i delay %i * %i --> %i picoseconds" % ((_adc+1), _val, self.get('adc_delay_factor'), _val*self.get('adc_delay_factor'))
  333. logging.vinfo(s)
  334. adc_s = 'adc_%i_delay'%(_adc+1)
  335. self.update(adc_s, _val)
  336. def set_delay(self, n, ignore_seperate_delay=False):
  337. """
  338. Set delays
  339. :param n: ?
  340. :param ignore_seperate_delay: ignore the setting of a seperate delay for adc 1
  341. """
  342. def write_delay(value, channel):
  343. '''write the delays to the board'''
  344. cmd = '00501' + '%01x' % value + str(channel)
  345. pci.write(self.identifier, cmd, reg='0x9060')
  346. time.sleep(0.005)
  347. logging.vinfo("Setting T/H Delay: " + str(n))
  348. write_delay(n, 3)
  349. self.update('th_delay', n)
  350. delay = n + self.get('th_to_adc_cycles')
  351. if delay > self.get('adc_delay_max'):
  352. delay -= self.get('adc_delay_max') + 1
  353. write_delay(delay, 5)
  354. self.update('adc_2_delay', delay)
  355. write_delay(delay, 6)
  356. self.update('adc_3_delay', delay)
  357. write_delay(delay, 7)
  358. self.update('adc_4_delay', delay)
  359. #ADC 1 might have an individual delay
  360. if self.get('adc_1_delay_individual') > 0:
  361. try:
  362. delay = n + self.make_uint(self.get('adc_1_delay_individual'), 16, 'ADC 1 individual delay')
  363. logging.vinfo("Setting ADC1 individual delay to " + str(delay))
  364. except ValueError:
  365. logging.vinfo(r"'adc_1_delay_individual' not set or inactive. Using default.")
  366. if delay > self.get('adc_delay_max'):
  367. delay -= self.get('adc_delay_max') + 1
  368. write_delay(delay, 4)
  369. self.update('adc_1_delay', delay)
  370. def update_header(self, state):
  371. """
  372. Set the flag to write Header to files when acquiring.
  373. :param state: True to enabling header and False to disable
  374. :return: -
  375. """
  376. try:
  377. control = pci.read(self.identifier, 1, '0x9040')[0]
  378. control_bits = '{0:032b}'.format(int(control, 16))
  379. if state:
  380. control_bits = control_bits[:3] + '1' + control_bits[4:]
  381. else:
  382. control_bits = control_bits[:3] + '0' + control_bits[4:]
  383. dec_val_bits = int(control_bits, 2)
  384. pci.write(self.identifier, hex(dec_val_bits), '0x9040')
  385. except BoardError as e:
  386. reason = str(e) if str(e) != '' else "Unknown"
  387. logging.error("Error in Board Communication, was unable to write value to board "+reason)
  388. def read_from_board(self):
  389. """
  390. Read values from board and update them in the configuration (Mainly used for skip init functionality)
  391. """
  392. try:
  393. settings = ['chip_1_delay','chip_2_delay','chip_3_delay','chip_4_delay']
  394. # --[ read fine/chip delays ]
  395. val = pci.read(self.identifier, reg='9080')[0]
  396. # --[ set chip_1_delay ]--
  397. self.update('chip_1_delay', int(val[6:8], 16))
  398. # --[ set chip_2_delay ]--
  399. self.update('chip_2_delay', int(val[4:6], 16))
  400. # --[ set chip_3_delay ]--
  401. self.update('chip_3_delay', int(val[2:4], 16))
  402. # --[ set chip_4_delay ]--
  403. self.update('chip_4_delay', int(val[0:2], 16))
  404. # --[ read and set th delay ]--
  405. val = pci.read(self.identifier, reg='90a0')[0]
  406. self.update('th_delay', int(val, 16))
  407. # --[ check for seperate adc1 delay ]--
  408. val = pci.read(self.identifier, reg='9088')[0]
  409. if int(val, 16) != self.get('th_delay') + self.get('adc_1_delay_individual'):
  410. self.update('adc_1_delay_individual', int(val, 16)-self.get('th_delay'))
  411. else:
  412. self.update('adc_1_delay_individual', -1)
  413. # --[ read and set number of orbits to acquire ]--
  414. val = pci.read(self.identifier, reg='9020')[0]
  415. self.update('orbits_observe', int(val, 16))
  416. # --[ read and set number of orbits to skip ]--
  417. val = pci.read(self.identifier, reg='9028')[0]
  418. self.update('orbits_skip', int(val, 16))
  419. # --[ read and update header ]--
  420. control = pci.read(self.identifier, 1, '0x9040')[0]
  421. control_bits = '{0:032b}'.format(int(control, 16))
  422. if control_bits[3] == '1':
  423. self.update('header', True)
  424. else:
  425. self.update('header', False)
  426. except IndexError:
  427. error(0x002, "Could not Read data from Board. Pci returned wrong amount of data.")