diff --git a/@MyAppColors/MyAppColors.m b/@MyAppColors/MyAppColors.m index 9cba18d..59eb103 100644 --- a/@MyAppColors/MyAppColors.m +++ b/@MyAppColors/MyAppColors.m @@ -1,156 +1,150 @@ % Set of colors indended to introduce some uniformity in GUIs classdef (Abstract) MyAppColors methods (Static) %% Predefined colors % Colors are represented by rgb triplets returned by static methods function rgb = warning() rgb = [0.93, 0.69, 0.13]; % Orange end function rgb = error() rgb = [1,0,0]; % Red end % Labview-style lamp indicator colors function rgb = lampOn() rgb = [0,1,0]; % Bright green end function rgb = lampOff() rgb = [0,0.4,0]; % Dark green end % Recolor app according to a new color scheme function applyScheme(Obj, scheme) persistent init_default default_main_color ... default_label_text_color default_edit_text_color ... default_edit_field_color default_axes_label_color if ~exist('scheme', 'var') scheme = 'default'; end switch lower(scheme) case 'dark' main_color = [0.18, 0.19,0.57]; label_text_color = [1,1,1]; edit_text_color = [0,0,0]; edit_field_color = [1,1,1]; axes_label_color = [0.9,0.9,1]; case 'bright' main_color = [1,1,1]; label_text_color = [0,0,0.4]; edit_text_color = [0,0,0.]; edit_field_color = [1,1,1]; axes_label_color = [0,0,0]; case 'default' if isempty(init_default) % Create invisible components and read their % colors Uf = uifigure('Visible', false); Ef = uieditfield(Uf); Lbl = uilabel(Uf); Ax = axes(Uf); default_main_color = Uf.Color; default_label_text_color = Lbl.FontColor; default_edit_text_color = Ef.FontColor; default_edit_field_color = Ef.BackgroundColor; default_axes_label_color = Ax.XColor; delete(Uf); init_default = false; end main_color = default_main_color; label_text_color = default_label_text_color; edit_text_color = default_edit_text_color; edit_field_color = default_edit_field_color; axes_label_color = default_axes_label_color; otherwise error('Unknown scheme %s', scheme) end if isa(Obj, 'matlab.apps.AppBase') Fig = findFigure(Obj); MyAppColors.applyScheme(Fig, scheme); return end if ~isprop(Obj, 'Type') return end switch Obj.Type case 'figure' Obj.Color = main_color; case 'uitabgroup' % Nothing to do case 'uitab' Obj.ForegroundColor = edit_text_color; Obj.BackgroundColor = main_color; case 'uibutton' Obj.FontColor = label_text_color; Obj.BackgroundColor = main_color; case 'uistatebutton' Obj.FontColor = label_text_color; Obj.BackgroundColor = main_color; case 'uidropdown' Obj.FontColor = label_text_color; Obj.BackgroundColor = main_color; - case 'uieditfield' + case {'uieditfield', 'uispinner', 'uitextarea', 'uilistbox'} Obj.FontColor = edit_text_color; Obj.BackgroundColor = edit_field_color; case {'uilabel', 'uicheckbox', 'uiradiobutton'} Obj.FontColor = label_text_color; - case 'uilistbox' - Obj.FontColor = edit_text_color; - Obj.BackgroundColor = edit_field_color; - case 'uitextarea' - Obj.FontColor = edit_text_color; - Obj.BackgroundColor = edit_field_color; case {'uipanel', 'uibuttongroup'} Obj.ForegroundColor = label_text_color; Obj.BackgroundColor = main_color; case 'axes' try % This property is only present in uiaxes Obj.BackgroundColor = main_color; catch end Obj.XColor = axes_label_color; Obj.YColor = axes_label_color; Obj.GridColor = [0.15, 0.15, 0.15]; Obj.MinorGridColor = [0.15, 0.15, 0.15]; case 'uimenu' Obj.ForegroundColor = edit_text_color; case 'uicontrol' % The following switch case is for programmatically % created components switch Obj.Style case {'text', 'pushbutton', 'togglebutton'} Obj.ForegroundColor = label_text_color; Obj.BackgroundColor = main_color; case 'popupmenu' Obj.ForegroundColor = edit_text_color; Obj.BackgroundColor = edit_field_color; end end if isprop(Obj, 'Children') % Recolor children for i = 1:length(Obj.Children) MyAppColors.applyScheme(Obj.Children(i), scheme); end end end end end diff --git a/@MyNewportUsbComm/MyNewportUsbComm.m b/@MyNewportUsbComm/MyNewportUsbComm.m index 97dd250..8f87a29 100644 --- a/@MyNewportUsbComm/MyNewportUsbComm.m +++ b/@MyNewportUsbComm/MyNewportUsbComm.m @@ -1,77 +1,77 @@ classdef MyNewportUsbComm < MySingleton 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 singleton class should only be invoked from % the instance 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); end function str = query(this, addr, cmd) % Check if the driver is already being used by another process. % A race condition with various strange consequences is % potentially possible if it is. if this.isbusy warning('NewportUsbComm is already in use') end this.isbusy = true; % Send query using the QueryData buffer 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 singleton constructor. function this = instance() persistent UniqueInstance if isempty(UniqueInstance)||(~isvalid(UniqueInstance)) - disp('Creating new instance of NewportUsbComm') + disp('Creating a new instance of NewportUsbComm') this = MyNewportUsbComm(); UniqueInstance = this; else this = UniqueInstance; end end end end diff --git a/@MyTlb6700/MyTlb6700.m b/@MyTlb6700/MyTlb6700.m index ad8df93..27bd779 100644 --- a/@MyTlb6700/MyTlb6700.m +++ b/@MyTlb6700/MyTlb6700.m @@ -1,228 +1,230 @@ % Class for communication with NewFocus TLB6700 tunable laser controllers % Needs UsbDllWrap.dll from Newport USB driver on Matlab path % % Start instrument as MyTlb6700('address','USBaddr'), where USBaddr % is indicated in the instrument menu. Example: MyTlb6700('address', '1'). % % This class uses MyNewportUsbComm, an instance of which needs to be shared % between multiple devices, as the Newport driver, apparently, cannot % handle concurrent calls. classdef MyTlb6700 < MyScpiInstrument properties (GetAccess = public, ... SetAccess = {?MyClassParser, ?MyTlb6700}) % Interface field is not used in this instrument, but keep it % for the sake of information interface = 'usb'; address = ''; end properties (GetAccess = public, SetAccess = protected) % Instance of Newport.USBComm.USB used for communication. % Must be shared between the devices UsbComm end methods (Access = public) function this = MyTlb6700(varargin) P = MyClassParser(this); processInputs(P, this, varargin{:}); % Convert address to number this.address = str2double(this.address); % Get the unique instance of control class for Newport driver this.UsbComm = MyNewportUsbComm.instance(); + + createCommandList(this); end end methods (Access = protected) function createCommandList(this) % Commands for this class do not start from ':', as the % protocol does not fully comply with SCPI standard addCommand(this, 'wavelength', 'SENSe:WAVElength', ... 'format', '%e', ... 'info', 'Output wavelength (nm)', ... 'access', 'r'); addCommand(this, 'current', 'SENSe:CURRent:DIODe', ... 'format', '%e', ... 'info', 'Diode current (mA)', ... 'access', 'r'); addCommand(this, 'temp_diode', 'SENSe:TEMPerature:DIODe', ... 'format', '%e', ... 'info', 'Diode temperature (C)', ... 'access', 'r'); addCommand(this, 'power', 'SENSe:POWer:DIODe', ... 'format', '%e', ... 'info', 'Output power (mW)', ... 'access', 'r'); addCommand(this, 'wavelength_sp', 'SOURce:WAVElength', ... 'format', '%e', ... 'info', 'Wavelength setpoint (nm)'); addCommand(this, 'const_power', 'SOURce:CPOWer', ... 'format', '%b', ... 'info', 'Constant power mode on/off'); addCommand(this, 'power_sp', 'SOURce:POWer:DIODe', ... 'format', '%e', ... 'info', 'Power setpoint (mW)'); addCommand(this, 'current_sp', 'SOURce:CURRent:DIODe', ... 'format', '%e', ... 'info', 'Current setpoint (mA)'); % Control mode local/remote addCommand(this, 'control_mode', 'SYSTem:MCONtrol', ... 'format', '%s',... 'info', 'Control local/remote', ... 'value_list', {'LOC','REM'}); % Output on/off addCommand(this, 'enable_output', 'OUTPut:STATe', ... 'format', '%b', ... 'info', 'on/off'); % Wavelength track on/off addCommand(this, 'wavelength_track', 'OUTPut:TRACk', ... 'format', '%b', ... 'info', 'on/off'); % Wavelength scan related commands % Scan start wavelength (nm) addCommand(this, 'scan_start_wl', 'SOURce:WAVE:START', ... 'format', '%e', ... 'info', '(nm)'); % Scan stop wavelength (nm) addCommand(this, 'scan_stop_wl', 'SOURce:WAVE:STOP', ... 'format', '%e', ... 'info', '(nm)'); % Scan speed (nm/s) addCommand(this, 'scan_speed', 'SOURce:WAVE:SLEW:FORWard', ... 'format', '%e', ... 'info', '(nm/s)'); % Maximum scan speed (nm/s) addCommand(this, 'scan_speed_max', 'SOURce:WAVE:MAXVEL', ... 'format', '%e', ... 'info', '(nm/s)', ... 'access', 'r'); end end methods (Access = public) function openComm(this) % Opening a single device is not supported by Newport Usb % Driver, so open all the devices of the given type OpenDevices(this.UsbComm.Usb, hex2num('100A')); end % Query textual command function result = queryString(this, str) try result = query(this.UsbComm, this.address, str); catch ME try % Attempt re-opening communication openComm(this); result = query(this.UsbComm, this.address, str); catch rethrow(ME); end end end % Redefine queryStrings of MyScpiInstrument function res_list = queryStrings(this, varargin) 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},';']; res_list{i} = queryString(this, cmd); end else res_list = {}; end end % Writing is done by sending a command and querying its status. % Still, redefine writeStrings of MyScpiInstrument for consistency % and clarity. function stat = writeString(this, str) stat = queryString(this, str); end function stat = writeStrings(this, varargin) stat = queryStrings(this, varargin{:}); end %% Laser power and scan control functions function stat = setMaxOutPower(this) % Depending on if the laser in the constat power or current % mode, set value to max if this.const_power stat = queryString(this, 'SOURce:POWer:DIODe MAX;'); else stat = queryString(this, 'SOURce:CURRent:DIODe MAX;'); end 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; % Read min wavelength of the laser writeStrings(this, 'SOURce:WAVE:START MIN'); resp = queryStrings(this, 'SOURce:WAVE:START?'); wl_min = str2double(resp{1}); % Read max wavelength of the laser writeStrings(this, 'SOURce:WAVE:START MAX'); resp = queryStrings(this, 'SOURce:WAVE:START?'); wl_max = str2double(resp{1}); % Return scan start to its original value this.scan_start_wl = tmp; end function configSingleScan(this) % Configure: % Do not switch the laser off during the backward scan, % Perform a signle scan, % Return at maximum speed writeStrings(this,'SOURce:WAVE:SCANCFG 0', ... 'SOURce:WAVE:DESSCANS 1', ... 'SOURce:WAVE:SLEW:RETurn MAX'); end function startScan(this) writeStrings(this, 'OUTPut:SCAN:START'); end function stopScan(this) writeStrings(this, 'OUTPut:SCAN:STOP'); end end end diff --git a/GUIs/GuiTlb.mlapp b/GUIs/GuiTlb.mlapp index 54755e0..d2cbd37 100644 Binary files a/GUIs/GuiTlb.mlapp and b/GUIs/GuiTlb.mlapp differ diff --git a/Utility functions/DataAcquisitionMenu.mlapp b/Utility functions/DataAcquisitionMenu.mlapp index 35c225f..3540b55 100644 Binary files a/Utility functions/DataAcquisitionMenu.mlapp and b/Utility functions/DataAcquisitionMenu.mlapp differ