diff --git a/@MyDaq/MyDaq.asv b/@MyDaq/MyDaq.asv deleted file mode 100644 index a31656a..0000000 --- a/@MyDaq/MyDaq.asv +++ /dev/null @@ -1,936 +0,0 @@ -classdef MyDaq < handle - properties - %Contains GUI handles - Gui; - %Contains Reference trace (MyTrace object) - Ref; - %Contains Data trace (MyTrace object) - Data; - %Contains Background trace (MyTrace object) - Background; - %List of all the programs with run files - ProgramList=struct(); - % List of running programs - RunningPrograms=struct(); - %Struct containing Cursor objects - Cursors=struct(); - %Struct containing Cursor labels - CrsLabels=struct(); - %Struct containing MyFit objects - Fits=struct(); - %Input parser - Parser; - %Struct for listeners - Listeners=struct(); - - %Sets the colors of fits, data and reference - fit_color='k'; - data_color='b'; - ref_color='r'; - bg_color='c'; - - %Properties for saving files - base_dir; - session_name; - file_name; - - %Flag for enabling the GUI - enable_gui; - end - - properties (Dependent=true) - save_dir; - main_plot; - open_fits; - open_crs; - savefile; - running_progs; - end - - methods (Access=public) - %% Class functions - %Constructor function - function this=MyDaq(varargin) - p=inputParser; - addParameter(p,'enable_gui',1); - this.Parser=p; - parse(this.Parser,varargin{:}); - - for i=1:length(this.Parser.Parameters) - %Takes the value from the inputParser to the appropriate - %property. - if isprop(this,this.Parser.Parameters{i}) - this.(this.Parser.Parameters{i})=... - this.Parser.Results.(this.Parser.Parameters{i}); - end - end - - createParser(this); - parseInputs(this); - - this.base_dir='M:\Measurement Campaigns\'; - this.ProgramList = readRunFiles(); - - if this.enable_gui - this.Gui=guihandles(eval('GuiDaq')); - initGui(this); - % Initialize the menu based on the available run files - content = menuFromRunFiles(this.ProgramList,... - 'show_in_daq',true); - set(this.Gui.InstrMenu,'String',[{'Select the application'};... - content.titles]); - % Add a property to the menu for storing the program file - % names - if ~isprop(this.Gui.InstrMenu, 'ItemsData') - addprop(this.Gui.InstrMenu, 'ItemsData'); - end - set(this.Gui.InstrMenu,'ItemsData',[{''};... - content.tags]); - set(this.Gui.BaseDir,'String',this.base_dir); - hold(this.main_plot,'on'); - end - - %Initializes empty trace objects - this.Ref=MyTrace(); - this.Data=MyTrace(); - this.Background=MyTrace(); - end - - function delete(this) - %Deletes the MyFit objects and their listeners - cellfun(@(x) deleteListeners(this,x), this.open_fits); - structfun(@(x) delete(x), this.Fits); - - %Close the programs and delete their listeners - cellfun(@(x) deleteListeners(this, x), this.running_progs); - structfun(@(x) delete(x), this.RunningPrograms); - - if this.enable_gui - this.Gui.figure1.CloseRequestFcn=''; - %Deletes the figure - delete(this.Gui.figure1); - %Removes the figure handle to prevent memory leaks - this.Gui=[]; - end - end - end - - methods (Access=private) - %Sets the class variables to the inputs from the inputParser. - function parseInputs(this) - for i=1:length(this.Parser.Parameters) - %Takes the value from the inputParser to the appropriate - %property. - if isprop(this,this.Parser.Parameters{i}) - this.(this.Parser.Parameters{i})=... - this.Parser.Results.(this.Parser.Parameters{i}); - end - end - end - - %Sets callback functions for the GUI - initGui(this) - - %Executes when the GUI is closed - function closeFigure(this,~,~) - delete(this); - end - - %Updates fits - function updateFits(this) - %Pushes data into fits in the form of MyTrace objects, so that - %units etc follow. Also updates user supplised parameters. - for i=1:length(this.open_fits) - switch this.open_fits{i} - case {'Linear','Quadratic','Gaussian',... - 'Exponential','Beta'} - this.Fits.(this.open_fits{i}).Data=... - getFitData(this,'VertData'); - case {'Lorentzian','DoubleLorentzian'} - this.Fits.(this.open_fits{i}).Data=... - getFitData(this,'VertData'); - if isfield(this.Cursors,'VertRef') - ind=findCursorData(this,'Data','VertRef'); - this.Fits.(this.open_fits{i}).CalVals.line_spacing=... - range(this.Data.x(ind)); - end - case {'G0'} - this.Fits.G0.MechTrace=getFitData(this,'VertData'); - this.Fits.G0.CalTrace=getFitData(this,'VertRef'); - end - end - end - - % If vertical cursors are on, takes only data - %within cursors. - %If the cursor is not open, it takes all the data from the selected - %trace in the analysis trace selection dropdown - function Trace=getFitData(this,varargin) - %Parses varargin input - p=inputParser; - addOptional(p,'name','',@ischar); - parse(p,varargin{:}) - name=p.Results.name; - - %Finds out which trace the user wants to fit. - trc_opts=this.Gui.SelTrace.String; - trc_str=trc_opts{this.Gui.SelTrace.Value}; - % Note the use of copy here! This is a handle - %class, so if normal assignment is used, this.Fits.Data and - %this.(trace_str) will refer to the same object, causing roblems. - %Name input is the name of the cursor to be used to extract data. - Trace=copy(this.(trc_str)); - if isfield(this.Cursors,name) - ind=findCursorData(this, trc_str, name); - Trace.x=this.(trc_str).x(ind); - Trace.y=this.(trc_str).y(ind); - end - end - - %Finds data between named cursors in the given trace - function ind=findCursorData(this, trc_str, name) - crs_pos=sort([this.Cursors.(name){1}.Location,... - this.Cursors.(name){2}.Location]); - ind=(this.(trc_str).x>crs_pos(1) & this.(trc_str).x - %Prints the figure to the clipboard - print(newFig,'-clipboard','-dbitmap'); - %Deletes the figure - delete(newFig); - end - - function updateAxis(this) - axis(this.main_plot,'tight'); - end - end - - methods (Access=public) - %% Callbacks - - %Callback for copying the plot to clipboard - function copyPlotCallback(this,~,~) - copyPlot(this); - end - - %Callback for centering cursors - function centerCursorsCallback(this, ~, ~) - if ~this.Gui.LogX.Value - x_pos=mean(this.main_plot.XLim); - else - x_pos=10^(mean(log10(this.main_plot.XLim))); - end - - if ~this.Gui.LogY.Value - y_pos=mean(this.main_plot.YLim); - else - y_pos=10^(mean(log10(this.main_plot.YLim))); - end - - for i=1:length(this.open_crs) - switch this.Cursors.(this.open_crs{i}){1}.Orientation - case 'horizontal' - pos=y_pos; - case 'vertical' - pos=x_pos; - end - - %Centers the position - cellfun(@(x) set(x,'Location',pos), ... - this.Cursors.(this.open_crs{i})); - %Triggers the UpdateCursorBar event, which triggers - %listener callback to reposition text - cellfun(@(x) notify(x,'UpdateCursorBar'),... - this.Cursors.(this.open_crs{i})); - cellfun(@(x) notify(x,'EndDrag'),... - this.Cursors.(this.open_crs{i})); - end - end - - %Callback for creating vertical data cursors - function cursorButtonCallback(this, hObject, ~) - name=erase(hObject.Tag,'Button'); - %Gets the first four characters of the tag (Vert or Horz) - type=name(1:4); - - if hObject.Value - hObject.BackgroundColor=[0,1,0.2]; - createCursors(this,name,type); - else - hObject.BackgroundColor=[0.941,0.941,0.941]; - deleteCursors(this,name); - end - end - - %Callback for the instrument menu - function instrMenuCallback(this,hObject,~) - val=hObject.Value; - if val==1 - return - else - tag = hObject.ItemsData{val}; - end - - % Run-files themselves are supposed to prevent duplicated - % instances, but let DAQ handle it as well for safety - if ismember(tag, this.running_progs) - % Change focus to the instrument control window - fig_handle = findfigure(this.RunningPrograms.(tag)); - if isempty(fig_handle) - % If unable, try the same for .Gui object inside - try - fig_handle =... - findfigure(this.RunningPrograms.(tag).Gui); - catch - end - end - if ~isempty(fig_handle) - fig_handle.Visible='off'; - fig_handle.Visible='on'; - end - return - end - - try - [~, fname, ~] = fileparts(this.ProgramList.(tag).fullname); - prog = feval(fname); - this.RunningPrograms.(tag) = evalin('base', prog); - catch - error('Cannot run %s', this.ProgramList.(tag).fullname) - end - - % Add listeners to the NewData and ObjectBeingDestroyed events - try - this.Listeners.(tag).NewData=... - addlistener(this.RunningPrograms.(tag),'NewData',... - @(src, eventdata) acquireNewData(this, src, eventdata)); - catch - % Compatibility with apps, which have .Instr property - try - this.Listeners.(tag).NewData=... - addlistener(this.RunningPrograms.(tag).Instr,'NewData',... - @(src, eventdata) acquireNewData(this, src, eventdata)); - catch - warning(['No NewData event found, %s cannot transfer',... - ' data to the DAQ'],tag); - end - end - this.Listeners.(tag).Deletion=... - addlistener(this.RunningPrograms.(tag),... - 'ObjectBeingDestroyed',... - @(src, eventdata) removeProgram(this, src, eventdata)); - end - - %Select trace callback - function selTraceCallback(this, ~, ~) - updateFits(this) - end - - %Saves the data if the save data button is pressed. - function saveDataCallback(this, ~, ~) - if this.Data.validatePlot - save(this.Data,'save_dir',this.save_dir,'name',... - this.savefile) - else - errdlg('Data trace was empty, could not save'); - end - end - - %Saves the reference if the save ref button is pressed. - function saveRefCallback(this, ~, ~) - if this.Data.validatePlot - save(this.Ref,'save_dir',this.save_dir,'name',... - this.savefile) - else - errdlg('Reference trace was empty, could not save') - end - end - - %Toggle button callback for showing the data trace. - function showDataCallback(this, hObject, ~) - if hObject.Value - hObject.BackgroundColor=[0,1,0.2]; - setVisible(this.Data,this.main_plot,1); - updateAxis(this); - else - hObject.BackgroundColor=[0.941,0.941,0.941]; - setVisible(this.Data,this.main_plot,0); - updateAxis(this); - end - end - - %Toggle button callback for showing the ref trace - function showRefCallback(this, hObject, ~) - if hObject.Value - hObject.BackgroundColor=[0,1,0.2]; - setVisible(this.Ref,this.main_plot,1); - updateAxis(this); - else - hObject.BackgroundColor=[0.941,0.941,0.941]; - setVisible(this.Ref,this.main_plot,0); - updateAxis(this); - end - end - - %Callback for moving the data to reference. - function dataToRefCallback(this, ~, ~) - if this.Data.validatePlot - this.Ref.x=this.Data.x; - this.Ref.y=this.Data.y; - this.Ref.plotTrace(this.main_plot,'Color',this.ref_color,... - 'make_labels',true); - this.Ref.setVisible(this.main_plot,1); - updateFits(this); - this.Gui.ShowRef.Value=1; - this.Gui.ShowRef.BackgroundColor=[0,1,0.2]; - else - warning('Data trace was empty, could not move to reference') - end - end - - %Callback for ref to bg button. Sends the reference to background - function refToBgCallback(this, ~, ~) - if this.Ref.validatePlot - this.Background.x=this.Ref.x; - this.Background.y=this.Ref.y; - this.Background.plotTrace(this.main_plot,... - 'Color',this.bg_color,'make_labels',true); - this.Background.setVisible(this.main_plot,1); - else - warning('Reference trace was empty, could not move to background') - end - end - - %Callback for data to bg button. Sends the data to background - function dataToBgCallback(this, ~, ~) - if this.Data.validatePlot - this.Background.x=this.Data.x; - this.Background.y=this.Data.y; - this.Background.plotTrace(this.main_plot,... - 'Color',this.bg_color,'make_labels',true); - this.Background.setVisible(this.main_plot,1); - else - warning('Data trace was empty, could not move to background') - end - end - - %Callback for clear background button. Clears the background - function clearBgCallback(this, ~, ~) - this.Background.x=[]; - this.Background.y=[]; - this.Background.setVisible(this.main_plot,0); - end - - %Callback for LogY button. Sets the YScale to log/lin - function logYCallback(this, hObject, ~) - if hObject.Value - this.main_plot.YScale='Log'; - hObject.BackgroundColor=[0,1,0.2]; - else - this.main_plot.YScale='Linear'; - hObject.BackgroundColor=[0.941,0.941,0.941]; - end - updateAxis(this); - updateCursors(this); - end - - %Callback for LogX button. Sets the XScale to log/lin. Updates the - %axis and cursors afterwards. - function logXCallback(this, hObject, ~) - if get(hObject,'Value') - set(this.main_plot,'XScale','Log'); - set(hObject, 'BackgroundColor',[0,1,0.2]); - else - set(this.main_plot,'XScale','Linear'); - set(hObject, 'BackgroundColor',[0.941,0.941,0.941]); - end - updateAxis(this); - updateCursors(this); - end - - %Base directory callback. Sets the base directory. Also - %updates fit objects with the new save directory. - function baseDirCallback(this, hObject, ~) - this.base_dir=hObject.String; - for i=1:length(this.open_fits) - this.Fits.(this.open_fits{i}).save_dir=this.save_dir; - end - end - - %Callback for session name edit box. Sets the session name. Also - %updates fit objects with the new save directory. - function sessionNameCallback(this, hObject, ~) - this.session_name=hObject.String; - for i=1:length(this.open_fits) - this.Fits.(this.open_fits{i}).save_dir=this.save_dir; - end - end - - %Callback for filename edit box. Sets the file name. Also - %updates fit objects with the new file name. - function fileNameCallback(this, hObject,~) - this.file_name=hObject.String; - for i=1:length(this.open_fits) - this.Fits.(this.open_fits{i}).save_name=this.file_name; - end - end - - %Callback for the analyze menu (popup menu for selecting fits). - %Opens the correct MyFit object. - function analyzeMenuCallback(this, hObject, ~) - analyze_ind=hObject.Value; - %Finds the correct fit name by erasing spaces and other - %superfluous strings - analyze_name=hObject.String{analyze_ind}; - analyze_name=erase(analyze_name,'Fit'); - analyze_name=erase(analyze_name,'Calibration'); - analyze_name=erase(analyze_name,' '); - - switch analyze_name - case {'Linear','Quadratic','Lorentzian','Gaussian',... - 'DoubleLorentzian'} - openMyFit(this,analyze_name); - case 'g0' - openMyG(this); - case 'Beta' - openMyBeta(this); - end - end - - function openMyFit(this,fit_name) - %Sees if the MyFit object is already open, if it is, changes the - %focus to it, if not, opens it. - if ismember(fit_name,fieldnames(this.Fits)) - %Changes focus to the relevant fit window - figure(this.Fits.(fit_name).Gui.Window); - else - %Gets the data for the fit using the getFitData function - %with the vertical cursors - DataTrace=getFitData(this,'VertData'); - %Makes an instance of MyFit with correct parameters. - this.Fits.(fit_name)=MyFit(... - 'fit_name',fit_name,... - 'enable_plot',1,... - 'plot_handle',this.main_plot,... - 'Data',DataTrace,... - 'save_dir',this.save_dir,... - 'save_name',this.file_name); - - updateFits(this); - %Sets up a listener for the Deletion event, which - %removes the MyFit object from the Fits structure if it is - %deleted. - this.Listeners.(fit_name).Deletion=... - addlistener(this.Fits.(fit_name),'ObjectBeingDestroyed',... - @(src, eventdata) deleteFit(this, src, eventdata)); - - %Sets up a listener for the NewFit. Callback plots the fit - %on the main plot. - this.Listeners.(fit_name).NewFit=... - addlistener(this.Fits.(fit_name),'NewFit',... - @(src, eventdata) plotNewFit(this, src, eventdata)); - - %Sets up a listener for NewInitVal - this.Listeners.(fit_name).NewInitVal=... - addlistener(this.Fits.(fit_name),'NewInitVal',... - @(~,~) updateCursors(this)); - end - end - - %Opens MyG class if it is not open. - function openMyG(this) - if ismember('G0',this.open_fits) - figure(this.Fits.G0.Gui.figure1); - else - MechTrace=getFitData(this,'VertData'); - CalTrace=getFitData(this,'VertRef'); - this.Fits.G0=MyG('MechTrace',MechTrace,'CalTrace',CalTrace,... - 'name','G0'); - - %Adds listener for object being destroyed - this.Listeners.G0.Deletion=addlistener(this.Fits.G0,... - 'ObjectBeingDestroyed',... - @(~,~) deleteObj(this,'G0')); - end - end - - %Opens MyBeta class if it is not open. - function openMyBeta(this) - if ismember('Beta', this.open_fits) - figure(this.Fits.Beta.Gui.figure1); - else - DataTrace=getFitData(this); - this.Fits.Beta=MyBeta('Data',DataTrace); - - %Adds listener for object being destroyed, to perform cleanup - this.Listeners.Beta.Deletion=addlistener(this.Fits.Beta,... - 'ObjectBeingDestroyed',... - @(~,~) deleteObj(this,'Beta')); - end - end - - %Callback for load data button - function loadDataCallback(this, ~, ~) - if isempty(this.base_dir) - warning('Please input a valid folder name for loading a trace'); - this.base_dir=pwd; - end - - try - [load_name,path_name]=uigetfile('.txt','Select the trace',... - this.base_dir); - load_path=[path_name,load_name]; - dest_trc=this.Gui.DestTrc.String{this.Gui.DestTrc.Value}; - loadTrace(this.(dest_trc),load_path); - this.(dest_trc).plotTrace(this.main_plot,... - 'Color',this.(sprintf('%s_color',lower(dest_trc))),... - 'make_labels',true); - updateAxis(this); - updateCursors(this); - catch - error('Please select a valid file'); - end - end - end - - methods (Access=public) - %% Listener functions - %Callback function for NewFit listener. Plots the fit in the - %window using the plotFit function of the MyFit object - function plotNewFit(this, src, ~) - src.plotFit('Color',this.fit_color); - updateAxis(this); - updateCursors(this); - end - - %Callback function for the NewData listener - function acquireNewData(this, src, ~) - hline=getLineHandle(this.Data,this.main_plot); - this.Data=copy(src.Trace); - if ~isempty(hline); this.Data.hlines{1}=hline; end - clearData(src.Trace); - this.Data.plotTrace(this.main_plot,'Color',this.data_color,... - 'make_labels',true) - updateAxis(this); - updateCursors(this); - updateFits(this); - end - - %Deletes the object from the RunningPrograms struct - function removeProgram(this, src, ~) - % Find the object that is being deleted - ind=cellfun(@(x) isequal(this.RunningPrograms.(x), src),... - this.running_progs); - tag=this.running_progs{ind}; - this.RunningPrograms=rmfield(this.RunningPrograms,tag); - %Deletes the listeners from the Listeners struct - deleteListeners(this, tag); - end - - %Callback function for MyFit ObjectBeingDestroyed listener. - %Removes the relevant field from the Fits struct and deletes the - %listeners from the object. - function deleteFit(this, src, ~) - %Deletes the object from the Fits struct and deletes listeners - deleteObj(this,src.fit_name); - - %Clears the fits - src.clearFit; - - %Updates cursors since the fits are removed from the plot - updateCursors(this); - end - - %Callback function for other analysis method deletion listeners. - %Does the same as above. - function deleteObj(this,name) - if ismember(name,this.open_fits) - this.Fits=rmfield(this.Fits,name); - end - deleteListeners(this, name); - end - - %Listener update function for vertical cursor - function vertCursorUpdate(this, src) - %Finds the index of the cursor. All cursors are tagged - %(name)1, (name)2, e.g. VertData2, ind is the number. - ind=str2double(src.Tag(end)); - tag=src.Tag(1:(end-1)); - %Moves the cursor labels - set(this.CrsLabels.(tag){ind},'Position',[src.Location,... - this.CrsLabels.(tag){ind}.Position(2),0]); - if strcmp(tag,'VertData') - %Sets the edit box displaying the location of the cursor - this.Gui.(sprintf('EditV%d',ind)).String=... - num2str(src.Location); - %Sets the edit box displaying the difference in locations - this.Gui.EditV2V1.String=... - num2str(this.Cursors.VertData{2}.Location-... - this.Cursors.VertData{1}.Location); - end - end - - %Listener update function for horizontal cursor - function horzCursorUpdate(this, src) - %Finds the index of the cursor. All cursors are tagged - %(name)1, (name)2, e.g. VertData2, ind is the number. - ind=str2double(src.Tag(end)); - tag=src.Tag(1:(end-1)); - %Moves the cursor labels - set(this.CrsLabels.(tag){ind},'Position',... - [this.CrsLabels.(tag){ind}.Position(1),... - src.Location,0]); - if strcmp(tag,'HorzData') - %Sets the edit box displaying the location of the cursor - this.Gui.(sprintf('EditH%d',ind)).String=... - num2str(src.Location); - %Sets the edit box displaying the difference in locations - this.Gui.EditH2H1.String=... - num2str(this.Cursors.HorzData{2}.Location-... - this.Cursors.HorzData{1}.Location); - end - end - - %Function that deletes listeners from the listeners struct, - %corresponding to an object of name obj_name - function deleteListeners(this, obj_name) - %Finds if the object has listeners in the listeners structure - if ismember(obj_name, fieldnames(this.Listeners)) - %Grabs the fieldnames of the object's listeners structure - names=fieldnames(this.Listeners.(obj_name)); - for i=1:length(names) - %Deletes the listeners - delete(this.Listeners.(obj_name).(names{i})); - %Removes the field from the structure - this.Listeners.(obj_name)=... - rmfield(this.Listeners.(obj_name),names{i}); - end - %Removes the object's field from the structure - this.Listeners=rmfield(this.Listeners, obj_name); - end - end - end - - methods - - %% Set functions - function set.base_dir(this,base_dir) - if ~strcmp(base_dir(end),'\') - base_dir(end+1)='\'; - end - this.base_dir=base_dir; - end - - %% Get functions - - %Get function from save directory - function save_dir=get.save_dir(this) - save_dir=[this.base_dir,datestr(now,'yyyy-mm-dd '),... - this.session_name,'\']; - end - - %Get function for the plot handles - function main_plot=get.main_plot(this) - if this.enable_gui - main_plot=this.Gui.figure1.CurrentAxes; - else - main_plot=[]; - end - end - - %Get function for open fits - function open_fits=get.open_fits(this) - open_fits=fieldnames(this.Fits); - end - - function running_progs=get.running_progs(this) - running_progs=fieldnames(this.RunningPrograms); - end - - %Generates appropriate file name for the save file. - function savefile=get.savefile(this) - if get(this.Gui.AutoName,'Value') - date_time = datestr(now,'yyyy-mm-dd_HHMMSS'); - else - date_time=''; - end - - savefile=[this.file_name,date_time]; - end - - %Get function that displays names of open cursors - function open_crs=get.open_crs(this) - open_crs=fieldnames(this.Cursors); - end - end -end \ No newline at end of file diff --git a/@MyInstrument/MyInstrument.asv b/@MyInstrument/MyInstrument.asv deleted file mode 100644 index cedbc2e..0000000 --- a/@MyInstrument/MyInstrument.asv +++ /dev/null @@ -1,485 +0,0 @@ -classdef MyInstrument < dynamicprops - - properties (SetAccess=protected, GetAccess=public) - name=''; - interface=''; - address=''; - visa_brand=''; - %Contains the device object. struct() is a dummy, as Device - %needs to always support properties for consistency. - Device=struct(); - %Input parser for class constructor - ConstructionParser; - %Contains a list of the commands available for the instrument as - %well as the default values and input requirements - CommandList=struct(); - %Parses commands using an inputParser object - CommandParser; - %Trace object for storing data - Trace=MyTrace(); - end - - properties (Constant=true) - % Default parameters for VISA connection - DEFAULT_INP_BUFF_SIZE = 1e7; % buffer size bytes - DEFAULT_OUT_BUFF_SIZE = 1e7; % buffer size bytes - DEFAULT_TIMEOUT = 10; % Timeout in s - DEFAULT_VISA_BRAND = 'ni'; - end - - properties (Dependent=true) - command_names; - command_no; - write_commands; - read_commands; - end - - events - NewData; - end - - methods (Access=private) - function p = createConstructionParser(this) - p=inputParser(); - % Ignore unmatched parameters - p.KeepUnmatched = true; - addRequired(p,'interface',@ischar); - addRequired(p,'address',@ischar); - addParameter(p,'name','',@ischar); - addParameter(p,'visa_brand',this.DEFAULT_VISA_BRAND,@ischar); - this.ConstructionParser=p; - end - end - - methods (Access=public) - function this=MyInstrument(interface, address, varargin) - p = createConstructionParser(this); - parse(p,interface,address,varargin{:}); - %Loads parsed variables into class properties - this.name=p.Results.name; - this.interface=p.Results.interface; - this.address=p.Results.address; - this.visa_brand=p.Results.visa_brand; - end - - function delete(this) - %Closes the connection to the device - closeDevice(this); - %Deletes the device object - delete(this.Device); - clear('this.Device'); - end - - %% Read and write commands - %Writes properties to device. Can take multiple inputs. With the - %option all, the function writes default to all the - %available writeable parameters. - function writeProperty(this, varargin) - %Parses the inputs using the CommandParser - parse(this.CommandParser, varargin{:}); - - if this.CommandParser.Results.all - % If the 'all' is true, write all the commands - exec=this.write_commands; - else - % Check which commands were passed values - ind_val=cellfun(@(x)... - (~ismember(x, this.CommandParser.UsingDefaults)),... - this.write_commands); - exec=this.write_commands(ind_val); - end - - for i=1:length(exec) - %Creates the write command using the right string spec - write_command=[this.CommandList.(exec{i}).command,... - ' ',this.CommandList.(exec{i}).str_spec]; - %Gets the value to write to the device - this.(exec{i})=this.CommandParser.Results.(exec{i}); - command=sprintf(write_command, this.(exec{i})); - %Sends command to device - fprintf(this.Device, command); - end - end - - % Wrapper for writeProperty that opens and closes 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'); - closeDevice(this); - end - - function result=readProperty(this, varargin) - result = struct(); - read_all_flag = any(strcmp('all',varargin)); - if read_all_flag - % Read all the commands with read access - exec=this.read_commands; - else - ind_r=ismember(varargin,this.read_commands); - exec=varargin(ind_r); - if any(~ind_r) - % Issue warnings for commands not in the command_names - warning('The following are not valid read commands:'); - disp(varargin(~ind_r)); - end - end - % concatenate all commands in one string - read_command=join(cellfun(... - @(cmd)this.CommandList.(cmd).command,exec,... - 'UniformOutput',false),'?;:'); - read_command=[read_command{1},'?;']; - res_str = query(this.Device,read_command); - % drop the end-of-the-string symbol and split - res_str = split(res_str(1:end-1),';'); - if length(exec)==length(res_str) - for i=1:length(exec) - result.(exec{i})=sscanf(res_str{i},... - this.CommandList.(exec{i}).str_spec); - %Assign the values to the MyInstrument properties - this.(exec{i})=result.(exec{i}); - end - else - warning(['Not all the properties could be read, ',... - 'no instrument class values are not updated']); - end - end - - % Wrapper for readProperty that opens and closes the device - function result=readPropertyHedged(this, varargin) - openDevice(this); - try - result = readProperty(this, varargin{:}); - catch - warning('Error while reading the properties:'); - disp(varargin); - end - closeDevice(this); - end - - %Triggers event for acquired data - function triggerNewData(this) - notify(this,'NewData') - end - - %% Processing of the class variable values - % Extend the property value based on val_list - function std_val = standardizeValue(this, cmd, varargin) - if ~ismember(cmd,this.command_names) - warning('%s is not a valid command',cmd); - std_val = ''; - return - end - vlist = this.CommandList.(cmd).val_list; - % The value to normalize can be explicitly passed as - % varargin{1}, otherwise use the property value - if isempty(varargin) - val = this.(cmd); - else - val = varargin{1}; - end - % find matching commands - ismatch = false(1,length(vlist)); - for i=1:length(vlist) - n = min([length(val), length(vlist{i})]); - % compare first n symbols disregarding case - ismatch(i) = strncmpi(val, vlist{i},n); - end - % out of matching names pick the longest - if any(ismatch) - mvlist = vlist(ismatch); - str = mvlist{1}; - for i=1:length(mvlist) - if length(mvlist{i})>length(str) - str = mvlist{i}; - end - end - std_val = str; - % set the property if value was not given explicitly - if isempty(varargin) - this.(cmd) = std_val; - end - else - std_val = val; - end - end - - % Create a string of property values - function par_str = getConfigString(this) - % Try to find out the device name - if ~isempty(this.name) - name_str = this.name; - else - try - openDevice(this); - name_str = query(this.Device,'*IDN?'); - closeDevice(this); - % Remove the new line end symbol - name_str=name_str(1:end-1); - catch - warning('Could not get the device name'); - name_str = ''; - end - end - par_str = sprintf('Instrument name: %s\n',name_str); - % Append the values of all the commands - rcmds=this.read_commands; - for i=1:length(rcmds) - new_str = sprintf(['\t',rcmds{i},'\t',... - this.CommandList.(rcmds{i}).str_spec,'\n'],... - this.(rcmds{i})); - par_str = [par_str, new_str]; - end - end - - %% Connect, open, configure and close the device - % Connects to the device - function connectDevice(this, interface, address) - try - % visa brand, DEFAULT_VISA_BRAND if not specified - vb = this.visa_brand; - switch lower(interface) - case 'instr_list' - % load the InstrumentList structure - InstrumentList = getLocalInstrList(); - % In this case 'address' is the instrument name in - % the list - instr_name = address; - if ~isfield(InstrumentList, instr_name) - error('%s is not a field of InstrumentList',... - instr_name) - end - % A check to prevent hypothetical endless recursion - if isequal(InstrumentList.(instr_name).interface,'instr_list') - error('') - end - % Connect using the loaded parameters - connectDevice(this,... - InstrumentList.(instr_name).interface,... - InstrumentList.(instr_name).address); - this.name = instr_name; - case 'constructor' - % in this case the 'address' is a command - % (ObjectConstructorName) as returned by the - % instrhwinfo - this.Device=eval(address); - case 'visa' - this.Device=visa(vb, address); - case 'tcpip' - this.Device= visa(vb, sprintf(... - 'TCPIP0::%s::inst0::INSTR',this.address)); - case 'usb' - this.Device=visa(vb, sprintf(... - 'USB0::%s::INSTR',address)); - otherwise - warning('Device is not connected: unknown interface'); - end - configureDeviceDefault(this); - catch - warning('Device is not connected'); - end - end - - % Opens the device if it is not open - function openDevice(this) - if ~isopen(this) - try - fopen(this.Device); - catch - % try to find and close all the devices with the same - % VISA resource name - try - instr_list=instrfind('RsrcName',this.Device.RsrcName); - fclose(instr_list); - fopen(this.Device); - warning('Multiple instrument objects of address %s exist',... - this.address); - catch - error('Could not open device') - end - end - end - end - - % Closes the connection to the device - function closeDevice(this) - if isopen(this) - fclose(this.Device); - end - end - - function configureDeviceDefault(this) - dev_prop_list = properties(this.Device); - if ismember('OutputBufferSize',dev_prop_list) - this.Device.OutputBufferSize = this.DEFAULT_OUT_BUFF_SIZE; - end - if ismember('InputBufferSize',dev_prop_list) - this.Device.InputBufferSize = this.DEFAULT_INP_BUFF_SIZE; - end - if ismember('Timeout',dev_prop_list) - this.Device.Timeout = this.DEFAULT_TIMEOUT; - end - end - - %Checks if the connection to the device is open - function bool=isopen(this) - try - bool=strcmp(this.Device.Status, 'open'); - catch - warning('Cannot verify device Status property'); - bool=false; - end - end - - %% addCommand - %Adds a command to the CommandList - function addCommand(this, tag, command, varargin) - p=inputParser(); - addRequired(p,'tag',@ischar); - addRequired(p,'command',@ischar); - addParameter(p,'default','placeholder'); - addParameter(p,'classes',{},@iscell); - addParameter(p,'attributes',{},@iscell); - addParameter(p,'str_spec','%e',@ischar); - % list of the values the variable can take, {} means no - % restriction - addParameter(p,'val_list',{},@iscell); - addParameter(p,'access','rw',@ischar); - parse(p,tag,command,varargin{:}); - - %Adds the command to be sent to the device - this.CommandList.(tag).command=command; - this.CommandList.(tag).access=p.Results.access; - this.CommandList.(tag).write_flag=contains(p.Results.access,'w'); - this.CommandList.(tag).read_flag=contains(p.Results.access,'r'); - this.CommandList.(tag).default=p.Results.default; - this.CommandList.(tag).val_list=p.Results.val_list; - - % Adds the string specifier to the list. if the format - % specifier is not given explicitly, try to infer - if ismember('str_spec', p.UsingDefaults) - this.CommandList.(tag).str_spec=... - formatSpecFromAttributes(this,p.Results.classes... - ,p.Results.attributes); - elseif strcmp(p.Results.str_spec,'%b') - % b is a non-system specifier to represent the - % logical type - this.CommandList.(tag).str_spec='%i'; - else - this.CommandList.(tag).str_spec=p.Results.str_spec; - end - % Adds the attributes for the input to the command. If not - % given explicitly, infer from the format specifier - if ismember('classes',p.UsingDefaults) - [this.CommandList.(tag).classes,... - this.CommandList.(tag).attributes]=... - attributesFromFormatSpec(this, p.Results.str_spec); - else - this.CommandList.(tag).classes=p.Results.classes; - this.CommandList.(tag).attributes=p.Results.attributes; - end - - % Adds a property to the class corresponding to the tag - if ~isprop(this,tag) - addprop(this,tag); - end - this.(tag)=p.Results.default; - end - - %Creates inputParser using the command list - function p = createCommandParser(this) - %Use input parser - %Requires input of the appropriate class - p=inputParser; - p.StructExpand=0; - %Flag for whether the command should initialize the device with - %defaults - addParameter(p, 'all',false,@islogical); - - for i=1:length(this.write_commands) - %Adds optional inputs for each command, with the - %appropriate default value from the command list and the - %required attributes for the command input. - tag=this.write_commands{i}; - % Create validation function based on properties: - % class, attributes and list of values - if ~isempty(this.CommandList.(tag).val_list) - v_func = @(x) any(cellfun(@(y) isequal(y, x),... - this.CommandList.(tag).val_list)); - else - v_func = @(x) validateattributes(x,... - this.CommandList.(tag).classes,... - this.CommandList.(tag).attributes); - end - addParameter(p, tag,... - this.CommandList.(tag).default, v_func); - end - this.CommandParser=p; - end - - %% Auxiliary functions for auto format assignment to commands - function str_spec=formatSpecFromAttributes(~,classes,attributes) - if ismember('char',classes) - str_spec='%s'; - elseif ismember('logical',classes)||... - (ismember('numeric',classes)&&... - ismember('integer',attributes)) - str_spec='%i'; - else - %assign default value, i.e. double - str_spec='%e'; - end - end - - function [class,attribute]=attributesFromFormatSpec(~, str_spec) - % find index of the first letter after the % sign - ind_p=strfind(str_spec,'%'); - ind=ind_p+find(isletter(str_spec(ind_p:end)),1)-1; - str_spec_letter=str_spec(ind); - switch str_spec_letter - case {'d','f','e','g'} - class={'numeric'}; - attribute={}; - case 'i' - class={'numeric'}; - attribute={'integer'}; - case 's' - class={'char'}; - attribute={}; - case 'b' - class={'logical'}; - attribute={}; - otherwise - % Any of the above classes will pass - class={'numeric','char','logical'}; - attribute={}; - end - end - end - - %% Get functions - methods - function command_names=get.command_names(this) - command_names=fieldnames(this.CommandList); - end - - function write_commands=get.write_commands(this) - ind_w=structfun(@(x) x.write_flag, this.CommandList); - write_commands=this.command_names(ind_w); - end - - function read_commands=get.read_commands(this) - ind_r=structfun(@(x) x.read_flag, this.CommandList); - read_commands=this.command_names(ind_r); - end - - function command_no=get.command_no(this) - command_no=length(this.command_names); - end - end -end \ No newline at end of file diff --git a/GUIs/GuiRsa.mlapp b/GUIs/GuiRsa.mlapp index 413f590..b2afbf3 100644 Binary files a/GUIs/GuiRsa.mlapp and b/GUIs/GuiRsa.mlapp differ diff --git a/Utility functions/readRunFiles.asv b/Utility functions/readRunFiles.asv deleted file mode 100644 index bc8de2c..0000000 --- a/Utility functions/readRunFiles.asv +++ /dev/null @@ -1,54 +0,0 @@ -function rumn_files = 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_runm = startsWith(all_names.m,'run','IgnoreCase',false); - runm_names = all_names.m(is_runm); - rumn_files = repmat(struct(),length(runm_names),1); - % Read headers of all the run*.m files - for i=1:length(runm_names) - name_match = regexp(runm_names{i},'run(.*)\.m','tokens'); - rumn_files(i).name = name_match{1}{1}; - fname = fullfile(dir, runm_names{i}); - rumn_files(i).fullname = fname; - try - fid = fopen(fname,'r'); - % Read the file line by line, with a paranoid limitation on - % the number of cycles - j = 1; - header =''; - while j<100000 - j=j+1; - str = strtrim(fgetl(fid)); - if isempty(str) - % An empty string - skip - header = [header,str]; - continue - elseif str(1)=='%' - % A comment string - match = regexp(str,'[%\s]*(.*)=(.*)','tokens'); - try - tag = lower(match{1}{1}); - rumn_files(i).(tag) = match{1}{2}; - header = [header,str]; - catch - end - continue - else - % Stop when the code begins - break - end - end - fclose(fid); - catch - warning('Could not process the run file %s', fname) - end - end -end -