function [out,out1] = photon(varargin)


% Virtual deviced driver for the Dactron Active-X API
% This driver works with ID_ACQ the acquisition environment of SDT
%
% h=photon :  opens the Active-X server and the GUI
%
% photon('plothammer',batch)
%
% Acquired frames are stored in variable BATCH in the
% base MATLAB workspace.
%
% Warning : this is a prototype. Comments are welcome but SDTools
% does not provide support for it.
%
%

%       Etienne Balmes  28/09/02, 22/10/02
%       Copyright (c) 2002-2002 by SDtools
%       For revision info use photon('cvs')


% Handle to find the server between calls
gf=findall(0,'tag','SDTacq'); if isempty(gf) gf=id_acq('init'); end

ga=findall(gf,'tag','PhotonServer');
if isempty(ga)
 if isunix 
  warning('Photon Server is only available on windows');return;
 end
 ga=axes('parent',gf,'visible','off','tag','PhotonServer', ...
         'DeleteFcn','photon(''close'');');
 ua=[];
else ua=get(ga,'userdata');
end


[ua,PH]=openPhoton(ga,ua);
h=ua.photon;

if nargin==0 out=PH;return; else [CAM,Cam]=comstr(varargin{1},1);carg=2; end
sdtdef('diag',['photon(''' Cam ''')'])

% Supported returns list of device capabilities - - - - - - - - - - - - -
if comstr(Cam,'supported')

for j1=1:20 if h.SystemReady; break; end; 
 disp('Waiting for DSP boot');pause(10);
end % wait for boot

sup=struct('DataTypes',[]);

sup.DataTypes=h.DataTypes;

st=get(h.source,'types',1);st{end+1}='Channel 1';st{end+1}='Off';
sup.SourceTypes=st;

% Signal processing availlable
sup.BlockSizes=double(h.MeasSetup.BlocksizeRange);



sup.FreqRanges=FreqRanges;
st={}; for j1=1:length(sup.FreqRanges) 
    st{j1}=sprintf('%.0f',sup.FreqRanges(j1,2)*450/1024);
end
sup.RangeLabel=st;


sup.Windows=h.MeasSetup.Windows;
sup.TriggerModes=h.ArmTrigger.TriggerModes;
sup.ch={};
for j1=1:double(h.NumberOfInputs)
 r1=[];
 r1.Ranges=cellstr(num2str(double(get(h.input,'EU',j1))));
 st1=get(h.input,'couplings',j1);st1{end+1}='Off';
 r1.Coup=st1;
 sup.ch{j1}=r1;
end

out=sup;

% Current State - - - - - - - - - - - - - - - - - - - - - - - - - - -
elseif comstr(Cam,'state')

st={'DataType','DataType'};
out=[];
for j1=1:size(st,1)
 eval(sprintf('r1=PH.%s;',st{j1,1}),'r1=[];');
 eval(sprintf('out.%s=r1;',st{j1,2}),'');
end

% Source state
r1.type=get(PH.source,'type',1);

if ~get(h.source,'enable',1) r1.type='Off';end
r1.state=get(h.source,'state',1); 
if isempty(r1.state) r1.state='Stopped source';end

switch lower(r1.type)
case 'sine'
 r1.table={r1.state,'Sine','';
           'Frequency',num2str(get(h.source,'SineFreq',1)),'Hz';
           'Amplitude',get(h.source,'Amplitude',1),'V'};
otherwise 
 r1.table={r1.state,'Not supported'};
end

out.source={r1};
% Channel state
out.ch={};
for j1=1:double(h.NumberOfInputs)
 r1=[];
 r1.EU=get(h.input,'EU',j1);
 r1.EUScale=num2str(get(h.input,'EUScale',j1));
 r1.range=get(h.input,'range',j1);
 if get(h.input,'enable',j1) r1.cond=get(h.input,'coupling',j1);
 else r1.cond='Off';end
 out.ch{j1}=r1;
end

% Signal processing info
out.BlockSize=double(h.MeasSetup.Blocksize);
r2=FreqRanges; [r1,i1]=min(abs(r2(:,1)-h.MeasSetup.Span));
out.Fsamp=r2(i1,2);
out.window=h.MeasSetup.Window;

st=h.ArmTrigger.TriggerModes;
out.trigger=[double(h.ArmTrigger.TriggerChannel) ...
 find(strcmp(h.ArmTrigger.TriggerMode,st)) h.ArmTrigger.TriggerLevel ...
  h.ArmTrigger.TriggerDelay];

st={'PreInit','InitDone','Settling','PreArm','PreTrigger', ...
    'WaitTrigger','Processing','Transition'};
out.state=double(h.MeasState);

out1=PH;

% -----------------------------------------------------------------------
elseif comstr(Cam,'set') [CAM,Cam]=comstr(CAM,4);

cur=varargin{carg};carg=carg+1;
r1=varargin{carg};carg=carg+1;

switch lower(r1{1})
case 'blocksize';   set(h.MeasSetup,'BlockSize',r1{2});

case 'channel';     
  if strcmp(r1{2},'coupling')&strcmpi(r1{4},'off')
   set(h.input,'enable',r1{3},0);
  else set(h.input,r1{2:end});set(h.input,'enable',r1{3},1);
  end
case 'datatype';    set(h.datatype,r1{2});
case 'source';

switch r1{2}
case 'disable'; set(h.Source,'enable',r1{3},0);
case 'enable';  set(h.Source,'enable',r1{3},1);
otherwise
 warning xxx
 %set(h.Source,'type',1,st1);
end

case 'span';
 r2=FreqRanges;
 [r3,i1]=min(abs(r1{2}-r2(:,2)*450/1024));
 set(h.MeasSetup,'Span',r2(i1,1));

case 'triggermode';   set(h.ArmTrigger,'TriggerMode',r1{2});

case 'triggerparam';

 % level
  r2=get(h.ArmTrigger,'TriggerLevelRange');
  r3=r1{2};if ischar(r3) r3=str2num(r3);end
  if r3>=r2(1) & r3<=r2(2)
    set(h.ArmTrigger,'TriggerLevel',r3);
  else warning('Out of range trigger level');end
 % delay
 r3=r1{3};if ischar(r3) r3=str2num(r3);end
 set(h.ArmTrigger,'TriggerDelay',r3/cur.Fsamp);

case 'window';   set(h.MeasSetup,'Window',r1{2});
otherwise
 warning xxx
end


% -----------------------------------------------------------------------
% open
elseif comstr(Cam,'open') [CAM,Cam]=comstr(CAM,6);

% -----------------------------------------------------------------------
%  Handling standard frame plots
elseif comstr(Cam,'plot') [CAM,Cam]=comstr(CAM,5);

if comstr(Cam,'hammer')
 ph_hammer(varargin{carg}); carg=carg+1;
else
 error('Not a supported plot');
end


% -----------------------------------------------------------------------
% start
elseif comstr(Cam,'start') [CAM,Cam]=comstr(CAM,6);

Info=varargin{carg};carg=carg+1;
batch=varargin{carg};carg=carg+1;

ga=findobj(gf,'type','axes','tag','acq_table'); ua=get(ga,'userdata');
uf=get(gf,'userdata');

if length(ua.table)<3 id_acq('acqrefresh');return;end % Init not done yet
[cur,h]=feval(uf.driver,'state'); % xxx


set(Info,'string','Starting ...','backgroundcolor','red');

if h.MeasState==0 invoke(h,'open'); end

% Deal with need to start source - - - - - - - - - - - - - - - - - - -
i1=strmatch('source',lower(ua.table(:,1)));
if ~any(strncmp(lower(ua.table{i1,2}),{'off','cha'},3)) % start source
 if ~isempty(findstr(get(h.Source,'state',1),'idle'))
  invoke(h.Source,'start');
 end

 j1=1;
 while strcmp(get(h.source,'state',1),'Source idle') & j1<10
  j1=j1+1;pause(1);drawnow;
  set(Info,'string','Starting source ...');
 end
 if strcmp(get(h.source,'state',1),'Source idle')
  error('Failed to start source');
 end

else % deal with trigger channel enable
 set(h.Input,'enable',h.ArmTrigger.TriggerChannel,1);
end % end of source strating

% Start acquisition
invoke(h,'stop');   invoke(h,'start');
set(h.ArmTrigger,'ArmMode','Auto');
invoke(h,'ReadDone');

% Wait for acquisition to be ready
id_acq('acqrefresh');

Stop=findall(gf,'tag','stop');
set(Stop,'backgroundcolor','r','userdata',0)
set(findall(gf,'tag','start'),'backgroundcolor',backcol)
drawnow

%Initialize a few things

 if strcmpi(h.DataType,'time') batch.type='time'; else batch.type='freq';end

 i0=strmatch('Channel',ua.table(:,1));i0=i0(1); batch.ch=[];
 for j1=1:length(cur.ch)
  i1=strmatch(sprintf('Channel %i',j1),ua.table(:,1))-i0;
  if strcmpi(cur.ch{j1}.cond,'Off') set(h.Input,'enable',j1,0);
  else batch.ch(end+1)=i1;  set(h.Input,'enable',j1,1);
  end
 end
 assignin('base','batch',batch)

% This is the acquisition loop - - - - - - - - - - - - - - - - - - - - - -
while length(batch.frame)<=batch.MaxFrame & ~get(Stop,'userdata')

if strcmp(h.State,'Ready for Start')
  set(Info,'string','Waiting for start ...','backgroundcolor','red');
elseif ~h.DataAvailable
 switch double(h.MeasState)
 case {7};   set(Info,'string','Acquiring');
 case {5,6}; 
  set(Info,'string','Waiting for trigger ...','backgroundcolor','green');
 end
else % No data available
switch double(h.MeasState)
case {3}
 set(Info,'string','Initializing filters ...','backgroundcolor','yellow');
%case {4}
% set(Info,'string','Ready for Arm');
case {5,6}; 
 set(Info,'string','Waiting for trigger ...','backgroundcolor','yellow');
case 8
 set(Info,'string','Transition ...');
%case 7
%   set(Info,'string','Acquiring');
otherwise  
  % Read data

  get_frame(h,Info,gf,ua);
  invoke(h,'ReadDone');
  set(findall(gf,'tag','next'),'backgroundcolor',[1 .5 0],'userdata',0)
  
  % Reset for trigger
end % MeasState
end % DataAvailable

drawnow;id_acq; batch=evalin('base','batch');

end % end of acquisition loop

if h.MeasState>2 id_acq('stop');end
set(Info,'backgroundcolor',backcol);

% -----------------------------------------------------------------------
% stop
elseif comstr(Cam,'stop') [CAM,Cam]=comstr(CAM,6);

try
 invoke(PH,'Stop');
 invoke(PH.Source,'Stop'); 
 out='Stopped acquisition';
catch
 out='Stop failed';
end


% -----------------------------------------------------------------------
% -----------------------------------------------------------------------
% -----------------------------------------------------------------------
% next
elseif comstr(Cam,'next') [CAM,Cam]=comstr(CAM,5);

 
% Init for all acq commands
h=ua.photon;
ga=findobj(gf,'type','axes','tag','next_table');
if ~isempty(ga) ua=get(ga,'userdata');else ua=[];end

if isempty(Cam) % 'Next' - - - - - - - - - - - - - - - - -

batch=evalin('base','batch');

if ~isfield(batch,'save')
 warning('No data to save in current batch');
 return;
end

global IIw IIxf IIxe IIxh

i2=[];
i1=strmatch('H1',batch.save(1:2:end))*2; if ~isempty(i1)
 r2=batch.save{i1};
 IIxf(1:size(r2,1),end+[1:size(r2,2)])=r2; i2=size(IIxf,2);
end

i1=strmatch('H2',batch.save(1:2:end))*2; if ~isempty(i1)
 r2=batch.save{i1};
 IIxe(1:size(r2,1),end+[1:size(r2,2)])=r2;i2=size(IIxe,2);
end

i1=strmatch('COH',batch.save(1:2:end))*2; if ~isempty(i1)
 r2=batch.save{i1};
 IIxh(1:size(r2,1),end+[1:size(r2,2)])=r2;i2=size(IIxh,2);
end

i1=strmatch('f',batch.save(1:2:end))*2; if ~isempty(i1)
 r2=batch.save{i1};
 IIw=r2(:);
end
if ~isempty(i2) iicom(sprintf('ch %i',i2));end

batch.save={}; batch.frame=0;

assignin('base','batch',batch);

elseif comstr(Cam,'channel') % 'NextChannel' - - - - - - - - - - - - - - - - -

warning('Nothing done currently')

elseif comstr(Cam,'check') % 'NextCheck' - - - - - - - - - - - - - - - - - -

uo=varargin{carg};carg=carg+1;
st=lower(ua.table{uo.index(1),1});

if h.MeasState>1
 warndlg('Stop acquisition before modifying parameters','Photon');
elseif comstr(st,'channel')  % Deal with channel properties

end % of command handling

photon('nextrefresh');

elseif comstr(Cam,'refresh') % 'NextRefresh' - - - - - - - - - - - - - - - -

 %if isempty(ua)
  ga=[];ua.EditFcn={''}; ua.table={};
  ua.RefreshFcn='photon(''nextrefresh'',ga);';
 %end
 j2=1;

 global IIxf
 ua.table={sprintf('%i %i',size(IIxf)),'Reset'};
 ua.EditFcn{1,2}='photon(''NextReset'');';

 ua.Level=[1 1];
 ua.CheckFcn='photon(''nextcheck'',uo)';

 h=findall(gf,'tag','channel')
 st=cellstr(num2str([1:size(IIxf,2)]'))
 set(h,'string',st);

 if ~isempty(ga) set(ga,'userdata',ua); cingui('tablerefresh',ga);
 else cingui('tableinit',ua,'next_table',gf); end



%h.MeasSetup.BlockSizeRange
%ua.photon.MeasSetup.OverlapRange
%ua.photon.MeasSetup.Spans
elseif comstr(Cam,'reset') % 'NextReSet' - - - - - - - - - - - - - - - -

IIw=[]; IIxf=[]; IIxe=[]; IIxh=[]; 
disp('Resetting iiplot data');

else %
end % of next commands

% -----------------------------------------------------------------------
% close
elseif comstr(Cam,'close') |comstr(Cam,'quit') 
[CAM,Cam]=comstr(CAM,6);

h1=warndlg(sprintf('Closing down the Active Photon Server'),'PHOTON');
drawnow;
try
 if ~isempty(h)
  invoke(h,'Close'); 
  release(h); % delete ?
 end
 ua.photon=[];
end
if ~isempty(ua.photon)
 lasterr
 warning('There were problems closing the Photon Server');
end
set(ga,'userdata',ua);
delete(h1);delete(gf);

% -----------------------------------------------------------------------
elseif comstr(Cam,'save'); [CAM,Cam]=comstr(CAM,5);

if comstr(Cam,'setup')

 [fname, wd] = uiputfile('*.cfg', 'Save Measurement setup as');
 if ischar(fname)
  fname=fullfile(wd,fname);
  [wd,fname]=fileparts(fname);fname=fullfile(wd,[fname '.cfg']);
  invoke(PH,'SaveSetup',fname);
  sdtw('_IsGui','Save setup in %s',fname);
 end

else sdtw('Save%s unknow',CAM);end

% -----------------------------------------------------------------------
elseif comstr(Cam,'load'); [CAM,Cam]=comstr(CAM,5);

if comstr(Cam,'setup')

 [fname, wd] = uigetfile('*.cfg', 'Load Measurement setup');
 if ischar(fname)
  fname=fullfile(wd,fname);
  [wd,fname]=fileparts(fname);fname=fullfile(wd,[fname '.cfg']);
  invoke(PH,'LoadSetup',fname);
  sdtw('_IsGui','Loaded setup in %s',fname);
 end

else sdtw('Save%s unknow',CAM);end



% -----------------------------------------------------------------------
elseif comstr(Cam,'cvs')
 out='$Revision: 1.7 $  $Date: 2004/08/16 13:36:25 $';

% -----------------------------------------------------------------------
else error('Unknown command');end

% -----------------------------------------------------------------------
% -----------------------------------------------------------------------
% -----------------------------------------------------------------------
function  get_frame(h,Info,gf,ua)

 batch=evalin('base','batch');

 r1=[]; DataType=h.DataType;
 IsRetained='';
 r2=struct('X',[],'Y',[],'Overflow',[]);
 low=[]; high=[];
 for j2=batch.ch(:)'
    if isempty(batch.t) % read time and/or freq
     if strcmp(batch.type,'time') 
      batch.t=double(get(h,'xdata',j2));
      batch.f=1/diff(batch.t(1:2))*[0:length(batch.t)-1]/length(batch.t);
     else
     batch.f=double(get(h,'xdata',j2)); batch.t=0;
     end
    end
    y=double(get(h,'ydata',j2));
    if strcmp(DataType,'Time'); else y=[1 i]*reshape(y,2,length(y)/2); end

    r1=[r1 y(:)];

    % Over/Underflow behaviour - - - - - - - - - - - - - - - - - - - - - -
    if strcmp(get(h.Input,'RangeStatus',j2),'E_RANGE_OVER')
     
      r2=get(h.Input,'Ranges',j2); r3=get(h.Input,'Range',j2);
      if max(y)<r3*.4 low(end+1)=j2; % underflow
        
        IsRetained=sprintf('%s%i low, ',IsRetained,j2);
      elseif max(y)<r3*1.2 warning('problem with RangeStatus');
      elseif ~any(r2>r3) high(end+1)=j2; % impossibility of range change
      else high(end+1)=j2; 
      end
    end % Over/underflow
 end % loop on channels

 st1='(';
 if ~isempty(high) st1=[st1 'over:' sprintf('%i ',high)]; end
 if ~isempty(low) st1=[st1 'low:' sprintf('%i ',low)]; end
 if length(st1)==1 st1=''; else st1=[st1 ')'];end 
 r2.X=batch.t(:); r2.Y=r1;  r2.OverFlow=st1;

 batch.frame{end+1}=r2;
 assignin('base','batch',batch);
 id_acq('FramePlot');


% -----------------------------------------------------------------------
% -----------------------------------------------------------------------
% -----------------------------------------------------------------------
function  ContextMenus(gf);

     menu=uicontextmenu('parent',gf, ...
        'callback','photon(''nextchcontext'');', ...
        'tag','ch_context','HandleVisibility','callback');

     uimenu(menu,'label','Remove selected channels', ...
           'callback','photon(''nextchrm'');','visible','on')

   set(findall(gf,'tag','channel'),'uicontextmenu',menu)


     menu=uicontextmenu('parent',gf, ...
        'callback','photon(''framecontext'');', ...
        'tag','frame_context','HandleVisibility','callback');

     uimenu(menu,'label','Remove selected frame(s)', ...
           'callback','photon(''framerm'');','visible','on')

   set(findall(gf,'tag','frame'),'uicontextmenu',menu)

% -----------------------------------------------------------------------
% -----------------------------------------------------------------------
% -----------------------------------------------------------------------
function  [ua,PH]=openPhoton(ga,ua);

%try
if ~isfield(ua,'photon')|isempty(ua.photon)
 %ua.photon=actxserver('API.MeasEngine');
 ua.photon=actxserver('ME4R.MeasEngine');
 invoke(ua.photon,'Open');
end
%catch
% ua.photon=[];
 %warndlg('Could not open Photon server');
%end

set(ga,'userdata',ua)
PH = ua.photon; 

% Resource fiel VpuRes.dll is not found VPUDLL will not work properly

if 1==2

h=actxserver('ME4R.MeasEngine');
invoke(h,'open');
invoke(h,'start');

y=get(h,'ydata',1)

end



function out=backcol
 out=get(0,'defaultuicontrolbackgroundcolor');

% -----------------------------------------------------------------------
function out=FreqRanges

if 1==2
r1=h.MeasSetup.Spans;r1=r1(:);
for j1=1:size(r1,1);

  set(h.MeasSetup,'Blocksize',1024); set(h.MeasSetup,'span',r1(j1,1));
  r3=logspace(-2,1,512);
  for j2=1:length(r3)
   set(h.ArmTrigger,'TriggerDelay',r3(j2)/r1(j1));
   r2=h.ArmTrigger.TriggerDelay; 
   if r2; if j2==1 error('Not valid');end; break;end
  end
  r1(j1,2)=1/r2;
end
fprintf('out=[\n'); fprintf('%10.4f %10.4f;\n',r1')
fprintf('];');

else

out=[
   15.0000    40.0000;
   20.0000    46.8750;
   30.0000    80.0000;
   36.0000    93.7500;
   62.0000   160.0000;
   75.0000   187.5000;
  125.0000   320.0000;
  150.0000   375.0000;
  250.0000   640.0000;
  300.0000   750.0000;
  500.0000  1280.0000;
  600.0000  1500.0000;
 1000.0000  2560.0000;
 1200.0000  3000.0000;
 2000.0000  5120.0000;
 2400.0000  6000.0000;
 4000.0000 10240.0000;
 4680.0000 12000.0000;
 8000.0000 20480.0000;
 9500.0000 24000.0000;
16000.0000 40960.0000;
18750.0000 40960.0000;
];
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if 1==2

[cur,h]=feval('photon','state'); % xxx
sup=photon('supported');




r1=[15 40
 20 4.6875e+001
 9500 24000
]

r1(:,2)./r1(:,1)

end