From d91b71fde890aca308ba292de6aacb7187962dfa Mon Sep 17 00:00:00 2001
From: Cristian Galperti <cristian.galperti@epfl.ch>
Date: Wed, 9 Oct 2019 17:34:33 +0200
Subject: [PATCH] MARTe compatible bus checker implemented

through consolidate() TDI call
on MDS+ server side
---
 code/classes/SCDclass_expcode.m              | 17 ++++++
 code/classes/SCDclass_task.m                 | 50 +++++++++++++++-
 code/classes/SCDclass_taskcontainer.m        | 51 ++++++++++++++++-
 code/classes/SCDclass_taskmdscheckbusnames.m | 60 +++++++++++++++-----
 code/classes/SCDclass_taskmdsloadprevADC.m   |  6 ++
 5 files changed, 168 insertions(+), 16 deletions(-)

diff --git a/code/classes/SCDclass_expcode.m b/code/classes/SCDclass_expcode.m
index 10eac0c..6746b24 100644
--- a/code/classes/SCDclass_expcode.m
+++ b/code/classes/SCDclass_expcode.m
@@ -506,6 +506,22 @@ classdef SCDclass_expcode
           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
@@ -522,6 +538,7 @@ classdef SCDclass_expcode
             obj.mdscontainer.printMARTe2parconfig(shot);
         end
         
+        
         function printMARTe2wgbusconfig(obj, shot, ddname, busname, frequency)
             fprintf("+MDSWavegen_%s = {\n", busname);
             fprintf(" Class = MDSWavegen\n");
diff --git a/code/classes/SCDclass_task.m b/code/classes/SCDclass_task.m
index 145d698..b95f6c0 100644
--- a/code/classes/SCDclass_task.m
+++ b/code/classes/SCDclass_task.m
@@ -20,6 +20,7 @@ classdef SCDclass_task < matlab.mixin.Heterogeneous
         value               % value from MDS+
         getcommand          % full command for getting the value (callable by matlab eval)
         
+        marteclassname      % marte class name
     end
     
     properties 
@@ -65,6 +66,18 @@ classdef SCDclass_task < matlab.mixin.Heterogeneous
             name=obj.modelname;
         end
         
+        function [mdsserver] = getMDSserver(obj)
+          mdsserver = obj.mdsserver;
+        end
+        
+        function [mdstree] = getMDStree(obj)
+          mdstree = obj.mdstree;
+        end
+        
+        function str = genMARTe2MDSsourcestr(obj)
+          str = sprintf(' +Connection_%s_%s = {\n  Class=MDSObjConnection\n  Server=%s\n  Tree=%s',obj.mdsserver,obj.mdstree,obj.mdsserver,obj.mdstree);        
+        end
+        
     end
     
     % Not abstract methods common to all child classes
@@ -118,6 +131,39 @@ classdef SCDclass_task < matlab.mixin.Heterogeneous
         
     end
     
