Mercurial > hg > ltpda
view m-toolbox/classes/@LTPDAworkbench/cmds2pipeline.m @ 44:409a22968d5e default
Add unit tests
author | Daniele Nicolodi <nicolodi@science.unitn.it> |
---|---|
date | Tue, 06 Dec 2011 18:42:11 +0100 |
parents | f0afece42f48 |
children |
line wrap: on
line source
% 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