diff --git a/ivi/agilent/__init__.py b/ivi/agilent/__init__.py index aff58320..0544ab3b 100644 --- a/ivi/agilent/__init__.py +++ b/ivi/agilent/__init__.py @@ -153,7 +153,8 @@ from .agilentMSOX92504A import agilentMSOX92504A from .agilentMSOX92804A import agilentMSOX92804A from .agilentMSOX93204A import agilentMSOX93204A - +# Infinium S series +from .agilentDSOS204A import agilentDSOS204A # Spectrum Analyzers # 859xA series from .agilent8590A import agilent8590A diff --git a/ivi/agilent/agilent6000.py b/ivi/agilent/agilent6000.py index c6110db5..9fafefe0 100644 --- a/ivi/agilent/agilent6000.py +++ b/ivi/agilent/agilent6000.py @@ -23,9 +23,15 @@ THE SOFTWARE. """ - +import time from .agilentBaseInfiniiVision import * +CaptureMode = { + 'maximum': 'maximum', + 'normal': 'normal', + 'raw': 'raw'} + + class agilent6000(agilentBaseInfiniiVision): "Agilent InfiniiVision 6000 series IVI oscilloscope driver" @@ -42,10 +48,168 @@ def __init__(self, *args, **kwargs): self._bandwidth = 1e9 self._identity_description = "Agilent InfiniiVision 6000 series IVI oscilloscope driver" - self._identity_supported_instrument_models = ['DSO6012A','DSO6014A','DSO6032A', - 'DSO6034A','DSO6052A','DSO6054A','DSO6102A','DSO6104A','MSO6012A','MSO6014A', - 'MSO6032A','MSO6034A','MSO6052A','MSO6054A','MSO6102A','MSO6104A'] + self._identity_supported_instrument_models = ['DSO6012A', 'DSO6014A', 'DSO6032A', + 'DSO6034A', 'DSO6052A', 'DSO6054A', 'DSO6102A', 'DSO6104A', 'MSO6012A', 'MSO6014A', + 'MSO6032A', 'MSO6034A', 'MSO6052A', 'MSO6054A', 'MSO6102A', 'MSO6104A'] self._init_channels() - - + + self._add_property('acquisition.capture_mode', + self._get_acquisition_capture_mode, + self._set_acquisition_capture_mode, + None, + ivi.Doc(""" + Choose between the different capture modes on the scope, normal, raw and maximum, raises + and exception for other modes selected. Using raw capture mode allows all points to be pulled back + """)) + self._add_method('channels[].measurement.fetch_waveform_single', + self._measurement_fetch_waveform_single, + ivi.Doc(""" TODO:add doc + """)) + self._add_method('measurement.initiate_single()', self._measurement_single_shot_initiate, + ivi.Doc(""" TODO: Add doc + """)) + + def _set_acquisition_number_of_points_minimum(self, value): + value = int(value) + self._acquisition_number_of_points_minimum = value + if not self._driver_operation_simulate: + self._write(":waveform:points %d" % value) + self._set_cache_valid() + self._set_cache_valid(False, 'acquisition_record_length') + + def _set_acquisition_capture_mode(self,value): + if value not in CaptureMode: + raise ivi.ValueNotSupportedException() + if not self._driver_operation_simulate: + self._write(":stop") + self._write(":acquire:count 1") + self._write(":waveform:points:mode %s" % value) + self._set_cache_valid() + self._set_cache_valid(False, 'acquisition_record_length') + + def _get_acquisition_capture_mode(self): + if not self._driver_operation_simulate: + return self._ask(':waveform:points:mode?') + + def _measurement_single_shot_initiate(self): + self._write(':stop') + self._write(':single') + while True: + if '+1' in self._ask(':AER?'): + break + time.sleep(0.001) + + def _measurement_fetch_waveform_single(self, index): + index = ivi.get_index(self._channel_name, index) + + if self._driver_operation_simulate: + return list() + while True: + if int(self._ask(':OPERegister:CONDition?')) & 8 !=8: + break + time.sleep(0.001) + self._write(":waveform:byteorder msbfirst") + self._write(":waveform:unsigned 1") + self._write(":waveform:format word") + self._write(":waveform:source %s" % self._channel_name[index]) + + # Read preamble + + pre = self._ask(":waveform:preamble?").split(',') + + format = int(pre[0]) + type = int(pre[1]) + points = int(pre[2]) + count = int(pre[3]) + xincrement = float(pre[4]) + xorigin = float(pre[5]) + xreference = int(float(pre[6])) + yincrement = float(pre[7]) + yorigin = float(pre[8]) + yreference = int(float(pre[9])) + + if type == 1: + raise scope.InvalidAcquisitionTypeException() + + if format != 1: + raise UnexpectedResponseException() + + self._write(":waveform:data?") + + # Read waveform data + raw_data = raw_data = self._read_ieee_block() + + # Split out points and convert to time and voltage pairs + + data = list() + for i in range(points): + x = ((i - xreference) * xincrement) + xorigin + + yval = struct.unpack(">H", raw_data[i*2:i*2+2])[0] + + if yval == 0: + # hole value + y = float('nan') + else: + y = ((yval - yreference) * yincrement) + yorigin + + data.append((x, y)) + + return data + + + def _measurement_fetch_waveform(self, index): + index = ivi.get_index(self._channel_name, index) + + if self._driver_operation_simulate: + return list() + + self._write(":waveform:byteorder msbfirst") + self._write(":waveform:unsigned 1") + self._write(":waveform:format word") + self._write(":waveform:source %s" % self._channel_name[index]) + + # Read preamble + + pre = self._ask(":waveform:preamble?").split(',') + + format = int(pre[0]) + type = int(pre[1]) + points = int(pre[2]) + count = int(pre[3]) + xincrement = float(pre[4]) + xorigin = float(pre[5]) + xreference = int(float(pre[6])) + yincrement = float(pre[7]) + yorigin = float(pre[8]) + yreference = int(float(pre[9])) + + if type == 1: + raise scope.InvalidAcquisitionTypeException() + + if format != 1: + raise UnexpectedResponseException() + + self._write(":waveform:data?") + + # Read waveform data + raw_data = raw_data = self._read_ieee_block() + + # Split out points and convert to time and voltage pairs + + data = list() + for i in range(points): + x = ((i - xreference) * xincrement) + xorigin + + yval = struct.unpack(">H", raw_data[i*2:i*2+2])[0] + + if yval == 0: + # hole value + y = float('nan') + else: + y = ((yval - yreference) * yincrement) + yorigin + + data.append((x, y)) + + return data \ No newline at end of file diff --git a/ivi/agilent/agilentDSOS204A.py b/ivi/agilent/agilentDSOS204A.py new file mode 100644 index 00000000..625b4c4a --- /dev/null +++ b/ivi/agilent/agilentDSOS204A.py @@ -0,0 +1,44 @@ +""" + +Python Interchangeable Virtual Instrument Library + +Copyright (c) 2012-2014 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +""" + +from .agilents import * + +class agilentDSOS204A(agilents): + "KeySight InfiniiVision DSOS204A IVI oscilloscope driver" + + def __init__(self, *args, **kwargs): + self.__dict__.setdefault('_instrument_id', 'DSOS204A') + + super(agilentDSOS204A, self).__init__(*args, **kwargs) + + self._analog_channel_count = 4 + self._digital_channel_count = 0 + self._channel_count = self._analog_channel_count + self._digital_channel_count + self._bandwidth = 2e9 + + self._init_channels() + + \ No newline at end of file diff --git a/ivi/agilent/agilents.py b/ivi/agilent/agilents.py new file mode 100644 index 00000000..819a688f --- /dev/null +++ b/ivi/agilent/agilents.py @@ -0,0 +1,380 @@ +""" + +Python Interchangeable Virtual Instrument Library + +Copyright (c) 2012-2014 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +""" + +from .agilentBaseInfiniium import * + +AcquisitionModeMapping = { + 'etim': ('normal', 'equivalent_time'), + 'rtim': ('normal', 'real_time'), + 'pdet': ('peak_detect', 'real_time'), + 'hres': ('high_resolution', 'real_time'), + 'segm': ('normal', 'segmented'), + 'segp': ('peak_detect', 'segmented'), + 'segh': ('high_resolution', 'segmented') +} +AcquisitionType = set(['normal', 'peak_detect', 'high_resolution']) +VerticalCoupling = set(['dc']) +ScreenshotImageFormatMapping = { + 'tif': 'tif', + 'tiff': 'tif', + 'bmp': 'bmp', + 'bmp24': 'bmp', + 'png': 'png', + 'png24': 'png', + 'jpg': 'jpg', + 'jpeg': 'jpg', + 'gif': 'gif'} +SampleMode = set(['real_time', 'equivalent_time', 'segmented']) + +class agilents(agilentBaseInfiniium): + "Agilent Infiniium S series IVI oscilloscope driver" + + def __init__(self, *args, **kwargs): + self.__dict__.setdefault('_instrument_id', '') + self._analog_channel_name = list() + self._analog_channel_count = 4 + self._digital_channel_name = list() + self._digital_channel_count = 16 + self._channel_count = self._analog_channel_count + self._digital_channel_count + self._channel_common_mode = list() + self._channel_differential = list() + self._channel_differential_skew = list() + self._channel_display_auto = list() + self._channel_display_offset = list() + self._channel_display_range = list() + self._channel_display_scale = list() + + super(agilents, self).__init__(*args, **kwargs) + + self._analog_channel_name = list() + self._analog_channel_count = 4 + self._digital_channel_name = list() + self._digital_channel_count = 16 + self._channel_count = self._analog_channel_count + self._digital_channel_count + self._bandwidth = 0.5e9 + + self._horizontal_divisions = 10 + self._vertical_divisions = 8 + + self._display_color_grade = False + + self._identity_description = "KeySight Infiniium S series IVI oscilloscope driver" + self._identity_supported_instrument_models = ['DSOS054A','DSOS104A','DSOS204A','DSOS254A','DSOS404A','DSOS604A', + 'DSOS804A','MSOS054A','MSOS104A','MSOS204A','MSOS254A','MSOS404A','MSOS604A','MSOS804A'] + + self._add_property('channels[].common_mode', + self._get_channel_common_mode, + self._set_channel_common_mode, + None, + ivi.Doc(""" + Turns on/off common mode for the channel. Channels 2 and 4 may form a + common mode channel and channels 1 and 3 may form a common mode channel. + """)) + self._add_property('channels[].differential', + self._get_channel_differential, + self._set_channel_differential, + None, + ivi.Doc(""" + Turns on/off differential mode for the channel. Channels 2 and 4 may form + a differential channel and channels 1 and 3 may form a differential + channel. + """)) + self._add_property('channels[].differential_skew', + self._get_channel_differential_skew, + self._set_channel_differential_skew, + None, + ivi.Doc(""" + Specifies the skew that is applied to the differential or common mode pair + of channels. Units are seconds. + """)) + self._add_property('channels[].display_auto', + self._get_channel_display_auto, + self._set_channel_display_auto, + None, + ivi.Doc(""" + Sets the differential and common mode display scale and offset to track + the acquisition scale and offset. + """)) + self._add_property('channels[].display_offset', + self._get_channel_display_offset, + self._set_channel_display_offset, + None, + ivi.Doc(""" + Sets the displayed offset of the selected channel. Setting this parameter + disables display_auto. Units are volts. + """)) + self._add_property('channels[].display_range', + self._get_channel_display_range, + self._set_channel_display_range, + None, + ivi.Doc(""" + Sets the full scale vertical range of the selected channel. Setting this + parameter disables display_auto. Units are volts. + """)) + self._add_property('channels[].display_scale', + self._get_channel_display_scale, + self._set_channel_display_scale, + None, + ivi.Doc(""" + Sets the displayed scale of the selected channel per division. Setting + this parameter disables display_auto. Units are volts. + """)) + + self._init_channels() + + + def _utility_error_query(self): + error_code = 0 + error_message = "No error" + if not self._driver_operation_simulate: + error_code = self._ask(":system:error?") + error_code = int(error_code) + if error_code != 0: + error_message = "Unknown" + return (error_code, error_message) + + def _init_channels(self): + try: + super(agilents, self)._init_channels() + except AttributeError: + pass + + self._channel_common_mode = list() + self._channel_differential = list() + self._channel_differential_skew = list() + self._channel_display_auto = list() + self._channel_display_offset = list() + self._channel_display_range = list() + self._channel_display_scale = list() + + for i in range(self._analog_channel_count): + self._channel_common_mode.append(False) + self._channel_differential.append(False) + self._channel_differential_skew.append(0) + self._channel_display_auto.append(True) + self._channel_display_offset.append(0.0) + self._channel_display_range.append(1.0) + self._channel_display_scale.append(0.1) + + + def _display_fetch_screenshot(self, format='png', invert=False): + if self._driver_operation_simulate: + return b'' + + if format not in ScreenshotImageFormatMapping: + raise ivi.ValueNotSupportedException() + + format = ScreenshotImageFormatMapping[format] + + self._write(":display:data? %s, screen, on, %s" % (format, 'invert' if invert else 'normal')) + + return self._read_ieee_block() + + def _get_channel_common_mode(self, index): + index = ivi.get_index(self._analog_channel_name, index) + if not self._driver_operation_simulate and not self._get_cache_valid(index=index): + self._channel_common_mode[index] = bool(int(self._ask(":%s:commonmode?" % self._channel_name[index]))) + self._set_cache_valid(index=index) + return self._channel_common_mode[index] + + def _set_channel_common_mode(self, index, value): + index = ivi.get_index(self._analog_channel_name, index) + value = bool(value) + if not self._driver_operation_simulate: + self._write(":%s:commonmode %d" % (self._channel_name[index], int(value))) + self._channel_common_mode[index] = value + self._set_cache_valid(index=index) + + def _get_channel_differential(self, index): + index = ivi.get_index(self._analog_channel_name, index) + if not self._driver_operation_simulate and not self._get_cache_valid(index=index): + self._channel_differential[index] = bool(int(self._ask(":%s:differential?" % self._channel_name[index]))) + self._set_cache_valid(index=index) + return self._channel_differential[index] + + def _set_channel_differential(self, index, value): + index = ivi.get_index(self._analog_channel_name, index) + value = bool(value) + if not self._driver_operation_simulate: + self._write(":%s:differential %d" % (self._channel_name[index], int(value))) + self._channel_differential[index] = value + self._set_cache_valid(index=index) + + def _get_channel_differential_skew(self, index): + index = ivi.get_index(self._analog_channel_name, index) + if not self._driver_operation_simulate and not self._get_cache_valid(index=index): + self._channel_differential_skew[index] = float(self._ask(":%s:differential:skew?" % self._channel_name[index])) + self._set_cache_valid(index=index) + return self._channel_differential_skew[index] + + def _set_channel_differential_skew(self, index, value): + index = ivi.get_index(self._analog_channel_name, index) + value = float(value) + if not self._driver_operation_simulate: + self._write(":%s:differential:skew %e" % (self._channel_name[index], value)) + self._channel_differential_skew[index] = value + self._set_cache_valid(index=index) + + def _get_channel_display_auto(self, index): + index = ivi.get_index(self._analog_channel_name, index) + if not self._driver_operation_simulate and not self._get_cache_valid(index=index): + self._channel_display_auto[index] = bool(int(self._ask(":%s:display:auto?" % self._channel_name[index]))) + self._set_cache_valid(index=index) + return self._channel_display_auto[index] + + def _set_channel_display_auto(self, index, value): + index = ivi.get_index(self._analog_channel_name, index) + value = bool(value) + if not self._driver_operation_simulate: + self._write(":%s:display:auto %d" % (self._channel_name[index], int(value))) + self._channel_display_auto[index] = value + self._set_cache_valid(index=index) + + def _get_channel_display_offset(self, index): + index = ivi.get_index(self._analog_channel_name, index) + if not self._driver_operation_simulate and not self._get_cache_valid(index=index): + self._channel_display_offset[index] = float(self._ask(":%s:display:offset?" % self._channel_name[index])) + self._set_cache_valid(index=index) + return self._channel_display_offset[index] + + def _set_channel_display_offset(self, index, value): + index = ivi.get_index(self._analog_channel_name, index) + value = float(value) + if not self._driver_operation_simulate: + self._write(":%s:display:offset %e" % (self._channel_name[index], value)) + self._channel_display_offset[index] = value + self._set_cache_valid(index=index) + + def _get_channel_display_range(self, index): + index = ivi.get_index(self._analog_channel_name, index) + if not self._driver_operation_simulate and not self._get_cache_valid(index=index): + self._channel_display_range[index] = float(self._ask(":%s:display:range?" % self._channel_name[index])) + self._set_cache_valid(index=index) + return self._channel_display_range[index] + + def _set_channel_display_range(self, index, value): + index = ivi.get_index(self._analog_channel_name, index) + value = float(value) + if not self._driver_operation_simulate: + self._write(":%s:display:range %e" % (self._channel_name[index], value)) + self._channel_display_range[index] = value + self._set_cache_valid(index=index) + + def _get_channel_display_scale(self, index): + index = ivi.get_index(self._analog_channel_name, index) + if not self._driver_operation_simulate and not self._get_cache_valid(index=index): + self._channel_display_scale[index] = float(self._ask(":%s:display:scale?" % self._channel_name[index])) + self._set_cache_valid(index=index) + return self._channel_display_scale[index] + + def _set_channel_display_scale(self, index, value): + index = ivi.get_index(self._analog_channel_name, index) + value = float(value) + if not self._driver_operation_simulate: + self._write(":%s:display:scale %e" % (self._channel_name[index], value)) + self._channel_display_scale[index] = value + self._set_cache_valid(index=index) + + def _measurement_fetch_waveform(self, index): + index = ivi.get_index(self._channel_name, index) + + if self._driver_operation_simulate: + return list() + + self._write(":waveform:byteorder msbfirst") + self._write(":waveform:format word") + self._write(":waveform:streaming on") + self._write(":waveform:source %s" % self._channel_name[index]) + + # Read preamble + + pre = self._ask(":waveform:preamble?").split(',') + + format = int(pre[0]) + type = int(pre[1]) + points = int(pre[2]) + count = int(pre[3]) + xincrement = float(pre[4]) + xorigin = float(pre[5]) + xreference = int(float(pre[6])) + yincrement = float(pre[7]) + yorigin = float(pre[8]) + yreference = int(float(pre[9])) + + if type == 1: + raise scope.InvalidAcquisitionTypeException() + + if format != 2: + raise UnexpectedResponseException() + + self._write(":waveform:data?") + + # Read waveform data + raw_data = self._read_ieee_block() + + # Split out points and convert to time and voltage pairs + + data = list() + for i in range(points): + x = ((i - xreference) * xincrement) + xorigin + + yval = struct.unpack(">h", raw_data[i*2:i*2+2])[0] + + if yval == 31232: + # hole value + y = float('nan') + else: + y = ((yval - yreference) * yincrement) + yorigin + + data.append((x, y)) + + return data + + def _measurement_read_waveform(self, index, maximum_time): + return self._measurement_fetch_waveform(index) + + def _measurement_initiate(self): + if not self._driver_operation_simulate: + self._write(":acquire:complete 100") + self._write(":digitize") + self._set_cache_valid(False, 'trigger_continuous') + + def _set_working_directory(self,value): + if not self._driver_operation_simulate: + self._write(":DISK:CDIRECTORY %s" % '\"'+value+'\"') + + def _get_pwd(self): + if not self._driver_operation_simulate: + return self._ask(":DISK:PWD?") + + def _save_waveform(self,filename,source,filtype='BIN',header="ON"): + if not self._driver_operation_simulate: + self._write(":DISK:SAVE:WAVEFORM %s" % 'CHANnel'+str(source)+',\"'+filename+'\",'+filtype+','+header) + + def _set_save_waveform_all(self): + if not self._driver_operation_simulate: + self._write(":DISK:SEGMented ALL") +