source: MML/trunk/mml/getpv.m @ 4

Last change on this file since 4 was 4, checked in by zhangj, 11 years ago

Initial import--MML version from SOLEIL@2013

File size: 55.6 KB
Line 
1function [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
132t0 = clock;
133
134
135% Defaults
136FieldDefault = 'Monitor';
137Field = FieldDefault;
138DeviceList = [];
139t = 0;
140FreshDataFlag = 0;
141TimeOutPeriod = 10;
142ErrorFlag = 0;
143
144StructOutputFlag = 0;
145NumericOutputFlag = 0;
146ObjectOutputFlag = 0;
147ModeFlag = '';
148UnitsFlag = '';
149OutputDataType = 'Double';
150
151
152% Look if 'struct' or 'numeric' in on the input line
153InputFlags = {};
154for 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
240end
241
242if isempty(varargin)
243    error('Must have at least one input (Family, Data structure, or Channel Name).');
244end
245
246
247
248%%%%%%%%%%%%%%%%%%%%%%%%%%%%
249% CELL OR CELL ARRAY INPUT %
250%%%%%%%%%%%%%%%%%%%%%%%%%%%%
251if 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
538end
539%%%%%%%%%%%%%%%%%%
540% End cell input %
541%%%%%%%%%%%%%%%%%%
542
543
544
545%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
546% COMMONNAME - Commonname input with no family input %
547%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
548if 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
623end
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%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
633if 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   
715else
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
777end
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%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
787if isempty(t)
788    t = 0;
789end
790if 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
873else
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
962end
963
964
965if 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);
976end
977
978
979% Structure output
980if 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
991end
992
993
994
995%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
996%  Main Function for Getting Data Using Common Names  %
997%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
998function [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
1003if ErrorFlag
1004    AM=[]; tout=[]; DataTime=[];
1005    return;
1006else
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
1035end
1036
1037
1038
1039%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1040%  Main Function for Getting Data using the Channel Names  %
1041%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1042function [AM, tout, DataTime, ErrorFlag] = local_getbyname(ChannelName, OutputDataType, N, t, FreshDataFlag, TimeOutPeriod, varargin)
1043
1044t0 = clock;
1045ErrorFlag = 0;
1046
1047
1048if nargout < 3
1049    [AM, tout] = getpvonline(ChannelName, OutputDataType, N, t, varargin{:});
1050else
1051    [AM, tout, DataTime, ErrorFlag] = getpvonline(ChannelName, OutputDataType, N, t, varargin{:});
1052end
1053
1054
1055% FreshDataFlag
1056if 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);
1081end
1082
1083return
1084
1085%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1086%  Main Function for Getting Data using the Accelerator Object  %
1087%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1088function [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
1103t0 = clock;
1104ErrorFlag = 0;
1105N = 0;  % Output size
1106InputFlags ={};
1107
1108for 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
1116end
1117
1118% Find the index for where the desired data is in the total device list
1119DeviceListTotal = AO.DeviceList;
1120[DeviceIndex, iNotFound] = findrowindex(DeviceList, DeviceListTotal);
1121if 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));
1127end
1128
1129% Check the DeviceIndex
1130if 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;
1136end
1137
1138%% TANGO specific part
1139
1140% Load Field sub-structure into AOField
1141if ~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
1201end
1202
1203
1204AOField = AO.(Field);   % Should I replace this????
1205
1206% If mode does not exist, force to online mode
1207if isfield(AOField, 'Mode')
1208    Mode = AOField.Mode;
1209else
1210    Mode = 'Online';
1211end
1212
1213
1214% Check if Online should really be special
1215if strcmpi(Mode, 'Online')
1216   if isfield(AO.(Field), 'SpecialFunctionGet')
1217       Mode = 'Special';
1218   end
1219end
1220
1221
1222if ~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   
1235elseif 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
1361elseif 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
1445elseif 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
1524elseif 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
1542else
1543    error('Unknown mode for family %s.', AO.FamilyName);
1544end
1545
1546
1547
Note: See TracBrowser for help on using the repository browser.