rsmp 0.12.3 → 0.13.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d97c24017cb23ab7159bebda96f262f50813d902365e2fa1fabeb90d4771df01
4
- data.tar.gz: fde070792556ef05d68ebfe5d7757d696f81921d75e64ced80f2a1c4878d39ef
3
+ metadata.gz: dfc37b07159cf717f60f293434f6fda0ff6935ad209967b7d5ddb025a9794600
4
+ data.tar.gz: 5c5e6b1e7728bdffd50776e95a7beb0fd6261dbb58b4ec3f530f7b33ee15cdf4
5
5
  SHA512:
6
- metadata.gz: 2b58d0ed3307893fdd43fcd361b5da63e541baf199ac21860fa11cca756fe4339a63b4bf3420164232c248667e3cf75fe0b467928642e9fcd99f951308fa6e67
7
- data.tar.gz: 3c5cb9a04f22a56a16f51c41faff55a5d587fe51dd2774e6a018846da40b5bf066f08bbbfc7848382ec2a76c64a0b17cad372972b0357d7182359e934864b771
6
+ metadata.gz: 201cad0d07ee914d79af82d8ad2ee10740fbe49002e1f3cbb2740b3d573df61c26532688651e6f6f70ea538e0475f51cbe0a46055b2b6331cd5fff48aa4b8d3e
7
+ data.tar.gz: 74a44c4ac848c9dbe5f0fbd772f2839c5565a8322d7292218d64f7e31f5fdf8e4849e59845fee361d0ca1ed0ecaa2ce067fdc71a86eaf0e50959e0d826742b2f
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rsmp (0.12.3)
4
+ rsmp (0.13.2)
5
5
  async (~> 1.29.1)
6
6
  async-io (~> 1.32.2)
7
7
  colorize (~> 0.8.1)
@@ -68,7 +68,7 @@ GEM
68
68
  ffi (1.15.5-x64-mingw32)
69
69
  fiber-local (1.0.0)
70
70
  hana (1.3.7)
71
- json_schemer (0.2.20)
71
+ json_schemer (0.2.21)
72
72
  ecma-re-validator (~> 0.3)
73
73
  hana (~> 1.3)
74
74
  regexp_parser (~> 2.0)
@@ -79,7 +79,7 @@ GEM
79
79
  multi_test (0.1.2)
80
80
  nio4r (2.5.8)
81
81
  rake (13.0.6)
82
- regexp_parser (2.2.1)
82
+ regexp_parser (2.4.0)
83
83
  rsmp_schemer (0.4.0)
84
84
  json_schemer (~> 0.2.18)
85
85
  rspec (3.10.0)
@@ -1,33 +1,94 @@
1
1
  module RSMP
2
2
  # class that tracks the state of an alarm
3
3
  class AlarmState
4
- attr_reader :component_id, :code, :acknowledged, :suspended, :active, :timestamp, :category, :priority
4
+ attr_reader :component_id, :code, :acknowledged, :suspended, :active, :timestamp, :category, :priority, :rvs
5
5
 
6
- def initialize component_id:, code:
7
- @component_id = component_id
6
+ def initialize component:, code:
7
+ @component = component
8
+ @component_id = component.c_id
8
9
  @code = code
10
+ @suspended = false
9
11
  @acknowledged = false
10
12
  @suspended = false
11
13
  @active = false
12
14
  @timestamp = nil
13
- @category = nil
14
- @priority = nil
15
+ @category = 'D'
16
+ @priority = 2
17
+ @rvs = []
15
18
  end
16
19
 
17
20
  def suspend
18
- @suspended = true
21
+ change, @suspended = !@suspended, true
22
+ update_timestamp if change
23
+ change
19
24
  end
20
25
 
21
26
  def resume
22
- @suspended = false
27
+ change, @suspended = @suspended, false
28
+ update_timestamp if change
29
+ change
23
30
  end
24
31
 
25
32
  def activate
26
- @active = true
33
+ change, @active = !@active, true
34
+ update_timestamp if change
35
+ change
27
36
  end
28
37
 
29
38
  def deactivate
