Something went wrong on our end
-
Cristian Galperti authoredCristian Galperti authored
SCDclass_expcode.m 44.72 KiB
classdef SCDclass_expcode
%An SCD expcode object
%
% Main methods:
% .open: Open baseline .slx model
% open(N): Open node N
% open(N,M): Open thread M of node N
% .build, build(N), build(N,M): Generate C code for node N, thread M
% .compile, compile(N), compile(N,M): Compile Simulink model for node N, thread M)
% .close_all: Close all Simulink block diagrams
%
% .printinfo: Print information about components of this expcode
% .printtasks: Print configured tasks
% .printwavegens: Print configured wavegen signals
%.
properties (Access = public)
% Main properties
name % Expcode main name
maincode % Expcode numerical code
status % Expcode development status
end
properties (Access = protected)
loadverbose % Verbosity level of the loading (currently 0 or 1)
nodes % array of node properties structs
end
properties (Access = private)
activenodes % numerical list of configured active nodes
activecpus % numerical list of configured CPUs
%nodeddlist % list of data dictionaries at node level
wrapperlist % list of configured wrappers
algoobjlist % list of loaded algorithm objects
algonamelist % List of loaded algorithm names
algoddlist % list of data dictionaries at algorithm level
mdscontainer % container class for MDS+ interface objects
taskcontainer % container class for generic init and term task objects
exportedtps % list of tunable parameters variable to be exported
stdinits % list of standard inits scripts
modeltoactualize % name of the algorithm to actualize ('all' means all coonfigured)
algos % list of algorithms objects
end
%%
%% STATIC METHODS
%%
methods(Static)
function help
help(mfilename)
end
function node = defaultnode(nodenr)
node01.active = 0;
node01.ncpu = 1;
node01.type = 'std1cpu2015a';
node01.timing.t_start = -4.5;
node01.timing.t_stop = 3;
node01.timing.dt = 1e-4;
node01.thperiod = 1.0000e-03;
node01.buildcfg.conffile{1} = 'standard';
node01.buildcfg.initscdbeforecomp = 0;
node01.haswavegen = 1;
node01.hasethercat = 0;
node01.hasadc = 1;
node02.active = 0;
node02.ncpu = 4;
node02.type = 'std1cpu2015a';
node02.timing.t_start = -4.5;
node02.timing.t_stop = 3;
node02.timing.dt = 1e-4;
node02.thperiod = [1.0000e-03 1.0000e-03 1.0000e-03 1.0000e-03];
node02.buildcfg.conffile{1} = 'standard';
node02.buildcfg.conffile{2} = 'standard';
node02.buildcfg.conffile{3} = 'standard';
node02.buildcfg.conffile{4} = 'standard';
node02.buildcfg.conffile=node02.buildcfg.conffile';
node02.buildcfg.initscdbeforecomp = 0;
node02.haswavegen = 1;
node02.hasadc = 1;
node02.hasethercat = 1;
node03.active = 0;
node03.ncpu = 4;
node03.type = '4cpus2015a';
node03.timing.t_start = -2.0;
node03.timing.t_stop = 2.75;
node03.timing.dt = 1e-3;
node03.thperiod = [1.0000e-03 1.0000e-03 1.0000e-03 1.0000e-03];
node03.buildcfg.conffile{1} = 'standard';
node03.buildcfg.conffile{2} = 'standard';
node03.buildcfg.conffile{3} = 'standard';
node03.buildcfg.conffile{4} = 'standard';
node03.buildcfg.conffile=node03.buildcfg.conffile';
node03.buildcfg.initscdbeforecomp = [0 0 0 0];
node03.haswavegen = 1;
node03.hasadc = 0;
node03.hasethercat = 0;
node04.active = 0;
node04.ncpu = 4;
node04.type = 'std1cpu2015a';
node04.timing.t_start = -4.5;
node04.timing.t_stop = 3;
node04.timing.dt = 1e-4;
node04.thperiod = 1.0000e-04;
node04.buildcfg.conffile{1} = 'standard';
node04.buildcfg.initscdbeforecomp = 0;
node04.haswavegen = 1;
node04.hasadc = 0;
node04.hasethercat = 0;
node05.active = 0;
node05.ncpu = 1;
node05.type = 'std1cpu2015a';
node05.timing.t_start = -4.5;
node05.timing.t_stop = 3;
node05.timing.dt = 1e-4;
node05.thperiod = 1.0000e-04;
node05.buildcfg.conffile{1} = 'standard';
node05.buildcfg.initscdbeforecomp = 0;
node05.haswavegen = 1;
node05.hasadc = 0;
node05.hasethercat = 0;
node06.active = 0;
node06.ncpu = 4;
node06.type = '4cpus2015a';
node06.timing.t_start = 0.0;
node06.timing.t_stop = 2.75;
node06.timing.dt = 1e-3;
node06.thperiod = [1.0000e-03 1.0000e-03 1.0000e-03 1.0000e-03];
node06.buildcfg.conffile{1} = 'standard';
node06.buildcfg.conffile{2} = 'standard';
node06.buildcfg.conffile{3} = 'standard';
node06.buildcfg.conffile{4} = 'standard';
node06.buildcfg.conffile=node06.buildcfg.conffile';
node06.buildcfg.initscdbeforecomp = [0 0 0 0];
node06.haswavegen = 1;
node06.hasadc = 0;
node06.hasethercat = 0;
node07.active = 0;
node07.ncpu = 4;
node07.type = '4cpus2015a';
node07.timing.t_start = -0.5;
node07.timing.t_stop = 2.5;
node07.timing.dt = 1e-3;
node07.thperiod = [1.0000e-03 1.0000e-03 1.0000e-03 1.0000e-03];
node07.buildcfg.conffile{1} = 'standard';
node07.buildcfg.conffile{2} = 'standard';
node07.buildcfg.conffile{3} = 'standard';
node07.buildcfg.conffile{4} = 'standard';
node07.buildcfg.conffile=node07.buildcfg.conffile';
node07.buildcfg.initscdbeforecomp = [0 0 0 0];
node07.haswavegen = 1;
node07.hasadc = 1;
node07.hasethercat = 0;
node08.active = 0;
node08.ncpu = 1;
node08.type = '4cpus2015a';
node08.timing.t_start = -0.5;
node08.timing.t_stop = 2.5;
node08.timing.dt = 1e-3;
node08.thperiod = [1.0000e-03 1.0000e-03 1.0000e-03 1.0000e-03];
node08.buildcfg.conffile{1} = 'standard';
node08.buildcfg.conffile{2} = 'standard';
node08.buildcfg.conffile{3} = 'standard';
node08.buildcfg.conffile{4} = 'standard';
node08.buildcfg.conffile=node08.buildcfg.conffile';
node08.buildcfg.initscdbeforecomp = [0 0 0 0];
node08.haswavegen = 1;
node08.hasadc = 1;
node08.hasethercat = 0;
node = eval(sprintf('node%02d',nodenr));
% [general part]
node.hasrfm = 1; % all nodes have rfm
node.wrapper = cell(node.ncpu,1);
node.wrapdatadicts=cell(node.ncpu,1);
node.varalgo = ones(node.ncpu,1);
node.cpuactive = zeros(node.ncpu,1);
node.datadict=sprintf('SCD_rtc_%02d.sldd',nodenr);
for iwrap=1:node.ncpu
node.wrapper{iwrap} = sprintf('SCDwrap_template%02d%02d.slx',nodenr,iwrap);
node.wrapdatadicts{iwrap} = sprintf('SCDwrap_template%02d%02d.sldd',nodenr,iwrap);
end
end
function build_nodes(compileslx_list)
for mynodeslx = compileslx_list
fprintf(' *** Buiding Node %s ***\n',mynodeslx{1});
rtwbuild(mynodeslx{1});
end
end
function myslx = getslxname(inode,icpu)
if nargin==0
myslx = 'tcv';
elseif nargin==1
assert(isnumeric(inode))
myslx = sprintf('SCD_rtc_%02d',inode);
elseif nargin==2
myslx = sprintf('SCD_rtccode_%02d_%02d',inode,icpu);
else
error('invalid number of arguments');
end
end
function close_all(saveflag)
if nargin==0
saveflag = 1;
end
assert(saveflag == 1 || saveflag == 0,'saveflag must be 1 or 0')
if saveflag==1
closemsg = 'Saving and Closing %s\n';
else
closemsg = 'Dicarding changes and closing %s\n';
end
while ~isempty(bdroot)
fprintf(closemsg,bdroot);
close_system(bdroot,saveflag)
end
%TODO: add datadict closure
%Simulink.data.dictionary.closeAll
end
end
%%
%% PUBLIC METHODS
%%
methods
%% Constructor
function obj=SCDclass_expcode()
% All templates constructor
obj.name = 'template';
obj.maincode = 1;
obj.status = 'debug';
obj.loadverbose = 1;
obj.activenodes=[1 2 3 6 7 8];
obj.activecpus=[ {1}; ...
{1:4}; ...
{1:4}; ...
{1:4}; ...
{1:4}; ...
{1}];
obj.algonamelist={};
obj.algoddlist={};
obj.wrapperlist={};
obj.exportedtps = [];
obj.algos={};
obj.mdscontainer = SCDclass_mdsobjcontainer;
obj.taskcontainer = SCDclass_taskcontainer;
for inode = 1:8
tmp(inode) = SCDclass_expcode.defaultnode(inode);
end
obj.nodes = tmp; clear tmp;
end
%% Main expcode handling methods
function open(~,varargin)
openslx = SCDclass_expcode.getslxname(varargin{:});
fprintf('Opening %s.slx\n',openslx)
open(openslx);
end
function setup(obj)
% This function sets up the TCV Simulink model
% to simulate this experimental code.
% NOTE THAT it doesn't actualize tunable parameters
% and wavegens, call actualizedata for that
fprintf('Setting up expcode %d, ''%s'', configuring wrappers ...\n',obj.maincode,obj.name);
obj=obj.setupwrappers;
obj.setupvaralgo;
fprintf('Setting up expcode %d, ''%s'', configuring data dictionaries ...\n',obj.maincode,obj.name);
obj.setupwrapdd;
obj.setupalgodd;
fprintf('Setting up expcode %d, ''%s'', configuring default tunable parameters ...\n',obj.maincode,obj.name);
obj.updatedefaulttp;
fprintf('Setting up expcode %d, ''%s'', configuring global data ...\n',obj.maincode,obj.name);
obj.setupmain;
fprintf('Setting up expcode %d, ''%s'', configuring main workspace variables ...\n',obj.maincode,obj.name);
obj.buildworkspacesimstruct;
obj.buildworkspacetpstruct;
% Set cache and codegen folders
obj.setcachefolder;
obj.setcodegenfolder;
end
function actualize(obj, shot, varargin)
p=inputParser;
% if a model name is given, operations will be performed
% only on it, otherwise they will be performed on all
% configured models
addParameter(p,'model','',@(x) ischar(x));
parse(p,varargin{:});
if(isempty(p.Results.model))
obj.modeltoactualize='all';
else
obj.modeltoactualize=p.Results.model;
end
obj.actualizedata(shot);
fprintf('Actualizing expcode %d, ''%s'', performing tasks ...\n',obj.maincode,obj.name);
obj.taskcontainer.modeltoexecute=obj.modeltoactualize;
obj.taskcontainer.exectasksoninit(shot);
end
function callinits(obj)
if(~isempty(obj.algoobjlist))
for ii=1:numel(obj.algoobjlist)
if nargin==1
obj.algoobjlist{ii}.callinits();
elseif nargin==2
error('this use is deprecated, add tasks instead')
else
error('invalid number of arguments for callinits');
end
end
end
end
function updatemdsmodel(obj, algo)
obj.updatemds(algo, -1);
end
function compile(~,varargin)
myslx = SCDclass_expcode.getslxname(varargin{:});
fprintf('Compiling %s.slx\n',myslx)
try
eval(sprintf('%s([],[],[],''compile'')',myslx));
eval(sprintf('%s([],[],[],''term'')',myslx));
catch ME
rethrow(ME)
end
end
function sim(~,varargin)
SCDconf_setSIMconf
myslx = SCDclass_expcode.getslxname(varargin{:});
fprintf('Simulating %s.slx\n',myslx)
sim(myslx)
end
function build(obj,varargin)
if numel(varargin)==0
fprintf('\n=== Building all threads for %s ===\n',obj.name);
% make list of nodes to build
compileslx_list = cell(0);
for inode=1:8
nodeinfo=obj.nodes(inode);
for icpu = 1:nodeinfo.ncpu
if nodeinfo.cpuactive(icpu)
compileslx_list = [compileslx_list,...
SCDclass_expcode.getslxname(inode,icpu)]; %#ok<AGROW>
end
end
end
if isempty(compileslx_list)
fprintf('No active nodes found, no .slx to compile. Done\n');
return
end
else
% user passed nodes,threads to compile
myslx = SCDclass_expcode.getslxname(varargin{:});
fprintf('building %s.slx\n',myslx)
compileslx_list{1} = myslx;
end
% set CodeGen folder for this expcode (allows fast rebuilding)
CodeGenFolder = obj.setcodegenfolder;
% check env variable
assert(~isempty(getenv('RTCCODE_LIBPATH')),'RTCCODE_LIBPATH environment variable needs to be defined to compile');
% set configuration settings for compilation
SCDconf_setCODEconf('configurationSettingsCODEicc')
% Build
try
SCDclass_expcode.build_nodes(compileslx_list);
catch ME
% if fails on first attempt, clear build folder and retry
fprintf(' **** FIRST ATTEMPT BUILDING %s FAILED **** \n',obj.name)
fprintf(' Error message:\n %s\n',getReport(ME));
fprintf(' Try again clearning build folder\n')
system(sprintf('rm -rf %s/*',CodeGenFolder));
SCDclass_expcode.build_nodes(compileslx_list);
end
end
%% Printing methods
function printinfo(obj)
fprintf('*****************************************************\n');
fprintf('* SCD expcode: ''%s'', main code: %d\n',obj.name,obj.maincode);
fprintf('*****************************************************\n');
fprintf('* Configured wrappers:\n')
if(numel(obj.wrapperlist)>0)
for ii=1:numel(obj.wrapperlist)
fprintf(' Node: %d, CPU: %d, varalgo: %d, wrapper: ''%s'', datadict: ''%s''\n', ...
obj.wrapperlist{ii}{1}, ...
obj.wrapperlist{ii}{2}, ...
obj.wrapperlist{ii}{3}, ...
obj.wrapperlist{ii}{4}, ...
obj.wrapperlist{ii}{5} ...
);
end
end
fprintf('* Configured algorithms:\n');
if(numel(obj.algonamelist)>0)
for ii=1:numel(obj.algonamelist), fprintf(' ''%s''\n', char(obj.algonamelist{ii})); end
end
fprintf('* Configured algorithm data dictionaries:\n')
if(numel(obj.algoddlist)>0)
for ii=1:numel(obj.algoddlist), fprintf(' ''%s''\n', char(obj.algoddlist{ii})); end
end
fprintf('* Configured exported tunparams structures:\n')
if(numel(obj.exportedtps)>0)
for ii=1:numel(obj.exportedtps), fprintf(' ''%s''\n', char(obj.exportedtps{ii})); end
end
fprintf('* Configured MDS tunparams objects: %d (use printparameters method for details)\n', obj.mdscontainer.numparams);
fprintf('* Configured MDS wavegens objects: %d (use printwavegens method for details)\n', obj.mdscontainer.numwavegens);
fprintf('* Configured general purpose tasks: %d (use printtasks method for details)\n', obj.taskcontainer.numtasks);
fprintf('* Configured init scripts: %d (use printinits method for details)\n', numel(obj.stdinits));
end
function printtasks(obj)
obj.taskcontainer.printtasks;
end
function printinits(obj)
if(~isempty(obj.stdinits))
for ii=1:numel(obj.stdinits)
fprintf('%s -> %s\n',char(obj.stdinits{ii}{1}),char(obj.stdinits{ii}{2}));
end
end
end
function printMARTe2taskconfig(obj, shot, varargin)
p=inputParser;
% if a model name is given, operations will be performed
% only on it, otherwise they will be performed on all
% configured models
addParameter(p,'model','',@(x) ischar(x));
parse(p,varargin{:});
if(isempty(p.Results.model))
obj.taskcontainer.modeltogenerate='all';
else
obj.taskcontainer.modeltogenerate=p.Results.model;
end
obj.taskcontainer.printMARTe2taskconfig(shot);
end
function printMARTe2parconfig(obj, shot, varargin)
p=inputParser;
% if a model name is given, operations will be performed
% only on it, otherwise they will be performed on all
% configured models
addParameter(p,'model','',@(x) ischar(x));
parse(p,varargin{:});
if(isempty(p.Results.model))
obj.mdscontainer.modeltogenerate='all';
else
obj.mdscontainer.modeltogenerate=p.Results.model;
end
obj.mdscontainer.printMARTe2parconfig(shot);
end
function printMARTe2wgbusconfig(obj, shot, busname, frequency, varargin)
% printMARTe2wgbusconfig(obj, shot, busname, frequency, varargin)
%
% prints cfg file for loading busname Simulink.Bus
% as a wavegen (or a set of them) in MARTe2
% shot can be -1 or a fixed shot (usually -1), but currently
% the Shot= entry is populated by a fixed macro
% frequency is the frequency of signal generation in MARTe2
% the optional parameter 'ddname' can be given to specify
% the data dictionary where the bus definition is, if omitted
% tcv.sldd is used
p=inputParser;
addParameter(p,'ddname','tcv.sldd',@(x) ischar(x));
parse(p,varargin{:});
ddname = p.Results.ddname;
dim=obj.mdscontainer.printMARTe2wgbusconfig(shot, ddname, busname, frequency);
end
function printparameters(obj)
obj.mdscontainer.printparameters;
end
function printwavegens(obj)
obj.mdscontainer.printwavegens;
end
%% Configuration methods
function obj = addwrapper(obj, inode, icpu, varalgo, wrappername, varargin)
p=inputParser;
checknodes = @(x) ismember(x,obj.activenodes );
checkcpu = @(x) ismember(x,obj.activecpus{inode});
addRequired(p, 'node', checknodes);
addRequired(p, 'cpu', checkcpu);
addRequired(p, 'varalgo');
addRequired(p, 'modelname', @(x) ischar(x));
addOptional(p, 'datadictionary', '', @(x) ischar(x));
parse(p, inode, icpu, varalgo, wrappername, varargin{:});
% In data dcitionary is not specified it is assumed having
% the same name than the model
if(isempty(p.Results.datadictionary))
datadictionary=[p.Results.modelname '.sldd'];
else
datadictionary=[p.Results.datadictionary '.sldd'];
end
% First checking for duplicates
if(numel(obj.wrapperlist)>0)
wrappernamelist={};
wrapperddnamelist={};
for ii=1:numel(obj.wrapperlist)
wrappernamelist{end+1}=obj.wrapperlist{ii}{4};
wrapperddnamelist{end+1}=obj.wrapperlist{ii}{5};
end
if(ismember(p.Results.modelname,wrappernamelist) || ismember(p.Results.datadictionary,wrapperddnamelist))
warning('SCDclass_expcode:addwrapper','wrapper ''%s'' already present, ignoring.',wrappername);
return
end
end
% update node info
nodestr=sprintf('node%02d',inode);
obj.nodes(inode).varalgo(icpu) = varalgo;
obj.nodes(inode).wrapper{icpu} = wrappername;
obj.nodes(inode).cpuactive(icpu) = true;
obj.nodes(inode).active = true;
% save in wrapper list
tempwrapper=cell(10,1);
tempwrapper{1}=p.Results.node;
tempwrapper{2}=p.Results.cpu;
tempwrapper{3}=p.Results.varalgo;
tempwrapper{4}=p.Results.modelname;
tempwrapper{5}=datadictionary;
obj.wrapperlist{end+1}=tempwrapper;
end
function obj = addalgorithm(obj, in_node, in_cpu, in_algo)
% TODO: import the entrire object into a container class ??
p=inputParser;
checknodes = @(x) ismember(x,obj.activenodes );
checkcpu = @(x) ismember(x,obj.activecpus{in_node});
addRequired(p, 'node', checknodes);
addRequired(p, 'cpu', checkcpu);
addRequired(p, 'algo', @(x) isobject(x));
parse(p, in_node, in_cpu, in_algo);
node = p.Results.node;
cpu = p.Results.cpu;
algo = p.Results.algo;
% Checking and importing algorithm name
if(~ismember(algo.getname,obj.algonamelist))
obj.algonamelist{end+1}=algo.getname;
obj.algos{end+1}=algo;
else
warning('SCDclass_expcode:addalgorithm','algorithm ''%s'' already present in the expcode, skipping!',algo.getname);
return;
end
% Importing algorithm MDS objects into the main mdscontainer,
% filling base structure name
algomdscontainer=algo.getmdscontainer;
basewgstruct=sprintf('SCDsimdata.SCDnode%02d%02d_simdata.wavegen', node, cpu);
algomdscontainer=algomdscontainer.setwavegenbasestruct(basewgstruct);
obj.mdscontainer=obj.mdscontainer.importmdsobjects(algomdscontainer);
% Importing exported tps
algoexptps=algo.getexportedtps;
if(numel(algoexptps)>0)
for(ii=1:numel(algoexptps))
if(~ismember(algoexptps{ii},obj.exportedtps))
obj.exportedtps{end+1}=algoexptps{ii};
else
warning('SCDclass_expcode:addalgorithm','exported tunparams sctruct ''%s'' already present, ignoring',algoexptps{ii})
end
end
end
% Importing algorithms data dictionary, only those with proper
% name
algodd=algo.getdatadictionary;
if(strcmp(algodd(1:7),'SCDalgo'))
if(~ismember(algodd,obj.algoddlist))
obj.algoddlist{end+1}=algodd;
else
warning('SCDclass_expcode:addalgorithm','algorithm data dictionary ''%s'' already present, ignoring', algodd);
end
else
% warning here ?
end
% Importing tasks
algotaskcontainer=algo.gettaskcontainer;
obj.taskcontainer=obj.taskcontainer.importtaskobjects(algotaskcontainer);
% Importing inits
algoinits=algo.getinits;
if(numel(algoinits)>0)
toadd = ones(numel(algoinits),1);
for ii=1:numel(algoinits)
if(~isempty(obj.stdinits))
for jj=1:numel(obj.stdinits)
for kk=1:numel(obj.stdinits{jj}{2})
if(strcmp(char(obj.stdinits{jj}{2}{kk}),algoinits{ii}{2}))
warning('SCDclass_expcode:addalgorithm','An init driving the structure %s has already been added, ignoring this init.\d',algoinits{ii}{2})
toadd(ii)=0;
end
end
end
end
if toadd(ii)
temp=cell(10,1);
temp{1}=algoinits{ii}{1};
temp{2}=algoinits{ii}{2};
obj.stdinits{end+1}=temp;
end
end
if any(toadd) % if any inits from this algoobj were taken
obj.algoobjlist{end+1}=algo; %% Add the full algorithm object here, to see if it is fine
end
end
end
function out = getexportedtps(obj)
out = obj.exportedtps;
end
function obj = importexpcode(obj, expcode)
% This function imports settings of an existing expcode into another
warning('Not yet supported!');
return;
% tunparamstruct import
exportedtpstoadd = expcode.getexportedtps;
for ii=1:numel(exportedtpstoadd)
if ~sum(ismember(exportedtpstoadd{ii},obj.exportedtps))
obj.addtunparamstruct(exportedtpstoadd{ii});
end
end
% parameters import
obj.mdscontainer=obj.mdscontainer.importmdsobjects(expcode.mdscontainer);
end
%% Default values setup methods
function updatedefaulttp(obj)
% updatedefaulttp()
%
% updates _tmpl tunparams structures
% for every defined updating function
% To define an update function see SCDclass_algo.addtunparamstruct
for ii=1:numel(obj.algonamelist)
% if strcmp(algo, obj.algonamelist{ii})
obj.algos{ii}.updatetemplatetp();
% end
end
end
end
%% PRIVATE METHODS
methods (Access = private)
%% Matlab environmental setup methods
function CacheFolder = setcachefolder(obj)
% Set Cache Folder for experimental code (avoid conflicts with other tmp files)
CacheFolder = fullfile(fileparts(mfilename('fullpath')),'..','..',...
'gencodes',sprintf('CacheFolder-%d',obj.maincode));
fprintf('Setting Simulink Cache folder to %s\n',CacheFolder)
Simulink.fileGenControl('set',...
'CacheFolder',CacheFolder,...
'createdir',true);
end
function CodeGenFolder = setcodegenfolder(obj)
CodeGenFolder = fullfile(fileparts(mfilename('fullpath')),'..','..',...
'gencodes',sprintf('CodeGenFolder-%d',obj.maincode));
fprintf('Setting code generation folder to %s\n',CodeGenFolder)
Simulink.fileGenControl('set',...
'CodeGenFolder',CodeGenFolder,...
'createdir',true);
end
function obj=printlog(obj,str,varargin)
% printlog, allows sprintf()-like expressions
if obj.loadverbose==1
fprintf('Expcode %d, ', obj.maincode);
fprintf(str,varargin{:}); fprintf('\n');
end
end
function obj = buildworkspacetpstruct(obj)
% this funtion builds a workspace structures containing
% replicas of all tunable parameters structures in the data
% dictionaries, this structure is the one actually used
% for loading simulation wavegen data
% It is better not to use directly data dictionaries structures
% to avoid flooding dds with big sim data sets (and
% conseguently the rtccode GIT repo itself
dd=SCDconf_getdatadict('tcv.sldd');
for ii=1:numel(obj.exportedtps)
simstructnamedd=sprintf('%s_tmpl',char(obj.exportedtps(ii)));
simstructnamews=char(obj.exportedtps(ii));
try
simstruct=dd.getEntry(simstructnamedd).getValue;
catch
error('expcode:buildworkspacetpstruct',['tunable params structure ' simstructnamedd ' not found']);
end
assignstr=sprintf('%s=temp;',simstructnamews);
assignin('base','temp',simstruct);
evalin('base',assignstr);
end
evalin('base','clear temp;');
end
function obj = setupwrapdd(obj)
% Sets up the data dictionaries of the wrappers to be loaded
% on the nodes inside the main tcv.sldd
% For every node, given the current status finds its dictionary
% and the requred data sources, find actions to do and setup
% wrappers data sources accordingly
% It is assumed that there is only 1 wrapper and 1 wrapper data
% dictionary active at a given time for every CPU model
% Looping through every active node
for idx_nodedds=1:numel(obj.activenodes)
inode = obj.activenodes(idx_nodedds);
% Getting data dictionary and required data sources
datadictname = obj.nodes(inode).datadict';
nodedd=Simulink.data.dictionary.open(datadictname);
nodeddsources=nodedd.DataSources;
reqsources=obj.nodes(inode).wrapdatadicts';
% Filtering out not pertinent data sources by name prefix
nodeddsourcesok={};
nodeddsourcesokitems=0;
for ii=1:numel(nodeddsources)
if startsWith(nodeddsources{ii},'SCDwrap')
temp={nodeddsources{ii}, 0};
nodeddsourcesok=[nodeddsourcesok; temp];
nodeddsourcesokitems=nodeddsourcesokitems+1;
end
end
reqsourcesok={};
reqsourcesokitems=0;
for ii=1:numel(reqsources)
if startsWith(reqsources{ii},'SCDwrap')
temp={reqsources{ii}, 1};
reqsourcesok=[reqsourcesok; temp];
reqsourcesokitems=reqsourcesokitems+1;
else
warning('Proposed wrapper data dictionary %s does not begin with SCDwrap, ignoring it.', reqsources{ii});
end
end
% Finding which data sources to eliminate and which to add
if (nodeddsourcesokitems>0 && reqsourcesokitems>0)
for ii=1:nodeddsourcesokitems
todel=1;
for jj=1:reqsourcesokitems
if(strcmp(char(nodeddsourcesok{ii,1}),char(reqsourcesok{jj,1})))
todel=0;
break
end
end
nodeddsourcesok{ii,2}=todel;
end
for ii=1:reqsourcesokitems
toadd=1;
for jj=1:nodeddsourcesokitems
if(strcmp(char(reqsourcesok{ii,1}),char(nodeddsourcesok{jj,1})))
toadd=0;
break
end
end
reqsourcesok{ii,2}=toadd;
end
end
% Removing data sources
if(nodeddsourcesokitems>0)
for ii=1:nodeddsourcesokitems
if(nodeddsourcesok{ii,2}==1)
obj.printlog('Removing wrapper data source %s from %s', char(nodeddsourcesok{ii,1}), datadictname);
removeDataSource(nodedd, char(nodeddsourcesok{ii,1}));
end
end
end
% Adding data sources
if(reqsourcesokitems>0)
for ii=1:reqsourcesokitems
if(reqsourcesok{ii,2}==1)
obj.printlog('Adding wrapper data source %s to %s', char(reqsourcesok{ii,1}), datadictname);
addDataSource(nodedd, char(reqsourcesok{ii,1}));
end
end
end
end
end
function obj = setupalgodd(obj)
% Getting data dictionary and required data sources
tcvdd=Simulink.data.dictionary.open('tcv.sldd');
tcvddsources=tcvdd.DataSources;
reqsources=obj.algoddlist;
% Filtering out not pertinent data sources by name prefix
tcvddsourcesok={};
tcvddsourcesokitems=0;
for ii=1:numel(tcvddsources)
if(strcmp(tcvddsources{ii}(1:7),'SCDalgo'))
temp={tcvddsources{ii}, 1};
tcvddsourcesok=[tcvddsourcesok; temp];
tcvddsourcesokitems=tcvddsourcesokitems+1;
end
end
reqsourcesok={};
reqsourcesokitems=0;
for ii=1:numel(reqsources)
if(strcmp(reqsources{ii}(1:7),'SCDalgo'))
temp={reqsources{ii}, 1};
reqsourcesok=[reqsourcesok; temp];
reqsourcesokitems=reqsourcesokitems+1;
else
warning('SCDexpcode:setupalgodd','Proposed algo data dictionary %s does not begin with SCDalgo, ignoring it.', reqsources{ii});
end
end
% Finding which data sources to eliminate and which to add
if(tcvddsourcesokitems>0 && reqsourcesokitems>0)
for ii=1:tcvddsourcesokitems
todel=1;
for jj=1:reqsourcesokitems
if(strcmp(char(tcvddsourcesok{ii,1}),char(reqsourcesok{jj,1})))
todel=0;
break
end
end
tcvddsourcesok{ii,2}=todel;
end
for ii=1:reqsourcesokitems
toadd=1;
for jj=1:tcvddsourcesokitems
if(strcmp(char(reqsourcesok{ii,1}),char(tcvddsourcesok{jj,1})))
toadd=0;
break
end
end
reqsourcesok{ii,2}=toadd;
end
end
% Removing data sources
if(tcvddsourcesokitems>0)
for ii=1:tcvddsourcesokitems
if(tcvddsourcesok{ii,2}==1)
obj.printlog('Removing algorithm data source %s', char(tcvddsourcesok{ii,1}));
removeDataSource(tcvdd, char(tcvddsourcesok{ii,1}));
end
end
end
% Adding data sources
if(reqsourcesokitems>0)
for ii=1:reqsourcesokitems
if(reqsourcesok{ii,2}==1)
obj.printlog('Adding algorithm data source %s', char(reqsourcesok{ii,1}));
addDataSource(tcvdd, char(reqsourcesok{ii,1}));
end
end
end
end
function buildworkspacesimstruct(obj)
% obj.mdscontainer.buildworkspacesimstructnode(obj,node)
% obj.mdscontainer.buildworkspacesimstruct; % old
dd=SCDconf_getdatadict('tcv.sldd');
for ii = 1:numel(obj.activenodes)
inode = obj.activenodes(ii);
buildworkspacesimstructnode(obj,inode,dd);
end
evalin('base', 'SCDrefdata = SCDsimdata;');
end
function obj = setupmain(obj)
% sets up global configs for the expcode
assigncmd=sprintf('scd.expcode=%d;',obj.maincode);
Simulink.data.evalinGlobal('tcv',assigncmd);
end
function obj = setupwrappers(obj)
for ii=1:numel(obj.wrapperlist)
inode = obj.wrapperlist{ii}{1};
switch inode
%%% THIS SHOULD BE REFACTORED
case {1,8}
if(obj.wrapperlist{ii}{2}==1)
obj.nodes(inode).varalgo=obj.wrapperlist{ii}{3};
obj.nodes(inode).wrapdatadicts{1}=obj.wrapperlist{ii}{5};
else
warning('SCDclass_expcode:setupwrappers','not supported node%02d cpu',inode);
end
case {2,3,4,6,7}
if(obj.wrapperlist{ii}{2}>=1 && obj.wrapperlist{ii}{2}<=4)
obj.nodes(inode).varalgo(obj.wrapperlist{ii}{2})=obj.wrapperlist{ii}{3};
obj.nodes(inode).wrapdatadicts{obj.wrapperlist{ii}{2}}=obj.wrapperlist{ii}{5};
else
warning('SCDclass_expcode:setupwrappers','not supported node%02d cpu',inode);
end
otherwise
warning('SCDclass_expcode:setupwrappers','not supported node');
end
end
end
function obj = setupvaralgo(obj)
% Sets up varalgo structure in main tcv data dictionary
% according to varalgo info of the nodes
% Getting data section of main tcv data dictionary
d=Simulink.data.dictionary.open('tcv.sldd');
dd=getSection(d, 'Design Data');
varalgodd=dd.getEntry('SCDvaralgo');
s=struct();
% Looping through every active node
for ii=1:numel(obj.activenodes)
inode = obj.activenodes(ii);
varalgo=obj.nodes(inode).varalgo';
for jj=1:numel(varalgo)
fieldname = sprintf('algo%02d%02d',inode,jj);
s.(fieldname)=varalgo(jj);
end
end
varalgodd.setValue(s);
end
function obj = buildworkspacesimstructnode(obj,inode,dd)
node = obj.nodes(inode);
if evalin('base','exist(''SCDsimdata'',''var'')');
SCDsimdata = evalin('base','SCDsimdata');
else
SCDsimdata = struct(); % assign here if empty
end
if node.haswavegen
for ithread = 1:node.ncpu
% get whatever is in data dictionary template in wrappers
simstructname = sprintf('SCDnode%02d%02d_simdata',inode,ithread);
wgbusname = sprintf('WG%02d%02dbus',inode,ithread);
fprintf(' setting up %s',simstructname);
if dd.exist(simstructname)
simstruct = dd.getEntry(simstructname).getValue;
mybus=dd.getEntry(wgbusname).getValue; % get from data dictionary
if ~isstruct(simstruct) || ~isfield(simstruct,'wavegen')
fprintf('.. loaded simstruct wavegen is not compatible');
regenerate = true;
elseif SCDconf_structbuscmp(simstruct.wavegen,mybus)
fprintf('... loaded WG from data dictionary\n');
regenerate=false;
else
fprintf('... loaded WG structure from dd does not match bus definition...');
regenerate=true;
end
else
regenerate=true;
fprintf('... could not find %s in data dictionary',simstructname);
end
if regenerate
simstruct.wavegen = SCDconf_createstructfrombus(dd,wgbusname); % structure to match
%ddsource = dd.find('Name',wgbusname).DataSource; % dd containing bus
%wrapdd=Simulink.data.dictionary.open(ddsource).getSection('Design Data');
%wrapdd.addEntry(simstructname,simstruct)
fprintf('... re-generated from bus %s\n',wgbusname')
end
SCDsimdata.(simstructname) = simstruct;
end
end
% Node-specific
simstructname = sprintf('SCDnode%02dsimdata',inode);
if node.hasadc
adcbusname = sprintf('ADC%02dbus',inode);
fprintf(' setting up %s.adc\n',simstructname);
SCDsimdata.(simstructname).adc = SCDconf_createstructfrombus(dd,adcbusname);
end
if node.hasethercat
assert(inode==2,'Ethercat not yet implemented for other node than 2');
ethercatbusname = 'ETHCAT1IN';
fprintf(' setting up %s.ethercat\n',simstructname);
SCDsimdata.(simstructname).ethercat = ...
SCDconf_createstructfrombus(dd,ethercatbusname);
end
% add also RFM
RFMbusname = 'RFMINbus';
SCDsimdata.rfm = SCDconf_createstructfrombus(dd,RFMbusname);
% assign result in base workspace
assignin('base','SCDsimdata',SCDsimdata);
end
%% Actualization methods
function actualizedata(obj, shot)
% This function actualizes configured
% tunable parameters and wavegens timeseries
% according to the given shot
currentexpcode=Simulink.data.evalinGlobal('tcv','scd.expcode');
if(currentexpcode~=obj.maincode)
error('SCDclass_expcode:wrongexpcodeloaded','Cannot perform data actualization, the loaded expcode is not matching, try to setup the expcode first');
end
fprintf('Actualizing expcode %d, ''%s'', configuring tunable parameters ...\n',obj.maincode,obj.name);
obj.actualizeparameters(shot)
fprintf('Actualizing expcode %d, ''%s'', configuring wavegens ...\n',obj.maincode,obj.name);
obj.actualizewavegens(shot);
end
function actualizeparameters(obj,shot)
obj.mdscontainer.modeltoactualize=obj.modeltoactualize;
obj.mdscontainer.actualizeparameters(shot);
end
function actualizewavegens(obj,shot)
obj.mdscontainer.modeltoactualize=obj.modeltoactualize;
obj.mdscontainer.actualizewavegens(shot);
end
%% MDS update methods
function updatemds(obj, algo, shot)
if shot~=-1
error('SCDclass_expcode:updatemds','update permitted only on the model shot');
end
% % first update algorithm tunparams default locally
% for ii=1:numel(obj.algonamelist)
% if strcmp(algo, obj.algonamelist{ii})
% obj.algos{ii}.updatetemplatetp();
% end
% end
% % then update mds
obj.mdscontainer.modeltogenerate=algo;
obj.mdscontainer.autopopulateMDSparams(shot);
obj.mdscontainer.autopopulateMDSwavegens(shot);
end
end
end