diff --git a/@MyHfWs/MyHfWs.m b/@MyHfWs/MyHfWs.m index cf3904b..8971602 100644 --- a/@MyHfWs/MyHfWs.m +++ b/@MyHfWs/MyHfWs.m @@ -1,257 +1,258 @@ % Class for controlling HighFinesse wavelengthmeter, tested with WS6-200 classdef MyHfWs < handle properties (Access=public) name = '' % Files containg the functions for communication with % wavelengthmeter, dll and header dllname = 'wlmData.dll' headername = 'wlmData.hml' % Timeout for trying to run the wavelengthmeter server app run_server_timeout = 60 % seconds end properties (GetAccess=public, SetAccess=protected) wavelength = 0 % Wavelength in nm frequency = 0 % Frequency in THz idn_str = '' end properties (Dependent=true) libname end methods (Access=public) %% Constructor and destructor % Constructor can accept dummy 'interface' and 'address' arguments, % they will be stored in P.unmatched_nv function this = MyHfWs(varargin) P=MyClassParser(this); + P.PartialMatching=false; processInputs(P, this, varargin{:}); % Load dll library and its header loadWlmLib(this); % Check if the wavelengthmeter software is running if ~isServerRunning(this) disp(['Wavelength meter server apptication ', ... 'is not running. Attempting to start.']) runServer(this); startMeas(this); end % Identificate the instrument this.idn_str=idn(this); end %% Communication methods function loadWlmLib(this) dll_path = which(this.dllname); if isempty(dll_path) error([this.dllname,' is not found. This library ',... 'needs to be present on Matlab path.']) end header_path = which(this.headername); if isempty(header_path) error([this.headername,' is not found. This header ',... 'file needs to be present on Matlab path.']) end if ~libisloaded(this.libname) fprintf('Loading %s library with %s header\n', ... this.dllname, this.headername); loadlibrary(dll_path, header_path); end end function ret_val=readWavelength(this, varargin) p=inputParser(); addParameter(p, 'n_ch', 1, @(x)assert( (mod(x,1)==0) && ... (x>=1) && (x<=8), ... 'Channel number must be integer between 1 and 8.')) parse(p, varargin{:}) n_ch=p.Results.n_ch; % read out the measured wavelength ret_val = calllib(this.libname,'GetWavelengthNum',n_ch,0); end function ret_val=readFrequency(this, varargin) p=inputParser(); addParameter(p, 'n_ch', 1, @(x)assert( (mod(x,1)==0) && ... (x>=1) && (x<=8), ... 'Channel number must be integer between 1 and 8.')) parse(p, varargin{:}) n_ch=p.Results.n_ch; % read out the measured wavelength ret_val = calllib(this.libname,'GetFrequencyNum',n_ch,0); end % Run the wavelengthmeter control program function runServer(this) T=timer('Period',0.5,... 'ExecutionMode','fixedDelay',... 'TasksToExecute', ceil(this.run_server_timeout/0.5)); T.TimerFcn=@(x,y)this.runServerTimerCallback(x,y); % cCtrlWLMShow: 1 - displays the window of wlm server % application if it was hidden and starts the server if it is % not running if calllib(this.libname,'ControlWLM',1,0,0) == 1 start(T); wait(T); else warning('Wavelengthmeter server app could not be started.') end % Clean up delete(T); end function bool=isServerRunning(this) bool=calllib(this.libname,'Instantiate',0,0,0,0); end % Start continuous measurement on the server function stat=startMeas(this) stat=calllib(this.libname,'Operation',hex2dec('0002')); end % Stop measurement on the server function stat=stopMeas(this) stat=calllib(this.libname,'Operation',hex2dec('0000')); end % Return the identification string of the device function str = idn(this) % Get the device information % Wavelengthmeter type can be 5 to 8 type = calllib(this.libname,'GetWLMVersion',0); % Version number vers = calllib(this.libname,'GetWLMVersion',1); % Software version soft_vers = calllib(this.libname,'GetWLMVersion',2); str=['WS',num2str(type),', Version ',num2str(vers),... ', Software version ' num2str(soft_vers)]; end %% Measurement headers function Hdr=readHeader(this) Hdr=MyMetadata(); % Generate valid field name from instrument name if present and % class name otherwise if ~isempty(this.name) field_name=genvarname(this.name); else field_name=class(this); end addField(Hdr, field_name); % Add identification string as parameter addParam(Hdr, field_name, 'idn', this.idn_str); wl=this.wavelength; if wl<=0 % The last measurement was not ok, so get the error code % instead of the value wl=readErrorFromCode(this, wl); end addParam(Hdr, field_name, 'wavelength', wl, 'comment', '(nm)'); end %% Auxiliary functions %Convert error codes returned by readWavelength and %readFrequency commands to message function str=readErrorFromCode(~, code) if code>0 str='Measurement ok'; return end switch code case 0 str='No value measured'; case -1 str='The wavelengthmeter has not detected any signal'; case -2 str=['The wavelengthmeter has not detected a ',... 'calculatable signal']; case -3 str='Underexposed'; case -4 str='Overexposed'; case -5 str=['Server application is not running or ', ... 'wavelength meter is not active or available']; case -6 str=['The caller function is not avaliable for ',... 'this version of wavelengthmeter']; case -8 str='ErrNoPulse'; otherwise str='Unknown error'; end end end %% Auxiliary pivate methods methods (Access=private) function runServerTimerCallback(this, Timer, ~) if ~isServerRunning(this) % Check if the timer has reached its limit if Timer.TasksExecuted>=Timer.TasksToExecute warning(['Timeout for running the server ',... 'app (%is) is exceeded.'], this.run_server_timeout) end else stop(Timer); end end end %% Set and get methods methods function set.dllname(this, val) assert(ischar(val) && isvector(val), ['''dllname'' must be '... 'a character vector.']) [~,~,ext]=fileparts(this.dllname); assert(strcmpi(ext,'dll'), ['''dllname'' must be a ',... 'dynamic-link library and have extension .dll']) this.dllname=val; end function set.headername(this, val) assert(ischar(val) && isvector(val), ['''headername'' must be '... 'a character vector.']) this.headername=val; end function nm=get.libname(this) % dll name without extension [~,nm,~]=fileparts(this.dllname); end function wl=get.wavelength(this) wl=readWavelength(this); end function wl=get.frequency(this) wl=readFrequency(this); end end end diff --git a/GUIs/GuiTlb.mlapp b/GUIs/GuiTlb.mlapp index a68ac5f..3cd19de 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 442b1af..d6566d1 100644 Binary files a/Utility functions/DataAcquisitionMenu.mlapp and b/Utility functions/DataAcquisitionMenu.mlapp differ diff --git a/Utility functions/readRunFiles.m b/Utility functions/readRunFiles.m index a44930f..debf8e5 100644 --- a/Utility functions/readRunFiles.m +++ b/Utility functions/readRunFiles.m @@ -1,63 +1,69 @@ % Read all the files which names start from 'run' from the local base % directory and add entries, autometically generated from the % InstrumentList function RunFiles = readRunFiles(varargin) if ~isempty(varargin) && ischar(varargin{1}) % The directory to search in can be supplied as varargin{1} dir = varargin{1}; else % Otherwise use the local base directory dir = getLocalBaseDir(); end % Find all the names of .m files that start with 'run' all_names = what(dir); is_run = startsWith(all_names.m,'run','IgnoreCase',false); run_names = all_names.m(is_run); RunFiles = struct(); % Read headers of all the run*.m files for i=1:length(run_names) name_match = regexp(run_names{i},'run(.*)\.m','tokens'); nm = name_match{1}{1}; fname = fullfile(dir, run_names{i}); % Read the run file comment header RunFiles.(nm) = readCommentHeader(fname); if isfield(RunFiles.(nm),'show_in_daq') RunFiles.(nm).show_in_daq = eval(... lower(RunFiles.(nm).show_in_daq)); end % Add information about file name RunFiles.(nm).name = nm; % Expression that needs to be evaluated to run the program. In this % case full name of the file RunFiles.(nm).fullname = fname; [~, run_name, ~] = fileparts(fname); RunFiles.(nm).run_expr = run_name; end % Add entries, automatically generated from the InstrumentList InstrumentList = getLocalSettings('InstrumentList'); instr_names = fieldnames(InstrumentList); for i=1:length(instr_names) nm = instr_names{i}; % If run file for instrument was not specified explicitly and if % all the required fields in InstrList are filled, add an entry to % RunFiles try add_entry = ~isfield(RunFiles, nm) &&... - ~isempty(InstrumentList.(nm).interface) &&... - ~isempty(InstrumentList.(nm).address) &&... - ~isempty(InstrumentList.(nm).gui) &&... ~isempty(InstrumentList.(nm).control_class); catch end if add_entry RunFiles.(nm) = InstrumentList.(nm); - RunFiles.(nm).run_expr = ... - sprintf('runInstrumentWithGui(''%s'');',nm); + + % Command for running an instrument without gui + RunFiles.(nm).run_bg_expr = ... + sprintf('runInstrument(''%s'');',nm); + + % Command for running an instrument with gui, added only if gui + % is specified + if ~isempty(InstrumentList.(nm).gui) + RunFiles.(nm).run_expr = ... + sprintf('runInstrumentWithGui(''%s'');',nm); + end RunFiles.(nm).header = ['% This entry is automatically ',... 'generated from InstrumentList']; end end end diff --git a/Utility functions/runInstrumentWithGui.m b/Utility functions/runInstrument.m similarity index 57% copy from Utility functions/runInstrumentWithGui.m copy to Utility functions/runInstrument.m index 264b7fe..a11faeb 100644 --- a/Utility functions/runInstrumentWithGui.m +++ b/Utility functions/runInstrument.m @@ -1,93 +1,59 @@ -% run instrument instance with gui and add it to the collector -function [Instr, GuiInstr] = runInstrumentWithGui(name, instr_class, interface, address, gui) +% Create instrument instance and add it to the collector + +function Instr = runInstrument(name, instr_class, interface, address) Collector=getCollector(); if ~ismember(name, Collector.running_instruments) if nargin==1 - % load parameters from InstrumentList + % load instr_class, interface and address parameters + % from InstrumentList InstrumentList = getLocalSettings('InstrumentList'); if ~isfield(InstrumentList, name) error('%s is not a field of InstrumentList',... name); end if ~isfield(InstrumentList.(name), 'interface') error(['InstrumentList entry ', name,... ' has no ''interface'' field']); else interface = InstrumentList.(name).interface; end if ~isfield(InstrumentList.(name), 'address') error(['InstrumentList entry ', name,... ' has no ''address'' field']); else address = InstrumentList.(name).address; end - if ~isfield(InstrumentList.(name), 'gui') - error(['InstrumentList entry ', name,... - ' has no ''gui'' field']); - else - gui = InstrumentList.(name).gui; - end if ~isfield(InstrumentList.(name), 'control_class') error(['InstrumentList entry ', name,... ' has no ''control_class'' field']); else instr_class = InstrumentList.(name).control_class; end - elseif nargin==5 + elseif nargin==4 % Case when all the arguments are supplied explicitly, do % nothing else error(['Wrong number of input arguments. ',... 'Function can be called as f(name) or ',... - 'f(name, instr_class, interface, address, gui)']) + 'f(name, instr_class, interface, address).']) end Instr = feval(instr_class, interface, address, 'name', name); addInstrument(Collector, Instr, 'name', name); else % If instrument is already present in the Collector, do not create % a new object, but try taking the existing one. disp([name,' is already running. Assign existing instrument ',... 'instead of running a new one.']); try Instr = Collector.InstrList.(name); catch % Return with empty results in the case of falure warning('Could not assign instrument %s from Collector',name); Instr = []; - GuiInstr =[]; - return - end - end - - % Next turn to gui - gui_name = ['Gui',name]; - if ~isValidBaseVar(gui_name) - % If gui does not present in the base workspace, create it - GuiInstr = feval(gui, Instr); - if isprop(GuiInstr,'name') - GuiInstr.name = gui_name; - end - % Store gui handle in a global variable - assignin('base', GuiInstr.name, GuiInstr); - % Display instrument's name if given - fig_handle=findfigure(GuiInstr); - if ~isempty(fig_handle) - fig_handle.Name=char(name); - else - warning('No UIFigure found to assign the name') - end - else - % Otherwise return gui from base workspace - GuiInstr = evalin('base',['Gui',name]); - try - % bring app figure on top of other windows - Fig = findfigure(GuiInstr); - Fig.Visible = 'off'; - Fig.Visible = 'on'; - catch end end + end diff --git a/Utility functions/runInstrumentWithGui.m b/Utility functions/runInstrumentWithGui.m index 264b7fe..d12e184 100644 --- a/Utility functions/runInstrumentWithGui.m +++ b/Utility functions/runInstrumentWithGui.m @@ -1,93 +1,58 @@ -% run instrument instance with gui and add it to the collector +% Create instrument instance with gui and add it to the collector + function [Instr, GuiInstr] = runInstrumentWithGui(name, instr_class, interface, address, gui) - Collector=getCollector(); - - if ~ismember(name, Collector.running_instruments) - if nargin==1 - % load parameters from InstrumentList - InstrumentList = getLocalSettings('InstrumentList'); - if ~isfield(InstrumentList, name) - error('%s is not a field of InstrumentList',... - name); - end - if ~isfield(InstrumentList.(name), 'interface') - error(['InstrumentList entry ', name,... - ' has no ''interface'' field']); - else - interface = InstrumentList.(name).interface; - end - if ~isfield(InstrumentList.(name), 'address') - error(['InstrumentList entry ', name,... - ' has no ''address'' field']); - else - address = InstrumentList.(name).address; - end - if ~isfield(InstrumentList.(name), 'gui') - error(['InstrumentList entry ', name,... - ' has no ''gui'' field']); - else - gui = InstrumentList.(name).gui; - end - if ~isfield(InstrumentList.(name), 'control_class') - error(['InstrumentList entry ', name,... - ' has no ''control_class'' field']); - else - instr_class = InstrumentList.(name).control_class; - end - elseif nargin==5 - % Case when all the arguments are supplied explicitly, do - % nothing + % Run instrument + if nargin==1 + % load parameters from InstrumentList + InstrumentList = getLocalSettings('InstrumentList'); + if ~isfield(InstrumentList, name) + error('%s is not a field of InstrumentList',... + name); + end + if ~isfield(InstrumentList.(name), 'gui') + error(['InstrumentList entry ', name,... + ' has no ''gui'' field']); else - error(['Wrong number of input arguments. ',... - 'Function can be called as f(name) or ',... - 'f(name, instr_class, interface, address, gui)']) + gui = InstrumentList.(name).gui; end - Instr = feval(instr_class, interface, address, 'name', name); - addInstrument(Collector, Instr, 'name', name); + Instr = runInstrument(name); + elseif nargin==5 + % Case when all the arguments are supplied explicitly + Instr = runInstrument(name, instr_class, interface, address); else - % If instrument is already present in the Collector, do not create - % a new object, but try taking the existing one. - disp([name,' is already running. Assign existing instrument ',... - 'instead of running a new one.']); - try - Instr = Collector.InstrList.(name); - catch - % Return with empty results in the case of falure - warning('Could not assign instrument %s from Collector',name); - Instr = []; - GuiInstr =[]; - return - end + error(['Wrong number of input arguments. ',... + 'Function can be called as f(name) or ',... + 'f(name, instr_class, interface, address, gui)']) end - % Next turn to gui + % Run gui and assign handles to a variable in global workspace gui_name = ['Gui',name]; if ~isValidBaseVar(gui_name) % If gui does not present in the base workspace, create it GuiInstr = feval(gui, Instr); if isprop(GuiInstr,'name') GuiInstr.name = gui_name; end % Store gui handle in a global variable assignin('base', GuiInstr.name, GuiInstr); % Display instrument's name if given fig_handle=findfigure(GuiInstr); if ~isempty(fig_handle) fig_handle.Name=char(name); else warning('No UIFigure found to assign the name') end else % Otherwise return gui from base workspace GuiInstr = evalin('base',['Gui',name]); try % bring app figure on top of other windows Fig = findfigure(GuiInstr); Fig.Visible = 'off'; Fig.Visible = 'on'; catch end end end