30
- @active = false
39
+ change, @active = @active, false
40
+ update_timestamp if change
41
+ change
42
+ end
43
+
44
+ def update_timestamp
45
+ @timestamp = @component.node.clock.now
46
+ end
47
+
48
+ def to_message specialization:
49
+ Alarm.new(
50
+ 'cId' => @component_id,
51
+ 'aSp' => specialization,
52
+ 'aCId' => @code,
53
+ 'aTs' => Clock.to_s(@timestamp),
54
+ 'ack' => (@acknowledged ? 'Acknowledged' : 'notAcknowledged'),
55
+ 'sS' => (@suspended ? 'suspended' : 'notSuspended'),
56
+ 'aS' => (@active ? 'Active' : 'inActive'),
57
+ 'cat' => @category,
58
+ 'pri' => @priority.to_s,
59
+ 'rvs' => @rvs
60
+ )
31
61
  end
62
+
63
+ def differ_from_message? message
64
+ return true if @timestamp != message.attribute('aTs')
65
+ return true if message.attribute('ack') && @acknowledged != (message.attribute('ack') == 'True')
66
+ return true if message.attribute('sS') && @suspended != (message.attribute('sS') == 'True')
67
+ return true if message.attribute('aS') && @active != (message.attribute('aS') == 'True')
68
+ return true if message.attribute('cat') && @category != message.attribute('cat')
69
+ return true if message.attribute('pri') && @priority != message.attribute('pri').to_i
70
+ #return true @rvs = message.attribute('rvs')
71
+ false
72
+ end
73
+
74
+ # update from rsmp message
75
+ # component id, alarm code and specialization are not updated
76
+ def update_from_message message
77
+ unless differ_from_message? message
78
+ raise RepeatedAlarmError.new("no changes from previous alarm #{message.m_id_short}")
79
+ end
80
+ if Time.parse(message.attribute('aTs')) < Time.parse(message.attribute('aTs'))
81
+ raise TimestampError.new("timestamp is earlier than previous alarm #{message.m_id_short}")
82
+ end
83
+ ensure
84
+ @timestamp = message.attribute('aTs')
85
+ @acknowledged = message.attribute('ack') == 'True'
86
+ @suspended = message.attribute('sS') == 'True'
87
+ @active = message.attribute('aS') == 'True'
88
+ @category = message.attribute('cat')
89
+ @priority = message.attribute('pri').to_i
90
+ @rvs = message.attribute('rvs')
91
+ end
92
+
32
93
  end
33
94
  end
@@ -1,9 +1,7 @@
1
1
  module RSMP
2
-
3
2
  # RSMP component
4
-
5
3
  class Component < ComponentBase
6
- def initialize node:, id:, grouped: false
4
+ def initialize node:, id:, ntsOId: nil, xNId: nil, grouped: false
7
5
  super
8
6
  end
9
7
 
@@ -15,40 +13,38 @@ module RSMP
15
13
  raise UnknownStatus.new "Status #{status_code}/#{status_name} not implemented by #{self.class}"
16
14
  end
17
15
 
18
- def get_alarm_state alarm_code
19
- alarm = @alarms[alarm_code] ||= RSMP::AlarmState.new component_id: c_id, code: alarm_code
20
- end
21
-
22
16
  def suspend_alarm alarm_code
23
17
  alarm = get_alarm_state alarm_code
24
- return if alarm.suspended
25
- log "Suspending alarm #{alarm_code}", level: :info
26
- alarm.suspend
27
- @node.alarm_changed alarm
18
+ if alarm.suspend
19
+ log "Suspending alarm #{alarm_code}", level: :info
20
+ @node.alarm_suspended_or_resumed alarm
21
+ else
22
+ log "Alarm #{alarm_code} already suspended", level: :info
23
+ end
28
24
  end
29
25
 
30
26
  def resume_alarm alarm_code
31
27
  alarm = get_alarm_state alarm_code
32
- return unless alarm.suspended
33
- log "Resuming alarm #{alarm_code}", level: :info
34
- alarm.resume
35
- @node.alarm_changed alarm
28
+ if alarm.resume
29
+ log "Resuming alarm #{alarm_code}", level: :info
30
+ @node.alarm_suspended_or_resumed alarm
31
+ else
32
+ log "Alarm #{alarm_code} already resumed", level: :info
33
+ end
36
34
  end
37
35
 
38
36
  def activate_alarm alarm_code
39
37
  alarm = get_alarm_state alarm_code
40
- return if alarm.active
38
+ return unless alarm.activate
41
39
  log "Activating alarm #{alarm_code}", level: :info
