source: EcnlProtoTool/trunk/asp3_dcre/tecsgen/tecslib/plugin/NotifierPlugin.rb@ 270

Last change on this file since 270 was 270, checked in by coas-nagasima, 7 years ago

mruby版ECNLプロトタイピング・ツールを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-ruby
File size: 35.9 KB
Line 
1# -*- coding: utf-8 -*-
2#
3# Copyright (C) 2015 by Ushio Laboratory
4# Graduate School of Engineering Science, Osaka Univ., JAPAN
5# Copyright (C) 2015-2016 by Embedded and Real-Time Systems Laboratory
6# Graduate School of Information Science, Nagoya Univ., JAPAN
7#
8
9NotifierPluginArgProc = {
10 "factory" => Proc.new { |obj, rhs| obj.set_factory(rhs) },
11 "output_file" => Proc.new { |obj, rhs| obj.set_factory_output_file(rhs) }
12}
13
14class NotifierPlugin < CelltypePlugin
15
16 # ---------- アダプタ関数の生成 -------------
17 #
18 # siHandlerBodyの受け口関数は,タイムイベント通知の通知å…
19ˆã¨ã—て直接指定する
20 # ことはできない.シグネチャが一致していないことが理由である.このため,アダ
21 # プタとして動作する関数を生成し,カーネルからの呼出しをTECSの呼出しに変換で
22 # きるようにする必
23要がある.
24 #
25 # 基本的には,受け口毎にアダプタ関数を生成すれば十分である.しかし,これでは
26 # メモリ消費量が不必
27要に増加してしまう.そこで,通知å…
28ˆé–¢æ•°ã«intptr_t型の引数
29 # を渡せることに着目し,関数の"一般化"を図る.すなわち受け口のある属性(ここ
30 # では,結合å…
31ˆã®ã‚»ãƒ«ï¼Œæ·»å­—などを指す)を,アダプタ関数の引数として受け取れる
32 # ようにし,1個のアダプタ関数を2個以上の結合に対し用いることができるように
33 # する.
34 #
35 # アダプタ関数の属性について整理すると,
36 # - 受け口関数 - 一般化を行うと,実行時コストが大きく増大してしまうことが
37 # 確認されている.このため,一般化は行わない.EntryPropertyにも含めない.
38 # - セルインデックス - CELLIDX型で,型の規定はないが,"ポインタ値であったり
39 # 整数値であったりする。" (TECS 5.3.6) より,インデックスかポインタある
40 # ことが分かる.インデックスだとすると,この値はセルCBのアドレッシングに
41 # 使用されるので,intptr_tに収まる筈である.ポインタの場合,当然intptr_t
42 # に収まる.
43 # - 受け口é…
44åˆ—の添字 - int_t.同様にintptr_tに収まる筈である.
45 # これらのうち,セルインデックスと受け口é…
46åˆ—の添字はパラメータに含めることが
47 # できそうであるが,両方は無理である.
48 # 両方を格納したé…
49åˆ—を生成し,そのé…
50åˆ—の要素へのポインタを渡すようにするとい
51 # う選択肢も可能であるが,実行速度を優å…
52ˆã™ã‚‹ãŸã‚ã«ï¼Œã“の方法はとらなかった.
53 #
54 # このため,一般化は以下のパターンに分類して行う.
55 #
56 # 1. セルインデックスのみ一般化.セルインデックスのパターン数が受け口é…
57åˆ—の
58 # 添字のパターン数より多いか,あるいは受け口がé…
59åˆ—でない場合に行われる.
60 # 2. 受け口é…
61åˆ—の添字のみ一般化.この場合,セルごとに異なる関数を用いる.
62 #
63 # これより,各受け口関数について,アダプタ関数の生成個数は,
64 # O(min{セルインデックスのパターン数, 添字のパターン数})
65 # となる.
66 #
67 # プラグインでの処理をワンパスで行うために,tecsgen.cfgではアダプタ関数を直
68 # 接指定するのではなく,代わりにアダプタ関数を表すマクロを使用する.この
69 # マクロはアダプタ関数ハンドルと呼ぶことにする.
70 # アダプタ関数ハンドルは,次の2個の要素から成る.
71 # - アダプタ関数へののポインタ
72 # - アダプタ関数の引数
73
74 # @private
75 class AdapterGenerator
76
77 # 結合å…
78ˆã«é–¢ã™ã‚‹å±žæ€§ã‚’含む.セル,受け口é…
79åˆ—の添字から成る.
80 # 同一のEntryPropertyとなる結合は,å…
81¨ãåŒã˜æ–¹æ³•ã§ãã®å—け口関数を呼び
82 # 出せる.
83 # @private
84 class EntryProperty
85 # @return [Cell] 受け口側のセル.
86 attr_reader :cell
87
88 # @return [Integer, nil] 受け口é…
89åˆ—の添字.é…
90åˆ—でない場合はnil.
91 attr_reader :subscript
92
93 def initialize(cell, subscript)
94 @cell = cell
95 @subscript = subscript
96 end
97
98 def self.from_join(join)
99 EntryProperty.new(join.get_rhs_cell, join.get_rhs_subscript)
100 end
101
102 # 同値性の定義.Hashのキーとして使用するのに必
103要.
104 def eql?(o) @cell == o.cell && @subscript == o.subscript end
105 def hash() @cell.hash ^ @subscript.hash end
106 end
107
108 # @private
109 class EntryPort
110 # @param [Port] port 結合å…
111ˆã®ã‚»ãƒ«ã®ã‚»ãƒ«ã‚¿ã‚¤ãƒ—の受け口.
112 def initialize(port, prefix)
113 @port = port
114 @global_name = "#{prefix}_#{@port.get_celltype.get_global_name}_#{@port.get_name}"
115
116 # 受け口関数名.siHandlerBodyを想定しているので,関数名はmainで固定である.
117 @entry_fn_name = "#{@port.get_celltype.get_global_name}_#{@port.get_name}_main"
118
119 @props = [] # Array<EntryProperty>
120 @prop_map = {} # Hash<EntryProperty, Integer>
121 end
122
123 # @return [String] グローバルに一意(なものとして扱えるよう)な識別子.
124 attr_reader :global_name
125
126 # @return [Port]
127 attr_reader :port
128
129 # 指定したEntryPropertyに対応するアダプタ関数ハンドルを取得する.
130 # @param [EntryProperty] ep
131 # @return [String] アダプタ関数ハンドル.
132 # @private
133 def adapter_handle_for_entry_property(ep)
134 index = @prop_map.fetch(ep)
135 return [
136 "#{@global_name}_#{index}_fp",
137 "#{@global_name}_#{index}_arg"
138 ]
139 end
140
141 # 結合å…
142ˆã®æƒ…
143報に応じたアダプタ関数をソース・ヘッダーに出力する.
144 # 一般化指定は,`cell`または`subscript`の一方のみ行うことができる.
145 #
146 # @param [AdapterGenerator] context
147 # @param [String] fn_name 関数名.
148 # @param [Cell, Symbol] cell セル.セルについて一般化する場合は `:generic`
149 # @param [Integer, Symbol, nil] subscript 添字.添字について一般化する場合は `:generic`
150 # @private
151 def generate_inner(context, fn_name, cell, subscript)
152 source_file = context.source_file
153 header_file = context.header_file
154
155 source_file.print "void #{fn_name}(intptr_t extinf) {\n"
156
157 params = []
158 ct = @port.get_celltype
159
160 # シングルトンセルタイプ以外では,CELLIDXの指定が必
161要.
162 unless ct.is_singleton?
163 if cell == :generic
164 params << "(CELLIDX)extinf"
165 else
166 # セルのCELLIDXを得る
167 if ct.has_INIB? || ct.has_CB?
168 params << ct.get_name_array(cell)[7]
169 else
170 params << "0"
171 end
172 end
173 end
174
175 # 受け口é…
176åˆ—の添字.
177 if @port.get_array_size
178 if subscript == :generic
179 params << "(int_t)extinf"
180 else
181 params << "#{subscript}"
182 end
183 end
184
185 params_str = params.join(", ")
186
187 source_file.print "\t#{@entry_fn_name}(#{params_str});\n"
188 source_file.print "}\n\n"
189
190 header_file.print "extern void #{fn_name}(intptr_t extinf);\n\n"
191
192 end
193
194 # 指定したJoinに対応するアダプタ関数ハンドルを取得する.
195 # @return [Array] アダプタ関数ハンドル.
196 def make_adapter_handle(join)
197 prop = EntryProperty.from_join(join)
198 unless @prop_map.has_key?(prop)
199 @prop_map[prop] = @props.length
200 @props << prop
201 end
202 return adapter_handle_for_entry_property(prop)
203 end
204
205 # ソース・ヘッダーの記述を生成する.
206 # @param [AdapterGenerator] context
207 def generate(context)
208 header_file = context.header_file
209 return if @props.empty?
210
211 ct = @port.get_celltype
212
213 header_file.print "/*\n * #{@global_name}\n"
214
215 cells = @props.group_by { |prop| prop.cell }
216 subscripts = @props.group_by { |prop| prop.subscript }
217 no_cellidx = false
218 if !(ct.has_INIB? || ct.has_CB?)
219 # CB, INIB最適化により,CB, INIBが両方不要になったケース.
220 # CELLIDXが不要であるので,セルについて一般化しても意味
221 # はないので,添字による一般化を選択する.
222 generalize_by_cell_idx = false
223 no_cellidx = true
224
225 # å…
226¨ã¦ã®ã‚»ãƒ«ã‚’同一視する.
227 cells = { @props[0].cell => @props }
228
229 header_file.print " * No INIB & CB: generalized by subscript\n"
230 elsif @port.get_array_size
231 # 一般化パターンの分類を行うために,受け口側セルや添字の
232 # パターン数を分析して,最適な方を選択する.
233 generalize_by_cell_idx = cells.length >= subscripts.length
234 if generalize_by_cell_idx
235 header_file.print " * more cells than subscripts: generalized by cell\n"
236 else
237 header_file.print " * more subscripts than cells: generalized by subscript\n"
238 end
239 else
240 # 常にCELLIDXで一般化
241 generalize_by_cell_idx = true
242 header_file.print " * non-array entry port: generalized by cell\n"
243 end
244
245 header_file.print " */\n\n"
246
247 if generalize_by_cell_idx
248 # CELLIDXについて一般化
249 subscripts.each { |subscript, props|
250 if subscript
251 fn_name = "#{@global_name}_adap_#{subscript}"
252 else
253 # 受け口é…
254åˆ—でない場合
255 fn_name = "#{@global_name}_adap"
256 end
257
258 generate_inner context, fn_name,
259 :generic, subscript
260
261 props.each { |prop|
262 handle = adapter_handle_for_entry_property(prop)
263
264 # セルのCELLIDXを得る
265 if ct.has_INIB? || ct.has_CB?
266 idx = ct.get_name_array(prop.cell)[7]
267 else
268 idx = "0"
269 end
270 header_file.print "\#define #{handle[0]} &#{fn_name}\n"
271 header_file.print "\#define #{handle[1]} #{idx}\n\n"
272 }
273 }
274 else
275 # 添字について一般化
276 cells.each { |cell, props|
277 if no_cellidx
278 # CB/INIB なし
279 fn_name = "#{@global_name}_adap"
280 else
281 fn_name = "#{@global_name}_adap_#{cell.get_global_name}"
282 end
283
284 generate_inner context, fn_name,
285 cell, :generic
286
287 props.each { |prop|
288 handle = adapter_handle_for_entry_property(prop)
289
290 header_file.print "\#define #{handle[0]} &#{fn_name}\n"
291 header_file.print "\#define #{handle[1]} #{prop.subscript || 0}\n\n"
292 }
293 }
294 end
295 end
296 end
297
298 # @private
299 attr :source_file
300
301 # @private
302 attr :header_file
303
304 # @param [String] celltype_name ハンドラ関数のセルタイプ.
305 # @param [String] prefix 名前衝突を防ぐためのプレフィックス.
306 def initialize(celltype_name, prefix)
307 @celltype_name = celltype_name
308 @prefix = prefix
309
310 # Hash<Port, EntryPort>
311 @entry_ports = {}
312 end
313
314 # ===AdapterGenerator#make_adapter_handle===
315 # 指定した結合の呼出しを行うためのアダプタ関数ハンドルを生成する.
316 # @return [Array] アダプタ関数ハンドル.
317 def make_adapter_handle(join)
318 entry_port = @entry_ports[join.get_rhs_port]
319 unless entry_port
320 entry_port = EntryPort.new(join.get_rhs_port,
321 "#{@celltype_name}_#{@prefix}")
322 @entry_ports[join.get_rhs_port] = entry_port
323 end
324 return entry_port.make_adapter_handle(join)
325 end
326
327 # ===AdapterGenerator#finish===
328 # 各受け口に対し,アダプタ関数を生成する.
329 def finish
330 @source_file = AppFile.open( "#{$gen}/#{@celltype_name}.c" )
331 @source_file.print "\n/* Generated by #{self.class.name} */\n\n"
332 @source_file.print "\#include \"#{@celltype_name}_aux.h\"\n\n"
333 @source_file.print "\#include \"#{@celltype_name}_tecsgen.h\"\n\n"
334
335 @header_file = AppFile.open( "#{$gen}/#{@celltype_name}.h" )
336 @header_file.print "\n/* Generated by #{self.class.name} */\n\n"
337
338 # NotifierPluginを使用するセルタイプが複数ある場合,それぞれに
339 # 対しAdapterGenerator#finishが呼び出される.tTimeEventHandler.hに
340 # 続けて書き込んでしまうと,ヘッダーガードの関係で2回目以降の記述
341 # が読み込まれなくなってしまう.このため,ファイル名 + セルタイプ名
342 # という少し特殊なヘッダーガードを用いる.
343 header_guard = "#{@celltype_name}_H_#{@prefix}"
344
345 @header_file.print "\#ifndef #{header_guard}\n"
346 @header_file.print "\#define #{header_guard}\n\n"
347
348 # カーネルコンフィギュレータを実行する際,ハンドラ受け口のセルタイプ
349 # のセルCBの定義が必
350要な場合がある.
351 @header_file.print "\#include \"#{@celltype_name}_aux.h\"\n\n"
352
353 # 結合å…
354ˆã®ã‚»ãƒ«ã‚¿ã‚¤ãƒ—の定義は,自分のセルのtecsgen.hよりもå…
355ˆã«
356 # 読み込まなければならないが,このプラグインが複数実行されると,
357 # 順序が崩れてしまう.そこで,結合å…
358ˆã®ã‚»ãƒ«ã‚¿ã‚¤ãƒ—の定義はもう一つの
359 # ヘッダーファイル(tCelltypeName_aux.h)から読み込むようにする.
360 aux_header_file = AppFile.open( "#{$gen}/#{@celltype_name}_aux.h" )
361 aux_header_file.print "\n/* Generated by #{self.class.name} */\n\n"
362
363 aux_header_guard = "#{@celltype_name}_AUX_H_#{@prefix}"
364
365 aux_header_file.print "\#ifndef #{aux_header_guard}\n"
366 aux_header_file.print "\#define #{aux_header_guard}\n\n"
367
368 cb_type_only_guard = "#{@celltype_name}_AUX_H_#{@prefix}_CB_TYPE_ONLY"
369
370 # 結合å…
371ˆã®ã‚»ãƒ«ã‚¿ã‚¤ãƒ—の定義を読み込む
372 aux_header_file.print "#ifndef TOPPERS_CB_TYPE_ONLY\n"
373 aux_header_file.print "#define TOPPERS_CB_TYPE_ONLY\n"
374 aux_header_file.print "#define #{cb_type_only_guard}\n"
375 aux_header_file.print "#endif\n"
376 @entry_ports.values.map { |ep|
377 ep.port.get_celltype
378 }.uniq.each { |ct|
379 hname = "#{ct.get_global_name}_tecsgen.#{$h_suffix}"
380 aux_header_file.print "\#include \"#{hname}\"\n"
381 }
382 aux_header_file.print "#ifdef #{cb_type_only_guard}\n"
383 aux_header_file.print "#undef #{cb_type_only_guard}\n"
384 aux_header_file.print "#undef TOPPERS_CB_TYPE_ONLY\n"
385 aux_header_file.print "#endif\n\n"
386
387 aux_header_file.print "\#endif\n"
388 aux_header_file.close
389
390 @entry_ports.each { |port, entry_port|
391 entry_port.generate self
392 }
393
394 @header_file.print "\#endif\n"
395
396 @source_file.close
397 @header_file.close
398 end
399
400 end
401
402 # ------ 通知のハンドラの種類の定義 -------
403
404 class Handler
405 def initialize(call_port_name)
406 @call_port_name = call_port_name
407 end
408
409 attr :call_port_name
410 end
411
412 # 通常のハンドラ
413 EVENT_HANDLER = Handler::new("ciNotificationHandler")
414
415 # エラーハンドラ (通常のハンドラが失敗した場合に呼び出される)
416 ERROR_HANDLER = Handler::new("ciErrorNotificationHandler")
417
418 HANDLERS = [
419 EVENT_HANDLER,
420 ERROR_HANDLER
421 ]
422
423 class HandlerAttribute
424 def initialize(name, error_name = nil)
425 @name = name
426 @error_name = error_name || (name + 'ForError')
427 end
428
429 def name_for_handler(handler)
430 case handler
431 when EVENT_HANDLER then return @name
432 when ERROR_HANDLER then return @error_name
433 else raise "unknown handler #{handler}"
434 end
435 end
436 end
437
438 # ------ 通知の属性の定義 -------
439 #
440 # ハンドラタイプに合致しない属性が指定された場合に
441 # エラーを出力できるよう、å…
442¨ã¦ã®å±žæ€§ã‚’ここで列挙する。
443
444 SETVAR_ADDR_ATTR = HandlerAttribute::new("setVariableAddress")
445 SETVAR_VALUE_ATTR = HandlerAttribute::new("setVariableValue")
446 INCVAR_ADDR_ATTR = HandlerAttribute::new("incrementedVariableAddress")
447 SNDDTQ_VALUE_ATTR = HandlerAttribute::new("dataqueueSentValue")
448 SETFLG_FLAG_ATTR = HandlerAttribute::new("flagPattern")
449
450 ATTRS = [
451 SETVAR_ADDR_ATTR,
452 SETVAR_VALUE_ATTR,
453 INCVAR_ADDR_ATTR,
454 SNDDTQ_VALUE_ATTR,
455 SETFLG_FLAG_ATTR
456 ]
457
458 # ------ ハンドラタイプの定義 -------
459
460 class BaseHandlerType
461
462 def initialize()
463 super
464
465 # HandlerAttribute[]
466 @required_attributes = []
467 end
468
469 attr :required_attributes
470
471 #=== NotifierPlugin#BaseHandlerType#validate_join
472 # 指定したセルの結合å…
473ˆãŒã€ã“のハンドラタイプに該当するかを検証
474 # handler:: Handler : ハンドラ
475 # cell:: Cell : セル
476 # join:: Join : 結合 (declarationがPortであるもの)
477 def validate_join(handler, cell, join)
478 return !generate_attr_map(handler, cell).nil?
479 end
480
481 #=== NotifierPlugin#BaseHandlerType#generate_attr_map
482 # 指定したセルの属性と、既知のHandlerAttributeのマッピングを
483 # 生成し、Hash<HandlerAttribute, Join> (各属性とそれに対応する
484 # Join(declarationがDeclのもの)を表すHash)、あるいは、
485 # マッピングが行えない場合(属性の不足、過剰)はnilを返す。
486 #
487 # handler:: Handler : ハンドラ
488 # cell:: Cell : セル
489 def generate_attr_map(handler, cell)
490 map = {}
491
492 join_list = cell.get_join_list
493
494 ATTRS.each { |known_attr|
495 attr_name = known_attr.name_for_handler(handler)
496 join = join_list.get_item(attr_name.to_sym)
497
498 # このセルタイプにおいて必
499須の属性か?
500 is_required = @required_attributes.include?(known_attr)
501
502 # 属性の指定が不足している? or 過剰?
503 # 注: ハンドラタイプの判別には、セルで値が指定されているか
504 # が考æ…
505®ã•ã‚Œã‚‹ã€‚セルタイプで初期値が指定されていても、
506 # それはハンドラタイプの決定に影響しない。
507 return nil if join.nil? != !is_required
508
509 # 必
510要のない属性であり、指定もされていないので飛ばす
511 next if join.nil?
512
513 # TODO: attrの結合であることを検証
514
515 map[known_attr] = join
516 }
517
518 return map
519 end
520
521 #=== NotifierPlugin#BaseHandlerType#gen_cfg_handler_type
522 # タイムイベントの通知の種類を表すコンフィギュレータの記述を生成し、Stringまたはnilを返す
523 # handler:: Handler : ハンドラ
524 def gen_cfg_handler_type(handler)
525 raise "called abstract method gen_cfg_handler_type"
526 end
527
528 #=== NotifierPlugin#BaseHandlerType#gen_cfg_handler_parameters
529 # タイムイベントの通知の引数を表すコンフィギュレータの記述を生成し、String[]を返す
530 # handler:: Handler : ハンドラ
531 # join:: Join : 結合 (declarationがPortであるもの)
532 # attrMap:: Hash<HandlerAttribute, Join> :
533 # 各属性とそれに対応するJoin (declarationがDeclのもの)
534 # cell:: Cell : セル
535 # adpt_gen:: AdapterGenerator : アダプタ関数を生成するオブジェクト
536 def gen_cfg_handler_parameters(handler, join, attrMap, cell, adpt_gen)
537 return nil
538 end
539
540 #=== NotifierPlugin#BaseHandlerType#might_fail
541 # 通知の際、エラーが発生し、その結果エラー通知を呼ぶ必
542要が生じる
543 # かどうかを返す。
544 def might_fail
545 return false
546 end
547
548 end
549 class BaseTaskHandlerType < BaseHandlerType
550 def validate_join(handler, cell, join, *args)
551 return super(handler, cell, join, *args) &&
552 join && join.get_rhs_cell.get_celltype.get_name == :tTask
553 end
554 def gen_cfg_handler_parameters(handler, join, attrMap, cell, adpt_gen)
555 taskCell = join.get_cell
556 id_attr_join = taskCell.get_join_list.get_item(:id)
557 id_attr = join.get_rhs_cell.get_celltype.find(:id)
558 if id_attr_join
559 # セル生成時に初期化する場合
560 id = id_attr_join.get_rhs.to_s
561 else
562 # セルタイプの初期化値を使う場合
563 id = id_attr.get_initializer.to_s
564 end
565
566 # $id$等の置換
567 name_array = taskCell.get_celltype.get_name_array(taskCell)
568 id = taskCell.get_celltype.subst_name(id, name_array)
569
570 return [id]
571 end
572 def might_fail
573 return true
574 end
575 end
576 class ActivateTaskHandlerType < BaseTaskHandlerType
577 def validate_join(handler, cell, join, *args)
578 return super(handler, cell, join, *args) &&
579 join.get_port_name == :eiActivateNotificationHandler
580 end
581 def gen_cfg_handler_type(handler)
582 case handler
583 when EVENT_HANDLER then return "TNFY_ACTTSK"
584 when ERROR_HANDLER then return "TENFY_ACTTSK"
585 else raise "unknown handler #{handler}"
586 end
587 end
588 end
589 class WakeUpTaskHandlerType < BaseTaskHandlerType
590 def validate_join(handler, cell, join, *args)
591 return super(handler, cell, join, *args) &&
592 join.get_port_name == :eiWakeUpNotificationHandler
593 end
594 def gen_cfg_handler_type(handler)
595 case handler
596 when EVENT_HANDLER then return "TNFY_WUPTSK"
597 when ERROR_HANDLER then return "TENFY_WUPTSK"
598 else raise "unknown handler #{handler}"
599 end
600 end
601 end
602 class SetVariableHandlerType < BaseHandlerType
603 def initialize()
604 super
605 @required_attributes = [
606 SETVAR_ADDR_ATTR,
607 SETVAR_VALUE_ATTR
608 ] # .to_set
609 end
610 def validate_join(handler, cell, join, *args)
611 return super(handler, cell, join, *args) &&
612 join.nil? &&
613 handler == EVENT_HANDLER
614 end
615 def gen_cfg_handler_parameters(handler, join, attrMap, cell, adpt_gen)
616 var_addr = attrMap[SETVAR_ADDR_ATTR].get_rhs.to_s
617 var_value = attrMap[SETVAR_VALUE_ATTR].get_rhs.to_s
618
619 # $id$等の置換
620 name_array = cell.get_celltype.get_name_array(cell)
621 var_addr = cell.get_celltype.subst_name(var_addr, name_array)
622 var_value = cell.get_celltype.subst_name(var_value, name_array)
623
624 return [var_addr, var_value]
625 end
626 def gen_cfg_handler_type(handler)
627 case handler
628 when EVENT_HANDLER then return "TNFY_SETVAR"
629 else raise "unknown handler #{handler}"
630 end
631 end
632 end
633 class SetVariableToErrorCodeHandlerType < BaseHandlerType
634 def initialize()
635 super
636 @required_attributes = [
637 SETVAR_ADDR_ATTR
638 ] # .to_set
639 end
640 def validate_join(handler, cell, join, *args)
641 return super(handler, cell, join, *args) &&
642 join.nil? &&
643 handler == ERROR_HANDLER
644 end
645 def gen_cfg_handler_parameters(handler, join, attrMap, cell, adpt_gen)
646 var_addr = attrMap[SETVAR_ADDR_ATTR].get_rhs.to_s
647
648 # $id$等の置換
649 name_array = cell.get_celltype.get_name_array(cell)
650 var_addr = cell.get_celltype.subst_name(var_addr, name_array)
651
652 return [var_addr]
653 end
654 def gen_cfg_handler_type(handler)
655 case handler
656 when ERROR_HANDLER then return "TENFY_SETVAR"
657 else raise "unknown handler #{handler}"
658 end
659 end
660 end
661 class IncrementVariableHandlerType < BaseHandlerType
662 def initialize()
663 super
664 @required_attributes = [
665 INCVAR_ADDR_ATTR
666 ] # .to_set
667 end
668 def validate_join(handler, cell, join, *args)
669 return super(handler, cell, join, *args) &&
670 join.nil?
671 end
672 def gen_cfg_handler_parameters(handler, join, attrMap, cell, adpt_gen)
673 var_addr = attrMap[INCVAR_ADDR_ATTR].get_rhs.to_s
674
675 # $id$等の置換
676 name_array = cell.get_celltype.get_name_array(cell)
677 var_addr = cell.get_celltype.subst_name(var_addr, name_array)
678
679 return [var_addr]
680 end
681 def gen_cfg_handler_type(handler)
682 case handler
683 when EVENT_HANDLER then return "TNFY_INCVAR"
684 when ERROR_HANDLER then return "TENFY_INCVAR"
685 else raise "unknown handler #{handler}"
686 end
687 end
688 end
689 class SignalSemaphoreHandlerType < BaseHandlerType
690 def validate_join(handler, cell, join, *args)
691 return super(handler, cell, join, *args) &&
692 join && join.get_rhs_cell.get_celltype.get_name == :tSemaphore
693 end
694 def gen_cfg_handler_parameters(handler, join, attrMap, cell, adpt_gen)
695 semaphoreCell = join.get_cell
696 id_attr_join = semaphoreCell.get_join_list.get_item(:id)
697 id_attr = join.get_rhs_cell.get_celltype.find(:id)
698 if id_attr_join
699 # セル生成時に初期化する場合
700 id = id_attr_join.get_rhs.to_s
701 else
702 # セルタイプの初期化値を使う場合
703 id = id_attr.get_initializer.to_s
704 end
705
706 # $id$等の置換
707 name_array = semaphoreCell.get_celltype.get_name_array(semaphoreCell)
708 id = semaphoreCell.get_celltype.subst_name(id, name_array)
709
710 return [id]
711 end
712 def might_fail
713 return true
714 end
715 def gen_cfg_handler_type(handler)
716 case handler
717 when EVENT_HANDLER then return "TNFY_SIGSEM"
718 when ERROR_HANDLER then return "TENFY_SIGSEM"
719 else raise "unknown handler #{handler}"
720 end
721 end
722 end
723 class SetEventflagHandlerType < BaseHandlerType
724 def initialize()
725 super
726 @required_attributes = [
727 SETFLG_FLAG_ATTR
728 ] # .to_set
729 end
730 def validate_join(handler, cell, join, *args)
731 return super(handler, cell, join, *args) &&
732 join && join.get_rhs_cell.get_celltype.get_name == :tEventflag
733 end
734 def gen_cfg_handler_parameters(handler, join, attrMap, cell, adpt_gen)
735 eventflagCell = join.get_cell
736 id_attr_join = eventflagCell.get_join_list.get_item(:id)
737 id_attr = join.get_rhs_cell.get_celltype.find(:id)
738 if id_attr_join
739 # セル生成時に初期化する場合
740 id = id_attr_join.get_rhs.to_s
741 else
742 # セルタイプの初期化値を使う場合
743 id = id_attr.get_initializer.to_s
744 end
745 flg_pattern = attrMap[SETFLG_FLAG_ATTR].get_rhs.to_s
746
747 # $id$等の置換
748 name_array = eventflagCell.get_celltype.get_name_array(eventflagCell)
749 id = eventflagCell.get_celltype.subst_name(id, name_array)
750
751 name_array = cell.get_celltype.get_name_array(cell)
752 flg_pattern = cell.get_celltype.subst_name(flg_pattern, name_array)
753
754 return [id, flg_pattern]
755 end
756 def might_fail
757 return true
758 end
759 def gen_cfg_handler_type(handler)
760 case handler
761 when EVENT_HANDLER then return "TNFY_SETFLG"
762 when ERROR_HANDLER then return "TENFY_SETFLG"
763 else raise "unknown handler #{handler}"
764 end
765 end
766 end
767 class DataqueueHandlerType < BaseHandlerType
768 def initialize()
769 super
770 end
771 def validate_join(handler, cell, join, *args)
772 return super(handler, cell, join, *args) &&
773 join && join.get_rhs_cell.get_celltype.get_name == :tDataqueue
774 end
775 def gen_cfg_handler_parameters(handler, join, attrMap, cell, adpt_gen)
776 dataqueueCell = join.get_cell
777 id_attr_join = dataqueueCell.get_join_list.get_item(:id)
778 id_attr = join.get_rhs_cell.get_celltype.find(:id)
779 if id_attr_join
780 # セル生成時に初期化する場合
781 id = id_attr_join.get_rhs.to_s
782 else
783 # セルタイプの初期化値を使う場合
784 id = id_attr.get_initializer.to_s
785 end
786
787 # $id$等の置換
788 name_array = dataqueueCell.get_celltype.get_name_array(dataqueueCell)
789 id = dataqueueCell.get_celltype.subst_name(id, name_array)
790
791 name_array = cell.get_celltype.get_name_array(cell)
792
793 return [id]
794 end
795 def might_fail
796 return true
797 end
798 end
799 class SendToDataqueueHandlerType < DataqueueHandlerType
800 def initialize()
801 super
802 @required_attributes = [
803 SNDDTQ_VALUE_ATTR
804 ] # .to_set
805 end
806 def validate_join(handler, cell, join, *args)
807 return super(handler, cell, join, *args) && handler == EVENT_HANDLER
808 end
809 def gen_cfg_handler_parameters(handler, join, attrMap, cell, adpt_gen)
810 params = super(handler, join, attrMap, cell, adpt_gen)
811
812 sent_value = attrMap[SNDDTQ_VALUE_ATTR].get_rhs.to_s
813
814 # $id$等の置換
815 name_array = cell.get_celltype.get_name_array(cell)
816 sent_value = cell.get_celltype.subst_name(sent_value, name_array)
817
818 params << sent_value
819
820 return params
821 end
822 def gen_cfg_handler_type(handler)
823 case handler
824 when EVENT_HANDLER then return "TNFY_SNDDTQ"
825 else raise "unknown handler #{handler}"
826 end
827 end
828 end
829 class SendErrorCodeToDataqueueHandlerType < DataqueueHandlerType
830 def initialize()
831 super
832 end
833 def validate_join(handler, cell, join, *args)
834 return super(handler, cell, join, *args) && handler == ERROR_HANDLER
835 end
836 def gen_cfg_handler_type(handler)
837 case handler
838 when ERROR_HANDLER then return "TENFY_SNDDTQ"
839 else raise "unknown handler #{handler}"
840 end
841 end
842 end
843 class UserHandlerType < BaseHandlerType
844 def validate_join(handler, cell, join, *args)
845 return super(handler, cell, join, *args) &&
846 handler != ERROR_HANDLER && # invalid for error handler
847 join && join.get_rhs_cell.get_celltype.get_name == :tTimeEventHandler
848 end
849 def gen_cfg_handler_type(handler)
850 case handler
851 when EVENT_HANDLER then return "TNFY_HANDLER"
852 else raise "unknown handler #{handler}"
853 end
854 end
855 def gen_cfg_handler_parameters(handler, join, attrMap, cell, adpt_gen)
856 # tTimeEventHandlerの結合å…
857ˆã‚’取得
858 handler_cell = join.get_rhs_cell
859 call_join = handler_cell.get_join_list.get_item(:ciHandlerBody)
860
861 # 結合されていない場合はtecsgenがエラーを出すはずなのでここでは
862 # エラーにせず無視する.
863 return [] unless call_join
864
865 # アダプタ関数ハンドルを取得
866 adapter_handle = adpt_gen.make_adapter_handle(call_join)
867 return [adapter_handle[1], adapter_handle[0]]
868 end
869 end
870 class NullHandlerType < BaseHandlerType
871 def validate_join(handler, cell, join, *args)
872 return super(handler, cell, join, *args) &&
873 join.nil? &&
874 handler != EVENT_HANDLER # handler is mandatory for normal handler!
875 end
876 def gen_cfg_handler_type(handler)
877 case handler
878 when ERROR_HANDLER then return nil
879 else raise "unknown handler #{handler}"
880 end
881 end
882 end
883
884 HANDLER_TYPES = [
885 ActivateTaskHandlerType.new,
886 WakeUpTaskHandlerType.new,
887 SetVariableHandlerType.new,
888 SetVariableToErrorCodeHandlerType.new,
889 IncrementVariableHandlerType.new,
890 SignalSemaphoreHandlerType.new,
891 SetEventflagHandlerType.new,
892 SendToDataqueueHandlerType.new,
893 SendErrorCodeToDataqueueHandlerType.new,
894 UserHandlerType.new,
895 NullHandlerType.new
896 ]
897
898 #@celltype:: Celltype
899 #@option:: String :オプション文字列
900 def initialize( celltype, option )
901 super
902 @plugin_arg_check_proc_tab = NotifierPluginArgProc
903 @plugin_arg_str = option
904 @plugin_arg_str = option.gsub( /\A"(.*)/, '\1' ) # 前後の "" を取り除く
905 @plugin_arg_str.sub!( /(.*)"\z/, '\1' )
906 @factory = nil
907 @output_file = nil
908 parse_plugin_arg
909 unless @factory
910 cdl_error("ASP1003 celltype $1: option factory is not specified",
911 celltype.get_name)
912 end
913 unless @output_file
914 cdl_error("ASP1003 celltype $1: option output_file is not specified",
915 celltype.get_name)
916 end
917 end
918
919 def set_factory(template_string)
920 unless @factory.nil?
921 cdl_error("ASP1003 celltype $1: option factory was specified more than once",
922 celltype.get_name)
923 end
924 @factory = template_string
925 end
926
927 def set_factory_output_file(output_file)
928 unless @output_file.nil?
929 cdl_error("ASP1003 celltype $1: option output_file was specified more than once",
930 celltype.get_name)
931 end
932 @output_file = output_file
933 end
934
935 def gen_factory file
936 puts "===== begin #{@celltype.get_name.to_s} plugin ====="
937
938 kernelCfg = AppFile.open( "#{$gen}/#{@output_file}" )
939 kernelCfg.print "\n/* Generated by #{self.class.name} */\n"
940 kernelCfg.print "\#include \"tTimeEventHandler.h\"\n"
941
942 # アダプタ関数を生成する準備
943 @adpt_gen = AdapterGenerator.new("tTimeEventHandler", @celltype.get_global_name)
944
945 # 属性置換が行えることを検証する。
946 # ここで行うのは、factoryで指定された属性名が
947 # 存在することを確認し、しなければエラーを出力することのみである。
948 # セルごとの処理の最中にエラーを出力することも可能ではあるが、
949 # そうするとセルタイプ側の問題であるのにもかかわらず、セルごとに
950 # エラーが表示されてしまう。
951 # {{attribute_name}} -> attribute_value
952 @factory.scan(/\{\{([a-zA-Z0-9_]*?)\}\}/) { |match|
953 name = $1.to_sym
954
955 # {{_handler_params_}} はハンドラに関する指定。プラグイン内
956で値が生成される
957 next if name == :_handler_params_
958
959 subst_attr = @celltype.find(name)
960 unless subst_attr
961 cdl_error( "ASP1007 celltype $1: additional_param: attribute $2 does not exist.",
962 @celltype.get_name, name)
963 end
964 }
965
966 @celltype.get_cell_list.each { |cell|
967 gen_factory_for_cell kernelCfg, cell
968 }
969
970 # アダプタ関数の生成を完了させる
971 @adpt_gen.finish
972
973 kernelCfg.close
974 puts "===== end #{@celltype.get_name.to_s} plugin ====="
975 end
976
977 def gen_factory_for_cell(kernelCfg, cell)
978 handler_flags = []
979 handler_args = []
980
981 event_handler_might_fail = true
982 handler_flag = nil
983
984 # ignoreErrorsを取得
985 ignoreErrors_attr_join = cell.get_join_list.get_item(:ignoreErrors)
986 ignoreErrors_attr = cell.get_celltype.find(:ignoreErrors)
987 if ignoreErrors_attr_join
988 # セル生成時に初期化する場合
989 ignoreErrors = ignoreErrors_attr_join.get_rhs.to_s
990 else
991 # セルタイプの初期化値を使う場合
992 ignoreErrors = ignoreErrors_attr.get_initializer.to_s
993 end
994 case ignoreErrors
995 when 'true' then ignoreErrors = true
996 when 'false' then ignoreErrors = false
997 else
998 cdl_warning( "ASP1005 cell $1: unrecognized value '$2' specified for ignoreErrors",
999 cell.get_name, ignoreErrors )
1000 ignoreErrors = false
1001 end
1002
1003 [EVENT_HANDLER, ERROR_HANDLER].each { |handler|
1004 # 呼び口の結合を取得
1005 call_join = cell.get_join_list.get_item(handler.call_port_name.to_sym)
1006
1007 # ハンドラタイプを判別する
1008 matches = HANDLER_TYPES.select { |handler_type|
1009 handler_type.validate_join(handler, cell, call_join)
1010 }
1011
1012 if matches.length == 0
1013 cdl_error( "ASP1001 cell $1: no matching handler type found for $2", cell.get_name, handler.call_port_name )
1014 next
1015 end
1016
1017 # 最初に見つかった有効なハンドラタイプを使用
1018 ht = matches[0]
1019
1020 # 通知ハンドラで「エラーが発生するはずがない」のに「エラーハンドラが指定されている」
1021 # もしくはその逆のパターンを検出する。
1022 # (handler_flagがnilである場合、ハンドラタイプが不明であり、エラーが発生するか不明
1023 # なため、検出は行わない。)
1024 if handler == ERROR_HANDLER && !ht.is_a?(NullHandlerType) && !event_handler_might_fail
1025 cdl_error( "ASP1004 cell $1: handler type $2 which never raises an error was inferred for the normal notification handler, but an error notification handler was specified.",
1026 cell.get_name, handler_flag)
1027 end
1028 if handler == ERROR_HANDLER && ht.is_a?(NullHandlerType) && event_handler_might_fail && !ignoreErrors
1029 cdl_warning( "ASP1006 cell $1: handler type $2 which might raise an error was inferred for the normal notificaton handler, but an error notification handler was not specified.",
1030 cell.get_name, handler_flag)
1031 end
1032
1033 # assertion
1034 unless ht.validate_join(handler, cell, call_join)
1035 raise "!validate_join"
1036 end
1037
1038 # 通知方法の静的API記述を生成する
1039 handler_flag = ht.gen_cfg_handler_type(handler)
1040 handler_flags << handler_flag if handler_flag
1041
1042 attr_map = ht.generate_attr_map(handler, cell)
1043
1044 handler_arg = ht.gen_cfg_handler_parameters(handler, call_join, attr_map, cell, @adpt_gen)
1045 handler_args += handler_arg if handler_arg
1046
1047 if handler == EVENT_HANDLER
1048 event_handler_might_fail = ht.might_fail
1049 end
1050 }
1051
1052 # $id$等の置換
1053 name_array = cell.get_celltype.get_name_array(cell)
1054 handler_args.collect! { |e|
1055 if e == "$cbp$"
1056 cell.get_celltype.subst_name(e, name_array)
1057 else
1058 e
1059 end
1060 }
1061
1062 # tecsgen.cfgの記述を生成する。
1063 # factoryに対し、パラメータ置換を行う。
1064 # {{attribute_name}} -> attribute_value
1065 text = @factory.gsub(/\{\{([a-zA-Z0-9_]*?)\}\}/) { |match|
1066 name = $1.to_sym
1067 subst_attr = cell.get_celltype.find(name)
1068
1069 # {{_handler_params_}} はハンドラの指定に置換する。
1070 if name == :_handler_params_
1071 args_joined = handler_flags.join(' | ')
1072 if handler_args.length > 0
1073 args_joined << ", "
1074 args_joined << handler_args.join(', ')
1075 end
1076 next args_joined
1077 end
1078
1079 unless subst_attr
1080 # 属性が見つからないというエラーはすでに報告されているので
1081 # ここではダミー値を返しておくだけである。
1082 next ""
1083 end
1084
1085 subst_attr_join = cell.get_join_list.get_item(name)
1086 if subst_attr_join
1087 # セル生成時に初期化する場合
1088 subst = subst_attr_join.get_rhs.to_s
1089 else
1090 # セルタイプの初期化値を使う場合
1091 subst = subst_attr.get_initializer.to_s
1092 end
1093
1094 # $id$等の置換
1095 cell.get_celltype.subst_name(subst, name_array)
1096 }
1097
1098 # 出力
1099 kernelCfg.puts text
1100
1101 end
1102 private :gen_factory_for_cell
1103
1104end
Note: See TracBrowser for help on using the repository browser.