classdef SCDclass_node < SCDclass_component
  % node class containing wrappers or algos

  properties (SetAccess = private)
    nodenr
    active = false; % not active by default
    hasrfm = true; % all nodes have rfm
    haswavegen
    hasadc
    hasethercat
    ncpu           % number of CPUs
    cputype
    buildcfg
    initscdbeforecomp
    cpuactive
    wrappers % info about thread wrappers contained in this node
  end
  
  properties
    type = 'node';
  end
  
  methods
    
    function obj = SCDclass_node(nodenr)
      % constructor
      name = sprintf('SCD_rtc_%02d',nodenr);
      obj.nodenr = nodenr;
      obj.name    = name;
      obj.algos   = [];
      obj.ddname  = [name,'.sldd'];
      obj.mdlname = [name,'.slx'];
      obj.wrappers = [];
      
      % get node-specific configurations
      obj = defaultnodeconfig(obj,nodenr);
    end
    
    function obj = addwrapper(obj,wrapperObj,cpunr,varalgo,isactive)
      % add wrapper to a node at a given cpunumber
      % varalgo is the variant subsystem number used to select this wrapper
      % isactive (true by default) sets whether the addition of the wrapper
      % also sets the cpu to be active;
      assert(nargout==1,'must assign output for addwrapper method')
      
      % by default, activate CPU when adding a wrapper
      if nargin==4, isactive=true; end
      
      assert(isa(wrapperObj,'SCDclass_wrapper'));
      
      for ii=1:numel(obj.wrappers)
        assert(~isequal(wrapperObj,obj.wrappers{ii}.wrapperobj),...
          'wrapper %s is already present in node %d thread %d',...
          obj.wrappers{ii}.wrapperobj.name,obj.nodenr,cpunr)
      end
      
      mywrapper.wrapperobj = wrapperObj;
      mywrapper.cpunr      = cpunr;
      mywrapper.varalgo    = varalgo;
      
      % add wrapper to obj
      obj.wrappers{cpunr}  = mywrapper;
      % set cpu of this wrapper to active
      obj.cpuactive(cpunr) = isactive;
      % set receiving node cpu sample time to wrapper sample time
      obj.timing.thperiod(cpunr) = wrapperObj.timing.dt;
    end
    
    function node = defaultnodeconfig(node,nodenr)
      % Default configuration for nodes
      node.name = sprintf('NODE%02d',nodenr); %Default node names
      switch nodenr
        case 1
          node.name = sprintf('CRPPRT01%02d',nodenr); % special case for old node
          node.ncpu = 1;
          node.type = 'std1cpu2015a';
          node.timing.t_start = -4.5;
          node.timing.t_stop = 3;
          node.timing.dt = 1e-4;
          node.buildcfg.conffile{1} = 'standard';
          node.buildcfg.initscdbeforecomp = false;
          node.haswavegen = true;
          node.hasethercat = false;
          node.hasadc = true;
        case 2
          node.ncpu = 6;
          node.type = 'std1cpu2015a';
          node.timing.t_start = -4.5;
          node.timing.t_stop = 3;
          node.timing.dt = 1e-4;
          node.buildcfg.conffile = cell(node.ncpu,1);
          node.buildcfg.conffile{1} = 'standard';
          node.buildcfg.conffile{2} = 'standard';
          node.buildcfg.conffile{3} = 'standard';
          node.buildcfg.conffile{4} = 'standard';
          node.buildcfg.conffile{5} = 'standard';
          node.buildcfg.conffile{6} = 'standard';
          node.buildcfg.initscdbeforecomp = false;
          node.haswavegen = true;
          node.hasadc = true;
          node.hasethercat = true;
        case 3
          node.ncpu = 4;
          node.type = '4cpus2015a';
          node.timing.t_start = -2.0;
          node.timing.t_stop = 2.75;
          node.timing.dt = 1e-3;
          node.buildcfg.conffile = cell(node.ncpu,1);
          node.buildcfg.conffile{1} = 'standard';
          node.buildcfg.conffile{2} = 'standard';
          node.buildcfg.conffile{3} = 'standard';
          node.buildcfg.conffile{4} = 'standard';
          node.buildcfg.initscdbeforecomp = [0 0 0 0];
          node.haswavegen = true;
          node.hasadc = false;
          node.hasethercat = false;
        case 4
          node.ncpu = 4;
          node.type = 'std1cpu2015a';
          node.timing.t_start = -4.5;
          node.timing.t_stop = 3;
          node.timing.dt = 1e-4;
          node.buildcfg.conffile{1} = 'standard';
          node.buildcfg.initscdbeforecomp = false;
          node.haswavegen = true;
          node.hasadc = false;
          node.hasethercat = false;
        case 5
          node.ncpu = 1;
          node.type = 'std1cpu2015a';
          node.timing.t_start = -4.5;
          node.timing.t_stop = 3;
          node.timing.dt = 1e-4;
          node.buildcfg.conffile{1} = 'standard';
          node.buildcfg.initscdbeforecomp = false;
          node.haswavegen = true;
          node.hasadc = false;
          node.hasethercat = false;
        case 6
          node.ncpu = 4;
          node.type = '4cpus2015a';
          node.timing.t_start = 0.0;
          node.timing.t_stop = 2.75;
          node.timing.dt = 1e-3;
          node.buildcfg.conffile = cell(node.ncpu,1);
          node.buildcfg.conffile{1} = 'standard';
          node.buildcfg.conffile{2} = 'standard';
          node.buildcfg.conffile{3} = 'standard';
          node.buildcfg.conffile{4} = 'standard';
          node.buildcfg.initscdbeforecomp = [0 0 0 0];
          node.haswavegen = true;
          node.hasadc = false;
          node.hasethercat = false;
        case 7
          node.ncpu = 4;
          node.type = '4cpus2015a';
          node.timing.t_start = -0.5;
          node.timing.t_stop = 2.5;
          node.timing.dt = 1e-3;
          node.buildcfg.conffile = cell(node.ncpu,1);
          node.buildcfg.conffile{1} = 'standard';
          node.buildcfg.conffile{2} = 'standard';
          node.buildcfg.conffile{3} = 'standard';
          node.buildcfg.conffile{4} = 'standard';
          node.buildcfg.initscdbeforecomp = [0 0 0 0];
          node.haswavegen = true;
          node.hasadc = true;
          node.hasethercat = false;
        case 8
          node.ncpu = 1;
          node.type = '4cpus2015a';
          node.timing.t_start = -0.5;
          node.timing.t_stop = 2.5;
          node.timing.dt = 1e-3;
          node.buildcfg.conffile = cell(node.ncpu,1);
          node.buildcfg.conffile{1} = 'standard';
          node.buildcfg.conffile{2} = 'standard';
          node.buildcfg.conffile{3} = 'standard';
          node.buildcfg.conffile{4} = 'standard';
          node.buildcfg.initscdbeforecomp = [0 0 0 0];
          node.haswavegen = true;
          node.hasadc = true;
          node.hasethercat = false;
        case 9
          node.ncpu = 1;
          node.type = '10cpusI9';
          node.timing.t_start = -0.5;
          node.timing.t_stop = 2.5;
          node.timing.dt = 1e-4;
          node.buildcfg.conffile = cell(node.ncpu,1);
          node.buildcfg.conffile{1} = 'standard';
          node.buildcfg.conffile{2} = 'standard';
          node.buildcfg.conffile{3} = 'standard';
          node.buildcfg.conffile{4} = 'standard';
          node.buildcfg.initscdbeforecomp = [0 0 0 0];
          node.haswavegen = true;
          node.hasadc = true;
          node.hasethercat = false;         
      end
      node.cpuactive = zeros(1,node.ncpu);
      
      % thread timing
      if ~isfield(node.timing,'thperiod')
        node.timing.thperiod = 1e-3*ones(1,node.ncpu);
      end
      
      % add template node wrappers
      for icpu=1:node.ncpu
        wrappername = sprintf('SCDwrap_template%02d%02d',nodenr,icpu);
        mywrapper = SCDclass_wrapper(wrappername);
        varalgo = 1; % template value
        node = node.addwrapper(mywrapper,icpu,varalgo,false);
      end
    end
    
    function obj = setactive(obj,value)
      % set the node to be active
      assert(islogical(value),'value must be boolean')
      obj.active = value;
    end
    
    function updatetemplatetp(obj)
      % update wrapper algos
      for ii=1:numel(obj.wrappers)
        obj.wrappers{ii}.wrapperobj.updatetemplatetp;
      end
      % update node algos
      for ii=1:numel(obj.algos)
        if ~isempty(obj.algos(ii))
          obj.algos(ii).updatetemplatetp;
        end
      end
    end
    
    function printinfo(obj)
      % print wrapper and algo info
      fprintf('\nNode%02d, CPUs:%02d, name:%s, dt=%5.3fms\n',...
              obj.nodenr,obj.ncpu,obj.name,obj.timing.dt*1e3)
      for wrapper = obj.wrappers
        fprintf(' CPU %d wrapper: ',wrapper{:}.cpunr);
        wrapper{:}.wrapperobj.printinfo;
      end
      if ~isempty(obj.algos)
        fprintf(' Node Algos:\n')
        for ii=1:numel(obj.algos)
          algo = obj.algos(ii);
          fprintf('%s',algo.getname);
        end
      end
      fprintf('\n');
    end
  end
end
