|
- classdef Equipment < handle
- %EQUIPMENT Summary of this class goes here
- % Detailed explanation goes here
-
- properties (SetAccess=private)
- name
- tcp
- channel
- locked
- end
- properties (Dependent, SetAccess=private)
- error
- end
-
- methods
- function ecq = Equipment(ipAddress,port,channel)
- %EQUIPMENT Construct an instance of this class.
- % This functions opens the required TCP connection
- % for this device. Channel is GPIB-channel on prologix
- % converter if used, otherwise set channel to -1.
- % Name is queried from device via '*IDN?' command.
- ecq.tcp = Equipment.getTCP(ipAddress,port);
- ecq.locked = false;
- ecq.channel = channel;
- ecq.name = ecq.idn();
- if channel >= 0
- ecq.setPrologix;
- end
- end
-
- function id = idn(ecq)
- %IDN Queries identificantion from device via '*IDN?'.
- id = ecq.query_unsafe('*idn?');
- end
-
- function clear(ecq)
- %CLEAR Sends clear command to device via '*CLS'.
- ecq.write_unsafe('*cls');
- end
-
- function opc(ecq)
- %OPC executes 'operation complete query' to device.
- %Function holds untill device returns '1'. Must be
- %used to avoid interrupting busy device.
- ecq.query_unsafe('*OPC?');
- end
-
- function unlock(ecq)
- %UNLOCK Sets the device back to 'local control'
- %This function only supports devices via the Prologix.
- if ecq.channel >= 0
- fprintf(ecq.tcp,'++loc');
- ecq.locked = false;
- end
- end
-
- function lock(ecq)
- %UNLOCK Sets the device back to 'remote control'
- %This function only supports devices via the Prologix.
- if ecq.channel >= 0
- fprintf(ecq.tcp,'++llo');
- ecq.locked = true;
- else
- warning('Device does not support locking')
- end
- end
-
- function beep(ecq)
- %BEEP Sends the beep command to the device
- ecq.write('SYST:BEEP')
- end
-
- function write(ecq,message)
- %WRITE Sends a command to the channel.
- %The function will first check if the device is ready to
- %recieve a command via the OPC function. Then send the command
- %and eventually check if the device has thrown an error via
- %the ERROR function.
- %
- %See also QUERY
- ecq.opc;
- ecq.write_unsafe(message);
- ecq.error;
- end
-
- function output = read(ecq)
- %READ Extracts recieved data from the TCP-buffer.
- %This function sends the '++read'-command to the Prologix if
- %needed. Will always read the TCP-buffer in matlab.
- if ecq.channel >= 0
- ecq.write_unsafe('++read');
- end
- output = fscanf(ecq.tcp);
- fprintf(['<< ',output]);
- end
-
- function output = query(ecq,message)
- %QUERY Sends command to the device and read the respond.
- %The command is send via the WRITE and the respond is collected
- %from the device.
- %
- %See also WRITE, READ
- ecq.opc;
- output = ecq.query_unsafe(message);
- ecq.error;
- end
-
- function errorlist = get.error(ecq)
- %ERROR Checks for errors on device. If any, throws a warning.
- %The function will pull all errors from the device error stack.
- %This is up to a maximum of 20 errors. If errors have occured
- %the function will throw a warning with all the error messages.
- for i = 1:20
- output = ecq.query_unsafe('SYSTem:ERRor?'); %Query error message from device.
- errorlist(i,1:(length(output))) = output; %Store the error message in the errorlist array.
- %GPIB protocol states that the error code '0' means no
- %error. The for loop will break if the last recieved error
- %code is zero.
- if str2double(regexp(output,'\d*','match','once'))==0 %Check if last recieved error code is '0'
- % If the 'no error' message is the only error then no
- % warning will be trown. However if there is more than
- % one error in the list. The function gives a warning
- % with all error messages.
- if i>1 %check for more than one error message.
- warning('Error from device: %s %s',ecq.name,reshape(errorlist(1:i-1,:)',1,[]));
- end
- ecq.clear;
- break;
- end
- end
- end
- end
- methods (Access = protected)
-
- function write_unsafe(ecq,message)
- %WRITE_UNSAFE Sends command to device.
- %This function does not check if device is ready or check if an
- %error occured after writing. If possible one should always use
- %the WRITE function.
- %
- %See also WRITE, QUERY
- if ecq.channel >= 0
- fprintf(ecq.tcp,['++addr ', num2str(ecq.channel)]);
- fprintf(['>> ++addr ', num2str(ecq.channel),'\n']);
- end
- fprintf(ecq.tcp, message);
- fprintf(['>> ',message,'\n']);
- end
-
- function output = query_unsafe(ecq,message)
- %QUERY_UNSAFE Sends command to device and reads device output.
- %This function does not check if device is ready or check if an
- %error occured after writing. If possible one should always use
- %the QUERY function.
- %
- %See also QUERY, WRITE, READ
- ecq.write_unsafe(message);
- output = read(ecq);
- end
- end
- methods (Access = protected, Hidden)
-
- function setPrologix(ecq)
- fprintf(ecq.tcp, '++mode 1'); %set device in controller mode
- fprintf(ecq.tcp, '++auto 0'); %disable automatic datapull. this avoids errors on equipment.
- end
-
- function delete(ecq)
- %DELETE Destructs the current object.
- ecq.unlock;
- Equipment.getTCP(ecq.tcp.RemoteHost,-ecq.tcp.RemotePort);
- end
-
- end
-
- methods (Static)
- function tcpobject = getTCP(ipAddress,port)
- %GETTCP Returns TCP-object for TCP-connection.
- %Function makes a TCP-connection for specific ipAddress and
- %port. If TCP-connection already exist no new connection is
- %made and only existing handle is returned.
- %For existing connections the function will store the amount of
- %handles in use. Via the DELETE function the connection will be
- %closed if the connection is not in use anymore.
- %The connection will be removed if the port is negative number.
-
- persistent tcpconnection; %make variable persistent to share tcp-handles across multiple function calls.
- [ipname,ipAddress] = Equipment.ip2structname(ipAddress,abs(port)); %Get a structname and a cleaned ipaddress.
- if port > 0 %if port number is positive a connection is made.
- if isempty(tcpconnection)
- %if the tcpconnection is empty (first time function
- %call) make a struct in the variable.
- tcpconnection = struct;
- end
-
- if ~isfield(tcpconnection, ipname) %check if the handle is already made before.
- tcpconnection.(ipname).tcp = tcpip(ipAddress,port); %Make TCP-connection
- tcpconnection.(ipname).nopen = 1; %Set number of connections in use to 1
- fopen(tcpconnection.(ipname).tcp); %Open the TCP-connection
- else %If connection already exist. Increase number of connections in use by 1.
- tcpconnection.(ipname).nopen = tcpconnection.(ipname).nopen + 1;
- end
- tcpobject = tcpconnection.(ipname).tcp; %return the TCP-connection handle.
- elseif port < 0 %If the portnumber is negative the connection is removed.
- if tcpconnection.(ipname).nopen > 1
- %If more than one object uses this tcp-handle. Decrease
- %the number of connections in use by 1.
- tcpconnection.(ipname).nopen = tcpconnection.(ipname).nopen - 1; %Decrease the number by 1.
- else
- %If only one handle uses this connection. The
- %connection is closed and the field is removed from the
- %tcpconnection struct.
- fclose(tcpconnection.(ipname).tcp);
- tcpconnection = rmfield(tcpconnection,ipname);
- end
- else
- error([num2str(port),' is not a valid port number try a value between 1 and 65535.']);
- end
- end
-
- function bool = isnum(input)
- %ISNUM Tests if the input is numeric scalar
- bool = isnumeric(input)&&isscalar(input);
- end
-
- function num = forceNum(input)
- %FORCENUM Throws an error if the input is not numeric.
- if ~Equipment.isnum(input)
- error('Input should be a (single) number.');
- end
- num = input;
- end
-
- function iptest(ipAddress)
- %IPTEST Checks if the given IPv4-address is valid.
- validip = regexp(ipAddress,'^(?:(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9]))$', 'once');
- if isempty(validip)
- error('Invalid IP-address');
- end
- end
-
- function [structname,cleanip] = ip2structname(ipAddress,port)
- %IP2STRUCTNAME Returns a structname and ip w/out leading zeros.
- %structname to store stuff in struct (especially for GETTCP).
- %cleanip is a shortened ip without leading zeros.
- cleanip = regexprep(ipAddress,'(?:(?<=\.)|^)(?:0+)(?=\d)','');
- Equipment.iptest(cleanip);
- structname = matlab.lang.makeValidName(['ip',cleanip,'_',num2str(port)]);
- end
- end
- end
|