rsmp 0.9.9 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|