comparison 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
comparison
equal deleted inserted replaced
-1:000000000000 0:f0afece42f48
1 % CMDS2PIPELINE builds new pipelines in the given workbench from the
2 % set of LTPDA commands.
3 %
4 % CALL: cmds2pipeline(wb, name, cmds)
5 % cmds2pipeline(wb, name, cmds, blockpositions)
6 %
7 % M Hewitson 12-11-10
8 %
9 % $Id: cmds2pipeline.m,v 1.2 2011/04/08 08:56:32 hewitson Exp $
10 %
11 function cmds2pipeline(wb, docname, cmds, varargin)
12
13 if numel(varargin) > 0
14 blockPositions = varargin{1};
15 else
16 blockPositions = {};
17 end
18
19 % create new diagram
20 awtinvoke(wb.mp, 'createNewBlockDiagram', docname);
21 % logical array for checking that we only place
22 % each block once
23 blockplaced = zeros(size(cmds));
24
25 % Go through each command and place its block
26 cn = 1;
27 dX = 100;
28 dY = 150;
29 sX = 100;
30 X = sX; % starting X coord
31 Y = 50; % starting Y coord
32 % loop until all blocks are placed
33 blockNames = {};
34 while ~all(blockplaced) && cn <=numel(cmds)
35 if ~blockplaced(cn)
36 % parse this command
37 srcblock = LTPDAworkbench.parseCmd(cmds{cn});
38 %--------- build a block
39 % to do this we need an minfo object; we have the
40 % the method name but we need the class. Either this
41 % is a constructor or it must have an input object
42 ecmd = sprintf('%s.getInfo(''%s'');', srcblock.class, srcblock.method);
43 ii = eval(ecmd);
44 % override auto-generated positions if the user supplies them
45 if ~isempty(blockPositions)
46 pos = blockPositions{cn};
47 X = pos(1);
48 Y = pos(2);
49 end
50 name = wb.addBlock(srcblock.outname, ii, X,Y);
51 blockNames = [blockNames {name}];
52 blockplaced(cn) = 1;
53 % look for commands which take this output as an input
54 [blockplaced,blockNames] = placeBlock(wb, blockplaced, ...
55 blockPositions, srcblock.outname, cmds, X, dX, Y, cn, blockNames);
56 % reset X
57 X = sX+floor(utils.math.rand(10,20));
58 % increment in Y
59 Y = Y + dY;
60 end
61 % check next block
62 cn = cn + 1;
63 end
64
65 % Build a connection list
66 connections = struct('src', {}, 'srcport', {}, 'dst',{}, 'dstport', {});
67 cc = 1;
68 for cn =1:numel(cmds)
69 conn = cmd2conn(cmds{cn});
70 % deal with block-to-block connections
71 if numel(conn.srcports)==numel(conn.dstports)
72 for kk=1:numel(conn.srcblocks)
73 if numel(conn.srcblocks) == 1
74 % one-to-many
75 srcb = conn.srcblocks{1};
76 else
77 % one-to-one
78 srcb = conn.srcblocks{kk};
79 end
80 if numel(conn.dstblocks) == 1
81 % many-to-one
82 dstb = conn.dstblocks{1};
83 else
84 % one-to-one
85 dstb = conn.dstblocks{kk};
86 end
87 if ~isempty(srcb) && ~isempty(dstb)
88 % make connection
89 if ~isempty(dstb)
90 connections(cc) = struct('src', srcb, ...
91 'srcport', conn.srcports(kk), ...
92 'dst', dstb, ...
93 'dstport', conn.dstports(kk));
94 connections(end)
95 wb.connectBlocks(connections(cc).src, connections(cc).srcport+1, ...
96 connections(cc).dst, connections(cc).dstport+1);
97 cc = cc + 1;
98 end
99 end
100 end % End loop over src blocks
101 end
102 end % End first loop over commands
103
104 % also deal with connections to the plist
105 for kk=1:numel(cmds)
106 cconn = cmd2conn(cmds{kk});
107 conn = connFromPlist(cconn, blockNames);
108 if ~isempty(conn)
109 for ll=1:numel(conn)
110 % we need to know what destination port to use
111 % - look for max in connections for this dst block
112 b = wb.getBlockByName(conn(ll).dst);
113 p = b.getNextFreeInput();
114 connections(cc) = struct('src', conn(ll).src, ...
115 'srcport', conn(ll).srcport, ...
116 'dst', conn(ll).dst, ...
117 'dstport', p);
118 wb.connectBlocks(conn(ll).src, conn(ll).srcport+1, conn(ll).dst, p+1)
119 cc = cc + 1;
120 end
121 end
122 end
123
124 % upload plists
125 for cn =1:numel(cmds)
126 block = LTPDAworkbench.parseCmd(cmds{cn});
127 dstblock = block.outname;
128 % get src block name(s) and ports from each plist
129 for pp=1:numel(block.plists)
130 pl = block.plists{pp};
131 mtchs = regexp(pl, '(\w*)_PORT(\d*)', 'tokens');
132 % for each match, we look for a corresponding connection
133 % so that we can determine the destination port
134 if ~isempty(mtchs)
135 for kk=1:numel(mtchs)
136 srcblock = mtchs{kk}{1};
137 srcport = str2double(mtchs{kk}{2});
138 % look for srcblock/srcport/dstblock in connection list
139 % and get the dstport
140 dstport = -1;
141 for cc=1:numel(connections)
142 % if this matches...
143 if strcmp(connections(cc).src, srcblock) && ...
144 strcmp(connections(cc).dst, dstblock) && ...
145 connections(cc).srcport == srcport
146 % ... then we set the dstport
147 dstport = connections(cc).dstport;
148 end
149 end
150 % now we can fix up the plist
151 if dstport >= 0
152 pl = regexprep(pl, [srcblock '_PORT\d*'], ['''PORT_' num2str(dstport) '''']);
153 end
154 end
155 else
156 % Try also for any block name in the plist
157 for kk=1:numel(blockNames)
158 srcblock = blockNames{kk};
159 % look for this srcblock in the plist but we need a clever
160 % regular expression to check this is an argument of the plist and
161 % not part of a key, for example.
162 tks = regexp(pl, ['[\s\[,]+(' srcblock ')[\s,\]]+'], 'tokens');
163 dstport = -1;
164 for ll=1:numel(tks)
165 % To get the destination port, we need to find this
166 % connection in the connections list
167 for cc=1:numel(connections)
168 cnc = connections(cc);
169 if strcmp(cnc.src, srcblock) && ...
170 strcmp(cnc.dst, dstblock) && ...
171 cnc.srcport == 0
172 dstport = cnc.dstport;
173 end
174 end
175 end
176 if dstport >= 0
177 pl = regexprep(pl, srcblock, ['''PORT_' num2str(dstport) '''']);
178 end
179 end
180 end
181 % now we can upload the plist
182 wb.uploadPlist(dstblock, eval(pl));
183 end
184 end
185
186
187 end
188
189 %--------------------------------------------------------------------------
190 % Create a connection structure from a plist.
191 %
192 % This deals with those plists that have BLOCK_PORT# type entries.
193 %
194 function conn = connFromPlist(iconn, blocks)
195
196 conn = struct('src', {}, 'srcport', {}, 'dst',{}, 'dstport', {});
197 cc = 1;
198
199 for jj=1:numel(iconn.plist)
200 pl = iconn.plist{jj};
201 dsts = regexp(pl, '\w*_PORT\d*','match');
202 if ~isempty(dsts)
203 for kk=1:numel(dsts)
204 % parse dst string
205 tks = regexp(dsts{kk}, '(\w*)_PORT(\d*)', 'tokens');
206 for ll=1:numel(tks)
207 % make a connection
208 src = tks{ll}{1};
209 srcp = tks{ll}{2};
210 conn(cc).src = src;
211 conn(cc).srcport = str2double(srcp);
212 conn(cc).dst = iconn.dstblocks{1};
213 conn(cc).dstport = -1; % next free port
214 cc = cc + 1;
215 end
216 end
217 else
218 % also look for any input variables which are block names but have
219 % no _PORT# suffix
220 for kk=1:numel(blocks)
221 srcblock = blocks{kk};
222 % look for this srcblock in the plist but we need a clever
223 % regular expression to check this is an argument of the plist and
224 % not part of a key, for example.
225 tks = regexp(pl, ['[\s\[,]+(' srcblock ')[\s,\]]+'], 'tokens');
226 for ll=1:numel(tks)
227 conn(cc).src = tks{ll}{1};
228 conn(cc).srcport = 0;
229 conn(cc).dst = iconn.dstblocks{1};
230 conn(cc).dstport = -1; % next free port
231 cc = cc + 1;
232 end
233 end
234 end
235 end
236 end
237
238 %--------------------------------------------------------------------------
239 % Convert a connection to a command.
240 %
241 function conn = cmd2conn(cmd)
242
243 block = LTPDAworkbench.parse(cmd);
244
245 % first get block name from end
246 [s,r] = strtok(block.comment, '|');
247 if ~isempty(r)
248 blockname = {strrep(strtrim(r(2:end)), ' ', '_')};
249 else
250 blockname = '';
251 end
252
253 [outname,outports] = fixBlockdiagramName(block.outvars{1});
254
255 if isempty(blockname)
256 blockname = block.outvars(1);
257 end
258
259 innames = {};
260 srcports = [];
261 for kk=1:numel(block.invars)
262 [s,p] = fixBlockdiagramName(block.invars{kk});
263 if isempty(p)
264 p = 0;
265 end
266 innames = [innames s];
267 srcports = [srcports p];
268 end
269
270 % trim all strings and build output struct
271 conn.srcblocks = innames;
272 conn.srcports = srcports;
273 conn.dstblocks = blockname;
274 conn.dstports = [1:numel(innames)]-1;
275 conn.plist = block.pls;
276
277 end
278
279 %--------------------------------------------------------------------------
280 % Do some parsing of block diagram names to make sensible variable names.
281 %
282 function [name, ports] = fixBlockdiagramName(name)
283
284 name = strtrim(name);
285 if name(1) == '[' && name(end) == ']'
286 name = name(2:end-1);
287 end
288 % match the last occurance of '_PORT' and check there is a
289 % number behind it
290 pstrs = regexp(name, '_PORT(\d*)', 'tokens');
291 ports = [];
292 for kk=1:numel(pstrs)
293 ports(kk) = str2double(pstrs{kk}{1});
294 end
295
296 name = regexprep(name, '_PORT\d*', '');
297 end
298
299 %--------------------------------------------------------------------------
300 % Place a block on the canvas
301 %
302 function [blockplaced,blockNames] = placeBlock(wb, blockplaced, blockPositions, ...
303 outname, cmds, X, dX, Y, cn, blockNames)
304
305 % look for commands which take this output as an input
306 for kk=1:numel(cmds)
307 dstblock = LTPDAworkbench.parseCmd(cmds{kk});
308 if any(strcmp(outname, dstblock.innames)) %|| ~isempty(idx)
309 if ~blockplaced(kk)
310 blockplaced(kk) = 1;
311 %--------- build a block
312 % to do this we need an minfo object; we have the
313 % the method name but we need the class. Either this
314 % is a constructor or it must have an input object
315 ecmd = sprintf('%s.getInfo(''%s'');', dstblock.class, dstblock.method);
316 ii = eval(ecmd);
317 X = X + dX;
318 Y = Y + 30;
319 if ~isempty(blockPositions)
320 pos = blockPositions{kk};
321 X = pos(1);
322 Y = pos(2);
323 end
324 name = wb.addBlock(dstblock.outname, ii, X,Y);
325 blockNames = [blockNames {name}];
326 % name = wb.addBlock(doutname, ii, X,Y+ (mod(cn+kk-1,2))*50);
327 % recursively call for this block
328 [blockplaced,blockNames] = placeBlock(wb, blockplaced, blockPositions, ...
329 dstblock.outname, cmds, X, dX, Y, cn, blockNames);
330 end
331 end
332 end
333
334 end
335
336 %--------------------------------------------------------------------------
337 % Replace other block names with PORT_#
338 %
339 % #### OLD CODE #####
340 %
341 function [pl, newconnections] = fixpl(pl,connections)
342
343 % first we need to replace all BLOCK_PORT# with PORT_#
344 pl = regexprep(pl, '(\w*)_PORT(\d*)', '''PORT_$2''');
345
346 cn = 1;
347 % go through all connections
348 for kk=1:numel(connections)
349 conn = connections(kk);
350 % check if the plist has a token matching the src
351 rstr = ['[' conn.src ']'];
352 nstr = sprintf('''PORT_%d''', conn.dstport-1);
353 idx = strfind(pl, rstr);
354 pl = strrep(pl, rstr, nstr);
355 if ~isempty(idx)
356 newconnections(cn) = struct('src', conn.src, 'dst', conn.dst, ...
357 'srcport', conn.srcport, 'dstport', conn.dstport-1);
358 end
359 end
360
361 end
362
363 % END