def advanced_menu(self): """ Show a config dialog for advanced options, ie. gate width, interval for the rate measurement, options for writing pulse file and the write_daq_status option. :returns: None """ # get the actual channels from the DAQ card self.daq.put("DC") # wait explicitly until the channels get loaded self.logger.info("loading channel information...") time.sleep(1) # show dialog dialog = AdvancedDialog(get_setting("gate_width"), get_setting("time_window"), get_setting("write_daq_status")) if dialog.exec_() == 1: # update time window time_window = float(dialog.get_widget_value("time_window")) if time_window < 0.01 or time_window > 10000.: self.logger.warning("Time window too small or too big, " + "resetting to 5 s.") time_window = 5.0 update_setting("time_window", time_window) # update write_daq_status write_daq_status = dialog.get_widget_value("write_daq_status") update_setting("write_daq_status", write_daq_status) # update gate width gate_width = int(dialog.get_widget_value("gate_width")) update_setting("gate_width", gate_width) # transform gate width for daq msg gate_width = bin(gate_width // 10).replace('0b', '').zfill(16) gate_width_03 = format(int(gate_width[0:8], 2), 'x').zfill(2) gate_width_02 = format(int(gate_width[8:16], 2), 'x').zfill(2) # set gate widths self.daq.put("WC 03 %s" % gate_width_03) self.daq.put("WC 02 %s" % gate_width_02) # adjust the update interval self.widget_updater.start(time_window * 1000) self.logger.debug("Writing gate width WC 02 %s WC 03 %s" % (gate_width_02, gate_width_03)) self.logger.debug("Setting time window to %.2f " % time_window) self.logger.debug("Switching write_daq_status option to %s" % write_daq_status) self.daq.put("DC")
def threshold_menu(self): """ Shows thresholds dialog. :returns: None """ # get the actual thresholds from the DAQ card self.daq.put('TL') # wait explicitly until the thresholds get loaded self.logger.info("loading threshold information..") time.sleep(1.5) # get thresholds from settings thresholds = [get_setting("threshold_ch%d" % i, 300) for i in range(4)] # show dialog dialog = ThresholdDialog(thresholds) if dialog.exec_() == 1: commands = [] # update thresholds config for ch in range(4): val = dialog.get_widget_value("threshold_ch_%d" % ch) update_setting("threshold_ch%d" % ch, val) commands.append("TL %d %s" % (ch, val)) # apply new thresholds to daq card for cmd in commands: self.daq.put(cmd) self.logger.info("Set threshold of channel %s to %s" % (cmd.split()[1], cmd.split()[2])) self.daq.put('TL')
def get_thresholds_from_msg(self, msg): """ Explicitly scan message for threshold information. Return True if found, False otherwise. :param msg: daq message :type msg: str :returns: bool """ if msg.startswith('TL') and len(msg) > 9: msg = msg.split('=') update_setting("threshold_ch0", int(msg[1][:-2])) update_setting("threshold_ch1", int(msg[2][:-2])) update_setting("threshold_ch2", int(msg[3][:-2])) update_setting("threshold_ch3", int(msg[4])) self.logger.debug( "Got Thresholds %d %d %d %d" % tuple([get_setting("threshold_ch%d" % i) for i in range(4)])) return True else: return False
def process_incoming(self): """ This functions gets everything out of the daq. Handles all the messages currently in the daq and passes the results to the corresponding widgets. :returns: None """ while self.daq.data_available(): try: msg = self.daq.get(0) except DAQIOError: self.logger.debug("Queue empty!") return None # make daq msg public for child widgets self.last_daq_msg = msg # Check contents of message and do what it says self.get_widget("daq").update() gps_widget = self.get_widget("gps") # try to extract GPS information if widget is active and enabled if gps_widget.active() and gps_widget.isEnabled(): gps_widget.update() continue status_widget = self.get_widget("status") # update status widget if active if status_widget.isVisible() and status_widget.active(): status_widget.update() decay_widget = self.get_widget("decay") # update previous coincidence config on decay widget if active if msg.startswith('DC') and len(msg) > 2 and decay_widget.active(): try: split_msg = msg.split(" ") t_03 = split_msg[4].split("=")[1] t_02 = split_msg[3].split("=")[1] decay_widget.set_previous_coincidence_times(t_03, t_02) except Exception: self.logger.debug('Wrong DC command.') continue # check for threshold information if self.get_thresholds_from_msg(msg): continue # check for channel configuration if self.get_channels_from_msg(msg): continue # ignore status messages if msg.startswith('ST') or len(msg) < 50: continue # calculate rate if self.get_widget("rate").calculate(): continue # extract pulses if needed if (get_setting("write_pulses") or self.is_widget_active("pulse") or self.is_widget_active("decay") or self.is_widget_active("velocity")): self.pulses = self.pulse_extractor.extract(msg) # trigger calculation on all pulse widgets self.calculate_pulses()
def get_channels_from_msg(self, msg): """ Explicitly scan message for channel information. Return True if found, False otherwise. DC gives: DC C0=23 C1=71 C2=0A C3=00 Which has the meaning: MM - 00 -> 8bits for channel enable/disable, coincidence and veto +---------------------------------------------------------------------+ | bits | +====+====+===========+===========+========+========+========+========+ |7 |6 |5 |4 |3 |2 |1 |0 | +----+----+-----------+-----------+--------+--------+--------+--------+ |veto|veto|coincidence|coincidence|channel3|channel2|channel1|channel0| +----+----+-----------+-----------+--------+--------+--------+--------+ +-----------------+ |Set bits for veto| +=================+ |00 - ch0 is veto | +-----------------+ |01 - ch1 is veto | +-----------------+ |10 - ch2 is veto | +-----------------+ |11 - ch3 is veto | +-----------------+ +------------------------+ |Set bits for coincidence| +========================+ |00 - singles | +------------------------+ |01 - twofold | +------------------------+ |10 - threefold | +------------------------+ |11 - fourfold | +------------------------+ :param msg: daq message :type msg: str :returns: bool """ if msg.startswith('DC ') and len(msg) > 25: msg = msg.split(' ') coincidence_time = msg[4].split('=')[1] + msg[3].split('=')[1] msg = bin(int(msg[1][3:], 16))[2:].zfill(8) veto_config = msg[0:2] coincidence_config = msg[2:4] channel_config = msg[4:8] update_setting("gate_width", int(coincidence_time, 16) * 10) # set default veto config for i in range(4): if i == 0: update_setting("veto", True) else: update_setting("veto_ch%d" % (i - 1), False) # update channel config for i in range(4): update_setting("active_ch%d" % i, channel_config[3 - i] == '1') # update coincidence config for i, seq in enumerate(['00', '01', '10', '11']): update_setting("coincidence%d" % i, coincidence_config == seq) # update veto config for i, seq in enumerate(['00', '01', '10', '11']): if veto_config == seq: if i == 0: update_setting("veto", False) else: update_setting("veto_ch%d" % (i - 1), True) self.logger.debug('gate width timew indow %d ns' % get_setting("gate_width")) self.logger.debug( "Got channel configurations: %d %d %d %d" % tuple([get_setting("active_ch%d" % i) for i in range(4)])) self.logger.debug( "Got coincidence configurations: %d %d %d %d" % tuple([get_setting("coincidence%d" % i) for i in range(4)])) self.logger.debug( "Got veto configurations: %d %d %d %d" % tuple([get_setting("veto")] + [get_setting("veto_ch%d" % i) for i in range(3)])) return True else: return False
def config_menu(self): """ Show the channel config dialog. :returns: None """ # get the actual channels from the DAQ card self.daq.put("DC") # wait explicitly until the channels get loaded self.logger.info("loading channel information...") time.sleep(1) # get current config values channel_config = [get_setting("active_ch%d" % i) for i in range(4)] coincidence_config = [ get_setting("coincidence%d" % i) for i in range(4) ] veto = get_setting("veto") veto_config = [get_setting("veto_ch%d" % i) for i in range(3)] # show dialog dialog = ConfigDialog(channel_config, coincidence_config, veto, veto_config) if dialog.exec_() == 1: # get and update channel and coincidence config for i in range(4): channel_config[i] = dialog.get_widget_value( "channel_checkbox_%d" % i) coincidence_config[i] = dialog.get_widget_value( "coincidence_checkbox_%d" % i) update_setting("active_ch%d" % i, channel_config[i]) update_setting("coincidence%d" % i, coincidence_config[i]) # get and update veto state veto = dialog.get_widget_value("veto_checkbox") update_setting("veto", veto) # get and update veto channel config for i in range(3): veto_config[i] = dialog.get_widget_value("veto_checkbox_%d" % i) update_setting("veto_ch%d" % i, veto_config[i]) # build daq message to apply the new config to the card tmp_msg = "" if veto: if veto_config[0]: tmp_msg += "01" elif veto_config[1]: tmp_msg += "10" elif veto_config[2]: tmp_msg += "11" else: tmp_msg += "00" else: tmp_msg += "00" coincidence_set = False # singles, twofold, threefold, fourfold for i, coincidence in enumerate(["00", "01", "10", "11"]): if coincidence_config[i]: tmp_msg += coincidence coincidence_set = True if not coincidence_set: tmp_msg += "00" # now calculate the correct expression for the first # four bits self.logger.debug("The first four bits are set to %s" % tmp_msg) msg = "WC 00 %s" % hex(int(''.join(tmp_msg), 2))[-1].capitalize() channel_set = False enable = ['0', '0', '0', '0'] for i, active in enumerate(reversed(channel_config)): if active: enable[i] = '1' channel_set = True if channel_set: msg += hex(int(''.join(enable), 2))[-1].capitalize() else: msg += '0' # send the message to the daq card self.daq.put(msg) self.logger.info("The following message was sent to DAQ: %s" % msg) for i in range(4): self.logger.debug("channel%d selected %s" % (i, channel_config[i])) for i, name in enumerate( ["singles", "twofold", "threefold", "fourfold"]): self.logger.debug("coincidence %s %s" % (name, coincidence_config[i])) self.daq.put("DC")