diff --git a/@MyTlb6700/MyTlb6700.m b/@MyTlb6700/MyTlb6700.m index ac3f8d4..80291bf 100644 --- a/@MyTlb6700/MyTlb6700.m +++ b/@MyTlb6700/MyTlb6700.m @@ -1,304 +1,273 @@ % Class for communication with NewFocus TLB6700 tunable laser controllers % Needs UsbDllWrap.dll from Newport USB driver on Matlab path % Address field is ignored for this class. % Start instrument as MyTlb6700('','USBaddr'), where USBaddr is indicated % in the instrument menu. Example: MyTlb6700('','1') % % This class does not have 'Device' property but uses the communication % class UsbComm (which needs to be shared between multiple devices) to % mimic some of the standard MyInstrument operations. % % Operation of opening devices is time-consuming with Newport USB driver, % on the other hand multiple open devices do not interfere. So keep % the device open for the whole session classdef MyTlb6700 < MyScpiInstrument properties (SetAccess=protected, GetAccess=public) % Instance of Newport.USBComm.USB used for communication. - % Must be shared between the devices that use Newport USB driver + % Must be shared between the devices UsbComm end %% Constructor and destructor methods (Access=public) function this=MyTlb6700(interface, address, varargin) this@MyScpiInstrument(interface, address, varargin{:}); % Interface field is not used in this instrument, but is % assigned value for the purpose of information this.interface='usb'; % Convert address to number this.address=str2double(this.address); end end %% Protected functions methods (Access=protected) function createCommandList(this) % Commands for this class do not start from ':', as the % protocol does not fully comply with SCPI standard % Output wavelength, nm addCommand(this, 'wavelength','SENSe:WAVElength',... 'access','r','default',780,'fmt_spec','%e',... 'info','Output wavelength (nm)'); % Diode current, mA addCommand(this, 'current','SENSe:CURRent:DIODe',... 'access','r','default',1,'fmt_spec','%e',... 'info','Diode current (mA)'); % Diode temperature, C addCommand(this, 'temp_diode','SENSe:TEMPerature:DIODe',... 'access','r','default',10,'fmt_spec','%e',... 'info','Diode temperature (C)'); % Output power, mW addCommand(this, 'power','SENSe:POWer:DIODe',... 'access','r','default',1,'fmt_spec','%e',... 'info','Output power (mW)'); % Wavelength setpoint, nm addCommand(this, 'wavelength_sp','SOURce:WAVElength',... 'default',780,'fmt_spec','%e',... 'info','Wavelength setpoint (nm)'); % Constant power mode on/off addCommand(this, 'const_power','SOURce:CPOWer',... 'default',true,'fmt_spec','%b',... 'info','Constant power mode on/off'); % Power setpoint, mW addCommand(this, 'power_sp','SOURce:POWer:DIODe',... 'default',10,'fmt_spec','%e',... 'info','Power setpoint (mW)'); % Current setpoint, mA addCommand(this, 'current_sp','SOURce:CURRent:DIODe',... 'default',100,'fmt_spec','%e',... 'info','Current setpoint (mA)'); % Control mode local/remote addCommand(this, 'control_mode','SYSTem:MCONtrol',... 'val_list',{'LOC','REM'},... 'default','LOC','fmt_spec','%s',... 'info','Control local/remote'); % Output on/off addCommand(this, 'enable_output','OUTPut:STATe',... 'default',false,'fmt_spec','%b',... 'info','on/off'); % Wavelength track on/off addCommand(this, 'wavelength_track','OUTPut:TRACk',... 'default',true,'fmt_spec','%b',... 'info','on/off'); % Wavelength scan related commands % Scan start wavelength (nm) addCommand(this, 'scan_start_wl','SOURce:WAVE:START',... 'default',0,'fmt_spec','%e',... 'info','(nm)'); % Scan stop wavelength (nm) addCommand(this, 'scan_stop_wl','SOURce:WAVE:STOP',... 'default',0,'fmt_spec','%e',... 'info','(nm)'); % Scan speed (nm/s) addCommand(this, 'scan_speed','SOURce:WAVE:SLEW:FORWard',... 'default',0,'fmt_spec','%e',... 'info','(nm/s)'); % Maximum scan speed (nm/s) addCommand(this, 'scan_speed_max','SOURce:WAVE:MAXVEL',... 'access','r','default',0,'fmt_spec','%e',... 'info','(nm/s)'); end end %% Public functions including callbacks methods (Access=public) % NewFocus lasers no not support visa communication, thus need to % overload connectDevice, writeCommand and queryCommand methods function connectDevice(this) % In this case 'interface' property is ignored and 'address' is % the USB address, indicated in the controller menu - % Check if the usb driver is already present in the global - % workspace - name_exist = evalin('base',... - 'exist(''NewportUsbComm'', ''var'')'); - if ~name_exist - dll_path = which('UsbDllWrap.dll'); - if isempty(dll_path) - error(['UsbDllWrap.dll is not found. This library ',... - 'is a part of Newport USB driver and needs ',... - 'to be present on Matlab path.']) - end - - NetAsm=NET.addAssembly(dll_path); - % Create an instance of Newport.USBComm.USB class - Type=GetType(NetAsm.AssemblyHandle,'Newport.USBComm.USB'); - this.UsbComm = System.Activator.CreateInstance(Type); - - % Put the communication class in global workspace - NewportUsbComm.Usb = this.UsbComm; - assignin('base', 'NewportUsbComm', NewportUsbComm); - else - this.UsbComm=evalin('base', 'NewportUsbComm.Usb'); - end + % Get the unique instance of control class for Newport driver + this.UsbComm=MyNewportUsbComm.instance(); end function openDevice(this) - OpenDevices(this.UsbComm, hex2num('100A')); + OpenDevices(this.UsbComm.Usb, hex2num('100A')); end % Overload isopen method of MyInstrument function bool=isopen(this) % Could not find a better way to check if device is open other % than attempting communication with it - bool=false; - QueryData=System.Text.StringBuilder(64); try - stat = Query(this.UsbComm,this.address,'*IDN?',QueryData); - if stat==0 + str=query(this.UsbComm, this.address, '*IDN?'); + if ~isempty(str) bool=true; end catch + bool=false; end end function closeDevice(this) - CloseDevices(this.UsbComm); + disp(['A single device cannot be closed with Newport Usb Driver']) + % CloseDevices(this.UsbComm.Usb); end function stat_list=writeCommand(this, varargin) % Create auxiliary variable for device communication % Query is used for writing as the controller always returns % a status string that needs to be read out - QueryData=System.Text.StringBuilder(64); if ~isempty(varargin) n_cmd=length(varargin); stat_list=cell(n_cmd,1); % Send commands one by one as sending one query seems % to sometimes give errors if the string is very long for i=1:n_cmd cmd = [varargin{i},';']; - Query(this.UsbComm, this.address, cmd, QueryData); - stat_list{i} = char(ToString(QueryData)); + stat_list{i} = query(this.UsbComm, this.address, cmd); end end end function res_list=queryCommand(this, varargin) - % Create auxiliary variable for device communication - QueryData=System.Text.StringBuilder(64); if ~isempty(varargin) n_cmd=length(varargin); res_list=cell(n_cmd,1); % Query commands one by one as sending one query seems % to sometimes give errors if the string is very long for i=1:n_cmd cmd = [varargin{i},';']; - Query(this.UsbComm, this.address, cmd, QueryData); - res_list{i} = char(ToString(QueryData)); + res_list{i} = query(this.UsbComm, this.address, cmd); end else res_list={}; end end % readPropertyHedged and writePropertyHedged % are overloaded to not close the device function writePropertyHedged(this, varargin) openDevice(this); try writeProperty(this, varargin{:}); catch warning('Error while writing the properties:'); disp(varargin); end readProperty(this, 'all'); end function result=readPropertyHedged(this, varargin) openDevice(this); try result = readProperty(this, varargin{:}); catch warning('Error while reading the properties:'); disp(varargin); end end % Attempt communication and identification function [str, msg]=idn(this) - QueryData=System.Text.StringBuilder(64); try openDevice(this); - code=Query(this.UsbComm, this.address, '*IDN?', QueryData); - str=char(ToString(QueryData)); - if code~=0 + str=query(this.UsbComm, this.address, '*IDN?'); + if isempty(str) msg='Communication with controller failed'; else msg=''; end catch ErrorMessage str=''; msg=ErrorMessage.message; end this.idn_str=str; end function stat = setMaxOutPower(this) - QueryData=System.Text.StringBuilder(64); - openDevice(this); % Depending on if the laser in the constat power or current % mode, set value to max if this.const_power - Query(this.UsbComm, this.address, ... - 'SOURce:POWer:DIODe MAX;', QueryData); + stat = query(this.UsbComm, this.address, ... + 'SOURce:POWer:DIODe MAX;'); else - Query(this.UsbComm, this.address, ... - 'SOURce:CURRent:DIODe MAX;', QueryData); + stat = query(this.UsbComm, this.address, ... + 'SOURce:CURRent:DIODe MAX;'); end - stat = char(ToString(QueryData)); end % Returns minimum and maximum wavelengths of the laser. There does % not seem to be a more direct way of doing this with TLB6700 % other than setting and then reading the min/max values. function [wl_min, wl_max] = readMinMaxWavelength(this) tmp=this.scan_start_wl; openDevice(this); % Read min wavelength of the laser writeCommand(this, 'SOURce:WAVE:START MIN'); resp=queryCommand(this, 'SOURce:WAVE:START?'); wl_min=str2double(resp{1}); % Read max wavelength of the laser writeCommand(this, 'SOURce:WAVE:START MAX'); resp=queryCommand(this, 'SOURce:WAVE:START?'); wl_max=str2double(resp{1}); % Return scan start to its original value writeProperty(this, 'scan_start_wl', tmp); end %% Wavelength scan-related functions function configSingleScan(this) openDevice(this); % Configure: % Do not switch the laser off during the backward scan, % Perform a signle scan, % Return at maximum speed writeCommand(this,'SOURce:WAVE:SCANCFG 0',... 'SOURce:WAVE:DESSCANS 1',... 'SOURce:WAVE:SLEW:RETurn MAX'); end function startScan(this) openDevice(this); writeCommand(this,'OUTPut:SCAN:START'); end function stopScan(this) openDevice(this); writeCommand(this,'OUTPut:SCAN:STOP'); end end end diff --git a/Required packages/Singletone/license.txt b/Required packages/Singletone/license.txt new file mode 100644 index 0000000..f93aaa7 --- /dev/null +++ b/Required packages/Singletone/license.txt @@ -0,0 +1,29 @@ +https://www.mathworks.com/matlabcentral/fileexchange/24911-design-pattern-singleton-creational + +Copyright (c) 2016, The MathWorks, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * In all cases, the software is, and all modifications and derivatives + of the software shall be, licensed to you solely for use in conjunction + with MathWorks products and service offerings. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/Utility functions/@MyNewportUsbComm/MyNewportUsbComm.m b/Utility functions/@MyNewportUsbComm/MyNewportUsbComm.m index c80ca40..099833f 100644 --- a/Utility functions/@MyNewportUsbComm/MyNewportUsbComm.m +++ b/Utility functions/@MyNewportUsbComm/MyNewportUsbComm.m @@ -1,65 +1,67 @@ classdef MyNewportUsbComm < MySingletone properties (GetAccess=public, SetAccess=private) isbusy = false % driver in use QueryData % query buffer end properties (Access=public) Usb % Instance of Newport.USBComm.USB class end methods(Access=private) % The constructor of a singletone class should only be invoked from % the getInstance method. function this = MyNewportUsbComm() this.QueryData=System.Text.StringBuilder(64); loadLib(this); end end methods(Access=public) % Load dll function loadLib(this) dll_path = which('UsbDllWrap.dll'); if isempty(dll_path) error(['UsbDllWrap.dll is not found. This library ',... 'is a part of Newport USB driver and needs ',... 'to be present on Matlab path.']) end NetAsm=NET.addAssembly(dll_path); % Create an instance of Newport.USBComm.USB class Type=GetType(NetAsm.AssemblyHandle,'Newport.USBComm.USB'); - this.Usb = System.Activator.CreateInstance(Type); + this.Usb=System.Activator.CreateInstance(Type); end function str=query(this, addr, cmd) this.isbusy=true; % Send query using the QueryData buffer - stat = Query(this.Asm, addr, cmd, this.QueryData); + stat = Query(this.Usb, addr, cmd, this.QueryData); if stat==0 str = char(ToString(this.QueryData)); else str=''; warning('Query to Newport usb driver was unsuccessful.'); end this.isbusy=false; end end methods(Static) % Concrete implementation of the singletone constructor. - function this = getInstance() + function this = instance() persistent UniqueInstance if isempty(UniqueInstance)||(~isvalid(UniqueInstance)) this = MyNewportUsbComm(); UniqueInstance = this; + disp('creating new instance of NewportUsbComm') else this = UniqueInstance; + disp('returning existing instance of NewportUsbComm') end end end end diff --git a/Utility functions/@MySingletone/MySingletone.m b/Utility functions/@MySingletone/MySingletone.m index 5d734fa..12dc470 100644 --- a/Utility functions/@MySingletone/MySingletone.m +++ b/Utility functions/@MySingletone/MySingletone.m @@ -1,14 +1,13 @@ % This an abstract class used to derive subclasses only one instance of -% which is allowed to exist at a time. +% which can exist at a time. % See https://ch.mathworks.com/matlabcentral/fileexchange/24911-design-pattern-singleton-creational % for more information. -% Different to the reference above, the class constructor here is public classdef MySingletone < handle methods(Abstract, Static) - this = getInstance(); + this = instance(); end end