Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
en:python-ivi:writing-drivers [2013/07/22 04:39] alex |
en:python-ivi:writing-drivers [2013/07/22 06:17] (current) alex |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Writing New Python-IVI Drivers ====== | + | ====== Writing New Python IVI Drivers ====== |
Note: this page is under construction | Note: this page is under construction | ||
Line 17: | Line 17: | ||
Test the interface and identity query by instantiating your driver and connecting to the instrument by running something like this in ipython: | Test the interface and identity query by instantiating your driver and connecting to the instrument by running something like this in ipython: | ||
- | <code> | + | <code python> |
import ivi | import ivi | ||
mso = ivi.agilent.agilentMSO7104A("TCPIP0::192.168.1.104::INSTR") | mso = ivi.agilent.agilentMSO7104A("TCPIP0::192.168.1.104::INSTR") | ||
Line 28: | Line 28: | ||
Finally, you need to go write python code for all of the functions that the instrument supports. Take a look at some ''_get''/''_set'' pairs for some of the existing drivers to see the format. It's rather straightforward but quite tedious. | Finally, you need to go write python code for all of the functions that the instrument supports. Take a look at some ''_get''/''_set'' pairs for some of the existing drivers to see the format. It's rather straightforward but quite tedious. | ||
+ | |||
+ | ===== Driver Template ===== | ||
+ | |||
+ | This is a sample template driver that incorporates all of the major components. It is drawn from the Agilent 7000 series driver. | ||
+ | |||
+ | <code python> | ||
+ | """ | ||
+ | |||
+ | Python Interchangeable Virtual Instrument Library | ||
+ | |||
+ | Copyright (c) 2012 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. | ||
+ | |||
+ | """ | ||
+ | |||
+ | import struct | ||
+ | |||
+ | from .. import ivi | ||
+ | from .. import scope | ||
+ | |||
+ | AcquisitionTypeMapping = { | ||
+ | 'normal': 'norm', | ||
+ | 'peak_detect': 'peak', | ||
+ | 'high_resolution': 'hres', | ||
+ | 'average': 'aver'} | ||
+ | # more instrument-specific sets and mappings | ||
+ | |||
+ | class agilent7000(ivi.Driver, scope.Base, scope.TVTrigger, | ||
+ | scope.GlitchTrigger, scope.WidthTrigger, scope.AcLineTrigger, | ||
+ | scope.WaveformMeasurement, scope.MinMaxWaveform, | ||
+ | scope.ContinuousAcquisition, scope.AverageAcquisition, | ||
+ | scope.SampleMode, scope.AutoSetup): | ||
+ | "Agilent InfiniiVision 7000 series IVI oscilloscope driver" | ||
+ | | ||
+ | def __init__(self, *args, **kwargs): | ||
+ | self._analog_channel_name = list() | ||
+ | self._analog_channel_count = 4 | ||
+ | self._digital_channel_name = list() | ||
+ | self._digital_channel_count = 16 | ||
+ | self._channel_label = list() | ||
+ | # other per-channel instrument-specific variables that are | ||
+ | # referenced in _init_channels | ||
+ | | ||
+ | super(agilent7000, self).__init__(*args, **kwargs) | ||
+ | | ||
+ | self._instrument_id = 'AGILENT TECHNOLOGIES' | ||
+ | self._analog_channel_name = list() | ||
+ | self._analog_channel_count = 4 | ||
+ | self._digital_channel_name = list() | ||
+ | self._digital_channel_count = 16 | ||
+ | self._channel_count = 20 | ||
+ | self._bandwidth = 1e9 | ||
+ | # initialize other instrument-specific variables | ||
+ | | ||
+ | self._identity_description = "Agilent InfiniiVision 7000 series IVI oscilloscope driver" | ||
+ | self._identity_identifier = "" | ||
+ | self._identity_revision = "" | ||
+ | self._identity_vendor = "" | ||
+ | self._identity_instrument_manufacturer = "Agilent Technologies" | ||
+ | self._identity_instrument_model = "" | ||
+ | self._identity_instrument_firmware_revision = "" | ||
+ | self._identity_specification_major_version = 4 | ||
+ | self._identity_specification_minor_version = 1 | ||
+ | self._identity_supported_instrument_models =['DSO7012A','DSO7014A','DSO7032A', | ||
+ | 'DSO7034A','DSO7052A','DSO7054A','DSO7104A','MSO7012A','MSO7014A','MSO7032A', | ||
+ | 'MSO7034A','MSO7052A','MSO7054A','MSO7104A','DSO7012B','DSO7014B','DSO7032B', | ||
+ | 'DSO7034B','DSO7052B','DSO7054B','DSO7104B','MSO7012B','MSO7014B','MSO7032B', | ||
+ | 'MSO7034B','MSO7052B','MSO7054B','MSO7104B'] | ||
+ | | ||
+ | self.channels._add_property('label', | ||
+ | self._get_channel_label, | ||
+ | self._set_channel_label) | ||
+ | # other instrument specific properties | ||
+ | | ||
+ | self._init_channels() | ||
+ | | ||
+ | def initialize(self, resource = None, id_query = False, reset = False, **keywargs): | ||
+ | "Opens an I/O session to the instrument." | ||
+ | | ||
+ | self._channel_count = self._analog_channel_count + self._digital_channel_count | ||
+ | | ||
+ | super(agilent7000, self).initialize(resource, id_query, reset, **keywargs) | ||
+ | | ||
+ | # interface clear | ||
+ | if not self._driver_operation_simulate: | ||
+ | self._clear() | ||
+ | | ||
+ | # check ID | ||
+ | if id_query and not self._driver_operation_simulate: | ||
+ | id = self.identity.instrument_model | ||
+ | id_check = self._instrument_id | ||
+ | id_short = id[:len(id_check)] | ||
+ | if id_short != id_check: | ||
+ | raise Exception("Instrument ID mismatch, expecting %s, got %s", id_check, id_short) | ||
+ | | ||
+ | # reset | ||
+ | if reset: | ||
+ | self.utility.reset() | ||
+ | | ||
+ | | ||
+ | def _load_id_string(self): | ||
+ | if self._driver_operation_simulate: | ||
+ | self._identity_instrument_manufacturer = "Not available while simulating" | ||
+ | self._identity_instrument_model = "Not available while simulating" | ||
+ | self._identity_instrument_firmware_revision = "Not available while simulating" | ||
+ | else: | ||
+ | lst = self._ask("*IDN?").split(",") | ||
+ | self._identity_instrument_manufacturer = lst[0] | ||
+ | self._identity_instrument_model = lst[1] | ||
+ | self._identity_instrument_firmware_revision = lst[3] | ||
+ | self._set_cache_valid(True, 'identity_instrument_manufacturer') | ||
+ | self._set_cache_valid(True, 'identity_instrument_model') | ||
+ | self._set_cache_valid(True, 'identity_instrument_firmware_revision') | ||
+ | | ||
+ | def _get_identity_instrument_manufacturer(self): | ||
+ | if self._get_cache_valid(): | ||
+ | return self._identity_instrument_manufacturer | ||
+ | self._load_id_string() | ||
+ | return self._identity_instrument_manufacturer | ||
+ | | ||
+ | def _get_identity_instrument_model(self): | ||
+ | if self._get_cache_valid(): | ||
+ | return self._identity_instrument_model | ||
+ | self._load_id_string() | ||
+ | return self._identity_instrument_model | ||
+ | | ||
+ | def _get_identity_instrument_firmware_revision(self): | ||
+ | if self._get_cache_valid(): | ||
+ | return self._identity_instrument_firmware_revision | ||
+ | self._load_id_string() | ||
+ | return self._identity_instrument_firmware_revision | ||
+ | | ||
+ | def _utility_disable(self): | ||
+ | pass | ||
+ | | ||
+ | def _utility_error_query(self): | ||
+ | error_code = 0 | ||
+ | error_message = "No error" | ||
+ | if not self._driver_operation_simulate: | ||
+ | error_code, error_message = self._ask(":system:error?").split(',') | ||
+ | error_code = int(error_code) | ||
+ | error_message = error_message.strip(' "') | ||
+ | return (error_code, error_message) | ||
+ | | ||
+ | def _utility_lock_object(self): | ||
+ | pass | ||
+ | | ||
+ | def _utility_reset(self): | ||
+ | if not self._driver_operation_simulate: | ||
+ | self._write("*RST") | ||
+ | self.driver_operation.invalidate_all_attributes() | ||
+ | | ||
+ | def _utility_reset_with_defaults(self): | ||
+ | self._utility_reset() | ||
+ | | ||
+ | def _utility_self_test(self): | ||
+ | code = 0 | ||
+ | message = "Self test passed" | ||
+ | if not self._driver_operation_simulate: | ||
+ | code = int(self._ask("*TST?")) | ||
+ | if code != 0: | ||
+ | message = "Self test failed" | ||
+ | return (code, message) | ||
+ | | ||
+ | def _utility_unlock_object(self): | ||
+ | pass | ||
+ | | ||
+ | def _init_channels(self): | ||
+ | super(agilent7000, self)._init_channels() | ||
+ | | ||
+ | self._channel_name = list() | ||
+ | self._channel_label = list() | ||
+ | # init per-channel instrument-specific variables | ||
+ | | ||
+ | for i in range(self._channel_count): | ||
+ | self._channel_name.append("channel%d" % (i+1)) | ||
+ | self._channel_label.append("%d" % (i+1)) | ||
+ | # init per-channel instrument-specific variables | ||
+ | | ||
+ | self.channels._set_list(self._channel_name) | ||
+ | | ||
+ | def _get_acquisition_start_time(self): | ||
+ | pos = 0 | ||
+ | if not self._driver_operation_simulate and not self._get_cache_valid(): | ||
+ | pos = float(self._ask(":timebase:position?")) | ||
+ | self._set_cache_valid() | ||
+ | self._acquisition_start_time = pos - self._get_acquisition_time_per_record() * 5 / 10 | ||
+ | return self._acquisition_start_time | ||
+ | | ||
+ | def _set_acquisition_start_time(self, value): | ||
+ | value = float(value) | ||
+ | value = value + self._get_acquisition_time_per_record() * 5 / 10 | ||
+ | if not self._driver_operation_simulate: | ||
+ | self._write(":timebase:position %e" % value) | ||
+ | self._acquisition_start_time = value | ||
+ | self._set_cache_valid() | ||
+ | | ||
+ | # more definitions | ||
+ | | ||
+ | </code> | ||
+ | |||
+ |