diff m-toolbox/classes/@LTPDAworkbench/cmds2pipeline.m @ 0:f0afece42f48

Import.
author Daniele Nicolodi <nicolodi@science.unitn.it>
date Wed, 23 Nov 2011 19:22:13 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m-toolbox/classes/@LTPDAworkbench/cmds2pipeline.m	Wed Nov 23 19:22:13 2011 +0100
@@ -0,0 +1,363 @@
+% CMDS2PIPELINE builds new pipelines in the given workbench from the
+% set of LTPDA commands.
+%
+% CALL: cmds2pipeline(wb, name, cmds)
+%       cmds2pipeline(wb, name, cmds, blockpositions)
+%
+% M Hewitson 12-11-10
+%
+% $Id: cmds2pipeline.m,v 1.2 2011/04/08 08:56:32 hewitson Exp $
+%
+function cmds2pipeline(wb, docname, cmds, varargin)
+  
+  if numel(varargin) > 0
+    blockPositions = varargin{1};
+  else
+    blockPositions = {};
+  end
+  
+  % create new diagram
+  awtinvoke(wb.mp, 'createNewBlockDiagram', docname);
+  % logical array for checking that we only place
+  % each block once
+  blockplaced = zeros(size(cmds));
+  
+  % Go through each command and place its block
+  cn = 1;
+  dX = 100;
+  dY = 150;
+  sX = 100;
+  X = sX; % starting X coord
+  Y = 50; % starting Y coord
+  % loop until all blocks are placed
+  blockNames = {};
+  while ~all(blockplaced) && cn <=numel(cmds)
+    if ~blockplaced(cn)
+      % parse this command
+      srcblock = LTPDAworkbench.parseCmd(cmds{cn});
+      %--------- build a block
+      % to do this we need an minfo object; we have the
+      % the method name but we need the class. Either this
+      % is a constructor or it must have an input object
+      ecmd = sprintf('%s.getInfo(''%s'');', srcblock.class, srcblock.method);
+      ii = eval(ecmd);
+      % override auto-generated positions if the user supplies them
+      if ~isempty(blockPositions)
+        pos = blockPositions{cn};
+        X = pos(1);
+        Y = pos(2);
+      end
+      name = wb.addBlock(srcblock.outname, ii, X,Y);
+      blockNames = [blockNames {name}];
+      blockplaced(cn) = 1;
+      % look for commands which take this output as an input
+      [blockplaced,blockNames] = placeBlock(wb, blockplaced, ...
+        blockPositions, srcblock.outname, cmds, X, dX, Y, cn, blockNames);
+      % reset X
+      X = sX+floor(utils.math.rand(10,20));
+      % increment in Y
+      Y = Y + dY;
+    end
+    % check next block
+    cn = cn + 1;
+  end
+  
+  % Build a connection list
+  connections = struct('src', {}, 'srcport', {}, 'dst',{}, 'dstport', {});
+  cc = 1;
+  for cn =1:numel(cmds)
+    conn = cmd2conn(cmds{cn});    
+    % deal with block-to-block connections
+    if numel(conn.srcports)==numel(conn.dstports)
+      for kk=1:numel(conn.srcblocks)
+        if numel(conn.srcblocks) == 1
+          % one-to-many
+          srcb = conn.srcblocks{1};
+        else
+          % one-to-one
+          srcb = conn.srcblocks{kk};
+        end
+        if numel(conn.dstblocks) == 1
+          % many-to-one
+          dstb = conn.dstblocks{1};
+        else
+          % one-to-one
+          dstb = conn.dstblocks{kk};
+        end
+        if ~isempty(srcb) && ~isempty(dstb)
+          % make connection
+          if ~isempty(dstb)
+            connections(cc) = struct('src', srcb, ...
+              'srcport', conn.srcports(kk), ...
+              'dst', dstb, ...
+              'dstport', conn.dstports(kk));
+            connections(end)
+            wb.connectBlocks(connections(cc).src, connections(cc).srcport+1, ...
+              connections(cc).dst, connections(cc).dstport+1);
+            cc = cc + 1;
+          end
+        end
+      end % End loop over src blocks
+    end
+  end % End first loop over commands
+  
+  % also deal with connections to the plist
+  for kk=1:numel(cmds)
+    cconn = cmd2conn(cmds{kk});
+    conn = connFromPlist(cconn, blockNames);
+    if ~isempty(conn)
+      for ll=1:numel(conn)
+        % we need to know what destination port to use
+        % - look for max in connections for this dst block
+        b = wb.getBlockByName(conn(ll).dst);
+        p = b.getNextFreeInput();
+        connections(cc) = struct('src', conn(ll).src, ...
+          'srcport', conn(ll).srcport, ...
+          'dst', conn(ll).dst, ...
+          'dstport', p);
+        wb.connectBlocks(conn(ll).src, conn(ll).srcport+1, conn(ll).dst, p+1)
+        cc = cc + 1;
+      end
+    end    
+  end
+  
+  % upload plists
+  for cn =1:numel(cmds)
+    block = LTPDAworkbench.parseCmd(cmds{cn});
+    dstblock = block.outname;
+    % get src block name(s) and ports from each plist
+    for pp=1:numel(block.plists)
+      pl = block.plists{pp};
+      mtchs = regexp(pl, '(\w*)_PORT(\d*)', 'tokens');
+      % for each match, we look for a corresponding connection
+      % so that we can determine the destination port
+      if ~isempty(mtchs)
+        for kk=1:numel(mtchs)
+          srcblock = mtchs{kk}{1};
+          srcport  = str2double(mtchs{kk}{2});
+          % look for srcblock/srcport/dstblock in connection list
+          % and get the dstport
+          dstport = -1;
+          for cc=1:numel(connections)
+            % if this matches...
+            if strcmp(connections(cc).src, srcblock) && ...
+                strcmp(connections(cc).dst, dstblock) && ...
+                connections(cc).srcport == srcport
+              % ... then we set the dstport
+              dstport = connections(cc).dstport;
+            end
+          end
+          % now we can fix up the plist
+          if dstport >= 0
+            pl = regexprep(pl, [srcblock '_PORT\d*'], ['''PORT_' num2str(dstport) '''']);
+          end
+        end
+      else
+        % Try also for any block name in the plist
+        for kk=1:numel(blockNames)
+          srcblock = blockNames{kk};
+          % look for this srcblock in the plist but we need a clever
+          % regular expression to check this is an argument of the plist and
+          % not part of a key, for example.
+          tks = regexp(pl, ['[\s\[,]+(' srcblock ')[\s,\]]+'], 'tokens');
+          dstport = -1;
+          for ll=1:numel(tks)
+            % To get the destination port, we need to find this
+            % connection in the connections list
+            for cc=1:numel(connections)
+              cnc = connections(cc);
+              if strcmp(cnc.src, srcblock) && ...
+                  strcmp(cnc.dst, dstblock) && ...
+                  cnc.srcport == 0
+                dstport = cnc.dstport;
+              end
+            end
+          end
+          if dstport >= 0
+            pl = regexprep(pl, srcblock, ['''PORT_' num2str(dstport) '''']);
+          end
+        end
+      end
+      % now we can upload the plist
+      wb.uploadPlist(dstblock, eval(pl));
+    end
+  end
+  
+  
+end
+
+%--------------------------------------------------------------------------
+% Create a connection structure from a plist.
+% 
+% This deals with those plists that have BLOCK_PORT# type entries.
+% 
+function conn = connFromPlist(iconn, blocks)
+  
+  conn = struct('src', {}, 'srcport', {}, 'dst',{}, 'dstport', {});
+  cc = 1;
+  
+  for jj=1:numel(iconn.plist)
+    pl = iconn.plist{jj};
+    dsts = regexp(pl, '\w*_PORT\d*','match');
+    if ~isempty(dsts)
+      for kk=1:numel(dsts)
+        % parse dst string
+        tks = regexp(dsts{kk}, '(\w*)_PORT(\d*)', 'tokens');
+        for ll=1:numel(tks)
+          % make a connection
+          src = tks{ll}{1};
+          srcp = tks{ll}{2};
+          conn(cc).src = src;
+          conn(cc).srcport  = str2double(srcp);
+          conn(cc).dst = iconn.dstblocks{1};
+          conn(cc).dstport  = -1; % next free port
+          cc = cc + 1;
+        end
+      end
+    else
+      % also look for any input variables which are block names but have
+      % no _PORT# suffix
+      for kk=1:numel(blocks)
+        srcblock = blocks{kk};
+        % look for this srcblock in the plist but we need a clever
+        % regular expression to check this is an argument of the plist and
+        % not part of a key, for example.
+        tks = regexp(pl, ['[\s\[,]+(' srcblock ')[\s,\]]+'], 'tokens');
+        for ll=1:numel(tks)
+          conn(cc).src = tks{ll}{1};
+          conn(cc).srcport  = 0;
+          conn(cc).dst = iconn.dstblocks{1};
+          conn(cc).dstport  = -1; % next free port
+          cc = cc + 1;
+        end
+      end
+    end
+  end
+end
+
+%--------------------------------------------------------------------------
+% Convert a connection to a command.
+% 
+function conn = cmd2conn(cmd)
+  
+  block = LTPDAworkbench.parse(cmd);
+  
+  % first get block name from end
+  [s,r] = strtok(block.comment, '|');
+  if ~isempty(r)
+    blockname = {strrep(strtrim(r(2:end)), ' ', '_')};
+  else
+    blockname = '';
+  end
+    
+  [outname,outports] = fixBlockdiagramName(block.outvars{1});
+  
+  if isempty(blockname)
+    blockname = block.outvars(1);
+  end
+  
+  innames = {};
+  srcports = [];
+  for kk=1:numel(block.invars)
+    [s,p] = fixBlockdiagramName(block.invars{kk});
+    if isempty(p)
+      p = 0;
+    end
+    innames = [innames s];
+    srcports  = [srcports p];
+  end
+  
+  % trim all strings and build output struct
+  conn.srcblocks = innames;
+  conn.srcports  = srcports;
+  conn.dstblocks = blockname;
+  conn.dstports  = [1:numel(innames)]-1;
+  conn.plist     = block.pls;
+  
+end
+
+%--------------------------------------------------------------------------
+% Do some parsing of block diagram names to make sensible variable names.
+% 
+function [name, ports] = fixBlockdiagramName(name)
+  
+  name = strtrim(name);
+  if name(1) == '[' && name(end) == ']'
+    name = name(2:end-1);
+  end
+  % match the last occurance of '_PORT' and check there is a
+  % number behind it  
+  pstrs = regexp(name, '_PORT(\d*)', 'tokens');
+  ports = [];
+  for kk=1:numel(pstrs)
+    ports(kk) = str2double(pstrs{kk}{1});
+  end
+  
+  name = regexprep(name, '_PORT\d*', '');
+end
+
+%--------------------------------------------------------------------------
+% Place a block on the canvas
+% 
+function [blockplaced,blockNames] = placeBlock(wb, blockplaced, blockPositions, ...
+                                               outname, cmds, X, dX, Y, cn, blockNames)
+  
+  % look for commands which take this output as an input
+  for kk=1:numel(cmds)
+    dstblock = LTPDAworkbench.parseCmd(cmds{kk});
+    if any(strcmp(outname, dstblock.innames)) %|| ~isempty(idx)
+      if ~blockplaced(kk)
+        blockplaced(kk) = 1;
+        %--------- build a block
+        % to do this we need an minfo object; we have the
+        % the method name but we need the class. Either this
+        % is a constructor or it must have an input object
+        ecmd = sprintf('%s.getInfo(''%s'');', dstblock.class, dstblock.method);
+        ii = eval(ecmd);
+        X = X + dX;
+        Y = Y + 30;
+        if ~isempty(blockPositions)
+          pos = blockPositions{kk};
+          X = pos(1);
+          Y = pos(2);
+        end
+        name = wb.addBlock(dstblock.outname, ii, X,Y);
+        blockNames = [blockNames {name}];
+        %         name = wb.addBlock(doutname, ii, X,Y+ (mod(cn+kk-1,2))*50);
+        % recursively call for this block
+        [blockplaced,blockNames] = placeBlock(wb, blockplaced, blockPositions, ...
+                                             dstblock.outname, cmds, X, dX, Y, cn, blockNames);
+      end
+    end
+  end
+  
+end
+
+%--------------------------------------------------------------------------
+% Replace other block names with PORT_#
+% 
+% #### OLD CODE #####
+% 
+function [pl, newconnections] = fixpl(pl,connections)
+  
+  % first we need to replace all BLOCK_PORT# with PORT_#
+  pl = regexprep(pl, '(\w*)_PORT(\d*)', '''PORT_$2''');
+  
+  cn = 1;
+  % go through all connections
+  for kk=1:numel(connections)
+    conn = connections(kk);
+    % check if the plist has a token matching the src
+    rstr = ['[' conn.src ']'];
+    nstr = sprintf('''PORT_%d''', conn.dstport-1);
+    idx = strfind(pl, rstr);
+    pl = strrep(pl, rstr, nstr);
+    if ~isempty(idx)
+      newconnections(cn) = struct('src', conn.src, 'dst', conn.dst, ...
+        'srcport', conn.srcport, 'dstport', conn.dstport-1);
+    end
+  end
+  
+end
+
+% END