source: asp3_tinet_ecnl_arm/trunk/asp3_dcre/tecsgen/tecslib/plugin/NotifierPlugin.rb@ 352

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

arm向けASP3版ECNLを追加

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