42
- alarm.activate
43
- @node.alarm_changed alarm
40
+ @node.alarm_activated_or_deactivated alarm
44
41
  end
45
42
 
46
43
  def deactivate_alarm alarm_code
47
44
  alarm = get_alarm_state alarm_code
48
- return unless alarm.active
45
+ return unless alarm.deactivate
49
46
  log "Deactivating alarm #{alarm_code}", level: :info
50
- alarm.deactivate
51
- @node.alarm_changed alarm
47
+ @node.alarm_activated_or_deactivated alarm
52
48
  end
53
49
  end
54
50
  end
@@ -5,7 +5,8 @@ module RSMP
5
5
  class ComponentBase
6
6
  include Inspect
7
7
 
8
- attr_reader :c_id, :node, :alarms, :statuses, :aggregated_status, :aggregated_status_bools, :grouped
8
+ attr_reader :c_id, :ntsOId, :xNId, :node, :alarms, :statuses,
9
+ :aggregated_status, :aggregated_status_bools, :grouped
9
10
 
10
11
  AGGREGATED_STATUS_KEYS = [ :local_control,
11
12
  :communication_distruption,
@@ -16,12 +17,21 @@ module RSMP
16
17
  :rest,
17
18
  :not_connected ]
18
19
 
19
- def initialize node:, id:, grouped: false
20
+ def initialize node:, id:, ntsOId: nil, xNId: nil, grouped: false
21
+ if grouped==false && (ntsOId || xNId)
22
+ raise RSMP::ConfigurationError.new("ntsOId and xNId are only allowed for grouped objects")
23
+ end
20
24
  @c_id = id
25
+ @ntsOId = ntsOId
26
+ @xNId = xNId
21
27
  @node = node
22
28
  @grouped = grouped
23
- @alarms = {}
24
29
  clear_aggregated_status
30
+ @alarms = {}
31
+ end
32
+
33
+ def get_alarm_state alarm_code
34
+ alarm = @alarms[alarm_code] ||= RSMP::AlarmState.new component: self, code: alarm_code
25
35
  end
26
36
 
27
37
  def clear_aggregated_status
@@ -1,10 +1,9 @@
1
1
  module RSMP
2
-
3
2
  # A proxy to a remote RSMP component.
4
-
5
3
  class ComponentProxy < ComponentBase
6
4
  def initialize node:, id:, grouped: false
7
5
  super
6
+ @alarms = {}
8
7
  @statuses = {}
9
8
  @allow_repeat_updates = {}
10
9
  end
@@ -45,23 +44,12 @@ module RSMP
45
44
  @allow_repeat_updates[sCI].delete(n) if @allow_repeat_updates[sCI]
46
45
  end
47
46
  end
48
-
47
+
49
48
  # handle incoming alarm
50
49
  def handle_alarm message
51
- # code = message.attribute('aCId')
52
- # previous = @alarms[code]
53
- # if previous
54
- # unless message.differ?(previous)
55
- # raise RepeatedAlarmError.new("no changes from previous alarm #{previous.m_id_short}")
56
- # end
57
- # if Time.parse(message.attribute('aTs')) < Time.parse(previous.attribute('aTs'))
58
- # raise TimestampError.new("timestamp is earlier than previous alarm #{previous.m_id_short}")
59
- # end
60
- # end
61
- # p message
62
- # ensure
63
- # @alarms[code] = message
50
+ code = message.attribute('aCId')
51
+ alarm = get_alarm_state code
52
+ alarm.update_from_message message
64
53
  end
65
-
66
- end
54
+ end
67
55
  end
data/lib/rsmp/message.rb CHANGED
@@ -68,7 +68,13 @@ module RSMP
68
68
  when /Acknowledge/i
69
69
  AlarmAcknowledged.new attributes
70
70
  when /Suspend/i
71
- AlarmSuspend.new attributes
71
+ if attributes['sS'] =~ /suspended/i
72
+ AlarmSuspended.new attributes
73
+ elsif attributes['sS'] =~ /notSuspended/i
74
+ AlarmResumed.new attributes
75
+ else
76
+ AlarmSuspend.new attributes
77
+ end
72
78
  when /Resume/i
73
79
  AlarmResume.new attributes
74
80
  else
@@ -264,7 +270,23 @@ module RSMP
264
270
  end
265
271
  end
266
272
 
