You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

240 line
10KB

  1. classdef Equipment < handle
  2. %EQUIPMENT Summary of this class goes here
  3. % Detailed explanation goes here
  4. properties (SetAccess=private)
  5. name
  6. tcp
  7. channel
  8. locked
  9. end
  10. properties (Dependent, SetAccess=private)
  11. error
  12. end
  13. methods
  14. function ecq = Equipment(ipAddress,port,channel)
  15. %EQUIPMENT Construct an instance of this class.
  16. % This functions opens the required TCP connection
  17. % for this device. Channel is GPIB-channel on prologix
  18. % converter if used, otherwise set channel to -1.
  19. % Name is queried from device via '*IDN?' command.
  20. ecq.tcp = Equipment.getTCP(ipAddress,port);
  21. ecq.locked = false;
  22. ecq.channel = channel;
  23. ecq.name = ecq.idn();
  24. end
  25. function id = idn(ecq)
  26. %IDN Queries identificantion from device via '*IDN?'.
  27. id = ecq.query_unsafe('*idn?');
  28. end
  29. function clear(ecq)
  30. %CLEAR Sends clear command to device via '*CLS'.
  31. ecq.write_unsafe('*cls');
  32. end
  33. function opc(ecq)
  34. %OPC executes 'operation complete query' to device.
  35. %Function holds untill device returns '1'. Must be
  36. %used to avoid interrupting busy device.
  37. ecq.query_unsafe('*OPC?');
  38. end
  39. function unlock(ecq)
  40. %UNLOCK Sets the device back to 'local control'
  41. %This function only supports devices via the Prologix.
  42. if ecq.channel >= 0
  43. fprintf(ecq.tcp,'++loc');
  44. ecq.locked = false;
  45. end
  46. end
  47. function lock(ecq)
  48. %UNLOCK Sets the device back to 'remote control'
  49. %This function only supports devices via the Prologix.
  50. if ecq.channel >= 0
  51. fprintf(ecq.tcp,'++llo');
  52. ecq.locked = true;
  53. else
  54. warning('Device does not support locking')
  55. end
  56. end
  57. function beep(ecq)
  58. %BEEP Sends the beep command to the device
  59. ecq.write('SYST:BEEP')
  60. end
  61. function write(ecq,message)
  62. %WRITE Sends a command to the channel.
  63. %The function will first check if the device is ready to
  64. %recieve a command via the OPC function. Then send the command
  65. %and eventually check if the device has thrown an error via
  66. %the ERROR function.
  67. %
  68. %See also QUERY
  69. ecq.opc;
  70. ecq.write_unsafe(message);
  71. ecq.error;
  72. end
  73. function output = read(ecq)
  74. %READ Extracts recieved data from the TCP-buffer.
  75. %This function sends the '++read'-command to the Prologix if
  76. %needed. Will always read the TCP-buffer in matlab.
  77. if ecq.channel >= 0
  78. write_unsafe('++read');
  79. end
  80. output = fscanf(ecq.tcp);
  81. end
  82. function output = query(ecq,message)
  83. %QUERY Sends command to the device and read the respond.
  84. %The command is send via the WRITE and the respond is collected
  85. %from the device.
  86. %
  87. %See also WRITE, READ
  88. ecq.opc;
  89. output = ecq.query_unsafe(message);
  90. ecq.error;
  91. end
  92. function errorlist = get.error(ecq)
  93. %ERROR Checks for errors on device. If any, throws a warning.
  94. %The function will pull all errors from the device error stack.
  95. %This is up to a maximum of 20 errors. If errors have occured
  96. %the function will throw a warning with all the error messages.
  97. for i = 1:20
  98. output = ecq.query_unsafe('SYSTem:ERRor?'); %Query error message from device.
  99. errorlist(i,1:(length(output))) = output; %Store the error message in the errorlist array.
  100. %GPIB protocol states that the error code '0' means no
  101. %error. The for loop will break if the last recieved error
  102. %code is zero.
  103. if str2double(regexp(output,'\d*','match','once'))==0 %Check if last recieved error code is '0'
  104. % If the 'no error' message is the only error then no
  105. % warning will be trown. However if there is more than
  106. % one error in the list. The function gives a warning
  107. % with all error messages.
  108. if i>1 %check for more than one error message.
  109. warning('Error from device: %s %s',ecq.name,reshape(errorlist(1:i-1,:)',1,[]));
  110. end
  111. ecq.clear;
  112. break;
  113. end
  114. end
  115. end
  116. end
  117. methods (Access = protected)
  118. function write_unsafe(ecq,message)
  119. %WRITE_UNSAFE Sends command to device.
  120. %This function does not check if device is ready or check if an
  121. %error occured after writing. If possible one should always use
  122. %the WRITE function.
  123. %
  124. %See also WRITE, QUERY
  125. if ecq.channel >= 0
  126. fprintf(ecq.tcp,['++addr ', num2str(ecq.channel)]);
  127. end
  128. fprintf(ecq.tcp, message);
  129. end
  130. function output = query_unsafe(ecq,message)
  131. %QUERY_UNSAFE Sends command to device and reads device output.
  132. %This function does not check if device is ready or check if an
  133. %error occured after writing. If possible one should always use
  134. %the QUERY function.
  135. %
  136. %See also QUERY, WRITE, READ
  137. ecq.write_unsafe(message);
  138. output = read(ecq);
  139. end
  140. end
  141. methods (Access = protected, Hidden)
  142. function delete(ecq)
  143. %DELETE Destructs the current object.
  144. ecq.unlock;
  145. Equipment.getTCP(ecq.tcp.RemoteHost,-ecp.tcp.RemotePort);
  146. end
  147. end
  148. methods (Static)
  149. function tcpobject = getTCP(ipAddress,port)
  150. %GETTCP Returns TCP-object for TCP-connection.
  151. %Function makes a TCP-connection for specific ipAddress and
  152. %port. If TCP-connection already exist no new connection is
  153. %made and only existing handle is returned.
  154. %For existing connections the function will store the amount of
  155. %handles in use. Via the DELETE function the connection will be
  156. %closed if the connection is not in use anymore.
  157. %The connection will be removed if the port is negative number.
  158. persistent tcpconnection; %make variable persistent to share tcp-handles across multiple function calls.
  159. [ipname,ipAddress] = Equipment.ip2structname(ipAddress,abs(port)); %Get a structname and a cleaned ipaddress.
  160. if port > 0 %if port number is positive a connection is made.
  161. if isempty(tcpconnection)
  162. %if the tcpconnection is empty (first time function
  163. %call) make a struct in the variable.
  164. tcpconnection = struct;
  165. end
  166. if ~isfield(tcpconnection, ipname) %check if the handle is already made before.
  167. tcpconnection.(ipname).tcp = tcpip(ipAddress,port); %Make TCP-connection
  168. tcpconnection.(ipname).nopen = 1; %Set number of connections in use to 1
  169. fopen(tcpconnection.(ipname).tcp); %Open the TCP-connection
  170. else %If connection already exist. Increase number of connections in use by 1.
  171. tcpconnection.(ipname).nopen = tcpconnection.(ipname).nopen + 1;
  172. end
  173. tcpobject = tcpconnection.(ipname).tcp; %return the TCP-connection handle.
  174. elseif port < 0 %If the portnumber is negative the connection is removed.
  175. if tcpconnection.(ipname).nopen > 1
  176. %If more than one object uses this tcp-handle. Decrease
  177. %the number of connections in use by 1.
  178. tcpconnection.(ipname).nopen = tcpconnection.(ipname).nopen - 1; %Decrease the number by 1.
  179. else
  180. %If only one handle uses this connection. The
  181. %connection is closed and the field is removed from the
  182. %tcpconnection struct.
  183. fclose(tcpconnection.(ipname).tcp);
  184. tcpconnection = rmfield(tcpconnection,ipname);
  185. end
  186. else
  187. error([num2str(port),' is not a valid port number try a value between 1 and 65535.']);
  188. end
  189. end
  190. function bool = isnum(input)
  191. %ISNUM Tests if the input is numeric scalar
  192. bool = isnumeric(input)&&isscalar(input);
  193. end
  194. function num = forceNum(input)
  195. %FORCENUM Throws an error if the input is not numeric.
  196. if ~isnum(input)
  197. error('Input should be a (single) number.');
  198. end
  199. num = input;
  200. end
  201. function iptest(ipAddress)
  202. %IPTEST Checks if the given IPv4-address is valid.
  203. 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');
  204. if isempty(validip)
  205. error('Invalid IP-address');
  206. end
  207. end
  208. function [structname,cleanip] = ip2structname(ipAddress,port)
  209. %IP2STRUCTNAME Returns a structname and ip w/out leading zeros.
  210. %structname to store stuff in struct (especially for GETTCP).
  211. %cleanip is a shortened ip without leading zeros.
  212. cleanip = regexprep(ipAddress,'(?:(?<=\.)|^)(?:0+)(?=\d)','');
  213. Equipment.iptest(cleanip);
  214. structname = matlab.lang.makeValidName(['ip',cleanip,'_',num2str(port)]);
  215. end
  216. end
  217. end