Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

336 lignes
14KB

  1. classdef Equipment < handle
  2. %EQUIPMENT Summary of this class goes here
  3. % Detailed explanation goes here
  4. properties (SetAccess=protected)
  5. name
  6. tcp
  7. channel
  8. locked
  9. end
  10. properties (Dependent, SetAccess=private)
  11. error
  12. end
  13. properties (Hidden)
  14. debugbool
  15. end
  16. methods
  17. function ecq = Equipment(ipAddress,port,channel)
  18. %EQUIPMENT Construct an instance of this class.
  19. % This functions opens the required TCP connection
  20. % for this device. Channel is GPIB-channel on prologix
  21. % converter if used, otherwise set channel to -1.
  22. % Name is queried from device via '*IDN?' command.
  23. ecq.tcp = Equipment.getTCP(ipAddress,port);
  24. ecq.locked = false;
  25. ecq.channel = channel;
  26. ecq.name = ecq.idn();
  27. ecq.debugbool = false;
  28. if channel >= 0
  29. ecq.setPrologix;
  30. end
  31. end
  32. function id = idn(ecq)
  33. %IDN Queries identificantion from device via '*IDN?'.
  34. id = ecq.query_unsafe('*idn?');
  35. end
  36. function clear(ecq)
  37. %CLEAR Sends clear command to device via '*CLS'.
  38. %This function also clears the TCP inputbuffer;
  39. ecq.write_unsafe('*cls');
  40. flushinput(ecq.tcp);
  41. end
  42. function reset(ecq)
  43. %RESET Sends reset command to device via '*RST'.
  44. ecq.write_unsafe('*rst');
  45. end
  46. function debug(ecq)
  47. ecq.debugbool = ~ecq.debugbool;
  48. end
  49. function flush(ecq)
  50. flushinput(ecq.tcp);
  51. flushoutput(ecq.tcp);
  52. end
  53. function opc(ecq)
  54. %OPC executes 'operation complete query' to device.
  55. %Function holds untill device returns '1'. Must be
  56. %used to avoid interrupting busy device.
  57. ecq.write_unsafe('*OPC?');
  58. for i = 1:10
  59. ack = ecq.read;
  60. if strcmp(ack(1),'1')
  61. return
  62. end
  63. end
  64. error('Device is not ready');
  65. end
  66. function unlock(ecq)
  67. %UNLOCK Sets the device back to 'local control'
  68. %This function only supports devices via the Prologix.
  69. if ecq.channel >= 0
  70. fprintf(ecq.tcp,'++loc');
  71. ecq.locked = false;
  72. end
  73. end
  74. function lock(ecq)
  75. %UNLOCK Sets the device back to 'remote control'
  76. %This function only supports devices via the Prologix.
  77. if ecq.channel >= 0
  78. fprintf(ecq.tcp,'++llo');
  79. ecq.locked = true;
  80. else
  81. warning('Device does not support locking')
  82. end
  83. end
  84. function beep(ecq)
  85. %BEEP Sends the beep command to the device
  86. ecq.write('SYST:BEEP')
  87. end
  88. function write(ecq,message)
  89. %WRITE Sends a command to the channel.
  90. %The function will first check if the device is ready to
  91. %recieve a command via the OPC function. Then send the command
  92. %and eventually check if the device has thrown an error via
  93. %the ERROR function.
  94. %
  95. %See also QUERY
  96. ecq.opc;
  97. ecq.write_unsafe(message);
  98. ecq.error;
  99. end
  100. function data = bin_read(ecq,datalength,type,typesize)
  101. try
  102. if nargin < 4
  103. typesize = 8;
  104. end
  105. data = zeros(1,datalength);
  106. totalread = 0;
  107. maxlength = floor(ecq.tcp.InputBufferSize/typesize)-16;
  108. while datalength > 0
  109. readlength = min(datalength,maxlength);
  110. lastcount = 0;
  111. [lastdata,lastcount] = fread(ecq.tcp,[1,readlength],type);
  112. if lastcount == 0
  113. error('Data stream from device shorter than expected');
  114. end
  115. data(totalread+1:totalread+lastcount) = lastdata;
  116. totalread = totalread+lastcount;
  117. datalength = datalength - lastcount;
  118. end
  119. flushinput(ecq.tcp)
  120. ecq.clear
  121. catch ME
  122. flushinput(ecq.tcp);
  123. rethrow(ME);
  124. end
  125. end
  126. function data = bin_read_float(ecq,datalength)
  127. data = bin_read(ecq,datalength,'float',4);
  128. end
  129. function output = read(ecq)
  130. %READ Extracts recieved data from the TCP-buffer.
  131. %This function sends the '++read'-command to the Prologix if
  132. %needed. Will always read the TCP-buffer in matlab.
  133. if ecq.channel >= 0
  134. ecq.write_unsafe('++read');
  135. end
  136. output = fscanf(ecq.tcp);
  137. if ecq.debugbool
  138. fprintf(['<< ',output]);
  139. end
  140. end
  141. function output = query(ecq,message)
  142. %QUERY Sends command to the device and read the respond.
  143. %The command is send via the WRITE and the respond is collected
  144. %from the device.
  145. %
  146. %See also WRITE, READ
  147. ecq.opc;
  148. output = ecq.query_unsafe(message);
  149. ecq.error;
  150. end
  151. function errorlist = get.error(ecq)
  152. %ERROR Checks for errors on device. If any, throws a warning.
  153. %The function will pull all errors from the device error stack.
  154. %This is up to a maximum of 20 errors. If errors have occured
  155. %the function will throw a warning with all the error messages.
  156. for i = 1:20
  157. output = ecq.query_unsafe('SYSTem:ERRor?'); %Query error message from device.
  158. % [msgstr, msgid] = lastwarn;
  159. % if strcmp(msgid,'instrument:fscanf:unsuccessfulRead')
  160. % error(['Lost connection with ' ecq.name]);
  161. % end
  162. errorlist(i,1:(length(output))) = output; %Store the error message in the errorlist array.
  163. %GPIB protocol states that the error code '0' means no
  164. %error. The for loop will break if the last recieved error
  165. %code is zero.
  166. if str2double(regexp(output,'\d*','match','once'))==0 %Check if last recieved error code is '0'
  167. % If the 'no error' message is the only error then no
  168. % warning will be trown. However if there is more than
  169. % one error in the list. The function gives a warning
  170. % with all error messages.
  171. if i>1 %check for more than one error message.
  172. warning('Error from device: %s %s',ecq.name,reshape(errorlist(1:i-1,:)',1,[]));
  173. end
  174. ecq.clear;
  175. break;
  176. end
  177. end
  178. end
  179. end
  180. methods% (Access = protected)
  181. function write_unsafe(ecq,message)
  182. %WRITE_UNSAFE Sends command to device.
  183. %This function does not check if device is ready or check if an
  184. %error occured after writing. If possible one should always use
  185. %the WRITE function.
  186. %
  187. %See also WRITE, QUERY
  188. if ecq.channel >= 0
  189. fprintf(ecq.tcp,['++addr ', num2str(ecq.channel)]);
  190. if ecq.debugbool
  191. fprintf(['>> ++addr ', num2str(ecq.channel),'\n']);
  192. end
  193. end
  194. fprintf(ecq.tcp, message);
  195. if ecq.debugbool
  196. fprintf(['>> ',message,'\n']);
  197. end
  198. end
  199. function write_noerror(ecq,message)
  200. %WRITE Sends a command to the channel.
  201. %The function will first check if the device is ready to
  202. %recieve a command via the OPC function. Then send the command.
  203. %
  204. %See also WRITE
  205. ecq.opc;
  206. ecq.write_unsafe(message);
  207. end
  208. function output = query_unsafe(ecq,message)
  209. %QUERY_UNSAFE Sends command to device and reads device output.
  210. %This function does not check if device is ready or check if an
  211. %error occured after writing. If possible one should always use
  212. %the QUERY function.
  213. %
  214. %See also QUERY, WRITE, READ
  215. ecq.write_unsafe(message);
  216. output = read(ecq);
  217. end
  218. end
  219. methods (Access = protected, Hidden)
  220. function setPrologix(ecq)
  221. fprintf(ecq.tcp, '++mode 1'); %set device in controller mode
  222. fprintf(ecq.tcp, '++auto 0'); %disable automatic datapull. this avoids errors on equipment.
  223. end
  224. function delete(ecq)
  225. %DELETE Destructs the current object.
  226. ecq.unlock;
  227. Equipment.getTCP(ecq.tcp.RemoteHost,-ecq.tcp.RemotePort);
  228. end
  229. end
  230. methods (Static)
  231. function tcpobject = getTCP(ipAddress,port)
  232. %GETTCP Returns TCP-object for TCP-connection.
  233. %Function makes a TCP-connection for specific ipAddress and
  234. %port. If TCP-connection already exist no new connection is
  235. %made and only existing handle is returned.
  236. %For existing connections the function will store the amount of
  237. %handles in use. Via the DELETE function the connection will be
  238. %closed if the connection is not in use anymore.
  239. %The connection will be removed if the port is negative number.
  240. persistent tcpconnection; %make variable persistent to share tcp-handles across multiple function calls.
  241. if isempty(tcpconnection)
  242. %if the tcpconnection is empty (first time function
  243. %call) make a struct in the variable.
  244. tcpconnection = struct;
  245. end
  246. [ipname,ipAddress] = Equipment.ip2structname(ipAddress,abs(port)); %Get a structname and a cleaned ipaddress.
  247. if port > 0 %if port number is positive a connection is made.
  248. if ~isfield(tcpconnection, ipname) %check if the handle is already made before.
  249. tcpconnection.(ipname).tcp = tcpip(ipAddress,port); %Make TCP-connection
  250. tcpconnection.(ipname).nopen = 1; %Set number of connections in use to 1
  251. tcpconnection.(ipname).tcp.InputBufferSize = 2^24; %make really large buffer size 64MB. To acquire complete waveforms.
  252. tcpconnection.(ipname).tcp.Timeout = 5; %set timeout to 5 seconds.
  253. fopen(tcpconnection.(ipname).tcp); %Open the TCP-connection
  254. else %If connection already exist. Increase number of connections in use by 1.
  255. tcpconnection.(ipname).nopen = tcpconnection.(ipname).nopen + 1;
  256. end
  257. tcpobject = tcpconnection.(ipname).tcp; %return the TCP-connection handle.
  258. elseif port < 0 %If the portnumber is negative the connection is removed.
  259. if ~isfield(tcpconnection, ipname)
  260. return;
  261. elseif tcpconnection.(ipname).nopen > 1
  262. %If more than one object uses this tcp-handle. Decrease
  263. %the number of connections in use by 1.
  264. tcpconnection.(ipname).nopen = tcpconnection.(ipname).nopen - 1; %Decrease the number by 1.
  265. else
  266. %If only one handle uses this connection. The
  267. %connection is closed and the field is removed from the
  268. %tcpconnection struct.
  269. flushinput(tcpconnection.(ipname).tcp);
  270. fclose(tcpconnection.(ipname).tcp);
  271. tcpconnection = rmfield(tcpconnection,ipname);
  272. end
  273. else
  274. error([num2str(port),' is not a valid port number try a value between 1 and 65535.']);
  275. end
  276. end
  277. function bool = isnum(input)
  278. %ISNUM Tests if the input is numeric scalar
  279. bool = isnumeric(input)&&isscalar(input);
  280. end
  281. function num = forceNum(input)
  282. %FORCENUM Throws an error if the input is not numeric.
  283. if ~Equipment.isnum(input)
  284. error('Input should be a (single) number.');
  285. end
  286. num = input;
  287. end
  288. function iptest(ipAddress)
  289. %IPTEST Checks if the given IPv4-address is valid.
  290. 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');
  291. if isempty(validip)
  292. error('Invalid IP-address');
  293. end
  294. end
  295. function [structname,cleanip] = ip2structname(ipAddress,port)
  296. %IP2STRUCTNAME Returns a structname and ip w/out leading zeros.
  297. %structname to store stuff in struct (especially for GETTCP).
  298. %cleanip is a shortened ip without leading zeros.
  299. cleanip = regexprep(ipAddress,'(?:(?<=\.)|^)(?:0+)(?=\d)','');
  300. Equipment.iptest(cleanip);
  301. structname = matlab.lang.makeValidName(['ip',cleanip,'_',num2str(port)]);
  302. end
  303. end
  304. end