273
+ class AlarmSuspended < Alarm
274
+ def initialize attributes = {}
275
+ super({
276
+ "aSp" => "Suspend",
277
+ "sS" => "suspended"
278
+ }.merge attributes)
279
+ end
280
+ end
267
281
 
282
+ class AlarmResumed < Alarm
283
+ def initialize attributes = {}
284
+ super({
285
+ "aSp" => "Suspend",
286
+ "sS" => "notSuspended"
287
+ }.merge attributes)
288
+ end
289
+ end
268
290
 
269
291
  class Watchdog < Message
270
292
  def initialize attributes = {}
data/lib/rsmp/proxy.rb CHANGED
@@ -643,5 +643,13 @@ module RSMP
643
643
  return { sent: message }
644
644
  end
645
645
  end
646
+
647
+ def set_nts_message_attributes message
648
+ return unless @site && @site.main
649
+ ntsOId = @site.main.ntsOId
650
+ xNId = @site.main.xNId
651
+ message.attributes['ntsOId'] = ntsOId if ntsOId
652
+ message.attributes['xNId'] = xNId if xNId
653
+ end
646
654
  end
647
655
  end
data/lib/rsmp/site.rb CHANGED
@@ -93,23 +93,31 @@ module RSMP
93
93
  end
94
94
  end
95
95
 
96
- def alarm_state_to_message alarm_state
97
- Alarm.new(
96
+ def alarm_state_to_hash alarm_state
97
+ {
98
98
  'cId' => alarm_state.component_id,
99
- 'aTs' => clock.to_s,
100
99
  'aCId' => alarm_state.code,
101
- 'aSp' => (alarm_state.suspended ? 'Suspend' : 'Issue'),
100
+ 'aTs' => Clock.to_s(alarm_state.timestamp),
102
101
  'ack' => (alarm_state.acknowledged ? 'Acknowledged' : 'notAcknowledged'),
103
102
  'sS' => (alarm_state.suspended ? 'suspended' : 'notSuspended'),
104
103
  'aS' => (alarm_state.active ? 'Active' : 'inActive'),
105
- 'cat' => (alarm_state.category || 'D'),
106
- 'pri' => (alarm_state.priority || '2'),
107
- 'rvs' => []
108
- )
104
+ 'cat' => alarm_state.category,
105
+ 'pri' => alarm_state.priority.to_s,
106
+ 'rvs' => alarm_state.rvs
107
+ }
108
+ end
109
+
110
+ def alarm_suspended_or_resumed alarm_state
111
+ alarm = AlarmIssue.new( alarm_state_to_hash(alarm_state).merge('aSp' => 'Suspend') )
112
+ send_alarm alarm
113
+ end
114
+
115
+ def alarm_activated_or_deactivated alarm_state
116
+ alarm = AlarmIssue.new( alarm_state_to_hash(alarm_state).merge('aSp' => 'Issue') )
117
+ send_alarm alarm
109
118
  end
110
119
 
111
- def alarm_changed alarm_state
112
- alarm = alarm_state_to_message alarm_state
120
+ def send_alarm alarm
113
121
  @proxies.each do |proxy|
114
122
  proxy.send_message alarm if proxy.ready?
115
123
  end
@@ -63,7 +63,7 @@ module RSMP
63
63
  process_aggregated_status message
64
64
  when AggregatedStatusRequest
65
65
  will_not_handle message
66
- when Alarm
66
+ when AlarmIssue, AlarmSuspended, AlarmResumed
67
67
  process_alarm message
68
68
  when CommandResponse
69
69
  process_command_response message
@@ -114,13 +114,11 @@ module RSMP
114
114
  def request_aggregated_status component, options={}
115
115
  validate_ready 'request aggregated status'
116
116
  m_id = options[:m_id] || RSMP::Message.make_m_id
117
-
118
117
  message = RSMP::AggregatedStatusRequest.new({
119
- "ntsOId" => '',
120
- "xNId" => '',
121
- "cId" => component,
122
- "mId" => m_id
118
+ "cId" => component,
119
+ "mId" => m_id
123
120
  })
121
+ set_nts_message_attributes message
124
122
  send_and_optionally_collect message, options do |collect_options|