+    methods(Access=protected)
+    
+        function entrystring = genMARTe2entrycommon(obj, shot)
+            obj=obj.actualizetdiexpr(shot);
+            %entrystring = sprintf('+%-50s = { Class=%-30s Path=%-40s',obj.gettargetparammarte,obj.marteclassname,obj.tdiexprused);
+            entrystring = sprintf('+%-50s = { Class=%-30s Path=%-40s',obj.id,obj.marteclassname,obj.genMARTe2MDStdiexpression); 
+        end
+        
+        function str = genMARTe2MDStdiexpression(obj)
+            % Duplicate first backslash
+%             if(obj.tdiexprused(1)=='\' && not(obj.tdiexprused(2)=='\'))
+%                 martetdi=['\' obj.tdiexprused];
+%             else
+%                 martetdi=obj.tdiexprused;
+%             end
+            % Duplicate backslashes
+            martetdi=strrep(obj.tdiexprused, '\', '\\');
+            %substitute every " with '
+            martetdi=strrep(martetdi, '"', '''');
+            %put double string quota
+            martetdi=['"' martetdi '"'];
+            str=martetdi;
+        end
+        
+        function obj=actualizetdiexpr(obj, shot)
+            if(shot==-1)
+                obj.tdiexprused=obj.tdiexprmodel;
+            else
+                obj.tdiexprused=obj.tdiexprshot;
+            end            
+        end
+        
+    end    
     
     % Abstract method actually implemented by child classes
     methods (Abstract)
@@ -133,8 +179,8 @@ classdef SCDclass_task < matlab.mixin.Heterogeneous
         % and tree opened
         [obj, value] = getdata(obj, shot)
         
-        % Generate C++ code 
-        %gencode(obj)
+        % Generate MARTe2 configuration entry
+        entrystring = genMARTe2entry(obj, shot)
         
         % Prints the parameter info summary
         printinfo(obj)
diff --git a/code/classes/SCDclass_taskcontainer.m b/code/classes/SCDclass_taskcontainer.m
index fecf970..d01a012 100644
--- a/code/classes/SCDclass_taskcontainer.m
+++ b/code/classes/SCDclass_taskcontainer.m
@@ -9,6 +9,7 @@ classdef SCDclass_taskcontainer
         numtasks            % number of configured tasks
         tasks               % tasks list
         modeltoexecute      % model name whose tasks will be executed 'all' for all
+        modeltogenerate     % model name whose tasks will be generate 'all' for all, TODO: check overlap with the previous
     end
     
     methods
@@ -99,8 +100,56 @@ classdef SCDclass_taskcontainer
                        
         end
         
-               
+        function printMARTe2taskconfig(obj, shot)
+          switch obj.modeltogenerate
+            case 'all'
+              iorder = getParamsServerTreeOrder(obj);  % order entries following mdsserver, mdstree order
+              prevServer = ''; % init 
+              
+              % Header for MDS for loader
+              loaderStr = sprintf('\n\n+MDSTasks = {\n Class=MDSObjLoader\n Shot=%d\n',shot);
+              fprintf("%s",loaderStr);
+         
+              for ii=1:obj.numtasks
+                mytask = obj.tasks(iorder(ii));
+
+                currentServer = mytask.getMDSserver;
+
+                % generate header for MDSsource if necessary
+                if ~strcmp(currentServer,prevServer) %if a new server needs to be opened
+                  if ii~=1, fprintf(' }\n'), end % close bracket for previous one
+                  % print new source header
+                  fprintf("%s\n",mytask.genMARTe2MDSsourcestr); 
+                end
+                prevServer = currentServer;
                 
+                % generate data source entry
+                str = mytask.genMARTe2entry(shot);
+                fprintf("  %s\n",str);
+              end
+              fprintf(" }\n}\n\n");
+
+            otherwise
+              for ii=1:obj.numparams
+                if(strcmp(obj.modeltogenerate,obj.tasks(ii).getmodelname))
+                  str=obj.tasks(ii).genMARTe2entry(shot);
+                  fprintf("  %s\n",str);
+                end
+              end
+          end
+        end
+
+        function iorder = getParamsServerTreeOrder(obj)
+          % find server-tree order of parameters
+          mdsservertree = cell(numel(obj.tasks),2);
+          for ii=1:numel(obj.tasks)
+            mdsservertree{ii,1} = obj.tasks(ii).getMDSserver;
+            mdsservertree{ii,2} = obj.tasks(ii).getMDStree;
+          end
+          [~,iorder] = sortrows(mdsservertree);
+        end
+
+                      
     end
 end
 
diff --git a/code/classes/SCDclass_taskmdscheckbusnames.m b/code/classes/SCDclass_taskmdscheckbusnames.m
index 757b859..5755ccb 100644
--- a/code/classes/SCDclass_taskmdscheckbusnames.m
+++ b/code/classes/SCDclass_taskmdscheckbusnames.m
@@ -3,13 +3,17 @@ classdef SCDclass_taskmdscheckbusnames < SCDclass_task
     % of a Simulink bus against the list names given by the tdi expression
     % some rules apply:
     % 1) : in MDS+ fields are subsituted by _
-    % 2) check is performed up to the minimum number of elemes ether if the
+    % 2) check is performed up to the minimum number of elemes either if the
     % MDS+ node or in the simulink one.
     % if MDS+ begins with a number, a leading 's' is added to its name
     % if MDS+ name is empty the check is skipped (Q: is it safe ?, at least not on -1 shot!)
+    % for being MARTe compatible the list of channels names are retrieved
+    % from MDS+ with the TDI consolidate() function (which must be present
+    % server side) and all names are transferred as a single long string
 
     properties
         modelbus
+        nelems
     end
     
     methods
@@ -17,9 +21,13 @@ classdef SCDclass_taskmdscheckbusnames < SCDclass_task
         function obj=SCDclass_taskmdscheckbusnames(id, varargin)   
             obj@SCDclass_task(id, varargin);
             obj.cparser.addRequired('modelbus',@(x) ischar(x));
+            obj.cparser.addRequired('nelems',@(x) (isnumeric(x) && x>0));
+            
             obj=obj.parseconstructorcommon(id, varargin);
-            obj.modelbus=obj.cparser.Results.modelbus;            
+            obj.modelbus=obj.cparser.Results.modelbus;        
+            obj.nelems=obj.cparser.Results.nelems;
             obj.classname=mfilename;
+            obj.marteclassname='MDSParBusChecker';
         end
         
         function init(obj, shot)
@@ -34,19 +42,27 @@ classdef SCDclass_taskmdscheckbusnames < SCDclass_task
             
             d=Simulink.data.dictionary.open(sprintf('%s',obj.datadictionary));
             dd=getSection(d, 'Design Data');
-         
             busElems=dd.getEntry(obj.modelbus).getValue.Elements;
             
-            %assert(numel(busElems)==numel(value), 'SCDclass_mdscheckbus: Number of elements must match.');
-            
-            lastcheck=min(numel(busElems), numel(value));
+            %% MDS+ string cell array buildup from the consolidated full string 
+            mdsnamelength = numel(value) / obj.nelems;
+            cnt=1;
+            for ii=1:numel(obj.nelems)
+                mdsnames{ii}=value(cnt:cnt+mdsnamelength-1);
+                cnt=cnt+mdsnamelength;
+            end
             
+            %% Original version, not compatible with MARTe 
+            % (C++ MDS+ thin client used there desn't support the retrieval
+            % of array of strings)
             
-            for ii=1:lastcheck
-               if numel(char(value{ii}))==0 || numel(strfind(char(value{ii}),' '))==numel(char(value{ii}))
-                   continue
+             %assert(numel(busElems)==numel(value), 'SCDclass_mdscheckbus: Number of elements must match.');
+             lastcheck=min(numel(busElems), numel(mdsnames));
+             for ii=1:lastcheck
+                if numel(char(mdsnames{ii}))==0 || numel(strfind(char(mdsnames{ii}),' '))==numel(char(mdsnames{ii}))
+                    continue
                end
-               strsrc=upper(deblank(strrep(char(value{ii}),':','_')));
+               strsrc=upper(deblank(strrep(char(mdsnames{ii}),':','_')));
                if(isstrprop(strsrc(1),'digit'))
                    strsrc=['S' strsrc];
                end
@@ -54,7 +70,9 @@ classdef SCDclass_taskmdscheckbusnames < SCDclass_task
                strdst=upper(deblank(busElems(ii).Name));
                
                assert(strcmp(strsrc,strdst), 'SCDclass_mdscheckbus: names mismatching, MDS+ name: ''%s'', Bus name: ''%s''', strsrc, strdst);
-            end            
+            end
+            
+          
         end
         
         %function term(obj, shot)
@@ -62,8 +80,7 @@ classdef SCDclass_taskmdscheckbusnames < SCDclass_task
         %end
         
         function [obj, value] = getdata(obj,shot)
-            obj=obj.actualizegetcmd('mdsvalue(''%s'')', shot);
-                        
+            obj=obj.actualizegetcmd('mdsvalue(''consolidate(%s)'')', shot);                      
             value=eval(obj.getcommand);
         end
         
@@ -72,6 +89,23 @@ classdef SCDclass_taskmdscheckbusnames < SCDclass_task
             fprintf('  Checked model bus: %s\n',obj.modelbus);
         end
         
+        function entrystring = genMARTe2entry(obj, shot)
+            mdsconnect(obj.mdsserver);
+            mdsopen(obj.mdstree, shot);
+            [obj,value]=obj.getdata(shot);
+            entrystring=obj.genMARTe2entrycommon(shot);
+            entrystring=[entrystring 'NElems = ' num2str(obj.nelems) ' '];
+            entrystring=[entrystring 'Against = "' value];
+            entrystring=[entrystring '" }'];
+        end
+
+        
+    end
+    
+    methods(Access=private)
+        
+
+        
     end
 end
 
diff --git a/code/classes/SCDclass_taskmdsloadprevADC.m b/code/classes/SCDclass_taskmdsloadprevADC.m
index 817d0e7..8720ad9 100644
--- a/code/classes/SCDclass_taskmdsloadprevADC.m
+++ b/code/classes/SCDclass_taskmdsloadprevADC.m
@@ -50,6 +50,12 @@ classdef SCDclass_taskmdsloadprevADC < SCDclass_task
             fprintf('  Init model bus: %s, node: %d, ws base struct: %s\n',obj.modelbus, obj.node, obj.workspacedatabasestructure);
         end
         
+            
+        function entrystring = genMARTe2entry(obj, shot)
+           % TODO: this is a workaround which works by chance, need a more accurate fix 
+           entrystring = ''; 
+        end
+        
     end
     
     methods(Access = private)
-- 
GitLab