From 777200b5b9a74a0493a9ea44374ff0bcfddd2c56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9ouven=20Assouly?= Date: Wed, 26 Jun 2019 15:42:38 +0200 Subject: [PATCH 01/12] AWG: use events instead of on/off for easier synchronisation with the acquisition cards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code is a slightly modified version of the code written by Raphaƫl and Zaki. --- .../instruments/drivers/visa/tektro_awg.py | 155 ++++++++++++++++++ exopy_hqc_legacy/tasks/tasks/instr/run_awg.py | 32 +++- .../tasks/instr/views/run_awg_views.enaml | 7 +- 3 files changed, 191 insertions(+), 3 deletions(-) diff --git a/exopy_hqc_legacy/instruments/drivers/visa/tektro_awg.py b/exopy_hqc_legacy/instruments/drivers/visa/tektro_awg.py index 821d6d26..ddc2dcfe 100644 --- a/exopy_hqc_legacy/instruments/drivers/visa/tektro_awg.py +++ b/exopy_hqc_legacy/instruments/drivers/visa/tektro_awg.py @@ -443,6 +443,90 @@ def __init__(self, connection_info, caching_allowed=True, caching_permissions, auto_open) self.channels = {} self.lock = Lock() + self.AWG_FILE_FORMAT_HEAD = { + 'SAMPLING_RATE': 'd', # d + 'REPETITION_RATE': 'd', # # NAME? + 'HOLD_REPETITION_RATE': 'h', # True | False + 'CLOCK_SOURCE': 'h', # Internal | External + 'REFERENCE_SOURCE': 'h', # Internal | External + 'EXTERNAL_REFERENCE_TYPE': 'h', # Fixed | Variable + 'REFERENCE_CLOCK_FREQUENCY_SELECTION': 'h', + 'REFERENCE_MULTIPLIER_RATE': 'h', # + 'DIVIDER_RATE': 'h', # 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 256 + 'TRIGGER_SOURCE': 'h', # Internal | External + 'INTERNAL_TRIGGER_RATE': 'd', # + 'TRIGGER_INPUT_IMPEDANCE': 'h', # 50 ohm | 1 kohm + 'TRIGGER_INPUT_SLOPE': 'h', # Positive | Negative + 'TRIGGER_INPUT_POLARITY': 'h', # Positive | Negative + 'TRIGGER_INPUT_THRESHOLD': 'd', # + 'EVENT_INPUT_IMPEDANCE': 'h', # 50 ohm | 1 kohm + 'EVENT_INPUT_POLARITY': 'h', # Positive | Negative + 'EVENT_INPUT_THRESHOLD': 'd', + 'JUMP_TIMING': 'h', # Sync | Async + 'INTERLEAVE': 'h', # On | This setting is stronger than . + 'ZEROING': 'h', # On | Off + 'COUPLING': 'h', # The Off | Pair | All setting is weaker than . + 'RUN_MODE': 'h', # Continuous | Triggered | Gated | Sequence + 'WAIT_VALUE': 'h', # First | Last + 'RUN_STATE': 'h', # On | Off + 'INTERLEAVE_ADJ_PHASE': 'd', + 'INTERLEAVE_ADJ_AMPLITUDE': 'd', + } + + self.AWG_FILE_FORMAT_CHANNEL = { + # Include NULL.(Output Waveform Name for Non-Sequence mode) + 'OUTPUT_WAVEFORM_NAME_N': 's', + 'CHANNEL_STATE_N': 'h', # On | Off + 'ANALOG_DIRECT_OUTPUT_N': 'h', # On | Off + 'ANALOG_FILTER_N': 'h', # Enum type. + 'ANALOG_METHOD_N': 'h', # Amplitude/Offset, High/Low + # When the Input Method is High/Low, it is skipped. + 'ANALOG_AMPLITUDE_N': 'd', + # When the Input Method is High/Low, it is skipped. + 'ANALOG_OFFSET_N': 'd', + # When the Input Method is Amplitude/Offset, it is skipped. + 'ANALOG_HIGH_N': 'd', + # When the Input Method is Amplitude/Offset, it is skipped. + 'ANALOG_LOW_N': 'd', + 'MARKER1_SKEW_N': 'd', + 'MARKER1_METHOD_N': 'h', # Amplitude/Offset, High/Low + # When the Input Method is High/Low, it is skipped. + 'MARKER1_AMPLITUDE_N': 'd', + # When the Input Method is High/Low, it is skipped. + 'MARKER1_OFFSET_N': 'd', + # When the Input Method is Amplitude/Offset, it is skipped. + 'MARKER1_HIGH_N': 'd', + # When the Input Method is Amplitude/Offset, it is skipped. + 'MARKER1_LOW_N': 'd', + 'MARKER2_SKEW_N': 'd', + 'MARKER2_METHOD_N': 'h', # Amplitude/Offset, High/Low + # When the Input Method is High/Low, it is skipped. + 'MARKER2_AMPLITUDE_N': 'd', + # When the Input Method is High/Low, it is skipped. + 'MARKER2_OFFSET_N': 'd', + # When the Input Method is Amplitude/Offset, it is skipped. + 'MARKER2_HIGH_N': 'd', + # When the Input Method is Amplitude/Offset, it is skipped. + 'MARKER2_LOW_N': 'd', + 'DIGITAL_METHOD_N': 'h', # Amplitude/Offset, High/Low + # When the Input Method is High/Low, it is skipped. + 'DIGITAL_AMPLITUDE_N': 'd', + # When the Input Method is High/Low, it is skipped. + 'DIGITAL_OFFSET_N': 'd', + # When the Input Method is Amplitude/Offset, it is skipped. + 'DIGITAL_HIGH_N': 'd', + # When the Input Method is Amplitude/Offset, it is skipped. + 'DIGITAL_LOW_N': 'd', + 'EXTERNAL_ADD_N': 'h', # AWG5000 only + 'PHASE_DELAY_INPUT_METHOD_N': 'h', # Phase/DelayInme/DelayInints + 'PHASE_N': 'd', # When the Input Method is not Phase, it is skipped. + # When the Input Method is not DelayInTime, it is skipped. + 'DELAY_IN_TIME_N': 'd', + # When the Input Method is not DelayInPoint, it is skipped. + 'DELAY_IN_POINTS_N': 'd', + 'CHANNEL_SKEW_N': 'd', + 'DC_OUTPUT_LEVEL_N': 'd', # V + } def reopen_connection(self): """Clear buffer on connection reseting. @@ -498,6 +582,21 @@ 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_file, filename = 'setup'): + """Command to send and load and .awg file into the AWG + awg_file = bytearray + + """ + name_str = 'MMEMory:DATA "{}",'.format(filename+'.awg').encode('ASCII') + size_str = ('#' + str(len(str(len(awg_file)))) + str(len(awg_file))).encode('ASCII') + mes = name_str + size_str + awg_file + self.write('MMEMory:CDIRectory "/Users/OEM/Documents"') +# mes = self._driver.read_raw() + self._driver.write_raw(mes) + self.write('AWGCONTROL:SRESTORE "{}"'.format(filename+'.awg')) + @secure_communication() def clear_sequence(self): """Command to delete the sequence @@ -514,6 +613,37 @@ 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' + str(position) + ':JTARget:TYPE INDex') + self.write('SEQuence:ELEMent' + str(position) + ':JTARget:INDex ' + + str(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 + + """ + pos = self.ask('AWGC:SEQ:POS?') + return(pos) + + @secure_communication() + def force_jump_to(self, pos): + """Make the sequencer jump to position pos + + """ + self.ask('SEQUENCE:JUMP:IMMEDIATE %d'%pos) + @secure_communication() def set_repeat(self, position, repeat): """Sets the loop count for the specified subsequence element. @@ -706,6 +836,7 @@ def running(self, value): if value in ('RUN', 1, 'True'): self.write('AWGC:RUN:IMM') if int(self.query('AWGC:RST?')) not in (1, 2): + raise InstrIOError(cleandoc('''Instrument did not set correctly the run state''')) elif value in ('STOP', 0, 'False'): @@ -766,8 +897,32 @@ def delete_all_waveforms(self): """Deletes all user-defined waveforms from the currently loaded setup """ + try: + nb_waveforms = int(self.ask("WLIST:SIZE?")) - 25 #nb of user defined wf + except Exception: + nb_waveforms = 0 + wait_time = 1+int(nb_waveforms/120) self.write('WLIST:WAVEFORM:DELETE ALL') + print('Waiting {}s for {} waveforms to be deleted'.format(wait_time, + nb_waveforms)) + time.sleep(wait_time) + + def get_waveform_name(self, index): + """Get the name of waveform at given index + + """ + waveform_name = self.ask("WLIST:NAME? %d"%index) + + return waveform_name[1:-2] + + def get_waveform_number(self): + """Get the current number of waveforms in the waveform list + + """ + nb_waveforms = int(self.ask("WLIST:SIZE?")) + return nb_waveforms + def clear_all_sequences(self): """Clear the all sequences played by the AWG. diff --git a/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py b/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py index 0bd2b3bb..b520cb16 100644 --- a/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py +++ b/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py @@ -10,6 +10,8 @@ """ import logging +import numbers +import time from atom.api import (Str, set_default) @@ -22,20 +24,46 @@ class RunAWGTask(InstrumentTask): """ #: Switch to choose the AWG run mode: on or off switch = Str('Off').tag(pref=True, feval=validators.SkipLoop()) + + delay = Float(0).tag(pref=True, + feval=validators.SkipLoop(types=numbers.Real)) + database_entries = set_default({'output': 0}) def perform(self, switch=None): """Default interface behavior. """ + delay = self.format_and_eval_string(self.delay) if switch is None: switch = self.format_and_eval_string(self.switch) if switch == 'On' or switch == 1: - self.driver.running = 1 + print('On') + self.driver.send_event() + # The delay is required when loading large sequences + self.driver.run_awg(1, delay=delay) self.write_in_database('output', 1) + elif switch == 'Event': + print('Event') + time.sleep(delay) + self.driver.send_event() + elif switch == 'Rearm': + print('Rearm') + time.sleep(delay) + success = False + while not success: + self.driver.send_event() + pos = int(self.driver.ask_sequencer_pos()) + print(pos) + if pos == 1: + success = True + print(success) + time.sleep(delay) else: - self.driver.running = 0 + print('Off') + time.sleep(delay) + self.driver.run_awg(0) self.write_in_database('output', 0) log = logging.getLogger(__name__) msg = 'AWG running state OK' 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..647c66ea 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 @@ -40,5 +40,10 @@ enamldef RunAWGView(InstrView): view: hug_width = 'ignore' text := task.switch entries_updater << task.list_accessible_database_entries - tool_tip = EVALUATER_TOOLTIP + tool_tip = 'Should be On, Off or Event' + Label: delay: + text = 'Delay (s)' + FloatField: delay_val: + value := task.delay + tool_tip = 'Estimated time for the AWG to load the entire sequence' From 7bfe84bb9bef57f2c5f63e11bb5b537328847abf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9ouven=20Assouly?= Date: Fri, 2 Aug 2019 14:52:16 +0200 Subject: [PATCH 02/12] Clean up --- .../instruments/drivers/visa/tektro_awg.py | 130 ++---------------- exopy_hqc_legacy/tasks/tasks/instr/run_awg.py | 7 - 2 files changed, 14 insertions(+), 123 deletions(-) diff --git a/exopy_hqc_legacy/instruments/drivers/visa/tektro_awg.py b/exopy_hqc_legacy/instruments/drivers/visa/tektro_awg.py index ddc2dcfe..549d93ad 100644 --- a/exopy_hqc_legacy/instruments/drivers/visa/tektro_awg.py +++ b/exopy_hqc_legacy/instruments/drivers/visa/tektro_awg.py @@ -443,90 +443,6 @@ def __init__(self, connection_info, caching_allowed=True, caching_permissions, auto_open) self.channels = {} self.lock = Lock() - self.AWG_FILE_FORMAT_HEAD = { - 'SAMPLING_RATE': 'd', # d - 'REPETITION_RATE': 'd', # # NAME? - 'HOLD_REPETITION_RATE': 'h', # True | False - 'CLOCK_SOURCE': 'h', # Internal | External - 'REFERENCE_SOURCE': 'h', # Internal | External - 'EXTERNAL_REFERENCE_TYPE': 'h', # Fixed | Variable - 'REFERENCE_CLOCK_FREQUENCY_SELECTION': 'h', - 'REFERENCE_MULTIPLIER_RATE': 'h', # - 'DIVIDER_RATE': 'h', # 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 256 - 'TRIGGER_SOURCE': 'h', # Internal | External - 'INTERNAL_TRIGGER_RATE': 'd', # - 'TRIGGER_INPUT_IMPEDANCE': 'h', # 50 ohm | 1 kohm - 'TRIGGER_INPUT_SLOPE': 'h', # Positive | Negative - 'TRIGGER_INPUT_POLARITY': 'h', # Positive | Negative - 'TRIGGER_INPUT_THRESHOLD': 'd', # - 'EVENT_INPUT_IMPEDANCE': 'h', # 50 ohm | 1 kohm - 'EVENT_INPUT_POLARITY': 'h', # Positive | Negative - 'EVENT_INPUT_THRESHOLD': 'd', - 'JUMP_TIMING': 'h', # Sync | Async - 'INTERLEAVE': 'h', # On | This setting is stronger than . - 'ZEROING': 'h', # On | Off - 'COUPLING': 'h', # The Off | Pair | All setting is weaker than . - 'RUN_MODE': 'h', # Continuous | Triggered | Gated | Sequence - 'WAIT_VALUE': 'h', # First | Last - 'RUN_STATE': 'h', # On | Off - 'INTERLEAVE_ADJ_PHASE': 'd', - 'INTERLEAVE_ADJ_AMPLITUDE': 'd', - } - - self.AWG_FILE_FORMAT_CHANNEL = { - # Include NULL.(Output Waveform Name for Non-Sequence mode) - 'OUTPUT_WAVEFORM_NAME_N': 's', - 'CHANNEL_STATE_N': 'h', # On | Off - 'ANALOG_DIRECT_OUTPUT_N': 'h', # On | Off - 'ANALOG_FILTER_N': 'h', # Enum type. - 'ANALOG_METHOD_N': 'h', # Amplitude/Offset, High/Low - # When the Input Method is High/Low, it is skipped. - 'ANALOG_AMPLITUDE_N': 'd', - # When the Input Method is High/Low, it is skipped. - 'ANALOG_OFFSET_N': 'd', - # When the Input Method is Amplitude/Offset, it is skipped. - 'ANALOG_HIGH_N': 'd', - # When the Input Method is Amplitude/Offset, it is skipped. - 'ANALOG_LOW_N': 'd', - 'MARKER1_SKEW_N': 'd', - 'MARKER1_METHOD_N': 'h', # Amplitude/Offset, High/Low - # When the Input Method is High/Low, it is skipped. - 'MARKER1_AMPLITUDE_N': 'd', - # When the Input Method is High/Low, it is skipped. - 'MARKER1_OFFSET_N': 'd', - # When the Input Method is Amplitude/Offset, it is skipped. - 'MARKER1_HIGH_N': 'd', - # When the Input Method is Amplitude/Offset, it is skipped. - 'MARKER1_LOW_N': 'd', - 'MARKER2_SKEW_N': 'd', - 'MARKER2_METHOD_N': 'h', # Amplitude/Offset, High/Low - # When the Input Method is High/Low, it is skipped. - 'MARKER2_AMPLITUDE_N': 'd', - # When the Input Method is High/Low, it is skipped. - 'MARKER2_OFFSET_N': 'd', - # When the Input Method is Amplitude/Offset, it is skipped. - 'MARKER2_HIGH_N': 'd', - # When the Input Method is Amplitude/Offset, it is skipped. - 'MARKER2_LOW_N': 'd', - 'DIGITAL_METHOD_N': 'h', # Amplitude/Offset, High/Low - # When the Input Method is High/Low, it is skipped. - 'DIGITAL_AMPLITUDE_N': 'd', - # When the Input Method is High/Low, it is skipped. - 'DIGITAL_OFFSET_N': 'd', - # When the Input Method is Amplitude/Offset, it is skipped. - 'DIGITAL_HIGH_N': 'd', - # When the Input Method is Amplitude/Offset, it is skipped. - 'DIGITAL_LOW_N': 'd', - 'EXTERNAL_ADD_N': 'h', # AWG5000 only - 'PHASE_DELAY_INPUT_METHOD_N': 'h', # Phase/DelayInme/DelayInints - 'PHASE_N': 'd', # When the Input Method is not Phase, it is skipped. - # When the Input Method is not DelayInTime, it is skipped. - 'DELAY_IN_TIME_N': 'd', - # When the Input Method is not DelayInPoint, it is skipped. - 'DELAY_IN_POINTS_N': 'd', - 'CHANNEL_SKEW_N': 'd', - 'DC_OUTPUT_LEVEL_N': 'd', # V - } def reopen_connection(self): """Clear buffer on connection reseting. @@ -582,19 +498,17 @@ 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_file, filename = 'setup'): + def send_load_awg_file(self, awg_file, filename='setup'): """Command to send and load and .awg file into the AWG awg_file = bytearray """ - name_str = 'MMEMory:DATA "{}",'.format(filename+'.awg').encode('ASCII') - size_str = ('#' + str(len(str(len(awg_file)))) + str(len(awg_file))).encode('ASCII') + name_str = 'MMEMory:DATA "{}",'.format(filename+'.awg') + size_str = ('#' + str(len(str(len(awg_file)))) + str(len(awg_file))) mes = name_str + size_str + awg_file self.write('MMEMory:CDIRectory "/Users/OEM/Documents"') -# mes = self._driver.read_raw() - self._driver.write_raw(mes) + self._driver.write_ascii_values(mes) self.write('AWGCONTROL:SRESTORE "{}"'.format(filename+'.awg')) @secure_communication() @@ -618,9 +532,8 @@ def set_jump_pos(self, position, jump): """Sets the jump value at position to jump """ - self.write('SEQuence:ELEMent' + str(position) + ':JTARget:TYPE INDex') - self.write('SEQuence:ELEMent' + str(position) + ':JTARget:INDex ' + - str(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): @@ -634,15 +547,14 @@ def ask_sequencer_pos(self): """Ask the current position index of the sequencer """ - pos = self.ask('AWGC:SEQ:POS?') - return(pos) + return self.ask('AWGC:SEQ:POS?') @secure_communication() def force_jump_to(self, pos): """Make the sequencer jump to position pos """ - self.ask('SEQUENCE:JUMP:IMMEDIATE %d'%pos) + self.ask('SEQUENCE:JUMP:IMMEDIATE {}'.format(pos)) @secure_communication() def set_repeat(self, position, repeat): @@ -835,8 +747,8 @@ def running(self, value): self.clear_output_buffer() if value in ('RUN', 1, 'True'): self.write('AWGC:RUN:IMM') - if int(self.query('AWGC:RST?')) not in (1, 2): - + values = self.query('AWGC:RST?', format=2, delay=self.delay) + if values[0] not in (1, 2): raise InstrIOError(cleandoc('''Instrument did not set correctly the run state''')) elif value in ('STOP', 0, 'False'): @@ -898,31 +810,17 @@ def delete_all_waveforms(self): """ try: - nb_waveforms = int(self.ask("WLIST:SIZE?")) - 25 #nb of user defined wf + # Number of user defined waveforms + nb_waveforms = int(self.ask("WLIST:SIZE?")) - 25 except Exception: nb_waveforms = 0 wait_time = 1+int(nb_waveforms/120) self.write('WLIST:WAVEFORM:DELETE ALL') - print('Waiting {}s for {} waveforms to be deleted'.format(wait_time, - nb_waveforms)) + logging.info('Waiting {}s for {} waveforms to be deleted'.format(wait_time, + nb_waveforms)) time.sleep(wait_time) - def get_waveform_name(self, index): - """Get the name of waveform at given index - - """ - waveform_name = self.ask("WLIST:NAME? %d"%index) - - return waveform_name[1:-2] - - def get_waveform_number(self): - """Get the current number of waveforms in the waveform list - - """ - nb_waveforms = int(self.ask("WLIST:SIZE?")) - return nb_waveforms - def clear_all_sequences(self): """Clear the all sequences played by the AWG. diff --git a/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py b/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py index b520cb16..8c0b32dd 100644 --- a/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py +++ b/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py @@ -34,18 +34,14 @@ def perform(self, switch=None): """Default interface behavior. """ - delay = self.format_and_eval_string(self.delay) if switch is None: switch = self.format_and_eval_string(self.switch) - if switch == 'On' or switch == 1: - print('On') self.driver.send_event() # The delay is required when loading large sequences self.driver.run_awg(1, delay=delay) self.write_in_database('output', 1) elif switch == 'Event': - print('Event') time.sleep(delay) self.driver.send_event() elif switch == 'Rearm': @@ -55,13 +51,10 @@ def perform(self, switch=None): while not success: self.driver.send_event() pos = int(self.driver.ask_sequencer_pos()) - print(pos) if pos == 1: success = True - print(success) time.sleep(delay) else: - print('Off') time.sleep(delay) self.driver.run_awg(0) self.write_in_database('output', 0) From f2d29e364db3bcfbf47296f062ba67fa14997f7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9ouven=20Assouly?= Date: Fri, 2 Aug 2019 16:12:18 +0200 Subject: [PATCH 03/12] AWG: Use write_raw instead of write_ascii_values This is needed because we are working with a raw bytes array --- exopy_hqc_legacy/instruments/drivers/visa/tektro_awg.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exopy_hqc_legacy/instruments/drivers/visa/tektro_awg.py b/exopy_hqc_legacy/instruments/drivers/visa/tektro_awg.py index 549d93ad..58cde14b 100644 --- a/exopy_hqc_legacy/instruments/drivers/visa/tektro_awg.py +++ b/exopy_hqc_legacy/instruments/drivers/visa/tektro_awg.py @@ -506,9 +506,9 @@ def send_load_awg_file(self, awg_file, filename='setup'): """ name_str = 'MMEMory:DATA "{}",'.format(filename+'.awg') size_str = ('#' + str(len(str(len(awg_file)))) + str(len(awg_file))) - mes = name_str + size_str + awg_file + mes = name_str + size_str self.write('MMEMory:CDIRectory "/Users/OEM/Documents"') - self._driver.write_ascii_values(mes) + self._driver.write_raw(mes.encode('ASCII') + awg_file) self.write('AWGCONTROL:SRESTORE "{}"'.format(filename+'.awg')) @secure_communication() From 788a2ca5876dccd688e5a5c081d20947a03b2c74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9ouven=20Assouly?= Date: Fri, 27 Mar 2020 11:41:09 +0100 Subject: [PATCH 04/12] run_awg: cleanup --- .../instruments/drivers/visa/tabor_awg.py | 6 +-- .../instruments/drivers/visa/tektro_awg.py | 50 +++++++++---------- exopy_hqc_legacy/tasks/tasks/instr/run_awg.py | 37 +++++++------- .../tasks/instr/views/run_awg_views.enaml | 10 ++-- tests/pulses/contexts/test_awg_context.py | 2 +- 5 files changed, 50 insertions(+), 55 deletions(-) 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 58cde14b..a7efc7f6 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. # @@ -499,9 +499,10 @@ def to_send(self, name, waveform): self.write('*WAI') @secure_communication() - def send_load_awg_file(self, awg_file, filename='setup'): + def send_load_awg_file(self, awg_data, filename='setup'): """Command to send and load and .awg file into the AWG - awg_file = bytearray + + awg_data = bytearray """ name_str = 'MMEMory:DATA "{}",'.format(filename+'.awg') @@ -721,37 +722,21 @@ 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') - values = self.query('AWGC:RST?', format=2, delay=self.delay) + self.write('AWGC:RST?') + time.sleep(delay) + values = self.read_values(format=2) if values[0] 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 @@ -761,6 +746,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() + run = self.ask_for_values("AWGC:RST?")[0] + if run == 0: + return False + if run == 1 or run == 2: + return True + raise InstrIOError + @instrument_property @secure_communication() def run_mode(self): @@ -811,6 +810,7 @@ def delete_all_waveforms(self): """ try: # Number of user defined waveforms + # 25 is the number of default waveforms nb_waveforms = int(self.ask("WLIST:SIZE?")) - 25 except Exception: nb_waveforms = 0 diff --git a/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py b/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py index 8c0b32dd..a7911f8c 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,12 +10,11 @@ """ import logging -import numbers import time from atom.api import (Str, set_default) -from exopy.tasks.api import (InstrumentTask, validators) +from exopy.tasks.api import InstrumentTask class RunAWGTask(InstrumentTask): @@ -30,34 +29,32 @@ class RunAWGTask(InstrumentTask): 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: + if self.switch.lower() == 'on' or self.switch == '1': self.driver.send_event() # The delay is required when loading large sequences - self.driver.run_awg(1, delay=delay) + self.driver.set_running(True, delay=self.delay) self.write_in_database('output', 1) - elif switch == 'Event': - time.sleep(delay) + elif self.switch.lower() == 'event': + time.sleep(self.delay) self.driver.send_event() - elif switch == 'Rearm': - print('Rearm') - time.sleep(delay) + 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(delay) - else: - time.sleep(delay) - self.driver.run_awg(0) + 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(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 647c66ea..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,11 +35,10 @@ 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 = 'Should be On, Off or Event' + tool_tip = 'Should be On, Off, Event or Rearm' Label: delay: text = 'Delay (s)' diff --git a/tests/pulses/contexts/test_awg_context.py b/tests/pulses/contexts/test_awg_context.py index fa595633..3fe3070d 100644 --- a/tests/pulses/contexts/test_awg_context.py +++ b/tests/pulses/contexts/test_awg_context.py @@ -54,7 +54,7 @@ def __init__(self): self.sequences = {} self.defined_channels = [1, 2, 3, 4] self.channels = {i: DummyChannel(self, i) for i in range(1, 5)} - self.running = False + self.set_running(False) def to_send(self, name, array): self.sequences[name] = array From 5e2eb7ad70348c9085464b2f4f59080b81a5841b Mon Sep 17 00:00:00 2001 From: bhuard Date: Fri, 27 Mar 2020 12:10:17 +0100 Subject: [PATCH 05/12] visa: fix typo --- exopy_hqc_legacy/instruments/drivers/visa_tools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exopy_hqc_legacy/instruments/drivers/visa_tools.py b/exopy_hqc_legacy/instruments/drivers/visa_tools.py index 576bb82d..09b9a8f9 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. From 29fc4bba09f6b78a631e9ec41d104ddce0e5203d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9ouven=20Assouly?= Date: Fri, 27 Mar 2020 12:16:10 +0100 Subject: [PATCH 06/12] Try to pass tests --- tests/pulses/contexts/test_awg_context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/pulses/contexts/test_awg_context.py b/tests/pulses/contexts/test_awg_context.py index 3fe3070d..fa595633 100644 --- a/tests/pulses/contexts/test_awg_context.py +++ b/tests/pulses/contexts/test_awg_context.py @@ -54,7 +54,7 @@ def __init__(self): self.sequences = {} self.defined_channels = [1, 2, 3, 4] self.channels = {i: DummyChannel(self, i) for i in range(1, 5)} - self.set_running(False) + self.running = False def to_send(self, name, array): self.sequences[name] = array From 7454ec91e0a84b90485d1f1d6bd99de2d961b0c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9ouven=20Assouly?= Date: Fri, 27 Mar 2020 13:49:10 +0100 Subject: [PATCH 07/12] Update to set_running() --- exopy_hqc_legacy/pulses/contexts/awg_context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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, {} From b296a21bd0612a268b29ea97db68c3baed21bda4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9ouven=20Assouly?= Date: Fri, 27 Mar 2020 13:52:54 +0100 Subject: [PATCH 08/12] typo --- exopy_hqc_legacy/tasks/tasks/instr/run_awg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py b/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py index a7911f8c..33f7007a 100644 --- a/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py +++ b/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py @@ -57,4 +57,4 @@ def perform(self): else: logger = logging.getLogger(__name__) msg = "Unable to recognize {} running mode" - logger.warning(msg.format(switch)) + logger.warning(msg.format(self.switch)) From ba095f842a9a5da1474cd436ea4cddc58e2f6e78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9ouven=20Assouly?= Date: Fri, 27 Mar 2020 15:43:27 +0100 Subject: [PATCH 09/12] Fix tests --- tests/pulses/contexts/test_awg_context.py | 2 ++ 1 file changed, 2 insertions(+) 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. From 0a2593ca1a99013d9bb09d3ac5a759e5119b7bac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9ouven=20Assouly?= Date: Fri, 27 Mar 2020 19:07:09 +0100 Subject: [PATCH 10/12] Fixes and formatting --- .../instruments/drivers/visa/tektro_awg.py | 30 +++++++++---------- .../instruments/drivers/visa_tools.py | 4 +-- exopy_hqc_legacy/tasks/tasks/instr/run_awg.py | 2 +- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/exopy_hqc_legacy/instruments/drivers/visa/tektro_awg.py b/exopy_hqc_legacy/instruments/drivers/visa/tektro_awg.py index a7efc7f6..72bd9cc9 100644 --- a/exopy_hqc_legacy/instruments/drivers/visa/tektro_awg.py +++ b/exopy_hqc_legacy/instruments/drivers/visa/tektro_awg.py @@ -506,10 +506,10 @@ def send_load_awg_file(self, awg_data, filename='setup'): """ name_str = 'MMEMory:DATA "{}",'.format(filename+'.awg') - size_str = ('#' + str(len(str(len(awg_file)))) + str(len(awg_file))) + 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_file) + self._driver.write_raw(mes.encode('ASCII') + awg_data) self.write('AWGCONTROL:SRESTORE "{}"'.format(filename+'.awg')) @secure_communication() @@ -548,14 +548,14 @@ def ask_sequencer_pos(self): """Ask the current position index of the sequencer """ - return self.ask('AWGC:SEQ:POS?') + return self.query('AWGC:SEQ:POS?') @secure_communication() def force_jump_to(self, pos): """Make the sequencer jump to position pos """ - self.ask('SEQUENCE:JUMP:IMMEDIATE {}'.format(pos)) + self.query('SEQUENCE:JUMP:IMMEDIATE {}'.format(pos)) @secure_communication() def set_repeat(self, position, repeat): @@ -730,10 +730,8 @@ def set_running(self, value, delay=0.0): self.clear_output_buffer() if value in ('RUN', 1, 'True', True): self.write('AWGC:RUN:IMM') - self.write('AWGC:RST?') - time.sleep(delay) - values = self.read_values(format=2) - if values[0] 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', False): @@ -753,12 +751,12 @@ def running(self): """ self.clear_output_buffer() - run = self.ask_for_values("AWGC:RST?")[0] - if run == 0: + running = int(self.query("AWGC:RST?")) + if running == 0: return False - if run == 1 or run == 2: + if running == 1 or running == 2: return True - raise InstrIOError + raise InstrIOError(cleandoc('''Couldn't read the run mode''')) @instrument_property @secure_communication() @@ -811,14 +809,14 @@ def delete_all_waveforms(self): try: # Number of user defined waveforms # 25 is the number of default waveforms - nb_waveforms = int(self.ask("WLIST:SIZE?")) - 25 + nb_waveforms = int(self.query("WLIST:SIZE?")) - 25 except Exception: nb_waveforms = 0 - wait_time = 1+int(nb_waveforms/120) + wait_time = 1 + int(nb_waveforms / 120) self.write('WLIST:WAVEFORM:DELETE ALL') - logging.info('Waiting {}s for {} waveforms to be deleted'.format(wait_time, - nb_waveforms)) + 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): diff --git a/exopy_hqc_legacy/instruments/drivers/visa_tools.py b/exopy_hqc_legacy/instruments/drivers/visa_tools.py index 09b9a8f9..21b5b8b1 100644 --- a/exopy_hqc_legacy/instruments/drivers/visa_tools.py +++ b/exopy_hqc_legacy/instruments/drivers/visa_tools.py @@ -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/tasks/tasks/instr/run_awg.py b/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py index 33f7007a..87a8e71d 100644 --- a/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py +++ b/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py @@ -12,7 +12,7 @@ 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 From bcc966aac06a1de1115c865b80b7d95096fc02ae Mon Sep 17 00:00:00 2001 From: phymeso Date: Fri, 26 Feb 2021 10:34:22 +0100 Subject: [PATCH 11/12] remove broken validators --- exopy_hqc_legacy/tasks/tasks/instr/run_awg.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py b/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py index 87a8e71d..22edbde0 100644 --- a/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py +++ b/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py @@ -22,10 +22,9 @@ 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 = Float(0).tag(pref=True, - feval=validators.SkipLoop(types=numbers.Real)) + delay = Float(0).tag(pref=True) database_entries = set_default({'output': 0}) From e30fd47ff99d31d9dd6cc8e40e819ebfef9e3e9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9ouven=20Assouly?= Date: Fri, 26 Feb 2021 17:58:27 +0100 Subject: [PATCH 12/12] Add comment --- exopy_hqc_legacy/tasks/tasks/instr/run_awg.py | 1 + 1 file changed, 1 insertion(+) diff --git a/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py b/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py index 22edbde0..386c8c67 100644 --- a/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py +++ b/exopy_hqc_legacy/tasks/tasks/instr/run_awg.py @@ -24,6 +24,7 @@ class RunAWGTask(InstrumentTask): #: Switch to choose the AWG run mode: on or off 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})