125
123
  AggregatedStatusCollector.new(
126
124
  self,
@@ -187,12 +185,11 @@ module RSMP
187
185
  request_list = status_list.map { |item| item.slice('sCI','n') }
188
186
 
189
187
  message = RSMP::StatusRequest.new({
190
- "ntsOId" => '',
191
- "xNId" => '',
192
188
  "cId" => component,
193
189
  "sS" => request_list,
194
190
  "mId" => m_id
195
191
  })
192
+ set_nts_message_attributes message
196
193
  send_and_optionally_collect message, options do |collect_options|
197
194
  StatusCollector.new(
198
195
  self,
@@ -232,12 +229,11 @@ module RSMP
232
229
  component.allow_repeat_updates subscribe_list
233
230
 
234
231
  message = RSMP::StatusSubscribe.new({
235
- "ntsOId" => '',
236
- "xNId" => '',
237
232
  "cId" => component_id,
238
233
  "sS" => subscribe_list,
239
234
  'mId' => m_id
240
235
  })
236
+ set_nts_message_attributes message
241
237
  send_and_optionally_collect message, options do |collect_options|
242
238
  StatusCollector.new(
243
239
  self,
@@ -262,11 +258,10 @@ module RSMP
262
258
  end
263
259
 
264
260
  message = RSMP::StatusUnsubscribe.new({
265
- "ntsOId" => '',
266
- "xNId" => '',
267
261
  "cId" => component_id,
268
262
  "sS" => status_list
269
263
  })
264
+ set_nts_message_attributes message
270
265
  send_message message, validate: options[:validate]
271
266
  message
272
267
  end
@@ -292,12 +287,11 @@ module RSMP
292
287
  validate_ready 'send command'
293
288
  m_id = options[:m_id] || RSMP::Message.make_m_id
294
289
  message = RSMP::CommandRequest.new({
295
- "ntsOId" => '',
296
- "xNId" => '',
297
290
  "cId" => component,
298
291
  "arg" => command_list,
299
292
  "mId" => m_id
300
293
  })
294
+ set_nts_message_attributes message
301
295
  send_and_optionally_collect message, options do |collect_options|
302
296
  CommandResponseCollector.new(
303
297
  self,
@@ -105,7 +105,7 @@ module RSMP
105
105
  process_status_subcribe message
106
106
  when StatusUnsubscribe
107
107
  process_status_unsubcribe message
108
- when AlarmAcknowledged, AlarmSuspend, AlarmResume, AlarmRequest
108
+ when Alarm, AlarmAcknowledged, AlarmSuspend, AlarmResume, AlarmRequest
109
109
  process_alarm message
110
110
  else
111
111
  super message
@@ -160,7 +160,7 @@ module RSMP
160
160
  "se" => component.aggregated_status_bools,
161
161
  "mId" => m_id,
162
162
  })
163
-
163
+ set_nts_message_attributes message
164
164
  send_and_optionally_collect message, options do |collect_options|
165
165
  Collector.new self, collect_options.merge(task:@task, type: 'MessageAck')
166
166
  end
@@ -9,9 +9,9 @@ module RSMP
9
9
  :functional_position,
10
10
  :startup_sequence_active, :startup_sequence, :startup_sequence_pos
11
11
 
12
- def initialize node:, id:, cycle_time: 10, signal_plans:,
12
+ def initialize node:, id:, ntsOId: nil, xNId: nil, cycle_time: 10, signal_plans:,
13
13
  startup_sequence:, live_output:nil, inputs:{}
14
- super node: node, id: id, grouped: true
14
+ super node: node, id: id, ntsOId: ntsOId, xNId: xNId, grouped: true
15
15
  @signal_groups = []
16
16
  @detector_logics = []
17
17
  @plans = signal_plans
@@ -52,7 +52,10 @@ module RSMP
52
52
  def build_component id:, type:, settings:{}
53
53
  component = case type
54
54
  when 'main'
55
- @main = TrafficController.new node: self, id: id,
55
+ @main = TrafficController.new node: self,
56
+ id: id,
57
+ ntsOId: settings['ntsOId'],
58
+ xNId: settings['xNId'],
56
59
  cycle_time: settings['cycle_time'],
57
60
  startup_sequence: @startup_sequence,
58
61
  signal_plans: @signal_plans,
data/lib/rsmp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module RSMP
2
- VERSION = "0.12.3"
2
+ VERSION = "0.13.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rsmp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.3
4
+ version: 0.13.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Emil Tin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-04-05 00:00:00.000000000 Z
11
+ date: 2022-05-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async