rsmp 0.9.9 → 0.10.1
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/config/tlc.yaml +1 -0
- data/lib/rsmp/component.rb +22 -0
- data/lib/rsmp/site.rb +6 -0
- data/lib/rsmp/supervisor_proxy.rb +6 -0
- data/lib/rsmp/tlc/inputs.rb +134 -0
- data/lib/rsmp/tlc/traffic_controller.rb +44 -49
- data/lib/rsmp/version.rb +1 -1
- data/lib/rsmp.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 58dea443fbf263b26902f047bc4b9127add5b43eea514be23e8f1c1354b34686
|
4
|
+
data.tar.gz: be065deb840d556e81194ca9862616d48fb5be475167899c155295a1b2276a5d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 594fc45b7d42a0ad33c23ac2789c0b090a72afa5fb5355a9543586272f5623f4ea58a37265bd79c74c3cb0efe3e07d731265ca01c56188eb62084f1694ee3e09
|
7
|
+
data.tar.gz: aac8c6bc88b8498139232e2c131626f7d9e1663aeea1c85fbce579b499d21a4bc40ebbcb064281b34009dd413d3a79a1a4191f2c771ae3fa5253180317fa8436
|
data/Gemfile.lock
CHANGED
data/config/tlc.yaml
CHANGED
data/lib/rsmp/component.rb
CHANGED
@@ -77,6 +77,7 @@ module RSMP
|
|
77
77
|
raise UnknownStatus.new "Status #{status_code}/#{status_name} not implemented by #{self.class}"
|
78
78
|
end
|
79
79
|
|
80
|
+
# handle incoming alarm
|
80
81
|
def handle_alarm message
|
81
82
|
code = message.attribute('aCId')
|
82
83
|
previous = @alarms[code]
|
@@ -92,6 +93,27 @@ module RSMP
|
|
92
93
|
@alarms[code] = message
|
93
94
|
end
|
94
95
|
|
96
|
+
# set alarm
|
97
|
+
def send_alarm code:, status:
|
98
|
+
# TODO
|
99
|
+
# we need to manage the state of alarms internally (an ALarm class probably),
|
100
|
+
# and handle request from the supervisor to suspend and resume alarms etc.
|
101
|
+
# when this state changes, we then send an alarm message
|
102
|
+
alarm = Alarm.new(
|
103
|
+
'cId' => c_id,
|
104
|
+
'aTs' => @node.clock.to_s,
|
105
|
+
'aCId' => code,
|
106
|
+
'aSp' => 'Issue',
|
107
|
+
'ack' => 'Acknowledged',
|
108
|
+
'sS' => 'notSuspended',
|
109
|
+
'aS' => status,
|
110
|
+
'cat' => 'D',
|
111
|
+
'pri' => '2',
|
112
|
+
'rvs' => []
|
113
|
+
)
|
114
|
+
@node.alarm_changed self, alarm
|
115
|
+
end
|
116
|
+
|
95
117
|
# Handle an incoming status respone, by storing the values
|
96
118
|
def handle_status_response message
|
97
119
|
store_status message, check_repeated: false
|
data/lib/rsmp/site.rb
CHANGED
@@ -93,6 +93,12 @@ module RSMP
|
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
|
+
def alarm_changed component, alarm
|
97
|
+
@proxies.each do |proxy|
|
98
|
+
proxy.send_alarm component, alarm if proxy.ready?
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
96
102
|
def connect_to_supervisor task, supervisor_settings
|
97
103
|
proxy = build_proxy({
|
98
104
|
site: self,
|
@@ -172,6 +172,12 @@ module RSMP
|
|
172
172
|
end
|
173
173
|
end
|
174
174
|
|
175
|
+
def send_alarm component, alarm, options={}
|
176
|
+
send_and_optionally_collect alarm, options do |collect_options|
|
177
|
+
Collector.new self, collect_options.merge(task:@task, type: 'MessageAck')
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
175
181
|
def process_aggregated_status message
|
176
182
|
se = message.attribute("se")
|
177
183
|
validate_aggregated_status(message,se) == false
|
@@ -0,0 +1,134 @@
|
|
1
|
+
module RSMP
|
2
|
+
module TLC
|
3
|
+
# class that maintains the state of TLC inputs
|
4
|
+
# indexing is 1-based since that's how the RSMP messages are specified
|
5
|
+
class Inputs
|
6
|
+
attr_reader :size
|
7
|
+
|
8
|
+
def initialize size
|
9
|
+
@size = size
|
10
|
+
reset
|
11
|
+
end
|
12
|
+
|
13
|
+
def reset
|
14
|
+
string_size = @size+1
|
15
|
+
@value = '0'*string_size
|
16
|
+
@forced = '0'*string_size
|
17
|
+
@forced_value = '0'*string_size
|
18
|
+
@actual = '0'*string_size
|
19
|
+
end
|
20
|
+
|
21
|
+
def set input, value
|
22
|
+
check_input input
|
23
|
+
report_change(input) do
|
24
|
+
@value[input] = to_digit value
|
25
|
+
update_actual input
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def set_forcing input, force=true, forced_value=true
|
30
|
+
check_input input
|
31
|
+
report_change(input) do
|
32
|
+
@forced[input] = to_digit force
|
33
|
+
@forced_value[input] = to_digit forced_value
|
34
|
+
update_actual input
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def force input, forced_value=true
|
39
|
+
report_change(input) do
|
40
|
+
set_forcing input, true, forced_value
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def release input
|
45
|
+
report_change(input) do
|
46
|
+
set_forcing input, false, false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def value input
|
51
|
+
check_input input
|
52
|
+
from_digit @value[input]
|
53
|
+
end
|
54
|
+
|
55
|
+
def forced? input
|
56
|
+
check_input input
|
57
|
+
from_digit @forced[input]
|
58
|
+
end
|
59
|
+
|
60
|
+
def forced_value input
|
61
|
+
check_input input
|
62
|
+
from_digit @forced_value[input]
|
63
|
+
end
|
64
|
+
|
65
|
+
def actual input
|
66
|
+
check_input input
|
67
|
+
from_digit @actual[input]
|
68
|
+
end
|
69
|
+
|
70
|
+
def report input
|
71
|
+
{
|
72
|
+
value: value(input),
|
73
|
+
forced: forced?(input),
|
74
|
+
forced_value: forced_value(input),
|
75
|
+
actual:actual(input)
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
def value_string
|
80
|
+
@value[1..-1]
|
81
|
+
end
|
82
|
+
|
83
|
+
def value_string
|
84
|
+
@value[1..-1]
|
85
|
+
end
|
86
|
+
|
87
|
+
def forced_string
|
88
|
+
@forced[1..-1]
|
89
|
+
end
|
90
|
+
|
91
|
+
def forced_value_string
|
92
|
+
@forced[1..-1]
|
93
|
+
end
|
94
|
+
|
95
|
+
def actual_string
|
96
|
+
@actual[1..-1]
|
97
|
+
end
|
98
|
+
|
99
|
+
protected
|
100
|
+
|
101
|
+
def check_input input
|
102
|
+
raise ArgumentError.new("Input index #{input} must be in the range 1-#{@size}") if input<1 || input>@size
|
103
|
+
end
|
104
|
+
|
105
|
+
def from_digit input
|
106
|
+
input == '1'
|
107
|
+
end
|
108
|
+
|
109
|
+
def to_digit input
|
110
|
+
input ? '1' : '0'
|
111
|
+
end
|
112
|
+
|
113
|
+
def update_actual input
|
114
|
+
if from_digit @forced[input]
|
115
|
+
@actual[input] = @forced_value[input]
|
116
|
+
else
|
117
|
+
@actual[input] = @value[input]
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def report_change input, &block
|
122
|
+
before = @actual[input]
|
123
|
+
yield
|
124
|
+
if @actual[input] != before
|
125
|
+
from_digit @actual[input]
|
126
|
+
else
|
127
|
+
nil
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
|
@@ -19,12 +19,12 @@ module RSMP
|
|
19
19
|
@num_traffic_situations = 1
|
20
20
|
|
21
21
|
if inputs
|
22
|
-
|
22
|
+
num_inputs = inputs['total']
|
23
23
|
@input_programming = inputs['programming']
|
24
24
|
else
|
25
|
-
@num_inputs = 8
|
26
25
|
@input_programming = nil
|
27
26
|
end
|
27
|
+
@inputs = TLC::Inputs.new num_inputs || 8
|
28
28
|
|
29
29
|
@startup_sequence = startup_sequence
|
30
30
|
@live_output = live_output
|
@@ -48,25 +48,18 @@ module RSMP
|
|
48
48
|
|
49
49
|
def reset
|
50
50
|
reset_modes
|
51
|
-
|
52
51
|
@cycle_counter = 0
|
53
52
|
@plan = 1
|
54
53
|
@intersection = 0
|
55
54
|
@emergency_route = false
|
56
55
|
@emergency_route_number = 0
|
57
56
|
@traffic_situation = 0
|
58
|
-
|
59
|
-
@inputs = '0'*@num_inputs
|
60
|
-
@input_activations = '0'*@num_inputs
|
61
|
-
@input_forced = '0'*@num_inputs
|
62
|
-
@input_forced_values = '0'*@num_inputs
|
63
|
-
@input_results = '0'*@num_inputs
|
64
|
-
|
65
57
|
@day_time_table = {}
|
66
58
|
@startup_sequence_active = false
|
67
59
|
@startup_sequence_initiated_at = nil
|
68
60
|
@startup_sequence_pos = 0
|
69
61
|
@time_int = nil
|
62
|
+
@inputs.reset
|
70
63
|
end
|
71
64
|
|
72
65
|
def dark?
|
@@ -263,43 +256,36 @@ module RSMP
|
|
263
256
|
end
|
264
257
|
end
|
265
258
|
|
266
|
-
def
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
259
|
+
def input_logic input, change
|
260
|
+
return unless @input_programming && change != nil
|
261
|
+
actions = @input_programming[input]
|
262
|
+
return unless actions
|
263
|
+
if actions['raise']
|
264
|
+
alarm_code = actions['raise']
|
265
|
+
if change
|
266
|
+
log "Activating alarm #{alarm_code}, because input #{input} was activated", level: :info
|
267
|
+
send_alarm code:alarm_code, status:'Active'
|
268
|
+
else
|
269
|
+
log "Deactivating alarm #{alarm_code}, because input #{input} was deactivated", level: :info
|
270
|
+
send_alarm code:alarm_code, status:'inActive'
|
271
|
+
end
|
273
272
|
end
|
274
273
|
end
|
275
274
|
|
276
275
|
def handle_m0006 arg
|
277
276
|
@node.verify_security_code 2, arg['securityCode']
|
278
277
|
input = arg['input'].to_i
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
recompute_input idx
|
285
|
-
activate = @input_activations[idx] == '1'
|
286
|
-
if activate
|
278
|
+
status = string_to_bool arg['status']
|
279
|
+
unless input>=1 && input<=@inputs.size
|
280
|
+
raise MessageRejected.new("Input must be in the range 1-#{@inputs.size}")
|
281
|
+
end
|
282
|
+
if status
|
287
283
|
log "Activating input #{input}", level: :info
|
288
284
|
else
|
289
285
|
log "Deactivating input #{input}", level: :info
|
290
286
|
end
|
291
|
-
|
292
|
-
if
|
293
|
-
actions = @input_programming[input]
|
294
|
-
if actions && actions['raise']
|
295
|
-
alarm_code = actions['raise']
|
296
|
-
if activate
|
297
|
-
log "Activating alarm #{alarm_code}, due to input #{input} programming", level: :info
|
298
|
-
else
|
299
|
-
log "Deactivating alarm #{alarm_code}, due to input #{input} programming", level: :info
|
300
|
-
end
|
301
|
-
end
|
302
|
-
end
|
287
|
+
change = @inputs.set input, status
|
288
|
+
input_logic input, change if change != nil
|
303
289
|
end
|
304
290
|
|
305
291
|
def handle_m0007 arg
|
@@ -361,6 +347,17 @@ module RSMP
|
|
361
347
|
@node.verify_security_code 2, arg['securityCode']
|
362
348
|
end
|
363
349
|
|
350
|
+
def string_to_bool bool_str
|
351
|
+
case bool_str
|
352
|
+
when 'True'
|
353
|
+
true
|
354
|
+
when 'False'
|
355
|
+
false
|
356
|
+
else
|
357
|
+
raise RSMP::MessageRejected.new "Invalid boolean '#{bool}', must be 'True' or 'False'"
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
364
361
|
def bool_string_to_digit bool
|
365
362
|
case bool
|
366
363
|
when 'True'
|
@@ -379,20 +376,18 @@ module RSMP
|
|
379
376
|
def handle_m0019 arg
|
380
377
|
@node.verify_security_code 2, arg['securityCode']
|
381
378
|
input = arg['input'].to_i
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
@input_forced[idx] = bool_string_to_digit arg['status']
|
387
|
-
if @input_forced[idx]
|
388
|
-
@input_forced_values[idx] = bool_string_to_digit arg['inputValue']
|
379
|
+
force = string_to_bool arg['status']
|
380
|
+
forced_value = string_to_bool arg['inputValue']
|
381
|
+
unless input>=1 && input<=@inputs.size
|
382
|
+
raise MessageRejected.new("Input must be in the range 1-#{@inputs.size}")
|
389
383
|
end
|
390
|
-
|
391
|
-
|
392
|
-
log "Forcing input #{input} to #{@input_forced_values[idx]}", level: :info
|
384
|
+
if force
|
385
|
+
log "Forcing input #{input} to #{forced_value}", level: :info
|
393
386
|
else
|
394
387
|
log "Releasing input #{input}", level: :info
|
395
388
|
end
|
389
|
+
change = @inputs.set_forcing input, force, forced_value
|
390
|
+
input_logic input, change if change != nil
|
396
391
|
end
|
397
392
|
|
398
393
|
def handle_m0020 arg
|
@@ -502,7 +497,7 @@ module RSMP
|
|
502
497
|
def handle_s0003 status_code, status_name=nil
|
503
498
|
case status_name
|
504
499
|
when 'inputstatus'
|
505
|
-
TrafficControllerSite.make_status @
|
500
|
+
TrafficControllerSite.make_status @inputs.actual_string
|
506
501
|
when 'extendedinputstatus'
|
507
502
|
TrafficControllerSite.make_status 0.to_s
|
508
503
|
end
|
@@ -704,7 +699,7 @@ module RSMP
|
|
704
699
|
def handle_s0029 status_code, status_name=nil
|
705
700
|
case status_name
|
706
701
|
when 'status'
|
707
|
-
TrafficControllerSite.make_status @
|
702
|
+
TrafficControllerSite.make_status @inputs.forced_string
|
708
703
|
end
|
709
704
|
end
|
710
705
|
|
data/lib/rsmp/version.rb
CHANGED
data/lib/rsmp.rb
CHANGED
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.
|
4
|
+
version: 0.10.1
|
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-03-
|
11
|
+
date: 2022-03-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: async
|
@@ -243,6 +243,7 @@ files:
|
|
243
243
|
- lib/rsmp/supervisor_proxy.rb
|
244
244
|
- lib/rsmp/task.rb
|
245
245
|
- lib/rsmp/tlc/detector_logic.rb
|
246
|
+
- lib/rsmp/tlc/inputs.rb
|
246
247
|
- lib/rsmp/tlc/signal_group.rb
|
247
248
|
- lib/rsmp/tlc/signal_plan.rb
|
248
249
|
- lib/rsmp/tlc/traffic_controller.rb
|