1 | function [AM, tout, DataTime, ErrorFlag] = getpv(varargin) |
---|
2 | %GETPV - Returns a variable from the online system or the model |
---|
3 | % |
---|
4 | % FamilyName/DeviceList Method |
---|
5 | % [AM, tout, DataTime] = getpv(Family, Field, DeviceList, t, FreshDataFlag, TimeOutPeriod) |
---|
6 | % |
---|
7 | % Data Structure |
---|
8 | % [AM, tout, DataTime] = getpv(DataStructure, t, FreshDataFlag, TimeOutPeriod) |
---|
9 | % |
---|
10 | % TangoName or ChannelName Method |
---|
11 | % [AM, tout, DataTime, ErrorFlag] = getpv(TangoName, t, FreshDataFlag, TimeOutPeriod) |
---|
12 | % |
---|
13 | % CommonName Method (Family can be '' to search all families, Field is optional) |
---|
14 | % [AM, tout, DataTime] = getpv(CommonName, Field, t, FreshDataFlag, TimeOutPeriod) |
---|
15 | % [AM, tout, DataTime] = getpv(Family, Field, CommonName, t, FreshDataFlag, TimeOutPeriod) |
---|
16 | % |
---|
17 | % INPUTS |
---|
18 | % 1. Family - Family Name |
---|
19 | % Data Structure |
---|
20 | % Channel Name |
---|
21 | % TangoName |
---|
22 | % Accelerator Object |
---|
23 | % For CommonNames, Family=[] searches all families |
---|
24 | % (or Cell Array of inputs) |
---|
25 | % |
---|
26 | % 2. Field - Subfield name of an accelerator family ('Monitor', 'Setpoint', etc) |
---|
27 | % {Default: 'Monitor' or '' or ChannelName method} |
---|
28 | % (For non-Family subfields, Field is added as .Field, see Note #8 below for more information.) |
---|
29 | % |
---|
30 | % 3. DeviceList - [Sector Device #] or [element #] list {Default or empty list: Entire family} |
---|
31 | % Note: if input 1 is a cell array then DeviceList must be a cell array |
---|
32 | % CommonName - Common name can replace a DeviceList (scalar or vector outputs) |
---|
33 | % |
---|
34 | % 4. t - Time vector of when to start taking data (t can not be a cell) {Default: 0} |
---|
35 | % |
---|
36 | % 5. FreshDataFlag - 0 -> Return after first measurement {Default} |
---|
37 | % else -> Return after FreshDataFlag number of new measurements have been read |
---|
38 | % Ie, getpv('BPMx',[1 1],0,2) measures the orbit then continues to read the orbit |
---|
39 | % until 2 new orbits have been measured and returns the last measurement. |
---|
40 | % Note: 1. t can only be a scalar when using the FreshDataFlag. |
---|
41 | % 2. FreshDataFlag cannot be used with 'Matrix' data types. |
---|
42 | % |
---|
43 | % 6. TimeOutPeriod - Time-out period when waiting for fresh data {Default: 10 seconds} |
---|
44 | % |
---|
45 | % 7. 'Struct' - Return a data structure {Default for data structure inputs} |
---|
46 | % 'Numeric' - Return numeric outputs {Default for non-data structure inputs} |
---|
47 | % 'Object' - Return a accelerator object (AccObj) |
---|
48 | % |
---|
49 | % 8. Units flag overrides |
---|
50 | % 'Physics' - Use physics units |
---|
51 | % 'Hardware' - Use hardware units |
---|
52 | % |
---|
53 | % 9. Mode flag overrides |
---|
54 | % 'Online' - Get data online |
---|
55 | % 'Model' - get data on the model |
---|
56 | % 'Manual' - Get data manually |
---|
57 | % |
---|
58 | % 10. 'Double' - The output will be a double {Default} |
---|
59 | % 'String' - The output will be a string |
---|
60 | % |
---|
61 | % |
---|
62 | % OUTPUTS |
---|
63 | % 1. AM - Monitor values (Column vector or matrix where each column is a data point in time) |
---|
64 | % |
---|
65 | % 2. tout - Time when measurement was completed according to the computer time (Matlab time) (row vector) |
---|
66 | % tout-t is the time it took to make the measurement. diff(t) can be arbitarily small, but tout will |
---|
67 | % report the actual completion time. |
---|
68 | % |
---|
69 | % 3. DataTime - Time when the data was measured (as report by the hardware) |
---|
70 | % Time since 00:00:00, Jan 1, 1970 in days (in the present time zone) |
---|
71 | % Units are in Matlab "serial day number" format (days) to be compatible with |
---|
72 | % timing functions like datevec, datenum, datetick, etc. |
---|
73 | % For exemple, [d,t,datatime] = getam('BPMx',[],0:.5:10); |
---|
74 | % plot(datatime, d); datetick x |
---|
75 | % When using the model, the datatime is the same a the computer time (Matlab time). |
---|
76 | % |
---|
77 | % NOTES |
---|
78 | % 1. The output will be a data structure if the word 'struct' appears somewhere on the input line |
---|
79 | % or if the input is a data structure and 'numeric' is not on the input line. |
---|
80 | % |
---|
81 | % 2. For data structure inputs: |
---|
82 | % Family - DataStructure.FamilyName (This field must exist) |
---|
83 | % Field - DataStructure.Field (Field can be overridden on the input line) |
---|
84 | % DeviceList - DataStructure.DeviceList (DeviceList can be overridden on the input line) |
---|
85 | % Units - DataStructure.Units (Units can be overridden on the input line) |
---|
86 | % (The Mode field is ignored!) |
---|
87 | % |
---|
88 | % 3. For data structure outputs: |
---|
89 | % TimeStamp - Time (Matlab clock) at the start of the function |
---|
90 | % tout - Delta time vector at the end of each measurement (relative to TimeStamp) |
---|
91 | % |
---|
92 | % 4. diff(t) should not be too small. If the desired time to collect the data is too |
---|
93 | % short then the data collecting will not be able to keep up. Always check tout. |
---|
94 | % (t - tout) is the time it took to collect the data on each iteration. |
---|
95 | % |
---|
96 | % 5. An easy way to averaged 10 monitors is: |
---|
97 | % PVmean = mean(getpv(Family,DeviceList,0:.5:4.5)')'; % .5 second between measurements |
---|
98 | % |
---|
99 | % 6. Channel name method is always Online! |
---|
100 | % |
---|
101 | % 7. It is often useful to measure the update rate of a set of channel by using a very |
---|
102 | % small time between measurements. |
---|
103 | % For example, [d, tout] = getpv('BPMx', 'Monitor', [], 0:eps:100*eps); |
---|
104 | % plot(tout(1:end-1), 1./diff(tout),'.-'); % Point-wise data rate |
---|
105 | % If the update rate of the hardware is slower then the control system, then |
---|
106 | % hardware data rate can be visually inspected by plotting, |
---|
107 | % plot(tout, d,'.-'); |
---|
108 | % |
---|
109 | % 8. For cell array inputs: |
---|
110 | % a. Input 1 defines the size of all cells |
---|
111 | % b. All of the cell array inputs must be the same size |
---|
112 | % c. Field does not have to be a cell array but DeviceList does (if they exist) |
---|
113 | % d. t, FreshDataFlag, TimeOutPeriod can not be cell arrays |
---|
114 | % e. Waveforms do not work with cell arrays. |
---|
115 | % |
---|
116 | % 8. The Field input can be used for getting the "dot" EPICS field. For instance, at the ALS |
---|
117 | % getpv('BPMx','SCAN',[1 2],'String') will return SR01S___IBPM2X_AM02.SCAN as a string. |
---|
118 | % (Note: at Spear ':' is used instead of '.') |
---|
119 | % |
---|
120 | % 10. Error flaga are not used at the moment since all errors cause a Matlab error. |
---|
121 | % Use try;catch statements to catch errors. |
---|
122 | % |
---|
123 | % 12. If say Golden is a software field in the MML structure in the BPMx family, then |
---|
124 | % getpv('BPMx','Golden', DeviceList) will return the data in that field. |
---|
125 | % |
---|
126 | % See also getam, getsp, setpv, steppv |
---|
127 | % |
---|
128 | % Written by Greg Portmann |
---|
129 | |
---|
130 | |
---|
131 | % Starting time |
---|
132 | t0 = clock; |
---|
133 | |
---|
134 | |
---|
135 | % Defaults |
---|
136 | FieldDefault = 'Monitor'; |
---|
137 | Field = FieldDefault; |
---|
138 | DeviceList = []; |
---|
139 | t = 0; |
---|
140 | FreshDataFlag = 0; |
---|
141 | TimeOutPeriod = 10; |
---|
142 | ErrorFlag = 0; |
---|
143 | |
---|
144 | StructOutputFlag = 0; |
---|
145 | NumericOutputFlag = 0; |
---|
146 | ObjectOutputFlag = 0; |
---|
147 | ModeFlag = ''; |
---|
148 | UnitsFlag = ''; |
---|
149 | OutputDataType = 'Double'; |
---|
150 | |
---|
151 | |
---|
152 | % Look if 'struct' or 'numeric' in on the input line |
---|
153 | InputFlags = {}; |
---|
154 | for i = length(varargin):-1:1 |
---|
155 | if isstruct(varargin{i}) |
---|
156 | % Ignor structures |
---|
157 | elseif iscell(varargin{i}) |
---|
158 | % Ignor cells |
---|
159 | elseif isa(varargin{i},'AccObj') |
---|
160 | AccObj1 = struct(varargin{i}); |
---|
161 | Families = fieldnames(AccObj1); |
---|
162 | j = 0; |
---|
163 | for k = 1:length(Families) |
---|
164 | if ~isempty(AccObj1.(Families{k})) |
---|
165 | j = j + 1; |
---|
166 | tmpcell{j} = AccObj1.(Families{k}); |
---|
167 | end |
---|
168 | end |
---|
169 | if length(tmpcell) == 1 |
---|
170 | varargin{i} = tmpcell{1}; |
---|
171 | else |
---|
172 | varargin{i} = tmpcell; |
---|
173 | end |
---|
174 | if ~NumericOutputFlag |
---|
175 | ObjectOutputFlag = 1; |
---|
176 | StructOutputFlag = 1; |
---|
177 | end |
---|
178 | elseif strcmpi(varargin{i},'struct') |
---|
179 | StructOutputFlag = 1; |
---|
180 | ObjectOutputFlag = 0; |
---|
181 | varargin(i) = []; |
---|
182 | elseif strcmpi(varargin{i},'numeric') |
---|
183 | NumericOutputFlag = 1; |
---|
184 | StructOutputFlag = 0; |
---|
185 | ObjectOutputFlag = 0; |
---|
186 | varargin(i) = []; |
---|
187 | elseif strcmpi(varargin{i},'simulator') || strcmpi(varargin{i},'model') |
---|
188 | ModeFlag = 'SIMULATOR'; |
---|
189 | InputFlags = [InputFlags varargin(i)]; |
---|
190 | varargin(i) = []; |
---|
191 | elseif strcmpi(varargin{i},'Online') |
---|
192 | ModeFlag = 'Online'; |
---|
193 | InputFlags = [InputFlags varargin(i)]; |
---|
194 | varargin(i) = []; |
---|
195 | elseif strcmpi(varargin{i},'Manual') |
---|
196 | ModeFlag = 'Manual'; |
---|
197 | InputFlags = [InputFlags varargin(i)]; |
---|
198 | varargin(i) = []; |
---|
199 | elseif strcmpi(varargin{i},'Special') |
---|
200 | ModeFlag = 'Special'; |
---|
201 | InputFlags = [InputFlags varargin(i)]; |
---|
202 | varargin(i) = []; |
---|
203 | elseif strcmpi(varargin{i},'physics') |
---|
204 | UnitsFlag = 'Physics'; |
---|
205 | InputFlags = [InputFlags varargin(i)]; |
---|
206 | varargin(i) = []; |
---|
207 | elseif strcmpi(varargin{i},'hardware') |
---|
208 | UnitsFlag = 'Hardware'; |
---|
209 | InputFlags = [InputFlags varargin(i)]; |
---|
210 | varargin(i) = []; |
---|
211 | elseif strcmpi(varargin{i},'archive') |
---|
212 | % Just remove |
---|
213 | varargin(i) = []; |
---|
214 | elseif strcmpi(varargin{i},'noarchive') |
---|
215 | % Just remove |
---|
216 | varargin(i) = []; |
---|
217 | elseif strcmpi(varargin{i},'String') |
---|
218 | OutputDataType = 'String'; |
---|
219 | InputFlags = [InputFlags varargin(i)]; |
---|
220 | varargin(i) = []; |
---|
221 | elseif strcmpi(varargin{i},'Double') |
---|
222 | OutputDataType = 'Double'; |
---|
223 | InputFlags = [InputFlags varargin(i)]; |
---|
224 | varargin(i) = []; |
---|
225 | elseif strcmpi(varargin{i},'WaveForm') || strcmpi(varargin{i},'Matrix') |
---|
226 | OutputDataType = 'Matrix'; |
---|
227 | InputFlags = [InputFlags varargin(i)]; |
---|
228 | varargin(i) = []; |
---|
229 | elseif strcmpi(varargin{i},'Object') |
---|
230 | ObjectOutputFlag = 1; |
---|
231 | StructOutputFlag = 1; |
---|
232 | varargin(i) = []; |
---|
233 | elseif strcmpi(varargin{i},'Retry') |
---|
234 | InputFlags = [InputFlags varargin(i)]; |
---|
235 | varargin(i) = []; |
---|
236 | elseif strcmpi(varargin{i},'NoRetry') |
---|
237 | InputFlags = [InputFlags varargin(i)]; |
---|
238 | varargin(i) = []; |
---|
239 | end |
---|
240 | end |
---|
241 | |
---|
242 | if isempty(varargin) |
---|
243 | error('Must have at least one input (Family, Data structure, or Channel Name).'); |
---|
244 | end |
---|
245 | |
---|
246 | |
---|
247 | |
---|
248 | %%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
249 | % CELL OR CELL ARRAY INPUT % |
---|
250 | %%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
251 | if iscell(varargin{1}) |
---|
252 | %if strcmpi(ModeFlag, 'Online') | (isempty(ModeFlag) & strcmpi(getmode(varargin{1}{1}), 'Online')) |
---|
253 | % % Unfortunately the following code using channelnames is not much of a speed improvement over |
---|
254 | % % interating over cell arrays (which is needed for simulator mode) |
---|
255 | % |
---|
256 | % % Online cell arrays |
---|
257 | % % |
---|
258 | % % Online cell arrays are treated differently because to the desired for speed. |
---|
259 | % % By loading all the channel names into one array then sending to the c-function |
---|
260 | % % with the t-vector, the total time is greatly sped up. However, using channel names |
---|
261 | % % only works in online mode. The one problem is all output have to scalars. |
---|
262 | % |
---|
263 | % |
---|
264 | % % Count the number of inputs which are cells (Family or DeviceList) or strings (possibly Field) |
---|
265 | % NCellOrString = 1; |
---|
266 | % for i = 2:length(varargin) |
---|
267 | % if ~iscell(varargin{i}) |
---|
268 | % if ~ischar(varargin{i}) |
---|
269 | % break; |
---|
270 | % else |
---|
271 | % NCellOrString = NCellOrString + 1; |
---|
272 | % end |
---|
273 | % else |
---|
274 | % NCellOrString = NCellOrString + 1; |
---|
275 | % %if length(varargin{1})~=length(varargin{NCellOrString}) | length(varargin{NCellOrString})==1 |
---|
276 | % % error('When using cell, all the cells must be the same size as input 1 or be length one.'); |
---|
277 | % %end |
---|
278 | % end |
---|
279 | % end |
---|
280 | % |
---|
281 | % % t (if it exists) should be the next input |
---|
282 | % if length(varargin) >= NCellOrString+1 |
---|
283 | % if iscell(varargin{NCellOrString+1}) |
---|
284 | % error(sprintf('Expecting input #%d to be a time vector not a cell', NCellOrString+1)); |
---|
285 | % end |
---|
286 | % if ischar(varargin{NCellOrString+1}) |
---|
287 | % error(sprintf('Expecting input #%d to be a time vector not a string', NCellOrString+1)); |
---|
288 | % end |
---|
289 | % t = varargin{NCellOrString+1}; |
---|
290 | % varargin{NCellOrString+1} = []; |
---|
291 | % if isempty(t) |
---|
292 | % t = 0; |
---|
293 | % end |
---|
294 | % end |
---|
295 | % |
---|
296 | % % FreshDataFlag (if it exists) should be the next input |
---|
297 | % if length(varargin) >= NCellOrString+1 |
---|
298 | % if iscell(varargin{NCellOrString+1}) |
---|
299 | % error(sprintf('Expecting input #%d to be FreshDataFlag not a cell', NCellOrString+2)); |
---|
300 | % end |
---|
301 | % if ischar(varargin{NCellOrString+1}) |
---|
302 | % error(sprintf('Expecting input #%d to be FreshDataFlag not a string', NCellOrString+2)); |
---|
303 | % end |
---|
304 | % FreshDataFlag = varargin{NCellOrString+1}; |
---|
305 | % varargin{NCellOrString+1} = []; |
---|
306 | % end |
---|
307 | % |
---|
308 | % % TimeOutPeriod (if it exists) should be the next input |
---|
309 | % if length(varargin) >= NCellOrString+1 |
---|
310 | % if iscell(varargin{NCellOrString+1}) |
---|
311 | % error(sprintf('Expecting input #%d to be TimeOutPeriod not a cell', NCellOrString+2)); |
---|
312 | % end |
---|
313 | % if ischar(varargin{NCellOrString+1}) |
---|
314 | % error(sprintf('Expecting input #%d to be TimeOutPeriod not a string', NCellOrString+2)); |
---|
315 | % end |
---|
316 | % TimeOutPeriod = varargin{NCellOrString+1}; |
---|
317 | % varargin{NCellOrString+1} = []; |
---|
318 | % end |
---|
319 | % |
---|
320 | % % Build the channel name matrix |
---|
321 | % ChannelNames = []; |
---|
322 | % for i = 1:size(varargin{1},1) |
---|
323 | % for j = 1:size(varargin{1},2) |
---|
324 | % if NCellOrString == 1 |
---|
325 | % NewNames = family2channel(varargin{1}{i,j}); |
---|
326 | % elseif NCellOrString == 2 |
---|
327 | % if iscell(varargin{2}) |
---|
328 | % NewNames = family2channel(varargin{1}{i,j}, varargin{2}{i,j}); |
---|
329 | % else |
---|
330 | % NewNames = family2channel(varargin{1}{i,j}, varargin{2}); |
---|
331 | % end |
---|
332 | % elseif NCellOrString == 3 |
---|
333 | % if iscell(varargin{2}) |
---|
334 | % NewNames = family2channel(varargin{1}{i,j}, varargin{2}{i,j}, varargin{3}{i,j}); |
---|
335 | % else |
---|
336 | % NewNames = family2channel(varargin{1}{i,j}, varargin{2}, varargin{3}{i,j}); |
---|
337 | % end |
---|
338 | % end |
---|
339 | % ChannelNames = strvcat(ChannelNames, NewNames); |
---|
340 | % NameSize(i,j) = size(NewNames,1); |
---|
341 | % end |
---|
342 | % end |
---|
343 | % |
---|
344 | % ExtraTimeDelay = etime(clock, t0); |
---|
345 | % |
---|
346 | % %if nargout >= 3 |
---|
347 | % [AMtmp, tout, DataTimetmp, ErrorFlag] = local_getbyname(ChannelNames, 'Double', 1, t-ExtraTimeDelay, FreshDataFlag, TimeOutPeriod); |
---|
348 | % %else |
---|
349 | % % [AMtmp, tout] = local_getbyname(ChannelNames, 'Double', 1, t-ExtraTimeDelay, FreshDataFlag, TimeOutPeriod) |
---|
350 | % %end |
---|
351 | % |
---|
352 | % %if StructOutputFlag | nargout >= 3 |
---|
353 | % % .DataTime is the time on computer taking the data but |
---|
354 | % % reference it w.r.t. the time zone where Matlab is running |
---|
355 | % DateNumber1970 = 719529; %datenum('1-Jan-1970'); |
---|
356 | % days = datenum(t0(1:3)) - DateNumber1970; |
---|
357 | % t0_sec = 24*60*60*days + 60*60*t0(4) + 60*t0(5) + t0(6); |
---|
358 | % TimeZoneDiff = round((t0_sec - real(DataTimetmp(1,1)))/60/60); |
---|
359 | % DataTimetmp = (real(DataTimetmp)/60/60 + TimeZoneDiff)/24 + DateNumber1970 + imag(DataTimetmp)/(1e9 * 60 * 60 * 24); |
---|
360 | % |
---|
361 | % % No time zone adjustment (UTC 00:00:00 Jan 1, 1970) |
---|
362 | % %DataTime = real(DataTime)/60/60/24 + imag(DataTime)/(1e9 * 60 * 60 * 24); |
---|
363 | % %end |
---|
364 | % |
---|
365 | % for i = 1:size(varargin{1},1) |
---|
366 | % for j = 1:size(varargin{1},2) |
---|
367 | % AM{i,j} = AMtmp(1:NameSize(i,j),:); |
---|
368 | % AMtmp(1:NameSize(i,j),:) = []; |
---|
369 | % %if nargout >= 3 |
---|
370 | % DataTime{i,j} = DataTimetmp(1:NameSize(i,j),:); |
---|
371 | % DataTimetmp(1:NameSize(i,j),:) = []; |
---|
372 | % %end |
---|
373 | % |
---|
374 | % % If input is a data structure, only change StructOutputFlag if 'numeric' is not on the input line |
---|
375 | % StructOutputFlagStart = StructOutputFlag; |
---|
376 | % if isstruct(varargin{1}{i,j}) |
---|
377 | % if isfield(varargin{1}{i,j},'Field') |
---|
378 | % if ~NumericOutputFlag |
---|
379 | % StructOutputFlag = 1; |
---|
380 | % end |
---|
381 | % end |
---|
382 | % end |
---|
383 | % |
---|
384 | % if StructOutputFlag |
---|
385 | % Datatmp = AM{i,j}; |
---|
386 | % DataTimetmp = DataTime{i,j}; |
---|
387 | % if NCellOrString == 1 |
---|
388 | % if isempty(UnitsFlag) |
---|
389 | % AM{i,j} = family2datastruct(varargin{1}{i,j}); |
---|
390 | % else |
---|
391 | % AM{i,j} = family2datastruct(varargin{1}{i,j}, UnitsFlag); |
---|
392 | % end |
---|
393 | % elseif NCellOrString == 2 |
---|
394 | % if iscell(varargin{2}) |
---|
395 | % if isempty(UnitsFlag) |
---|
396 | % AM{i,j} = family2datastruct(varargin{1}{i,j}, varargin{2}{i,j}); |
---|
397 | % else |
---|
398 | % AM{i,j} = family2datastruct(varargin{1}{i,j}, varargin{2}{i,j}, UnitsFlag); |
---|
399 | % end |
---|
400 | % else |
---|
401 | % if isempty(UnitsFlag) |
---|
402 | % AM{i,j} = family2datastruct(varargin{1}{i,j}, varargin{2}); |
---|
403 | % else |
---|
404 | % AM{i,j} = family2datastruct(varargin{1}{i,j}, varargin{2}, UnitsFlag); |
---|
405 | % end |
---|
406 | % end |
---|
407 | % elseif NCellOrString == 3 |
---|
408 | % if iscell(varargin{2}) |
---|
409 | % if isempty(UnitsFlag) |
---|
410 | % AM{i,j} = family2datastruct(varargin{1}{i,j}, varargin{2}{i,j}, varargin{3}{i,j}); |
---|
411 | % else |
---|
412 | % AM{i,j} = family2datastruct(varargin{1}{i,j}, varargin{2}{i,j}, varargin{3}{i,j}, UnitsFlag); |
---|
413 | % end |
---|
414 | % else |
---|
415 | % if isempty(UnitsFlag) |
---|
416 | % AM{i,j} = family2datastruct(varargin{1}{i,j}, varargin{2}, varargin{3}{i,j}); |
---|
417 | % else |
---|
418 | % AM{i,j} = family2datastruct(varargin{1}{i,j}, varargin{2}, varargin{3}{i,j}, UnitsFlag); |
---|
419 | % end |
---|
420 | % end |
---|
421 | % end |
---|
422 | % AM{i,j}.Data = Datatmp; |
---|
423 | % AM{i,j}.t = t; |
---|
424 | % AM{i,j}.tout = tout; |
---|
425 | % AM{i,j}.DataTime = DataTimetmp; |
---|
426 | % AM{i,j}.Mode = 'Online'; |
---|
427 | % AM{i,j}.CreatedBy = 'getpv'; |
---|
428 | % end |
---|
429 | % StructOutputFlag = StructOutputFlagStart; |
---|
430 | % end |
---|
431 | % end |
---|
432 | % |
---|
433 | % return |
---|
434 | % |
---|
435 | %else |
---|
436 | |
---|
437 | %%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
438 | % CELL OR CELL ARRAY INPUT % |
---|
439 | %%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
440 | % Iterate on each cell with special attention to the t vector input |
---|
441 | |
---|
442 | % For an empty input, return empty |
---|
443 | if isempty(varargin{1}) |
---|
444 | AM =[]; tout = []; DataTime = []; ErrorFlag = 0; |
---|
445 | return |
---|
446 | end |
---|
447 | |
---|
448 | % If input is a data structure, only change StructOutputFlag if 'numeric' is not on the input line |
---|
449 | if isstruct(varargin{1}{1}) && isfield(varargin{1}{1},'Field') |
---|
450 | if ~NumericOutputFlag |
---|
451 | StructOutputFlag = 1; |
---|
452 | end |
---|
453 | end |
---|
454 | |
---|
455 | |
---|
456 | % Count the number of inputs which are cells (Family or DeviceList) or strings (possibly Field) |
---|
457 | NCellOrString = 1; |
---|
458 | for i = 2:length(varargin) |
---|
459 | if ~iscell(varargin{i}) |
---|
460 | if ~ischar(varargin{i}) |
---|
461 | break; |
---|
462 | else |
---|
463 | NCellOrString = NCellOrString + 1; |
---|
464 | end |
---|
465 | else |
---|
466 | NCellOrString = NCellOrString + 1; |
---|
467 | %if length(varargin{1})~=length(varargin{NCellOrString}) | length(varargin{NCellOrString})==1 |
---|
468 | % error('When using cell, all the cells must be the same size as input 1 or be length one.'); |
---|
469 | %end |
---|
470 | end |
---|
471 | end |
---|
472 | |
---|
473 | % t (if it exists) should be the next input. Save it then zero it in varargin |
---|
474 | if length(varargin) >= NCellOrString+1 |
---|
475 | if iscell(varargin{NCellOrString+1}) |
---|
476 | error(sprintf('Expecting input #%d to be a time vector not a cell', NCellOrString+1)); |
---|
477 | end |
---|
478 | if ischar(varargin{NCellOrString+1}) |
---|
479 | error(sprintf('Expecting input #%d to be a time vector not a string', NCellOrString+1)); |
---|
480 | end |
---|
481 | t = varargin{NCellOrString+1}; |
---|
482 | varargin{NCellOrString+1} = 0; |
---|
483 | end |
---|
484 | |
---|
485 | |
---|
486 | ExtraTimeDelay = etime(clock, t0); |
---|
487 | t = t - ExtraTimeDelay; |
---|
488 | |
---|
489 | % Loop according to t |
---|
490 | for itime = 1:length(t) |
---|
491 | T = t(itime)-etime(clock, t0); |
---|
492 | if T > 0 |
---|
493 | pause(T); |
---|
494 | end |
---|
495 | |
---|
496 | for i = 1:size(varargin{1},1) |
---|
497 | for j = 1:size(varargin{1},2) |
---|
498 | |
---|
499 | % Build the input line |
---|
500 | for k = 1:length(varargin) |
---|
501 | if ~iscell(varargin{k}) |
---|
502 | Inputs1{1,k} = varargin{k}; |
---|
503 | elseif length(varargin{k}) == 1 |
---|
504 | Inputs1{1,k} = varargin{k}{1}; |
---|
505 | elseif (size(varargin{k},1) == size(varargin{1},1)) && (size(varargin{k},2) == size(varargin{1},2)) |
---|
506 | Inputs1{1,k} = varargin{k}{i,j}; |
---|
507 | else |
---|
508 | error('When using cells, all the cells must be the same size or length 1 (repeated).'); |
---|
509 | end |
---|
510 | end |
---|
511 | |
---|
512 | if StructOutputFlag |
---|
513 | if itime == 1 |
---|
514 | % Form the structure on the first time |
---|
515 | [AM{i,j}, tout(1,itime), DataTime{i,j}, ErrorFlagNew] = getpv(Inputs1{:}, 'Struct', InputFlags{:}); |
---|
516 | else |
---|
517 | % Add to the Data and time fields |
---|
518 | [AM{i,j}.Data(:,itime), tmp, AM{i,j}.DataTime(:,itime), ErrorFlagNew] = getpv(Inputs1{:}, 'Numeric', InputFlags{:}); |
---|
519 | AM{i,j}.t(1,itime) = t(itime); |
---|
520 | AM{i,j}.tout(1,itime) = etime(clock, t0); |
---|
521 | DataTime{i,j}(:,itime) = AM{i,j}.DataTime(:,itime); |
---|
522 | end |
---|
523 | else |
---|
524 | [AM{i,j}(:,itime), tmp, DataTime{i,j}(:,itime), ErrorFlagNew] = getpv(Inputs1{:}, 'Numeric', InputFlags{:}); |
---|
525 | end |
---|
526 | ErrorFlag = ErrorFlag | any(ErrorFlagNew); |
---|
527 | end |
---|
528 | tout(itime) = etime(clock, t0); |
---|
529 | end |
---|
530 | end |
---|
531 | |
---|
532 | % Make the output an AccObj object |
---|
533 | if ObjectOutputFlag |
---|
534 | AM = AccObj(AM); |
---|
535 | end |
---|
536 | |
---|
537 | return |
---|
538 | end |
---|
539 | %%%%%%%%%%%%%%%%%% |
---|
540 | % End cell input % |
---|
541 | %%%%%%%%%%%%%%%%%% |
---|
542 | |
---|
543 | |
---|
544 | |
---|
545 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
546 | % COMMONNAME - Commonname input with no family input % |
---|
547 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
548 | if isempty(varargin{1}) |
---|
549 | if length(varargin) >= 2 |
---|
550 | if ischar(varargin{2}) |
---|
551 | Field = varargin{2}; |
---|
552 | varargin(2) = []; |
---|
553 | end |
---|
554 | else |
---|
555 | % For an empty input, return empty |
---|
556 | if isempty(varargin{1}) |
---|
557 | AM =[]; tout = []; DataTime = []; ErrorFlag = 0; |
---|
558 | return |
---|
559 | end |
---|
560 | end |
---|
561 | if isempty(Field) |
---|
562 | Field = FieldDefault; |
---|
563 | end |
---|
564 | if length(varargin) >= 2 |
---|
565 | CommonNames = varargin{2}; |
---|
566 | else |
---|
567 | error('Common names not found on the input line.'); |
---|
568 | end |
---|
569 | if length(varargin) >= 3 |
---|
570 | t = varargin{3}; |
---|
571 | end |
---|
572 | if length(varargin) >= 4 |
---|
573 | FreshDataFlag = varargin{4}; |
---|
574 | end |
---|
575 | if length(varargin) >= 5 |
---|
576 | TimeOutPeriod = varargin{5}; |
---|
577 | end |
---|
578 | |
---|
579 | |
---|
580 | % Common names with no family name |
---|
581 | if ~ischar(CommonNames) |
---|
582 | error('If Family=[], then DeviceList must be a string of common names.') |
---|
583 | end |
---|
584 | [AM, tout, DataTime, DeviceList, ErrorFlag] = getbycommonname(CommonNames, Field, t, t0, FreshDataFlag, TimeOutPeriod, InputFlags{:}); |
---|
585 | if ErrorFlag |
---|
586 | return; |
---|
587 | end |
---|
588 | |
---|
589 | if StructOutputFlag || nargout >= 3 |
---|
590 | % .DataTime is the time on computer taking the data but |
---|
591 | % reference it w.r.t. the time zone where Matlab is running |
---|
592 | DateNumber1970 = 719529; %datenum('1-Jan-1970'); |
---|
593 | days = datenum(t0(1:3)) - DateNumber1970; |
---|
594 | t0_sec = 24*60*60*days + 60*60*t0(4) + 60*t0(5) + t0(6); |
---|
595 | TimeZoneDiff = round((t0_sec - real(DataTime(1,1)))/60/60); |
---|
596 | DataTime = (real(DataTime)/60/60 + TimeZoneDiff)/24 + DateNumber1970 + imag(DataTime)/(1e9 * 60 * 60 * 24); |
---|
597 | end |
---|
598 | |
---|
599 | % Structure output |
---|
600 | if StructOutputFlag |
---|
601 | AM = struct('Data', AM); |
---|
602 | AM.FamilyName = CommonNames; |
---|
603 | AM.Field = Field; |
---|
604 | AM.DeviceList = DeviceList; |
---|
605 | AM.Status = []; |
---|
606 | AM.t = t; |
---|
607 | AM.tout = tout; |
---|
608 | AM.DataTime = DataTime; |
---|
609 | AM.TimeStamp = t0; |
---|
610 | [DeviceList1, Family1] = common2dev(CommonNames(1,:)); |
---|
611 | AM.Mode = getmode(Family1); % Base on just the first common name |
---|
612 | [AM.Units, AM.UnitsString] = getunits(Family1); % Base on just the first common name |
---|
613 | AM.DataDescriptor = 'Get by Common Name'; |
---|
614 | AM.CreatedBy = 'getpv'; |
---|
615 | |
---|
616 | % Make the output an AccObj object |
---|
617 | if ObjectOutputFlag |
---|
618 | AM = AccObj(AM); |
---|
619 | end |
---|
620 | end |
---|
621 | |
---|
622 | return |
---|
623 | end |
---|
624 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
625 | % End CommonName input with no family input % |
---|
626 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
627 | |
---|
628 | |
---|
629 | |
---|
630 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
631 | % Parce inputs depending on Data structure, AO structure, Family, ChannelName method % |
---|
632 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
633 | if isstruct(varargin{1}) |
---|
634 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
635 | % STRUCTURE INPUTS - Data structure or AO structure % |
---|
636 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
637 | if isfield(varargin{1},'FamilyName') && isfield(varargin{1},'Field') |
---|
638 | % Data structure - select FamilyName, DeviceList, Units from the structure (.Mode flag???) |
---|
639 | % [AM, tout, DataTime, ErrorFlag] = getpv(DataStruct, Field {opt}, t, FreshDataFlag, TimeOutPeriod) |
---|
640 | |
---|
641 | % Only change StructOutputFlag if 'numeric' is not on the input line |
---|
642 | if ~NumericOutputFlag |
---|
643 | StructOutputFlag = 1; |
---|
644 | end |
---|
645 | |
---|
646 | Family = varargin{1}.FamilyName; |
---|
647 | |
---|
648 | Field = varargin{1}.Field; |
---|
649 | if length(varargin) >= 2 |
---|
650 | if ischar(varargin{2}) |
---|
651 | Field = varargin{2}; |
---|
652 | varargin(2) = []; |
---|
653 | end |
---|
654 | end |
---|
655 | |
---|
656 | DeviceList = varargin{1}.DeviceList; |
---|
657 | |
---|
658 | if length(varargin) >= 2 |
---|
659 | % If the input exists use it |
---|
660 | t = varargin{2}; |
---|
661 | else |
---|
662 | % Else, get it from the structure if the field exists |
---|
663 | if isfield(varargin{1},'t') |
---|
664 | t = varargin{1}.t; |
---|
665 | end |
---|
666 | end |
---|
667 | if length(varargin) >= 3 |
---|
668 | FreshDataFlag = varargin{3}; |
---|
669 | end |
---|
670 | if length(varargin) >= 4 |
---|
671 | TimeOutPeriod = varargin{4}; |
---|
672 | end |
---|
673 | |
---|
674 | [FamilyIndex, AO] = isfamily(Family); |
---|
675 | |
---|
676 | % Change Units to the data structure units |
---|
677 | if isfield(AO, Field) |
---|
678 | AO.(Field).Units = varargin{1}.Units; |
---|
679 | end |
---|
680 | |
---|
681 | elseif isfield(varargin{1},'FamilyName') |
---|
682 | % AO structure - use the AO structure directly |
---|
683 | % [AM, tout, DataTime, ErrorFlag] = getpv(AO, Field, DeviceList, t, FreshDataFlag, TimeOutPeriod) |
---|
684 | FamilyIndex = 1; |
---|
685 | AO = varargin{1}; |
---|
686 | Family = varargin{1}.FamilyName; |
---|
687 | |
---|
688 | Field = ''; |
---|
689 | if length(varargin) >= 2 |
---|
690 | if ischar(varargin{2}) |
---|
691 | Field = varargin{2}; |
---|
692 | varargin(2) = []; |
---|
693 | end |
---|
694 | end |
---|
695 | if length(varargin) >= 2 |
---|
696 | DeviceList = varargin{2}; |
---|
697 | else |
---|
698 | DeviceList = AO.DeviceList; |
---|
699 | iStatus = find(varargin{1}.Status == 0); |
---|
700 | DeviceList(iStatus,:) = []; |
---|
701 | end |
---|
702 | if length(varargin) >= 3 |
---|
703 | t = varargin{3}; |
---|
704 | end |
---|
705 | if length(varargin) >= 4 |
---|
706 | FreshDataFlag = varargin{4}; |
---|
707 | end |
---|
708 | if length(varargin) >= 5 |
---|
709 | TimeOutPeriod = varargin{5}; |
---|
710 | end |
---|
711 | else |
---|
712 | error('Input #1 of unknown type'); |
---|
713 | end |
---|
714 | |
---|
715 | else |
---|
716 | |
---|
717 | % Family, ChannelName, or Common name are still left |
---|
718 | [FamilyIndex, AO] = isfamily(varargin{1}); |
---|
719 | |
---|
720 | if FamilyIndex |
---|
721 | |
---|
722 | %%%%%%%%%%%%%%%% |
---|
723 | % FAMILY INPUT % |
---|
724 | %%%%%%%%%%%%%%%% |
---|
725 | % [AM, tout, DataTime, ErrorFlag] = getpv(Family, Field {opt}, DeviceList, t, FreshDataFlag, TimeOutPeriod) |
---|
726 | Family = varargin{1}; |
---|
727 | if length(varargin) >= 2 |
---|
728 | if ischar(varargin{2}) |
---|
729 | Field = varargin{2}; |
---|
730 | varargin(2) = []; |
---|
731 | end |
---|
732 | end |
---|
733 | if isempty(Field) |
---|
734 | Field = FieldDefault; |
---|
735 | end |
---|
736 | if length(varargin) >= 2 |
---|
737 | DeviceList = varargin{2}; |
---|
738 | end |
---|
739 | if length(varargin) >= 3 |
---|
740 | t = varargin{3}; |
---|
741 | end |
---|
742 | if length(varargin) >= 4 |
---|
743 | FreshDataFlag = varargin{4}; |
---|
744 | end |
---|
745 | if length(varargin) >= 5 |
---|
746 | TimeOutPeriod = varargin{5}; |
---|
747 | end |
---|
748 | |
---|
749 | else |
---|
750 | |
---|
751 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
752 | % CHANNEL NAME OR COMMON NAME INPUT % |
---|
753 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
754 | |
---|
755 | % Just do input parsing here |
---|
756 | Family = varargin{1}; |
---|
757 | |
---|
758 | % Default field is '' for channel names or it would be added as ChannelName.Field |
---|
759 | % But for common names it needs to be 'Monitor' |
---|
760 | Field = ''; |
---|
761 | if length(varargin) >= 2 |
---|
762 | if ~isnumeric(varargin{2}) |
---|
763 | Field = varargin{2}; |
---|
764 | varargin(2) = []; |
---|
765 | end |
---|
766 | end |
---|
767 | if length(varargin) >= 2 |
---|
768 | t = varargin{2}; |
---|
769 | end |
---|
770 | if length(varargin) >= 3 |
---|
771 | FreshDataFlag = varargin{3}; |
---|
772 | end |
---|
773 | if length(varargin) >= 4 |
---|
774 | TimeOutPeriod = varargin{4}; |
---|
775 | end |
---|
776 | end |
---|
777 | end |
---|
778 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
779 | % End selection of inputs depending on Family, Data Structure, AO structure, or ChannelName method % |
---|
780 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
781 | |
---|
782 | |
---|
783 | |
---|
784 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
785 | % AO, ChannelName, or CommonName % |
---|
786 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
787 | if isempty(t) |
---|
788 | t = 0; |
---|
789 | end |
---|
790 | if FamilyIndex |
---|
791 | %%%%%%%%%%%%%%%%% |
---|
792 | % FAMILY INPUTS % |
---|
793 | %%%%%%%%%%%%%%%%% |
---|
794 | |
---|
795 | % All ready done |
---|
796 | %if isempty(Field) |
---|
797 | % Field = 'Monitor'; |
---|
798 | %end |
---|
799 | |
---|
800 | if isempty(DeviceList) |
---|
801 | DeviceList = family2dev(Family); % Default behavior comes from family2dev |
---|
802 | %DeviceList = family2dev(Family,1); % Good status only |
---|
803 | %DeviceList = AO.DeviceList; % All devices |
---|
804 | end |
---|
805 | if ischar(DeviceList) |
---|
806 | % Convert common name to a DeviceList |
---|
807 | DeviceList = common2dev(DeviceList, AO); |
---|
808 | end |
---|
809 | if (size(DeviceList,2) == 1) |
---|
810 | DeviceList = elem2dev(Family, DeviceList); |
---|
811 | end |
---|
812 | |
---|
813 | |
---|
814 | % Look for command-line over-rides |
---|
815 | if isfield(AO, Field) |
---|
816 | if ~isempty(UnitsFlag) |
---|
817 | AO.(Field).Units = UnitsFlag; |
---|
818 | end |
---|
819 | if ~isempty(ModeFlag) |
---|
820 | if strcmp(ModeFlag, 'Online') && strcmp(AO.(Field).Mode, 'Special') |
---|
821 | % For Online over-rides, look for Special mode first |
---|
822 | AO.(Field).Mode = 'Special'; |
---|
823 | else |
---|
824 | AO.(Field).Mode = ModeFlag; |
---|
825 | end |
---|
826 | end |
---|
827 | end |
---|
828 | |
---|
829 | |
---|
830 | % Get data |
---|
831 | ExtraTimeDelay = etime(clock, t0); |
---|
832 | if StructOutputFlag || nargout >= 3 |
---|
833 | [AM, tout, DataTime, ErrorFlag, DeviceIndex] = local_getpv(AO, Field, DeviceList, OutputDataType, t-ExtraTimeDelay, FreshDataFlag, TimeOutPeriod, InputFlags{:}); |
---|
834 | |
---|
835 | |
---|
836 | else |
---|
837 | [AM, tout] = local_getpv(AO, Field, DeviceList, OutputDataType, t-ExtraTimeDelay, FreshDataFlag, TimeOutPeriod, InputFlags{:}); |
---|
838 | end |
---|
839 | tout = tout + ExtraTimeDelay; |
---|
840 | |
---|
841 | |
---|
842 | if StructOutputFlag |
---|
843 | % Structure output |
---|
844 | AM = struct('Data', AM); |
---|
845 | %AM.Data = AM; |
---|
846 | AM.FamilyName = Family; |
---|
847 | AM.Field = Field; |
---|
848 | AM.DeviceList = DeviceList; |
---|
849 | if length(AO.Status) == 1 |
---|
850 | AM.Status = AO.Status * ones(size(DeviceIndex)); |
---|
851 | else |
---|
852 | %AM.Status = family2status(Family, AM.DeviceList); |
---|
853 | AM.Status = AO.Status(DeviceIndex); |
---|
854 | end |
---|
855 | if isfield(AO, Field) |
---|
856 | AM.Mode = AO.(Field).Mode; |
---|
857 | AM.Units = AO.(Field).Units; |
---|
858 | if strcmpi(AM.Units,'hardware') |
---|
859 | AM.UnitsString = AO.(Field).HWUnits; |
---|
860 | else |
---|
861 | AM.UnitsString = AO.(Field).PhysicsUnits; |
---|
862 | end |
---|
863 | AM.DataDescriptor = 'Get by FamilyName'; |
---|
864 | else |
---|
865 | AM.Mode = 'Online'; |
---|
866 | AM.Units = ''; |
---|
867 | AM.UnitsString = ''; |
---|
868 | AM.DataDescriptor = 'Get by Channel Name'; |
---|
869 | end |
---|
870 | AM.CreatedBy = 'getpv'; |
---|
871 | end |
---|
872 | |
---|
873 | else |
---|
874 | |
---|
875 | % Look to see if it's a channel name or a common name |
---|
876 | % Just check the first name so it's a faster test |
---|
877 | [DeviceListTest, FamilyTest] = common2dev(Family(1,:)); |
---|
878 | |
---|
879 | if ~isempty(FamilyTest) |
---|
880 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
881 | % Common names where the family was the common name % |
---|
882 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
883 | |
---|
884 | % Field default will come from getbycommonname via another getpv call |
---|
885 | % The DeviceList does not matter (and should not be used) |
---|
886 | |
---|
887 | CommonNames = Family; |
---|
888 | [AM, tout, DataTime, DeviceList, ErrorFlag] = getbycommonname(CommonNames, Field, t, t0, FreshDataFlag, TimeOutPeriod, InputFlags{:}); |
---|
889 | if ErrorFlag |
---|
890 | return; |
---|
891 | end |
---|
892 | |
---|
893 | % Structure output |
---|
894 | if StructOutputFlag |
---|
895 | AM = struct('Data', AM); |
---|
896 | AM.FamilyName = CommonNames; |
---|
897 | AM.Field = Field; |
---|
898 | AM.DeviceList = DeviceList; |
---|
899 | AM.Status = []; |
---|
900 | AM.Mode = getmode(FamilyTest(1,:)); % Base on just the first common name |
---|
901 | [AM.Units, AM.UnitsString] = getunits(FamilyTest(1,:)); % Base on just the first common name |
---|
902 | AM.DataDescriptor = 'Get by Common Name'; |
---|
903 | AM.CreatedBy = 'getpv'; |
---|
904 | end |
---|
905 | |
---|
906 | else |
---|
907 | |
---|
908 | %%%%%%%%%%%%%%%% |
---|
909 | % CHANNEL NAME % |
---|
910 | %%%%%%%%%%%%%%%% |
---|
911 | |
---|
912 | % Can't use overrides with channel name method |
---|
913 | if ~isempty(UnitsFlag) |
---|
914 | error('You cannot change the units when using tango names.') |
---|
915 | end |
---|
916 | if ~(isempty(ModeFlag) || strcmpi(ModeFlag, 'Online')) |
---|
917 | error('Tango names only have an ''Online'' Mode.') |
---|
918 | end |
---|
919 | |
---|
920 | |
---|
921 | % Add Field to Family.Field |
---|
922 | FamilyOld = Family; |
---|
923 | if ~isempty(Field) |
---|
924 | Family = strcat(Family, ['.',Field]); |
---|
925 | end |
---|
926 | |
---|
927 | |
---|
928 | ExtraTimeDelay = etime(clock, t0); |
---|
929 | if strcmpi(OutputDataType,'String') |
---|
930 | % Get data with strings output |
---|
931 | if StructOutputFlag || nargout >= 3 |
---|
932 | [AM, tout, DataTime, ErrorFlag] = getpvonline(Family, 'String', 0, t-ExtraTimeDelay); |
---|
933 | else |
---|
934 | [AM, tout] = getpvonline(Family, 'String', 0, t-ExtraTimeDelay); |
---|
935 | end |
---|
936 | else |
---|
937 | % Get data at every point in time vector, t |
---|
938 | if StructOutputFlag || nargout >= 3 |
---|
939 | [AM, tout, DataTime, ErrorFlag] = local_getbyname(Family, OutputDataType, 0, t-ExtraTimeDelay, FreshDataFlag, TimeOutPeriod, InputFlags{:}); |
---|
940 | else |
---|
941 | [AM, tout] = local_getbyname(Family, OutputDataType, 0, t-ExtraTimeDelay, FreshDataFlag, TimeOutPeriod, InputFlags{:}); |
---|
942 | end |
---|
943 | end |
---|
944 | tout = tout + ExtraTimeDelay; |
---|
945 | |
---|
946 | |
---|
947 | % Structure output for channel name method |
---|
948 | if StructOutputFlag |
---|
949 | AM = struct('Data', AM); |
---|
950 | %AM.Data = AM; |
---|
951 | AM.FamilyName = FamilyOld; |
---|
952 | AM.Field = Field; |
---|
953 | AM.DeviceList = []; |
---|
954 | AM.Status = []; |
---|
955 | AM.Mode = 'Online'; |
---|
956 | AM.Units = ''; |
---|
957 | AM.UnitsString = ''; |
---|
958 | AM.DataDescriptor = 'Get by Channel Name'; |
---|
959 | AM.CreatedBy = 'getpv'; |
---|
960 | end |
---|
961 | end |
---|
962 | end |
---|
963 | |
---|
964 | |
---|
965 | if StructOutputFlag || nargout >= 3 |
---|
966 | % .DataTime is the time on computer taking the data but |
---|
967 | % reference it w.r.t. the time zone where Matlab is running |
---|
968 | DateNumber1970 = 719529; %datenum('1-Jan-1970'); |
---|
969 | days = datenum(t0(1:3)) - DateNumber1970; |
---|
970 | t0_sec = 24*60*60*days + 60*60*t0(4) + 60*t0(5) + t0(6); |
---|
971 | TimeZoneDiff = round((t0_sec - real(DataTime(1,1)))/60/60); |
---|
972 | DataTime = (real(DataTime)/60/60 + TimeZoneDiff)/24 + DateNumber1970 + imag(DataTime)/(1e9 * 60 * 60 * 24); |
---|
973 | |
---|
974 | % No time zone adjustment (UTC 00:00:00 Jan 1, 1970) |
---|
975 | %DataTime = real(DataTime)/60/60/24 + imag(DataTime)/(1e9 * 60 * 60 * 24); |
---|
976 | end |
---|
977 | |
---|
978 | |
---|
979 | % Structure output |
---|
980 | if StructOutputFlag |
---|
981 | % Add time to structure |
---|
982 | AM.t = t; |
---|
983 | AM.tout = tout; |
---|
984 | AM.DataTime = DataTime; |
---|
985 | AM.TimeStamp = t0; |
---|
986 | |
---|
987 | % Make the output an AccObj object |
---|
988 | if ObjectOutputFlag |
---|
989 | AM = AccObj(AM); |
---|
990 | end |
---|
991 | end |
---|
992 | |
---|
993 | |
---|
994 | |
---|
995 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
996 | % Main Function for Getting Data Using Common Names % |
---|
997 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
998 | function [AM, tout, DataTime, DeviceList, ErrorFlag] = getbycommonname(CommonNames, Field, t, t0, FreshDataFlag, TimeOutPeriod, varargin) |
---|
999 | |
---|
1000 | % Convert all the common names to Family and Device lists |
---|
1001 | [DeviceList, Family, ErrorFlag] = common2dev(CommonNames); |
---|
1002 | |
---|
1003 | if ErrorFlag |
---|
1004 | AM=[]; tout=[]; DataTime=[]; |
---|
1005 | return; |
---|
1006 | else |
---|
1007 | |
---|
1008 | % If all the families are the same then compress them |
---|
1009 | FamilyTest = unique(Family, 'rows'); |
---|
1010 | |
---|
1011 | if size(FamilyTest, 1) == 1 |
---|
1012 | % 1 Family, Multiple devices are ok |
---|
1013 | [AM, tout, DataTime, ErrorFlag] = getpv(FamilyTest, Field, DeviceList, t, FreshDataFlag, TimeOutPeriod, 'Numeric', varargin{:}); |
---|
1014 | else |
---|
1015 | % Multiple families (loop) |
---|
1016 | % It has to be in a loop for the simulator and to pickup special functions |
---|
1017 | |
---|
1018 | if FreshDataFlag >= 1 |
---|
1019 | error('The FreshDataFlag is not programmed yet when when getting common names from multiple families (GJP).'); |
---|
1020 | end |
---|
1021 | |
---|
1022 | % Loop on the time vector (t0 has already been started) |
---|
1023 | for itime = 1:length(t) |
---|
1024 | T = t(itime)-etime(clock, t0); |
---|
1025 | if T > 0 |
---|
1026 | pause(T); |
---|
1027 | end |
---|
1028 | for i = 1:size(Family,1) |
---|
1029 | [AM(i,itime), tmp, DataTime(i,itime), ErrorFlag1] = getpv(Family(i,:), Field, DeviceList(i,:), 'Numeric', varargin{:}); |
---|
1030 | tout(1,itime) = etime(clock, t0); |
---|
1031 | ErrorFlag = ErrorFlag | ErrorFlag1; |
---|
1032 | end |
---|
1033 | end |
---|
1034 | end |
---|
1035 | end |
---|
1036 | |
---|
1037 | |
---|
1038 | |
---|
1039 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
1040 | % Main Function for Getting Data using the Channel Names % |
---|
1041 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
1042 | function [AM, tout, DataTime, ErrorFlag] = local_getbyname(ChannelName, OutputDataType, N, t, FreshDataFlag, TimeOutPeriod, varargin) |
---|
1043 | |
---|
1044 | t0 = clock; |
---|
1045 | ErrorFlag = 0; |
---|
1046 | |
---|
1047 | |
---|
1048 | if nargout < 3 |
---|
1049 | [AM, tout] = getpvonline(ChannelName, OutputDataType, N, t, varargin{:}); |
---|
1050 | else |
---|
1051 | [AM, tout, DataTime, ErrorFlag] = getpvonline(ChannelName, OutputDataType, N, t, varargin{:}); |
---|
1052 | end |
---|
1053 | |
---|
1054 | |
---|
1055 | % FreshDataFlag |
---|
1056 | if FreshDataFlag && length(t) == 1 |
---|
1057 | % Only use FreshDataFlag for scalar t |
---|
1058 | FreshDataCounter = FreshDataFlag; |
---|
1059 | AM0 = AM; |
---|
1060 | while FreshDataCounter |
---|
1061 | if nargout < 3 |
---|
1062 | [AM, tout] = getpvonline(ChannelName, OutputDataType, N); |
---|
1063 | else |
---|
1064 | [AM, tout, DataTime, ErrorFlag] = getpvonline(ChannelName, OutputDataType, N); |
---|
1065 | end |
---|
1066 | |
---|
1067 | if ~any((AM-AM0)==0) |
---|
1068 | FreshDataCounter = FreshDataCounter - 1; |
---|
1069 | AM0 = AM; |
---|
1070 | end |
---|
1071 | |
---|
1072 | if etime(clock, t0) > TimeOutPeriod |
---|
1073 | k = find((AM-AM0)==0); |
---|
1074 | for j = 1:length(k) |
---|
1075 | fprintf('%s not changing.\n', deblank(ChannelName(k(j),:))); |
---|
1076 | end |
---|
1077 | error('Timed out waiting for fresh data.'); |
---|
1078 | end |
---|
1079 | end |
---|
1080 | tout = etime(clock, t0); |
---|
1081 | end |
---|
1082 | |
---|
1083 | return |
---|
1084 | |
---|
1085 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
1086 | % Main Function for Getting Data using the Accelerator Object % |
---|
1087 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
1088 | function [AM, tout, DataTime, ErrorFlag, DeviceIndex] = local_getpv(AO, Field, DeviceList, OutputDataType, t, FreshDataFlag, TimeOutPeriod, varargin) |
---|
1089 | % INPUTS |
---|
1090 | % 1. AO - the ACCELERATOR_OBJECT structure for the called family |
---|
1091 | % 2. Field - 'Monitor' or 'Setpoint' |
---|
1092 | % 3. DeviceList - Device list |
---|
1093 | % |
---|
1094 | % OUTPUTS |
---|
1095 | % 1. AM - Vector a read values |
---|
1096 | % 2. TimeStamp - timestamp when data collected |
---|
1097 | % 3. ErrorFlag - 0 if OK, else 1 |
---|
1098 | % 4. DeviceIndex - List of status 1 devices |
---|
1099 | |
---|
1100 | % Written by Gregory J. Portmann |
---|
1101 | % Modified by Laurent S. Nadolski |
---|
1102 | |
---|
1103 | t0 = clock; |
---|
1104 | ErrorFlag = 0; |
---|
1105 | N = 0; % Output size |
---|
1106 | InputFlags ={}; |
---|
1107 | |
---|
1108 | for i = length(varargin):-1:1 |
---|
1109 | if strcmpi(varargin{i},'Retry') |
---|
1110 | InputFlags = [InputFlags varargin(i)]; |
---|
1111 | varargin(i) = []; |
---|
1112 | elseif strcmpi(varargin{i},'NoRetry') |
---|
1113 | InputFlags = [InputFlags varargin(i)]; |
---|
1114 | varargin(i) = []; |
---|
1115 | end |
---|
1116 | end |
---|
1117 | |
---|
1118 | % Find the index for where the desired data is in the total device list |
---|
1119 | DeviceListTotal = AO.DeviceList; |
---|
1120 | [DeviceIndex, iNotFound] = findrowindex(DeviceList, DeviceListTotal); |
---|
1121 | if length(iNotFound) > 0 |
---|
1122 | % Device not found |
---|
1123 | for i = 1:length(iNotFound) |
---|
1124 | fprintf(' No devices to get for Family %s(%d,%d)\n', AO.FamilyName, DeviceList(i,1), DeviceList(i,2)); |
---|
1125 | end |
---|
1126 | error('%d Devices not found', length(iNotFound)); |
---|
1127 | end |
---|
1128 | |
---|
1129 | % Check the DeviceIndex |
---|
1130 | if isempty(DeviceIndex) |
---|
1131 | DataTime = 0 + 0*sqrt(-1); |
---|
1132 | tout = etime(clock, t0); |
---|
1133 | AM = []; |
---|
1134 | %fprintf(' WARNING: No devices to get for Family %s (getpv)\n', AO.FamilyName); |
---|
1135 | return; |
---|
1136 | end |
---|
1137 | |
---|
1138 | %% TANGO specific part |
---|
1139 | |
---|
1140 | % Load Field sub-structure into AOField |
---|
1141 | if ~isfield(AO, Field); |
---|
1142 | % Try to check it online or simulator |
---|
1143 | if isfield(AO, 'Setpoint') |
---|
1144 | Mode = getfamilydata(AO.FamilyName, 'Setpoint', 'Mode'); |
---|
1145 | elseif isfield(AO, 'Monitor') |
---|
1146 | Mode = getfamilydata(AO.FamilyName, 'Monitor', 'Mode'); |
---|
1147 | else |
---|
1148 | Mode = ''; |
---|
1149 | end |
---|
1150 | if strcmpi(Mode,'Simulator') || strcmpi(Mode,'Model') |
---|
1151 | ExtraTimeDelay = etime(clock, t0); |
---|
1152 | [AM, tout, DataTime, ErrorFlag] = getpvmodel(AO.FamilyName, Field, DeviceList, t-ExtraTimeDelay, 'Physics', 'Numeric', InputFlags{:}); |
---|
1153 | tout = tout + ExtraTimeDelay; |
---|
1154 | |
---|
1155 | % Since physics2hw conversions are not known for fields that are not families, just return |
---|
1156 | return |
---|
1157 | end |
---|
1158 | |
---|
1159 | % Try changing the suffix of the Monitor or Setpoint field |
---|
1160 | if isfield(AO, 'Setpoint') |
---|
1161 | Tango = family2tango(AO, 'Setpoint', DeviceList); |
---|
1162 | elseif isfield(AO, 'Monitor') |
---|
1163 | Tango = family2tango(AO, 'Monitor', DeviceList); |
---|
1164 | else |
---|
1165 | error(sprintf('Field %s not found for Family %s', Field, AO.FamilyName)); |
---|
1166 | end |
---|
1167 | if any(strcmpi(getfamilydata('Machine'),{'spear3','spear'})) |
---|
1168 | % Spear likes to change the channel name after the ':' |
---|
1169 | |
---|
1170 | %i = findstr(Channel(1,:),':'); |
---|
1171 | %if ~isempty(i) |
---|
1172 | % Channel(:,i:end) = []; |
---|
1173 | %end |
---|
1174 | %Channel = strcat(Channel, [':',Field]); |
---|
1175 | |
---|
1176 | % Since the location of ":" can be different in each row, loop |
---|
1177 | ChannelMat = []; |
---|
1178 | for j = 1:size(Channel,1) |
---|
1179 | i = findstr(Channel(j, :),':'); |
---|
1180 | if isempty(i) |
---|
1181 | % I'm not sure what to do if ":" is missing, I'm just add a ":" |
---|
1182 | ChannelMat = strvcat(ChannelMat, [Channel(j,1:i), ':', Field]); |
---|
1183 | else |
---|
1184 | ChannelMat = strvcat(ChannelMat, [Channel(j,1:i), Field]); |
---|
1185 | end |
---|
1186 | end |
---|
1187 | Tango = strcat(Tango, [':',Field]); |
---|
1188 | else |
---|
1189 | % Add a .Field |
---|
1190 | Tango = strcat(Tango, ['.',Field]); |
---|
1191 | end |
---|
1192 | |
---|
1193 | ExtraTimeDelay = etime(clock, t0); |
---|
1194 | if nargout < 3 |
---|
1195 | [AM, tout] = getpvonline(Tango, OutputDataType, N, t-ExtraTimeDelay, FreshDataFlag, TimeOutPeriod, InputFlags{:}); |
---|
1196 | else |
---|
1197 | [AM, tout, DataTime, ErrorFlag] = getpvonline(Tango, OutputDataType, N, t-ExtraTimeDelay, FreshDataFlag, TimeOutPeriod, InputFlags{:}); |
---|
1198 | end |
---|
1199 | tout = tout + ExtraTimeDelay; |
---|
1200 | return |
---|
1201 | end |
---|
1202 | |
---|
1203 | |
---|
1204 | AOField = AO.(Field); % Should I replace this???? |
---|
1205 | |
---|
1206 | % If mode does not exist, force to online mode |
---|
1207 | if isfield(AOField, 'Mode') |
---|
1208 | Mode = AOField.Mode; |
---|
1209 | else |
---|
1210 | Mode = 'Online'; |
---|
1211 | end |
---|
1212 | |
---|
1213 | |
---|
1214 | % Check if Online should really be special |
---|
1215 | if strcmpi(Mode, 'Online') |
---|
1216 | if isfield(AO.(Field), 'SpecialFunctionGet') |
---|
1217 | Mode = 'Special'; |
---|
1218 | end |
---|
1219 | end |
---|
1220 | |
---|
1221 | |
---|
1222 | if ~isstruct(AO.(Field)) |
---|
1223 | % If it's not a structure that just get the field |
---|
1224 | % Hardward and physics get ignored |
---|
1225 | t1 = clock; |
---|
1226 | [AM, ErrorFlag] = getfamilydata(AO.FamilyName, Field, DeviceList); |
---|
1227 | |
---|
1228 | tout = etime(t1, t0); |
---|
1229 | if nargout >= 3 |
---|
1230 | days = datenum(t1(1:3)) - 719529; %datenum('1-Jan-1970'); |
---|
1231 | tt = 24*60*60*days + 60*60*t1(4) + 60*t1(5) + t1(6); |
---|
1232 | DataTime(1:size(AM,1),1:length(t)) = fix(tt) + rem(tt,1)*1e9*sqrt(-1); |
---|
1233 | end |
---|
1234 | |
---|
1235 | elseif strcmpi(Mode,'online') |
---|
1236 | % Online |
---|
1237 | if strcmpi(AOField.DataType,'Scalar') |
---|
1238 | N = 1; % Output size |
---|
1239 | |
---|
1240 | ExtraTimeDelay = etime(clock, t0); |
---|
1241 | if nargout < 3 |
---|
1242 | [AM, tout] = getpvonline(AOField.TangoNames(DeviceIndex,:), Field, OutputDataType, N, t-ExtraTimeDelay, InputFlags{:}); |
---|
1243 | else |
---|
1244 | [AM, tout, DataTime, ErrorFlag] = getpvonline(AOField.TangoNames(DeviceIndex,:), Field, OutputDataType, N, t-ExtraTimeDelay, InputFlags{:}); |
---|
1245 | end |
---|
1246 | tout = tout + ExtraTimeDelay; |
---|
1247 | |
---|
1248 | % FreshDataFlag |
---|
1249 | if FreshDataFlag && length(t) == 1 |
---|
1250 | % Only use FreshDataFlag for scalar t |
---|
1251 | FreshDataCounter = FreshDataFlag; |
---|
1252 | AM0 = AM; |
---|
1253 | while FreshDataCounter |
---|
1254 | if nargout < 3 |
---|
1255 | [AM, tout] = getpvonline(AOField.TangoNames(DeviceIndex,:), Field,OutputDataType, N); |
---|
1256 | else |
---|
1257 | [AM, tout, DataTime, ErrorFlag] = getpvonline(AOField.TangoNames(DeviceIndex,:), Field, OutputDataType, N); |
---|
1258 | end |
---|
1259 | |
---|
1260 | if ~any((AM-AM0)==0) |
---|
1261 | FreshDataCounter = FreshDataCounter - 1; |
---|
1262 | AM0 = AM; |
---|
1263 | end |
---|
1264 | |
---|
1265 | if etime(clock, t0) > TimeOutPeriod |
---|
1266 | k = find((AM-AM0)==0); |
---|
1267 | for j = 1:length(k) |
---|
1268 | fprintf('%s not changing.\n', deblank((AOField.TangoNames(DeviceIndex(k(j)),:)))); |
---|
1269 | end |
---|
1270 | error('Timed out waiting for fresh data.'); |
---|
1271 | end |
---|
1272 | end |
---|
1273 | tout = etime(clock, t0); |
---|
1274 | end |
---|
1275 | |
---|
1276 | elseif strcmpi(AOField.DataType, 'Vector') |
---|
1277 | |
---|
1278 | |
---|
1279 | % Output(DataTypeIndex) must be equal to the number of elements in the family |
---|
1280 | |
---|
1281 | % There can only be one Tango or channel name for DataType='Vector' |
---|
1282 | TangoNames = deblank(AOField.TangoNames(1,:)); |
---|
1283 | |
---|
1284 | |
---|
1285 | |
---|
1286 | % Get data at every point in time vector, t |
---|
1287 | AM = []; |
---|
1288 | ExtraTimeDelay = etime(clock, t0); |
---|
1289 | t = t - ExtraTimeDelay; |
---|
1290 | for itime = 1:length(t) |
---|
1291 | T = t(itime)-etime(clock, t0); |
---|
1292 | if T > 0 |
---|
1293 | pause(T); |
---|
1294 | end |
---|
1295 | |
---|
1296 | % Get data |
---|
1297 | if nargout >= 3 |
---|
1298 | [tmp, tout, DataTime(:,itime), ErrorFlag] = getpvonline(TangoNames, 'Vector', N, InputFlags{:}); |
---|
1299 | else |
---|
1300 | tmp = getpvonline(TangoNames, 'Vector', N); |
---|
1301 | end |
---|
1302 | if isfield(AOField, 'DataTypeIndex') |
---|
1303 | tmp = tmp(AOField.DataTypeIndex); |
---|
1304 | end |
---|
1305 | AM = [AM tmp(DeviceIndex,:)]; |
---|
1306 | |
---|
1307 | tout(itime) = etime(clock, t0); |
---|
1308 | end |
---|
1309 | |
---|
1310 | % FreshDataFlag |
---|
1311 | if FreshDataFlag & length(t) == 1 |
---|
1312 | % Only use FreshDataFlag for scalar t |
---|
1313 | FreshDataCounter = FreshDataFlag; |
---|
1314 | AM0 = AM; |
---|
1315 | while FreshDataCounter |
---|
1316 | if nargout >= 3 |
---|
1317 | [AM, tout, DataTime, ErrorFlag] = getpvonline(TangoNames, 'Vector', N, InputFlags{:}); |
---|
1318 | else |
---|
1319 | AM = getpvonline(TangoNames, 'Vector', N); |
---|
1320 | end |
---|
1321 | if isfield(AOField, 'DataTypeIndex') |
---|
1322 | AM = AM(AOField.DataTypeIndex); |
---|
1323 | end |
---|
1324 | AM = AM(DeviceIndex,:); |
---|
1325 | |
---|
1326 | if ~any((AM-AM0)==0) |
---|
1327 | FreshDataCounter = FreshDataCounter - 1; |
---|
1328 | AM0 = AM; |
---|
1329 | end |
---|
1330 | |
---|
1331 | if etime(clock, t0) > TimeOutPeriod |
---|
1332 | k = find((AM-AM0)==0); |
---|
1333 | for j = 1:length(k) |
---|
1334 | fprintf('%s[%d,%d] not changing.\n', AO.FamilyName, DeviceList(k(j),1), DeviceList(k(j),2)); |
---|
1335 | end |
---|
1336 | error('Timed out waiting for fresh data.'); |
---|
1337 | end |
---|
1338 | end |
---|
1339 | tout = etime(clock, t0); |
---|
1340 | end |
---|
1341 | |
---|
1342 | elseif strcmpi(AOField.DataType,'Matrix') |
---|
1343 | |
---|
1344 | for iDev = 1:length(DeviceIndex) |
---|
1345 | %AM(iDev,:) = rand(1,10); DataTime(iDev,:) = now; ErrorFlag(iDev,:)=0; |
---|
1346 | [AM(iDev,:), tout, DataTime(iDev,:), ErrorFlag(iDev,1)] = getpvonline(AOField.TangoNames(DeviceIndex(iDev),:), 'Matrix', N, InputFlags{:}); |
---|
1347 | end |
---|
1348 | ErrorFlag = any(ErrorFlag); |
---|
1349 | tout = etime(clock, t0); |
---|
1350 | |
---|
1351 | else |
---|
1352 | error(sprintf('Unknown DataType for family %s.', AO.FamilyName)); |
---|
1353 | end |
---|
1354 | |
---|
1355 | % Change to physics units if Units = 'physics' |
---|
1356 | if strcmpi(AO.(Field).Units,'physics') |
---|
1357 | % Change to physics units |
---|
1358 | AM = hw2physics(AO.FamilyName, Field, AM, DeviceList); |
---|
1359 | end |
---|
1360 | |
---|
1361 | elseif strcmpi(Mode,'Special') |
---|
1362 | |
---|
1363 | if isfield(AOField, 'SpecialFunctionGet') |
---|
1364 | SpecialFunction = AOField.SpecialFunctionGet; |
---|
1365 | elseif isfield(AOField, 'SpecialFunction') |
---|
1366 | SpecialFunction = AOField.SpecialFunction; |
---|
1367 | else |
---|
1368 | error(sprintf('No special function specified for Family %s (getpv).', AO.FamilyName)); |
---|
1369 | end |
---|
1370 | |
---|
1371 | % Get data at every point in time vector, t |
---|
1372 | ExtraTimeDelay = etime(clock, t0); |
---|
1373 | t = t - ExtraTimeDelay; |
---|
1374 | [AM, tout, DataTime, ErrorFlag] = feval(SpecialFunction, AO.FamilyName, Field, DeviceList, t); |
---|
1375 | t1 = clock; |
---|
1376 | if isempty(tout) |
---|
1377 | tout = etime(t1, t0); |
---|
1378 | end |
---|
1379 | if nargout >= 3 && isempty(DataTime) |
---|
1380 | days = datenum(t1(1:3)) - 719529; %datenum('1-Jan-1970'); |
---|
1381 | tt = 24*60*60*days + 60*60*t1(4) + 60*t1(5) + t1(6); |
---|
1382 | DataTime(1:size(AM,1),1) = fix(tt) + rem(tt,1)*1e9*sqrt(-1); |
---|
1383 | end |
---|
1384 | if length(t) > length(tout) |
---|
1385 | for itime = 2:length(t) |
---|
1386 | T = t(itime)-etime(clock, t0); |
---|
1387 | if T > 0 |
---|
1388 | pause(T); |
---|
1389 | end |
---|
1390 | |
---|
1391 | % Get data |
---|
1392 | [Tmp, toutTmp, DataTimeTmp, ErrorFlag] = feval(SpecialFunction, AO.FamilyName, Field, DeviceList, t); |
---|
1393 | |
---|
1394 | AM = [AM Tmp]; |
---|
1395 | DataTime = [DataTime DataTimeTmp]; |
---|
1396 | |
---|
1397 | t1 = clock; |
---|
1398 | tout(1,itime) = etime(t1, t0); |
---|
1399 | if nargout >= 3 && isempty(DataTimeTmp) |
---|
1400 | days = datenum(t1(1:3)) - 719529; %datenum('1-Jan-1970'); |
---|
1401 | tt = 24*60*60*days + 60*60*t1(4) + 60*t1(5) + t1(6); |
---|
1402 | DataTime(1:size(AM,1),itime) = fix(tt) + rem(tt,1)*1e9*sqrt(-1); |
---|
1403 | end |
---|
1404 | end |
---|
1405 | end |
---|
1406 | |
---|
1407 | % FreshDataFlag |
---|
1408 | if FreshDataFlag && length(t) == 1 |
---|
1409 | % Only use FreshDataFlag for scalar t |
---|
1410 | FreshDataCounter = FreshDataFlag; |
---|
1411 | AM0 = AM; |
---|
1412 | while FreshDataCounter |
---|
1413 | % Get data |
---|
1414 | [AM, tout, DataTime, ErrorFlag] = feval(SpecialFunction, AO.FamilyName, Field, DeviceList, t); |
---|
1415 | |
---|
1416 | if ~any((AM-AM0)==0) |
---|
1417 | FreshDataCounter = FreshDataCounter - 1; |
---|
1418 | AM0 = AM; |
---|
1419 | end |
---|
1420 | |
---|
1421 | t1 = clock; |
---|
1422 | if etime(t1, t0) > TimeOutPeriod |
---|
1423 | k = find((AM-AM0)==0); |
---|
1424 | for j = 1:length(k) |
---|
1425 | fprintf('%s[%d,%d] not changing.\n', AO.FamilyName, DeviceList(k(j),1), DeviceList(k(j),2)); |
---|
1426 | end |
---|
1427 | error('Timed out waiting for fresh data.'); |
---|
1428 | end |
---|
1429 | end |
---|
1430 | tout = etime(t1, t0); |
---|
1431 | |
---|
1432 | if nargout >= 3 && isempty(DataTime) |
---|
1433 | days = datenum(t1(1:3)) - 719529; %datenum('1-Jan-1970'); |
---|
1434 | tt = 24*60*60*days + 60*60*t1(4) + 60*t1(5) + t1(6); |
---|
1435 | DataTime(1:size(AM,1),1) = fix(tt) + rem(tt,1)*1e9*sqrt(-1); |
---|
1436 | end |
---|
1437 | end |
---|
1438 | |
---|
1439 | % Change to physics units if Units = 'physics' |
---|
1440 | if strcmpi(AO.(Field).Units,'physics') |
---|
1441 | % Change to physics units |
---|
1442 | AM = hw2physics(AO.FamilyName, Field, AM, DeviceList); |
---|
1443 | end |
---|
1444 | |
---|
1445 | elseif strcmpi(Mode,'manual') |
---|
1446 | % Always return in hardware units (like connected to the IOC) |
---|
1447 | % The conversion to physics in done at the end |
---|
1448 | t = 0; |
---|
1449 | if strcmp(AO.FamilyName, 'TUNE') |
---|
1450 | HarmNumber = []; |
---|
1451 | RF = []; |
---|
1452 | if find(DeviceIndex == 1) |
---|
1453 | AM(1,1) = input(sprintf(' Input the horizontal tune (fraction or Hz) = ')); |
---|
1454 | if AM(1,1) > 1 |
---|
1455 | HarmNumber = getharmonicnumber; |
---|
1456 | RF = getrf('Struct'); |
---|
1457 | if strcmpi(RF.UnitsString,'MHz') |
---|
1458 | FundFreq = 1e6*RF.Data / HarmNumber; |
---|
1459 | elseif strcmpi(RF.UnitsString,'Hz') |
---|
1460 | FundFreq = RF.Data / HarmNumber; |
---|
1461 | else |
---|
1462 | error('RF units in not known.'); |
---|
1463 | end |
---|
1464 | %AM(1,1) = (AM(1,1)- RF) / FundFreq; |
---|
1465 | AM(1,1) = AM(1,1) / FundFreq; |
---|
1466 | fprintf(' Horizontal fraction tune computed to be %f\n\n', AM(1,1)); |
---|
1467 | end |
---|
1468 | end |
---|
1469 | if find(DeviceIndex == 2) |
---|
1470 | AM(2,1) = input(sprintf(' Input the vertical tune (fraction or Hz) = ')); |
---|
1471 | if AM(2,1) > 1 |
---|
1472 | if isempty(HarmNumber) |
---|
1473 | HarmNumber = getharmonicnumber; |
---|
1474 | end |
---|
1475 | if isempty(RF) |
---|
1476 | RF = getrf('Struct'); |
---|
1477 | end |
---|
1478 | if strcmpi(RF.UnitsString,'MHz') |
---|
1479 | FundFreq = 1e6*RF.Data / HarmNumber; |
---|
1480 | elseif strcmpi(RF.UnitsString,'Hz') |
---|
1481 | FundFreq = RF.Data / HarmNumber; |
---|
1482 | else |
---|
1483 | error('RF units in not known.'); |
---|
1484 | end |
---|
1485 | AM(2,1) = AM(2,1)/FundFreq; |
---|
1486 | %AM(2,1) = (AM(2,1) - HarmNumber * FundFreq)/FundFreq; |
---|
1487 | fprintf(' Vertical fraction tune computed to be %f\n\n', AM(2,1)); |
---|
1488 | end |
---|
1489 | end |
---|
1490 | if find(DeviceIndex == 3) |
---|
1491 | AM(2,1) = input(' Input the synchrotron tune = '); |
---|
1492 | end |
---|
1493 | elseif strcmp(AO.FamilyName, 'RF') |
---|
1494 | if strcmpi(AO.(Field).Units, 'Hardware') |
---|
1495 | AM(1) = input(sprintf(' Input the RF frequency [%s] = ', AO.(Field).HWUnits)); |
---|
1496 | else |
---|
1497 | AM(1) = input(sprintf(' Input the RF frequency [%s] = ', AO.(Field).PhysicsUnits)); |
---|
1498 | AM = physics2hw(AO.FamilyName, Field, AM, [1 1]); |
---|
1499 | end |
---|
1500 | else |
---|
1501 | for i = 1:length(DeviceIndex) |
---|
1502 | if strcmpi(AO.(Field).Units, 'Hardware') |
---|
1503 | AM(i,:) = input(sprintf(' Manual input: %s(%d,%d) [%s] = ', AO.FamilyName, AO.DeviceList(DeviceIndex(i),1), AO.DeviceList(DeviceIndex(i),2), AO.(Field).HWUnits)); |
---|
1504 | else |
---|
1505 | AM(i,:) = input(sprintf(' Manual input: %s(%d,%d) [%s] = ', AO.FamilyName, AO.DeviceList(DeviceIndex(i),1), AO.DeviceList(DeviceIndex(i),2), AO.(Field).PhysicsUnits)); |
---|
1506 | AM(i,:) = physics2hw(AO.FamilyName, Field, AM(i,:), AO.DeviceList(DeviceIndex(i),:)); |
---|
1507 | end |
---|
1508 | end |
---|
1509 | end |
---|
1510 | |
---|
1511 | t1 = clock; |
---|
1512 | tout = etime(t1, t0); |
---|
1513 | days = datenum(t1(1:3)) - 719529; %datenum('1-Jan-1970'); |
---|
1514 | tt = 24*60*60*days + 60*60*t1(4) + 60*t1(5) + t1(6); |
---|
1515 | DataTime(1:size(AM,1),1) = fix(tt) + rem(tt,1)*1e9*sqrt(-1); |
---|
1516 | |
---|
1517 | % Change to physics units if Units = 'physics' |
---|
1518 | if strcmpi(AO.(Field).Units,'physics') |
---|
1519 | % Change to physics units |
---|
1520 | AM = hw2physics(AO.FamilyName, Field, AM, DeviceList); |
---|
1521 | end |
---|
1522 | |
---|
1523 | |
---|
1524 | elseif strcmpi(Mode,'Simulator') || strcmpi(Mode,'Model') |
---|
1525 | |
---|
1526 | ExtraTimeDelay = etime(clock, t0); |
---|
1527 | %[AM, tout, DataTime, ErrorFlag] = getpvmodel(AO, Field, DeviceList, t-ExtraTimeDelay, 'Physics', 'Numeric'); |
---|
1528 | [AM, tout, DataTime, ErrorFlag] = getpvmodel(AO, Field, DeviceList, t-ExtraTimeDelay, AO.(Field).Units, 'Numeric'); |
---|
1529 | tout = tout + ExtraTimeDelay; |
---|
1530 | |
---|
1531 | |
---|
1532 | if strcmpi(OutputDataType, 'String') |
---|
1533 | AM = num2str(AM); |
---|
1534 | end |
---|
1535 | |
---|
1536 | % Change to physics units if Units = 'physics' |
---|
1537 | %if strcmpi(AO.(Field).Units,'Hardware') |
---|
1538 | % % Change to physics units |
---|
1539 | % AM = physics2hw(AO.FamilyName, Field, AM, DeviceList, getenergymodel); |
---|
1540 | %end |
---|
1541 | |
---|
1542 | else |
---|
1543 | error('Unknown mode for family %s.', AO.FamilyName); |
---|
1544 | end |
---|
1545 | |
---|
1546 | |
---|
1547 | |
---|