diff --git a/exopy_hqc_legacy/instruments/drivers/visa/tabor_awg.py b/exopy_hqc_legacy/instruments/drivers/visa/tabor_awg.py index 91898e14..ae9a7760 100644 --- a/exopy_hqc_legacy/instruments/drivers/visa/tabor_awg.py +++ b/exopy_hqc_legacy/instruments/drivers/visa/tabor_awg.py @@ -246,13 +246,13 @@ def sampling_frequency(self, value): def running(self): """Run state getter method """ - return '2 : Intrument is running' + return True - @running.setter @secure_communication() - def running(self, value): + def set_running(self, value, delay=0): """Run state setter method """ + pass @instrument_property diff --git a/exopy_hqc_legacy/instruments/drivers/visa/tektro_awg.py b/exopy_hqc_legacy/instruments/drivers/visa/tektro_awg.py index 821d6d26..72bd9cc9 100644 --- a/exopy_hqc_legacy/instruments/drivers/visa/tektro_awg.py +++ b/exopy_hqc_legacy/instruments/drivers/visa/tektro_awg.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- -# Copyright 2015-2018 by ExopyHqcLegacy Authors, see AUTHORS for more details. +# Copyright 2015-2020 by ExopyHqcLegacy Authors, see AUTHORS for more details. # # Distributed under the terms of the BSD license. # @@ -498,6 +498,20 @@ def to_send(self, name, waveform): self._driver.write_binary_values(header, waveform, datatype='B') self.write('*WAI') + @secure_communication() + def send_load_awg_file(self, awg_data, filename='setup'): + """Command to send and load and .awg file into the AWG + + awg_data = bytearray + + """ + name_str = 'MMEMory:DATA "{}",'.format(filename+'.awg') + size_str = ('#' + str(len(str(len(awg_data)))) + str(len(awg_data))) + mes = name_str + size_str + self.write('MMEMory:CDIRectory "/Users/OEM/Documents"') + self._driver.write_raw(mes.encode('ASCII') + awg_data) + self.write('AWGCONTROL:SRESTORE "{}"'.format(filename+'.awg')) + @secure_communication() def clear_sequence(self): """Command to delete the sequence @@ -514,6 +528,35 @@ def set_goto_pos(self, position, goto): self.write('SEQuence:ELEMent' + str(position) + ':GOTO:INDex ' + str(goto)) + @secure_communication() + def set_jump_pos(self, position, jump): + """Sets the jump value at position to jump + + """ + self.write('SEQuence:ELEMent{}:JTARget:TYPE INDex'.format(position)) + self.write('SEQuence:ELEMent{}:JTARget:INDex {}'.format(position, jump)) + + @secure_communication() + def send_event(self): + """Send an event + + """ + self.write('EVENt:IMM') + + @secure_communication() + def ask_sequencer_pos(self): + """Ask the current position index of the sequencer + + """ + return self.query('AWGC:SEQ:POS?') + + @secure_communication() + def force_jump_to(self, pos): + """Make the sequencer jump to position pos + + """ + self.query('SEQUENCE:JUMP:IMMEDIATE {}'.format(pos)) + @secure_communication() def set_repeat(self, position, repeat): """Sets the loop count for the specified subsequence element. @@ -679,36 +722,19 @@ def sampling_frequency(self, value): raise InstrIOError(cleandoc('''Instrument did not set correctly the sampling frequency''')) - @instrument_property @secure_communication() - def running(self): - """Run state getter method - - """ - self.clear_output_buffer() - run = self.query("AWGC:RST?") - if run == '0': - return '0 : Instrument has stopped' - elif run == '1': - return '1 : Instrument is waiting for trigger' - elif run == '2': - return '2 : Intrument is running' - else: - raise InstrIOError - - @running.setter - @secure_communication() - def running(self, value): + def set_running(self, value, delay=0.0): """Run state setter method """ self.clear_output_buffer() - if value in ('RUN', 1, 'True'): + if value in ('RUN', 1, 'True', True): self.write('AWGC:RUN:IMM') - if int(self.query('AWGC:RST?')) not in (1, 2): + run_mode = int(self.query('AWGC:RST?', delay=delay)) + if run_mode not in (1, 2): raise InstrIOError(cleandoc('''Instrument did not set correctly the run state''')) - elif value in ('STOP', 0, 'False'): + elif value in ('STOP', 0, 'False', False): self.write('AWGC:STOP:IMM') if int(self.query('AWGC:RST?')) != 0: raise InstrIOError(cleandoc('''Instrument did not set @@ -718,6 +744,20 @@ def running(self, value): running method''').format(value), 80) raise VisaTypeError(mess) + @instrument_property + @secure_communication() + def running(self): + """Run state getter method + + """ + self.clear_output_buffer() + running = int(self.query("AWGC:RST?")) + if running == 0: + return False + if running == 1 or running == 2: + return True + raise InstrIOError(cleandoc('''Couldn't read the run mode''')) + @instrument_property @secure_communication() def run_mode(self): @@ -766,8 +806,19 @@ def delete_all_waveforms(self): """Deletes all user-defined waveforms from the currently loaded setup """ + try: + # Number of user defined waveforms + # 25 is the number of default waveforms + nb_waveforms = int(self.query("WLIST:SIZE?")) - 25 + except Exception: + nb_waveforms = 0 + wait_time = 1 + int(nb_waveforms / 120) self.write('WLIST:WAVEFORM:DELETE ALL') + msg = 'Waiting {}s for {} waveforms to be deleted' + logging.info(msg.format(wait_time, nb_waveforms)) + time.sleep(wait_time) + def clear_all_sequences(self): """Clear the all sequences played by the AWG. diff --git a/exopy_hqc_legacy/instruments/drivers/visa_tools.py b/exopy_hqc_legacy/instruments/drivers/visa_tools.py index 576bb82d..21b5b8b1 100644 --- a/exopy_hqc_legacy/instruments/drivers/visa_tools.py +++ b/exopy_hqc_legacy/instruments/drivers/visa_tools.py @@ -152,7 +152,7 @@ def read_values(self, format=0): Simply call the `read_values` method of the `Instrument` object stored in the attribute `_driver` """ - return self._driver.read_values(format=0) + return self._driver.read_values(format) def read_ascii_values(self, converter='f', separator=','): """Read one line of the instrument's buffer and convert to values. @@ -174,13 +174,13 @@ def read_binary_values(self, datatype='f', is_big_endian=False): """ return self._driver.read_binary_values(datatype, is_big_endian) - def query(self, message): + def query(self, message, *args, **kwargs): """Send the specified message to the instrument and read its answer. Simply call the `query` method of the `Instrument` object stored in the attribute `_driver` """ - return self._driver.query(message) + return self._driver.query(message, *args, **kwargs) def query_ascii_values(self, message, converter='f', separator=','): """Send the specified message to the instrument and convert its answer diff --git a/exopy_hqc_legacy/pulses/contexts/awg_context.py b/exopy_hqc_legacy/pulses/contexts/awg_context.py index e0a53fff..8111a130 100644 --- a/exopy_hqc_legacy/pulses/contexts/awg_context.py +++ b/exopy_hqc_legacy/pulses/contexts/awg_context.py @@ -233,7 +233,7 @@ def _transfer_sequences(self, driver, sequences, infos): for ch_id in sequences: ch = driver.get_channel(ch_id) ch.output_state = 'ON' - driver.running = True + driver.set_running(True) return True, infos, {} diff --git a/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py b/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py index 0bd2b3bb..386c8c67 100644 --- a/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py +++ b/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- -# Copyright 2015-2018 by ExopyHqcLegacy Authors, see AUTHORS for more details. +# Copyright 2015-2020 by ExopyHqcLegacy Authors, see AUTHORS for more details. # # Distributed under the terms of the BSD license. # @@ -10,10 +10,11 @@ """ import logging +import time -from atom.api import (Str, set_default) +from atom.api import (Float, Str, set_default) -from exopy.tasks.api import (InstrumentTask, validators) +from exopy.tasks.api import InstrumentTask class RunAWGTask(InstrumentTask): @@ -21,22 +22,39 @@ class RunAWGTask(InstrumentTask): """ #: Switch to choose the AWG run mode: on or off - switch = Str('Off').tag(pref=True, feval=validators.SkipLoop()) + switch = Str('Off').tag(pref=True) + + #: Delay before setting the AWG. Useful when loading large sequences + delay = Float(0).tag(pref=True) + database_entries = set_default({'output': 0}) - def perform(self, switch=None): + def perform(self): """Default interface behavior. """ - if switch is None: - switch = self.format_and_eval_string(self.switch) - - if switch == 'On' or switch == 1: - self.driver.running = 1 + if self.switch.lower() == 'on' or self.switch == '1': + self.driver.send_event() + # The delay is required when loading large sequences + self.driver.set_running(True, delay=self.delay) self.write_in_database('output', 1) - else: - self.driver.running = 0 + elif self.switch.lower() == 'event': + time.sleep(self.delay) + self.driver.send_event() + elif self.switch.lower() == 'rearm': + time.sleep(self.delay) + success = False + while not success: + self.driver.send_event() + pos = int(self.driver.ask_sequencer_pos()) + if pos == 1: + success = True + time.sleep(self.delay) + elif self.switch.lower() == 'off' or self.switch == '0': + time.sleep(self.delay) + self.driver.set_running(False) self.write_in_database('output', 0) - log = logging.getLogger(__name__) - msg = 'AWG running state OK' - log.debug(msg) + else: + logger = logging.getLogger(__name__) + msg = "Unable to recognize {} running mode" + logger.warning(msg.format(self.switch)) diff --git a/exopy_hqc_legacy/tasks/tasks/instr/views/run_awg_views.enaml b/exopy_hqc_legacy/tasks/tasks/instr/views/run_awg_views.enaml index 578a0dba..7ad2c173 100644 --- a/exopy_hqc_legacy/tasks/tasks/instr/views/run_awg_views.enaml +++ b/exopy_hqc_legacy/tasks/tasks/instr/views/run_awg_views.enaml @@ -11,13 +11,12 @@ """ from enaml.stdlib.fields import FloatField from enaml.core.api import Conditional -from enaml.widgets.api import (GroupBox, Label, Field, ObjectCombo, CheckBox) +from enaml.widgets.api import (Label, Field) from enaml.layout.api import factory from textwrap import fill -from exopy.tasks.api import InstrTaskView, EVALUATER_TOOLTIP -from exopy.utils.widgets.qt_completers import QtLineCompleter +from exopy.tasks.api import InstrTaskView from exopy_hqc_legacy.utils.layouts import auto_grid_layout from ...base_instr_view import InstrView @@ -36,9 +35,13 @@ enamldef RunAWGView(InstrView): view: condition << not in_loop Label: text = 'Output' - QtLineCompleter: + Field: hug_width = 'ignore' text := task.switch - entries_updater << task.list_accessible_database_entries - tool_tip = EVALUATER_TOOLTIP + tool_tip = 'Should be On, Off, Event or Rearm' + Label: delay: + text = 'Delay (s)' + FloatField: delay_val: + value := task.delay + tool_tip = 'Estimated time for the AWG to load the entire sequence' diff --git a/tests/pulses/contexts/test_awg_context.py b/tests/pulses/contexts/test_awg_context.py index fa595633..f15cd124 100644 --- a/tests/pulses/contexts/test_awg_context.py +++ b/tests/pulses/contexts/test_awg_context.py @@ -62,6 +62,8 @@ def to_send(self, name, array): def get_channel(self, ch_id): return self.channels[ch_id] + def set_running(self, value, delay=None): + self.running = value class TestAWGContext(object): """Test the AWG5014 context capabilities.