rsmp 0.3.4 → 0.3.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/lib/rsmp/component.rb +14 -4
- data/lib/rsmp/components.rb +16 -3
- data/lib/rsmp/error.rb +3 -0
- data/lib/rsmp/message.rb +60 -5
- data/lib/rsmp/proxy.rb +9 -4
- data/lib/rsmp/site.rb +1 -1
- data/lib/rsmp/site_proxy.rb +15 -28
- data/lib/rsmp/supervisor_proxy.rb +0 -10
- data/lib/rsmp/tlc.rb +4 -2
- data/lib/rsmp/version.rb +1 -1
- data/lib/rsmp.rb +0 -1
- data/test.rb +27 -0
- metadata +4 -4
- data/lib/rsmp/alarm.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5e0675af3b49828fa77194f4dbec427378e6cf79e8a4923ed452cf28a39052a2
|
4
|
+
data.tar.gz: d0a681be3741ac8a87c4d1b17d1db75218cae8d8df34a0f6365052ff59578235
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4012fd3e7f6c4c39c6f473ac09b115fbf67bf1651803c421e10f37e9e17b78b3d096dc7a4c36e125117f30daf5baf2e0e755bd83a06926a143ae7cb4bed91def
|
7
|
+
data.tar.gz: be15a086298d27b3cd8530685a8b654519540ac3d64f1aecd62399d513bc4c323f200e9d606c0afa28e1efc57a8d6e51c9f7dd77c4893ceb493c2613792c6567
|
data/Gemfile.lock
CHANGED
data/lib/rsmp/component.rb
CHANGED
@@ -13,7 +13,7 @@ module RSMP
|
|
13
13
|
:rest,
|
14
14
|
:not_connected ]
|
15
15
|
|
16
|
-
def initialize node:, id:, grouped:
|
16
|
+
def initialize node:, id:, grouped: false
|
17
17
|
@c_id = id
|
18
18
|
@node = node
|
19
19
|
@grouped = grouped
|
@@ -57,9 +57,6 @@ module RSMP
|
|
57
57
|
def aggregated_status_changed options={}
|
58
58
|
@node.aggregated_status_changed self, options
|
59
59
|
end
|
60
|
-
|
61
|
-
def alarm code:, status:
|
62
|
-
end
|
63
60
|
|
64
61
|
def log str, options
|
65
62
|
@node.log str, options
|
@@ -73,5 +70,18 @@ module RSMP
|
|
73
70
|
raise UnknownStatus.new "Status #{status_code}/#{status_name} not implemented by #{self.class}"
|
74
71
|
end
|
75
72
|
|
73
|
+
def handle_alarm message
|
74
|
+
code = message.attribute('aCId')
|
75
|
+
alarm = @alarms[code]
|
76
|
+
if alarm
|
77
|
+
if alarm.differ? message
|
78
|
+
@alarms[code] = alarm
|
79
|
+
else
|
80
|
+
raise RepeatedAlarmError.new("no changes from previous alarm #{alarm.m_id_short}")
|
81
|
+
end
|
82
|
+
else
|
83
|
+
@alarms[code] = message
|
84
|
+
end
|
85
|
+
end
|
76
86
|
end
|
77
87
|
end
|
data/lib/rsmp/components.rb
CHANGED
@@ -38,10 +38,23 @@ module RSMP
|
|
38
38
|
Component.new id:id, node: self, grouped: type=='main'
|
39
39
|
end
|
40
40
|
|
41
|
-
def
|
41
|
+
def infer_component_type component_id
|
42
|
+
Component
|
43
|
+
end
|
44
|
+
|
45
|
+
def find_component component_id, build: true
|
42
46
|
component = @components[component_id]
|
43
|
-
|
44
|
-
|
47
|
+
return component if component
|
48
|
+
if build
|
49
|
+
inferred = infer_component_type component_id
|
50
|
+
component = inferred.new node: self, id: component_id
|
51
|
+
@components[ component_id] = component
|
52
|
+
class_name = component.class.name.split('::').last
|
53
|
+
log "Inferred #{class_name} component #{component_id}", level: :info
|
54
|
+
component
|
55
|
+
else
|
56
|
+
raise UnknownComponent.new("Component #{component_id} not found") unless component
|
57
|
+
end
|
45
58
|
end
|
46
59
|
|
47
60
|
end
|
data/lib/rsmp/error.rb
CHANGED
data/lib/rsmp/message.rb
CHANGED
@@ -36,7 +36,7 @@ module RSMP
|
|
36
36
|
when "Watchdog"
|
37
37
|
message = Watchdog.new attributes
|
38
38
|
when "Alarm"
|
39
|
-
message =
|
39
|
+
message = self.build_alarm attributes
|
40
40
|
when "CommandRequest"
|
41
41
|
message = CommandRequest.new attributes
|
42
42
|
when "CommandResponse"
|
@@ -59,6 +59,23 @@ module RSMP
|
|
59
59
|
message
|
60
60
|
end
|
61
61
|
|
62
|
+
def self.build_alarm attributes
|
63
|
+
case attributes["aSp"]
|
64
|
+
when 'Issue'
|
65
|
+
AlarmIssue.new attributes
|
66
|
+
when 'Request'
|
67
|
+
AlarmRequest.new attributes
|
68
|
+
when 'Acknowledge'
|
69
|
+
AlarmAcknowledged.new attributes
|
70
|
+
when 'Suspend'
|
71
|
+
AlarmSuspend.new attributes
|
72
|
+
when 'Resume'
|
73
|
+
AlarmResume.new attributes
|
74
|
+
else
|
75
|
+
Alarm.new attributes
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
62
79
|
def type
|
63
80
|
@attributes["type"]
|
64
81
|
end
|
@@ -191,26 +208,64 @@ module RSMP
|
|
191
208
|
def initialize attributes = {}
|
192
209
|
super({
|
193
210
|
"type" => "Alarm",
|
211
|
+
"ntsOId" => '',
|
212
|
+
"xNId" => '',
|
213
|
+
"xACId" => '',
|
214
|
+
"xNACId" => ''
|
194
215
|
}.merge attributes)
|
195
216
|
end
|
217
|
+
|
218
|
+
def differ? from
|
219
|
+
%w{aSp aCId ack aS sS aTs cat pri}.each do |key|
|
220
|
+
return true if attribute(key).downcase != from.attribute(key).downcase
|
221
|
+
end
|
222
|
+
return true if attribute('rvs') != from.attribute('rvs')
|
223
|
+
false
|
224
|
+
end
|
196
225
|
end
|
197
226
|
|
198
|
-
class
|
227
|
+
class AlarmIssue < Alarm
|
199
228
|
def initialize attributes = {}
|
200
229
|
super({
|
201
|
-
"
|
230
|
+
"aSp" => "Issue",
|
202
231
|
}.merge attributes)
|
203
232
|
end
|
204
233
|
end
|
205
234
|
|
206
|
-
class
|
235
|
+
class AlarmRequest < Alarm
|
207
236
|
def initialize attributes = {}
|
208
237
|
super({
|
209
|
-
"
|
238
|
+
"aSp" => "Request",
|
239
|
+
}.merge attributes)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
class AlarmAcknowledged < Alarm
|
244
|
+
def initialize attributes = {}
|
245
|
+
super({
|
246
|
+
"aSp" => "Acknowledge",
|
210
247
|
}.merge attributes)
|
211
248
|
end
|
212
249
|
end
|
213
250
|
|
251
|
+
class AlarmSuspend < Alarm
|
252
|
+
def initialize attributes = {}
|
253
|
+
super({
|
254
|
+
"aSp" => "Suspend",
|
255
|
+
}.merge attributes)
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
class AlarmResume < Alarm
|
260
|
+
def initialize attributes = {}
|
261
|
+
super({
|
262
|
+
"aSp" => "Resume",
|
263
|
+
}.merge attributes)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
|
268
|
+
|
214
269
|
class Watchdog < Message
|
215
270
|
def initialize attributes = {}
|
216
271
|
super({
|
data/lib/rsmp/proxy.rb
CHANGED
@@ -73,6 +73,11 @@ module RSMP
|
|
73
73
|
@state == :ready
|
74
74
|
end
|
75
75
|
|
76
|
+
def connected?
|
77
|
+
@state == :starting || @state == :ready
|
78
|
+
end
|
79
|
+
|
80
|
+
|
76
81
|
def start
|
77
82
|
set_state :starting
|
78
83
|
end
|
@@ -118,7 +123,6 @@ module RSMP
|
|
118
123
|
task.annotate "reader"
|
119
124
|
@stream ||= Async::IO::Stream.new(@socket)
|
120
125
|
@protocol ||= Async::IO::Protocol::Line.new(@stream,WRAPPING_DELIMITER) # rsmp messages are json terminated with a form-feed
|
121
|
-
|
122
126
|
while json = @protocol.read_line
|
123
127
|
beginning = Time.now
|
124
128
|
message = process_packet json
|
@@ -267,12 +271,13 @@ module RSMP
|
|
267
271
|
end
|
268
272
|
|
269
273
|
def send_message message, reason=nil, validate: true
|
274
|
+
raise NotReady unless connected?
|
270
275
|
raise IOError unless @protocol
|
271
276
|
message.direction = :out
|
272
277
|
message.generate_json
|
273
278
|
message.validate get_schemas unless validate==false
|
274
|
-
expect_acknowledgement message
|
275
279
|
@protocol.write_lines message.json
|
280
|
+
expect_acknowledgement message
|
276
281
|
notify message
|
277
282
|
log_send message, reason
|
278
283
|
rescue EOFError, IOError
|
@@ -303,9 +308,9 @@ module RSMP
|
|
303
308
|
end
|
304
309
|
|
305
310
|
def should_validate_ingoing_message? message
|
306
|
-
return
|
311
|
+
return true unless @site_settings
|
307
312
|
skip = @site_settings.dig('skip_validation')
|
308
|
-
return
|
313
|
+
return true unless skip
|
309
314
|
klass = message.class.name.split('::').last
|
310
315
|
!skip.include?(klass)
|
311
316
|
end
|
data/lib/rsmp/site.rb
CHANGED
data/lib/rsmp/site_proxy.rb
CHANGED
@@ -125,17 +125,11 @@ module RSMP
|
|
125
125
|
se = message.attribute("se")
|
126
126
|
validate_aggregated_status(message,se) == false
|
127
127
|
c_id = message.attributes["cId"]
|
128
|
-
component =
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
log "Adding component #{c_id} to site #{@site_id}", level: :info
|
134
|
-
else
|
135
|
-
reason = "component #{c_id} not found"
|
136
|
-
dont_acknowledge message, "Ignoring #{message.type}:", reason
|
137
|
-
return
|
138
|
-
end
|
128
|
+
component = find_component c_id
|
129
|
+
unless component
|
130
|
+
reason = "component #{c_id} not found"
|
131
|
+
dont_acknowledge message, "Ignoring #{message.type}:", reason
|
132
|
+
return
|
139
133
|
end
|
140
134
|
|
141
135
|
component.set_aggregated_status_bools se
|
@@ -148,11 +142,17 @@ module RSMP
|
|
148
142
|
end
|
149
143
|
|
150
144
|
def process_alarm message
|
145
|
+
component = find_component message.attribute("cId")
|
146
|
+
status = ["ack","aS","sS"].map { |key| message.attribute(key) }.join(',')
|
147
|
+
component.handle_alarm message
|
151
148
|
alarm_code = message.attribute("aCId")
|
152
149
|
asp = message.attribute("aSp")
|
153
|
-
status = ["ack","aS","sS"].map { |key| message.attribute(key) }.join(',')
|
154
150
|
log "Received #{message.type}, #{alarm_code} #{asp} [#{status}]", message: message, level: :log
|
155
151
|
acknowledge message
|
152
|
+
rescue RSMP::RepeatedAlarmError => e
|
153
|
+
str = "Rejected #{message.type} message, "
|
154
|
+
dont_acknowledge message, str, "#{e}"
|
155
|
+
notify_error e.exception("#{str}#{e.message} #{message.json}")
|
156
156
|
end
|
157
157
|
|
158
158
|
def version_acknowledged
|
@@ -241,13 +241,8 @@ module RSMP
|
|
241
241
|
|
242
242
|
def send_alarm_acknowledgement component, alarm_code, options={}
|
243
243
|
message = RSMP::AlarmAcknowledged.new({
|
244
|
-
"ntsOId" => '',
|
245
|
-
"xNId" => '',
|
246
244
|
"cId" => component,
|
247
245
|
"aCId" => alarm_code,
|
248
|
-
"xACId" => '',
|
249
|
-
"xNACId" => '',
|
250
|
-
"aSp" => 'Acknowledge'
|
251
246
|
})
|
252
247
|
send_message message, validate: options[:validate]
|
253
248
|
message
|
@@ -340,20 +335,12 @@ module RSMP
|
|
340
335
|
@supervisor.notify_error e, options if @supervisor
|
341
336
|
end
|
342
337
|
|
343
|
-
def
|
344
|
-
|
345
|
-
message = collect(parent_task,options.merge(type: "Alarm", with_message: true, num: 1)) do |message|
|
346
|
-
# TODO check components
|
347
|
-
matching_alarm = nil
|
348
|
-
alarm = message
|
338
|
+
def collect_alarms parent_task, options={}
|
339
|
+
collect(parent_task,options.merge(type: "Alarm")) do |alarm|
|
349
340
|
next if options[:aCId] && options[:aCId] != alarm.attribute("aCId")
|
350
341
|
next if options[:aSp] && options[:aSp] != alarm.attribute("aSp")
|
351
342
|
next if options[:aS] && options[:aS] != alarm.attribute("aS")
|
352
|
-
|
353
|
-
break
|
354
|
-
end
|
355
|
-
if item
|
356
|
-
{ message: message, status: matching_alarm }
|
343
|
+
true
|
357
344
|
end
|
358
345
|
end
|
359
346
|
|
@@ -363,16 +363,6 @@ module RSMP
|
|
363
363
|
end
|
364
364
|
end
|
365
365
|
|
366
|
-
def send_alarm
|
367
|
-
message = Alarm.new({
|
368
|
-
"aSTS"=>clock.to_s,
|
369
|
-
"fP"=>nil,
|
370
|
-
"fS"=>nil,
|
371
|
-
"se"=>@site.aggregated_status_bools
|
372
|
-
})
|
373
|
-
send_message message
|
374
|
-
end
|
375
|
-
|
376
366
|
def sxl_version
|
377
367
|
@site_settings['sxl_version']
|
378
368
|
end
|
data/lib/rsmp/tlc.rb
CHANGED
@@ -5,7 +5,7 @@ module RSMP
|
|
5
5
|
class TrafficController < Component
|
6
6
|
attr_reader :pos, :cycle_time
|
7
7
|
|
8
|
-
def initialize node:, id:, cycle_time:
|
8
|
+
def initialize node:, id:, cycle_time: 10
|
9
9
|
super node: node, id: id, grouped: true
|
10
10
|
@signal_groups = []
|
11
11
|
@detector_logics = []
|
@@ -625,13 +625,15 @@ module RSMP
|
|
625
625
|
class SignalGroup < Component
|
626
626
|
attr_reader :plan, :state
|
627
627
|
|
628
|
-
|
628
|
+
# plan is a string, with each character representing a signal phase at a particular second in the cycle
|
629
|
+
def initialize node:, id:, plan: nil
|
629
630
|
super node: node, id: id, grouped: false
|
630
631
|
@plan = plan
|
631
632
|
move 0
|
632
633
|
end
|
633
634
|
|
634
635
|
def get_state pos
|
636
|
+
return 'a' unless @plan # if no plan, use phase a, which means disabled/dark
|
635
637
|
if pos > @plan.length
|
636
638
|
'.'
|
637
639
|
else
|
data/lib/rsmp/version.rb
CHANGED
data/lib/rsmp.rb
CHANGED
data/test.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
class A
|
2
|
+
def go &block
|
3
|
+
@block = block # block will be converted automatically to a Proc
|
4
|
+
indirect
|
5
|
+
end
|
6
|
+
|
7
|
+
def call
|
8
|
+
@block.call
|
9
|
+
end
|
10
|
+
|
11
|
+
def indirect
|
12
|
+
call
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
a = A.new
|
18
|
+
|
19
|
+
a.go do
|
20
|
+
break # this is ok. break causes the block to exit, and the encasing method to return - go() will exit
|
21
|
+
end
|
22
|
+
|
23
|
+
# this raises an error. the block we passed to go() will be called again, and it tries to break
|
24
|
+
# but we're not inside a method we can exit from
|
25
|
+
|
26
|
+
|
27
|
+
a.indirect
|
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.3.
|
4
|
+
version: 0.3.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Emil Tin
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-10-
|
11
|
+
date: 2021-10-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: async
|
@@ -203,7 +203,6 @@ files:
|
|
203
203
|
- documentation/message_distribution.md
|
204
204
|
- exe/rsmp
|
205
205
|
- lib/rsmp.rb
|
206
|
-
- lib/rsmp/alarm.rb
|
207
206
|
- lib/rsmp/archive.rb
|
208
207
|
- lib/rsmp/cli.rb
|
209
208
|
- lib/rsmp/collector.rb
|
@@ -232,6 +231,7 @@ files:
|
|
232
231
|
- lib/rsmp/version.rb
|
233
232
|
- lib/rsmp/wait.rb
|
234
233
|
- rsmp.gemspec
|
234
|
+
- test.rb
|
235
235
|
homepage: https://github.com/rsmp-nordic/rsmp
|
236
236
|
licenses:
|
237
237
|
- MIT
|
@@ -255,7 +255,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
255
255
|
- !ruby/object:Gem::Version
|
256
256
|
version: '0'
|
257
257
|
requirements: []
|
258
|
-
rubygems_version: 3.2.
|
258
|
+
rubygems_version: 3.2.26
|
259
259
|
signing_key:
|
260
260
|
specification_version: 4
|
261
261
|
summary: RoadSide Message Protocol (RSMP) library.
|
data/lib/rsmp/alarm.rb
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
# RSMP Alarm. Manages the various states an alarm can be in.
|
2
|
-
|
3
|
-
module RSMP
|
4
|
-
class Alarm
|
5
|
-
|
6
|
-
def initialize code: code, blocked: blocked=false, suspended: suspended=false, acknowledged: acknowledged=false
|
7
|
-
@code = code
|
8
|
-
@code = code
|
9
|
-
@blocked = blocked
|
10
|
-
@suspended = suspended
|
11
|
-
@acknowledged = acknowledged
|
12
|
-
end
|
13
|
-
|
14
|
-
end
|
15
|
-
end
|