rsmp 0.48.4 → 0.51.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/CHANGELOG.md +14 -0
- data/Gemfile.lock +19 -20
- data/README.md +27 -3
- data/Rakefile +3 -1
- data/documentation/cli.md +79 -4
- data/documentation/collecting_message.md +90 -170
- data/documentation/configuration.md +8 -0
- data/documentation/message_distribution.md +17 -3
- data/documentation/tasks.md +65 -117
- data/lib/rsmp/cli.rb +93 -5
- data/lib/rsmp/collect/collector.rb +117 -134
- data/lib/rsmp/collect/distributor.rb +16 -3
- data/lib/rsmp/collect/queue.rb +14 -6
- data/lib/rsmp/collect/receiver.rb +1 -1
- data/lib/rsmp/collect/state_collector.rb +11 -2
- data/lib/rsmp/collection.rb +12 -0
- data/lib/rsmp/completion.rb +49 -0
- data/lib/rsmp/component/component_base.rb +3 -3
- data/lib/rsmp/convert/export/json_schema/index.rb +8 -4
- data/lib/rsmp/convert/import/yaml.rb +12 -8
- data/lib/rsmp/delivery.rb +18 -0
- data/lib/rsmp/event.rb +19 -0
- data/lib/rsmp/event_source.rb +36 -0
- data/lib/rsmp/exchange.rb +10 -0
- data/lib/rsmp/failure.rb +23 -0
- data/lib/rsmp/helpers/error.rb +14 -23
- data/lib/rsmp/message.rb +10 -9
- data/lib/rsmp/node/node.rb +3 -21
- data/lib/rsmp/node/site/connections.rb +4 -9
- data/lib/rsmp/node/site/site.rb +33 -17
- data/lib/rsmp/node/supervisor/modules/configuration.rb +24 -11
- data/lib/rsmp/node/supervisor/modules/connection.rb +19 -5
- data/lib/rsmp/node/supervisor/modules/sites.rb +16 -5
- data/lib/rsmp/node/supervisor/supervisor.rb +13 -14
- data/lib/rsmp/node/task.rb +59 -53
- data/lib/rsmp/proxy/modules/acknowledgements.rb +22 -9
- data/lib/rsmp/proxy/modules/lifecycle.rb +134 -0
- data/lib/rsmp/proxy/modules/receive.rb +109 -66
- data/lib/rsmp/proxy/modules/send.rb +109 -51
- data/lib/rsmp/proxy/modules/state.rb +15 -5
- data/lib/rsmp/proxy/modules/tasks.rb +96 -70
- data/lib/rsmp/proxy/modules/versions.rb +69 -19
- data/lib/rsmp/proxy/modules/watchdogs.rb +15 -2
- data/lib/rsmp/proxy/proxy.rb +7 -69
- data/lib/rsmp/proxy/site/connection.rb +27 -22
- data/lib/rsmp/proxy/site/modules/aggregated_status.rb +18 -8
- data/lib/rsmp/proxy/site/modules/alarms.rb +45 -38
- data/lib/rsmp/proxy/site/modules/commands.rb +18 -8
- data/lib/rsmp/proxy/site/modules/status.rb +44 -19
- data/lib/rsmp/proxy/site/site_proxy.rb +12 -10
- data/lib/rsmp/proxy/site/sxl_selection.rb +7 -2
- data/lib/rsmp/proxy/supervisor/modules/aggregated_status.rb +1 -1
- data/lib/rsmp/proxy/supervisor/modules/alarms.rb +1 -1
- data/lib/rsmp/proxy/supervisor/modules/commands.rb +1 -1
- data/lib/rsmp/proxy/supervisor/modules/message_buffer.rb +8 -9
- data/lib/rsmp/proxy/supervisor/modules/status.rb +1 -1
- data/lib/rsmp/proxy/supervisor/modules/status_updates.rb +1 -1
- data/lib/rsmp/proxy/supervisor/supervisor_proxy.rb +36 -31
- data/lib/rsmp/result.rb +95 -0
- data/lib/rsmp/schema/validation.rb +5 -3
- data/lib/rsmp/schema/version.rb +27 -0
- data/lib/rsmp/schema.rb +1 -0
- data/lib/rsmp/sxl/interface.rb +8 -1
- data/lib/rsmp/sxl/processing/catalogue.rb +61 -0
- data/lib/rsmp/sxl/processing/conflict_checker.rb +30 -0
- data/lib/rsmp/sxl/processing/dependency_graph.rb +37 -0
- data/lib/rsmp/sxl/processing/document.rb +158 -0
- data/lib/rsmp/sxl/processing/error.rb +8 -0
- data/lib/rsmp/sxl/processing/manifest.rb +144 -0
- data/lib/rsmp/sxl/processing/natural_sort.rb +22 -0
- data/lib/rsmp/sxl/processing/resolver.rb +94 -0
- data/lib/rsmp/sxl/processing/version_requirement.rb +86 -0
- data/lib/rsmp/sxl/processing.rb +18 -0
- data/lib/rsmp/sxl/supervisor_interface.rb +8 -1
- data/lib/rsmp/termination.rb +10 -0
- data/lib/rsmp/tlc/modules/plans.rb +0 -2
- data/lib/rsmp/tlc/modules/system.rb +2 -2
- data/lib/rsmp/tlc/proxy/control.rb +50 -16
- data/lib/rsmp/tlc/proxy/detectors.rb +15 -4
- data/lib/rsmp/tlc/proxy/io.rb +46 -31
- data/lib/rsmp/tlc/proxy/plans.rb +36 -19
- data/lib/rsmp/tlc/proxy/plans_bang.rb +44 -0
- data/lib/rsmp/tlc/proxy/status.rb +47 -23
- data/lib/rsmp/tlc/proxy/system.rb +16 -4
- data/lib/rsmp/tlc/supervisor_interface.rb +7 -1
- data/lib/rsmp/tlc/traffic_controller_site.rb +6 -9
- data/lib/rsmp/validation.rb +22 -0
- data/lib/rsmp/version.rb +1 -1
- data/lib/rsmp.rb +19 -4
- data/rsmp.gemspec +1 -1
- metadata +26 -4
- data/lib/rsmp/collect/collector/status.rb +0 -34
data/lib/rsmp/tlc/proxy/io.rb
CHANGED
|
@@ -6,7 +6,9 @@ module RSMP
|
|
|
6
6
|
module IO
|
|
7
7
|
# M0006 - Set a single input to a given status.
|
|
8
8
|
def set_input(input:, status:, within:)
|
|
9
|
-
validate_ready 'set input'
|
|
9
|
+
readiness = validate_ready 'set input'
|
|
10
|
+
return readiness if readiness.failure?
|
|
11
|
+
|
|
10
12
|
raise 'TLC main component not found' unless main
|
|
11
13
|
|
|
12
14
|
security_code = security_code_for(2)
|
|
@@ -27,12 +29,18 @@ module RSMP
|
|
|
27
29
|
'n' => 'input',
|
|
28
30
|
'v' => command_value('M0006', 'input', input)
|
|
29
31
|
}]
|
|
30
|
-
send_command_and_collect(command_list, within: within)
|
|
32
|
+
send_command_and_collect(command_list, within: within)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def set_input!(...)
|
|
36
|
+
set_input(...).value!
|
|
31
37
|
end
|
|
32
38
|
|
|
33
39
|
# M0013 - Set all inputs via a bit-pattern string.
|
|
34
40
|
def set_inputs(status, within:)
|
|
35
|
-
validate_ready 'set inputs'
|
|
41
|
+
readiness = validate_ready 'set inputs'
|
|
42
|
+
return readiness if readiness.failure?
|
|
43
|
+
|
|
36
44
|
raise 'TLC main component not found' unless main
|
|
37
45
|
|
|
38
46
|
security_code = security_code_for(2)
|
|
@@ -48,53 +56,60 @@ module RSMP
|
|
|
48
56
|
'n' => 'securityCode',
|
|
49
57
|
'v' => security_code.to_s
|
|
50
58
|
}]
|
|
51
|
-
send_command_and_collect(command_list, within: within)
|
|
59
|
+
send_command_and_collect(command_list, within: within)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def set_inputs!(...)
|
|
63
|
+
set_inputs(...).value!
|
|
52
64
|
end
|
|
53
65
|
|
|
54
66
|
# M0019 - Force an input to a given value.
|
|
55
67
|
def force_input(input:, status:, value:, within:)
|
|
56
|
-
validate_ready 'force input'
|
|
68
|
+
readiness = validate_ready 'force input'
|
|
69
|
+
return readiness if readiness.failure?
|
|
70
|
+
|
|
57
71
|
raise 'TLC main component not found' unless main
|
|
58
72
|
|
|
59
73
|
command_list = force_input_command_list(input, status, value)
|
|
60
74
|
confirm_status = force_input_confirm_status(input, status, value)
|
|
61
|
-
send_command_and_collect(command_list, within: within).
|
|
62
|
-
|
|
75
|
+
send_command_and_collect(command_list, within: within).and_then do |exchange|
|
|
76
|
+
wait_for_status("force input #{input}", confirm_status, timeout: within).map { exchange }
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def force_input!(...)
|
|
81
|
+
force_input(...).value!
|
|
63
82
|
end
|
|
64
83
|
|
|
65
84
|
# M0020 - Force an output to a given value.
|
|
66
85
|
def force_output(output:, status:, value:, within:)
|
|
67
|
-
validate_ready 'force output'
|
|
86
|
+
readiness = validate_ready 'force output'
|
|
87
|
+
return readiness if readiness.failure?
|
|
88
|
+
|
|
68
89
|
raise 'TLC main component not found' unless main
|
|
69
90
|
|
|
70
|
-
|
|
91
|
+
send_command_and_collect(force_output_command_list(output, status, value), within: within)
|
|
92
|
+
end
|
|
71
93
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
'cO' => 'setOutput',
|
|
75
|
-
'n' => 'status',
|
|
76
|
-
'v' => command_value('M0020', 'status', status)
|
|
77
|
-
}, {
|
|
78
|
-
'cCI' => 'M0020',
|
|
79
|
-
'cO' => 'setOutput',
|
|
80
|
-
'n' => 'securityCode',
|
|
81
|
-
'v' => security_code.to_s
|
|
82
|
-
}, {
|
|
83
|
-
'cCI' => 'M0020',
|
|
84
|
-
'cO' => 'setOutput',
|
|
85
|
-
'n' => 'output',
|
|
86
|
-
'v' => command_value('M0020', 'output', output)
|
|
87
|
-
}, {
|
|
88
|
-
'cCI' => 'M0020',
|
|
89
|
-
'cO' => 'setOutput',
|
|
90
|
-
'n' => 'outputValue',
|
|
91
|
-
'v' => command_value('M0020', 'outputValue', value)
|
|
92
|
-
}]
|
|
93
|
-
send_command_and_collect(command_list, within: within).ok!
|
|
94
|
+
def force_output!(...)
|
|
95
|
+
force_output(...).value!
|
|
94
96
|
end
|
|
95
97
|
|
|
96
98
|
private
|
|
97
99
|
|
|
100
|
+
def force_output_command_list(output, status, value)
|
|
101
|
+
security_code = security_code_for(2)
|
|
102
|
+
values = { 'status' => status, 'output' => output, 'outputValue' => value }
|
|
103
|
+
values.map do |name, item|
|
|
104
|
+
{ 'cCI' => 'M0020', 'cO' => 'setOutput', 'n' => name, 'v' => command_value('M0020', name, item) }
|
|
105
|
+
end.insert(1, {
|
|
106
|
+
'cCI' => 'M0020',
|
|
107
|
+
'cO' => 'setOutput',
|
|
108
|
+
'n' => 'securityCode',
|
|
109
|
+
'v' => security_code.to_s
|
|
110
|
+
})
|
|
111
|
+
end
|
|
112
|
+
|
|
98
113
|
def force_input_command_list(input, status, value)
|
|
99
114
|
security_code = security_code_for(2)
|
|
100
115
|
[
|
data/lib/rsmp/tlc/proxy/plans.rb
CHANGED
|
@@ -6,7 +6,9 @@ module RSMP
|
|
|
6
6
|
module Plans
|
|
7
7
|
# M0014 - Set dynamic bands for a signal plan.
|
|
8
8
|
def set_dynamic_bands(plan:, status:, within:)
|
|
9
|
-
validate_ready 'set dynamic bands'
|
|
9
|
+
readiness = validate_ready 'set dynamic bands'
|
|
10
|
+
return readiness if readiness.failure?
|
|
11
|
+
|
|
10
12
|
raise 'TLC main component not found' unless main
|
|
11
13
|
|
|
12
14
|
security_code = security_code_for(2)
|
|
@@ -27,12 +29,14 @@ module RSMP
|
|
|
27
29
|
'n' => 'plan',
|
|
28
30
|
'v' => command_value('M0014', 'plan', plan)
|
|
29
31
|
}]
|
|
30
|
-
send_command_and_collect(command_list, within: within)
|
|
32
|
+
send_command_and_collect(command_list, within: within)
|
|
31
33
|
end
|
|
32
34
|
|
|
33
35
|
# M0023 - Set timeout for dynamic bands.
|
|
34
36
|
def set_dynamic_bands_timeout(status, within:)
|
|
35
|
-
validate_ready 'set dynamic bands timeout'
|
|
37
|
+
readiness = validate_ready 'set dynamic bands timeout'
|
|
38
|
+
return readiness if readiness.failure?
|
|
39
|
+
|
|
36
40
|
raise 'TLC main component not found' unless main
|
|
37
41
|
|
|
38
42
|
security_code = security_code_for(2)
|
|
@@ -48,12 +52,14 @@ module RSMP
|
|
|
48
52
|
'n' => 'securityCode',
|
|
49
53
|
'v' => security_code.to_s
|
|
50
54
|
}]
|
|
51
|
-
send_command_and_collect(command_list, within: within)
|
|
55
|
+
send_command_and_collect(command_list, within: within)
|
|
52
56
|
end
|
|
53
57
|
|
|
54
58
|
# M0015 - Set offset for a signal plan.
|
|
55
59
|
def set_offset(plan:, offset:, within:)
|
|
56
|
-
validate_ready 'set offset'
|
|
60
|
+
readiness = validate_ready 'set offset'
|
|
61
|
+
return readiness if readiness.failure?
|
|
62
|
+
|
|
57
63
|
raise 'TLC main component not found' unless main
|
|
58
64
|
|
|
59
65
|
security_code = security_code_for(2)
|
|
@@ -74,12 +80,14 @@ module RSMP
|
|
|
74
80
|
'n' => 'plan',
|
|
75
81
|
'v' => command_value('M0015', 'plan', plan)
|
|
76
82
|
}]
|
|
77
|
-
send_command_and_collect(command_list, within: within)
|
|
83
|
+
send_command_and_collect(command_list, within: within)
|
|
78
84
|
end
|
|
79
85
|
|
|
80
86
|
# Set the timeplan (signal plan) on the remote TLC.
|
|
81
87
|
def set_timeplan(plan_nr, within:)
|
|
82
|
-
validate_ready 'set timeplan'
|
|
88
|
+
readiness = validate_ready 'set timeplan'
|
|
89
|
+
return readiness if readiness.failure?
|
|
90
|
+
|
|
83
91
|
raise 'TLC main component not found' unless main
|
|
84
92
|
|
|
85
93
|
security_code = security_code_for(2)
|
|
@@ -101,13 +109,16 @@ module RSMP
|
|
|
101
109
|
'v' => command_value('M0002', 'timeplan', plan_nr)
|
|
102
110
|
}]
|
|
103
111
|
confirm_status = [{ 'sCI' => 'S0014', 'n' => 'status', 's' => integer_value(plan_nr) }]
|
|
104
|
-
send_command_and_collect(command_list, within: within).
|
|
105
|
-
|
|
112
|
+
send_command_and_collect(command_list, within: within).and_then do |exchange|
|
|
113
|
+
wait_for_status("timeplan #{plan_nr}", confirm_status, timeout: within).map { exchange }
|
|
114
|
+
end
|
|
106
115
|
end
|
|
107
116
|
|
|
108
117
|
# M0016 - Set week table (mapping week days to traffic situations).
|
|
109
118
|
def set_week_table(status, within:)
|
|
110
|
-
validate_ready 'set week table'
|
|
119
|
+
readiness = validate_ready 'set week table'
|
|
120
|
+
return readiness if readiness.failure?
|
|
121
|
+
|
|
111
122
|
raise 'TLC main component not found' unless main
|
|
112
123
|
|
|
113
124
|
security_code = security_code_for(2)
|
|
@@ -123,12 +134,14 @@ module RSMP
|
|
|
123
134
|
'n' => 'securityCode',
|
|
124
135
|
'v' => security_code.to_s
|
|
125
136
|
}]
|
|
126
|
-
send_command_and_collect(command_list, within:)
|
|
137
|
+
send_command_and_collect(command_list, within:)
|
|
127
138
|
end
|
|
128
139
|
|
|
129
140
|
# M0017 - Set day table (mapping time periods to signal plans).
|
|
130
141
|
def set_day_table(status, within:)
|
|
131
|
-
validate_ready 'set day table'
|
|
142
|
+
readiness = validate_ready 'set day table'
|
|
143
|
+
return readiness if readiness.failure?
|
|
144
|
+
|
|
132
145
|
raise 'TLC main component not found' unless main
|
|
133
146
|
|
|
134
147
|
security_code = security_code_for(2)
|
|
@@ -144,12 +157,14 @@ module RSMP
|
|
|
144
157
|
'n' => 'securityCode',
|
|
145
158
|
'v' => security_code.to_s
|
|
146
159
|
}]
|
|
147
|
-
send_command_and_collect(command_list, within:)
|
|
160
|
+
send_command_and_collect(command_list, within:)
|
|
148
161
|
end
|
|
149
162
|
|
|
150
163
|
# M0018 - Set cycle time for a signal plan.
|
|
151
164
|
def set_cycle_time(plan:, cycle_time:, within:)
|
|
152
|
-
validate_ready 'set cycle time'
|
|
165
|
+
readiness = validate_ready 'set cycle time'
|
|
166
|
+
return readiness if readiness.failure?
|
|
167
|
+
|
|
153
168
|
raise 'TLC main component not found' unless main
|
|
154
169
|
|
|
155
170
|
security_code = security_code_for(2)
|
|
@@ -170,12 +185,13 @@ module RSMP
|
|
|
170
185
|
'n' => 'plan',
|
|
171
186
|
'v' => command_value('M0018', 'plan', plan)
|
|
172
187
|
}]
|
|
173
|
-
send_command_and_collect(command_list, within:)
|
|
188
|
+
send_command_and_collect(command_list, within:)
|
|
174
189
|
end
|
|
175
190
|
|
|
176
191
|
# M0010 - Order signal start for a signal group component.
|
|
177
192
|
def order_signal_start(component_id, within:)
|
|
178
|
-
validate_ready 'order signal start'
|
|
193
|
+
readiness = validate_ready 'order signal start'
|
|
194
|
+
return readiness if readiness.failure?
|
|
179
195
|
|
|
180
196
|
security_code = security_code_for(2)
|
|
181
197
|
|
|
@@ -190,12 +206,13 @@ module RSMP
|
|
|
190
206
|
'n' => 'securityCode',
|
|
191
207
|
'v' => security_code.to_s
|
|
192
208
|
}]
|
|
193
|
-
send_command_and_collect(command_list, component: component_id, within:)
|
|
209
|
+
send_command_and_collect(command_list, component: component_id, within:)
|
|
194
210
|
end
|
|
195
211
|
|
|
196
212
|
# M0011 - Order signal stop for a signal group component.
|
|
197
213
|
def order_signal_stop(component_id, within:)
|
|
198
|
-
validate_ready 'order signal stop'
|
|
214
|
+
readiness = validate_ready 'order signal stop'
|
|
215
|
+
return readiness if readiness.failure?
|
|
199
216
|
|
|
200
217
|
security_code = security_code_for(2)
|
|
201
218
|
|
|
@@ -210,7 +227,7 @@ module RSMP
|
|
|
210
227
|
'n' => 'securityCode',
|
|
211
228
|
'v' => security_code.to_s
|
|
212
229
|
}]
|
|
213
|
-
send_command_and_collect(command_list, component: component_id, within:)
|
|
230
|
+
send_command_and_collect(command_list, component: component_id, within:)
|
|
214
231
|
end
|
|
215
232
|
end
|
|
216
233
|
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module RSMP
|
|
2
|
+
module TLC
|
|
3
|
+
module Proxy
|
|
4
|
+
# Explicit exception-raising variants of finite plan operations.
|
|
5
|
+
module PlansBang
|
|
6
|
+
def set_dynamic_bands!(...)
|
|
7
|
+
set_dynamic_bands(...).value!
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def set_dynamic_bands_timeout!(...)
|
|
11
|
+
set_dynamic_bands_timeout(...).value!
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def set_offset!(...)
|
|
15
|
+
set_offset(...).value!
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def set_timeplan!(...)
|
|
19
|
+
set_timeplan(...).value!
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def set_week_table!(...)
|
|
23
|
+
set_week_table(...).value!
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def set_day_table!(...)
|
|
27
|
+
set_day_table(...).value!
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def set_cycle_time!(...)
|
|
31
|
+
set_cycle_time(...).value!
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def order_signal_start!(...)
|
|
35
|
+
order_signal_start(...).value!
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def order_signal_stop!(...)
|
|
39
|
+
order_signal_stop(...).value!
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -4,25 +4,28 @@ module RSMP
|
|
|
4
4
|
# Status reading and waiting methods for a remote TLC.
|
|
5
5
|
# Covers status subscriptions, group waits, and plan/band reading.
|
|
6
6
|
module Status
|
|
7
|
-
# Fetch the current signal plan from the remote TLC.
|
|
7
|
+
# Fetch the current signal plan from the remote TLC. Returns Result<Hash>.
|
|
8
8
|
def fetch_signal_plan(options: {})
|
|
9
|
-
validate_ready 'fetch signal plan'
|
|
10
9
|
timeout = options[:timeout] || @timeouts['status_response']
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
request_status_and_collect({ S0014: %i[status source] }, within: timeout).map do |exchange|
|
|
11
|
+
exchange.collection.messages.last.attributes['sS'].to_h do |item|
|
|
12
|
+
[item['n'], item['s']]
|
|
13
|
+
end
|
|
15
14
|
end
|
|
16
15
|
end
|
|
17
16
|
|
|
17
|
+
def fetch_signal_plan!(...)
|
|
18
|
+
fetch_signal_plan(...).value!
|
|
19
|
+
end
|
|
20
|
+
|
|
18
21
|
# Subscribe to one or more statuses and wait until they match the expected values.
|
|
19
|
-
# Raises RSMP::TimeoutError if the values don't match within the timeout.
|
|
20
|
-
#
|
|
21
22
|
# status_list items: { 'sCI' => ..., 'n' => ..., 's' => <expected value or Regexp> }
|
|
22
23
|
# component_id defaults to the main TLC component.
|
|
23
24
|
# timeout defaults to @timeouts['command'].
|
|
24
25
|
def wait_for_status(description, status_list, update_rate: 0, timeout: nil, component_id: nil)
|
|
25
|
-
validate_ready 'wait for status'
|
|
26
|
+
readiness = validate_ready 'wait for status'
|
|
27
|
+
return readiness if readiness.failure?
|
|
28
|
+
|
|
26
29
|
component_id ||= main.c_id
|
|
27
30
|
timeout ||= @timeouts['command']
|
|
28
31
|
|
|
@@ -35,13 +38,17 @@ module RSMP
|
|
|
35
38
|
log "Wait for #{description}", level: :debug
|
|
36
39
|
|
|
37
40
|
begin
|
|
38
|
-
subscribe_to_status_and_collect(subscribe_list, component: component_id, within: timeout)
|
|
41
|
+
subscribe_to_status_and_collect(subscribe_list, component: component_id, within: timeout)
|
|
39
42
|
ensure
|
|
40
43
|
unsubscribe_list = status_list.map { |item| item.slice('sCI', 'n') }
|
|
41
44
|
unsubscribe_to_status unsubscribe_list, component: component_id
|
|
42
45
|
end
|
|
43
46
|
end
|
|
44
47
|
|
|
48
|
+
def wait_for_status!(...)
|
|
49
|
+
wait_for_status(...).value!
|
|
50
|
+
end
|
|
51
|
+
|
|
45
52
|
# Wait for all signal groups to match state (as regex string, e.g. 'c' for yellow flash).
|
|
46
53
|
def wait_for_groups(state, timeout:)
|
|
47
54
|
regex = /^#{state}+$/
|
|
@@ -52,6 +59,10 @@ module RSMP
|
|
|
52
59
|
)
|
|
53
60
|
end
|
|
54
61
|
|
|
62
|
+
def wait_for_groups!(...)
|
|
63
|
+
wait_for_groups(...).value!
|
|
64
|
+
end
|
|
65
|
+
|
|
55
66
|
# Wait for the TLC to return to normal control mode (functional position NormalControl,
|
|
56
67
|
# yellow flash off, startup mode off).
|
|
57
68
|
def wait_for_normal_control(timeout: nil)
|
|
@@ -66,36 +77,49 @@ module RSMP
|
|
|
66
77
|
)
|
|
67
78
|
end
|
|
68
79
|
|
|
80
|
+
def wait_for_normal_control!(...)
|
|
81
|
+
wait_for_normal_control(...).value!
|
|
82
|
+
end
|
|
83
|
+
|
|
69
84
|
# Read cycle times for all plans via S0028.
|
|
70
85
|
# Returns a hash of plan_nr (Integer) => cycle_time (Integer, seconds).
|
|
71
86
|
def read_cycle_times(options: {})
|
|
72
|
-
validate_ready 'read cycle times'
|
|
73
87
|
timeout = options[:timeout] || @timeouts['status_response']
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
88
|
+
request_status_and_collect({ S0028: [:status] }, within: timeout).map do |exchange|
|
|
89
|
+
status_items(exchange.collection.messages.first.attributes['sS'].first['s']).to_h do |item|
|
|
90
|
+
item.split('-').map(&:to_i)
|
|
91
|
+
end
|
|
78
92
|
end
|
|
79
93
|
end
|
|
80
94
|
|
|
95
|
+
def read_cycle_times!(...)
|
|
96
|
+
read_cycle_times(...).value!
|
|
97
|
+
end
|
|
98
|
+
|
|
81
99
|
# Read the current signal plan number via S0014.
|
|
82
100
|
# Returns the plan number as an Integer.
|
|
83
101
|
def read_current_plan(options: {})
|
|
84
|
-
validate_ready 'read current plan'
|
|
85
102
|
timeout = options[:timeout] || @timeouts['status_response']
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
103
|
+
request_status_and_collect({ S0014: [:status] }, within: timeout).map do |exchange|
|
|
104
|
+
exchange.collection.messages.first.attributes['sS'].first['s'].to_i
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def read_current_plan!(...)
|
|
109
|
+
read_current_plan(...).value!
|
|
89
110
|
end
|
|
90
111
|
|
|
91
112
|
# Read the value of a single dynamic band for a given plan and band index via S0023.
|
|
92
113
|
# Returns the band value as an Integer, or nil if not found.
|
|
93
114
|
def read_dynamic_band(plan:, band:, options: {})
|
|
94
|
-
validate_ready 'read dynamic band'
|
|
95
115
|
timeout = options[:timeout] || @timeouts['status_response']
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
116
|
+
request_status_and_collect({ S0023: [:status] }, within: timeout).map do |exchange|
|
|
117
|
+
extract_band_value(exchange.collection, plan, band)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def read_dynamic_band!(...)
|
|
122
|
+
read_dynamic_band(...).value!
|
|
99
123
|
end
|
|
100
124
|
|
|
101
125
|
private
|
|
@@ -7,7 +7,9 @@ module RSMP
|
|
|
7
7
|
# M0103 - Change security code for a given level.
|
|
8
8
|
# Does not use security_code_for since the codes are passed explicitly.
|
|
9
9
|
def set_security_code(level:, old_code:, new_code:, within:)
|
|
10
|
-
validate_ready 'set security code'
|
|
10
|
+
readiness = validate_ready 'set security code'
|
|
11
|
+
return readiness if readiness.failure?
|
|
12
|
+
|
|
11
13
|
raise 'TLC main component not found' unless main
|
|
12
14
|
|
|
13
15
|
command_list = [{
|
|
@@ -26,15 +28,25 @@ module RSMP
|
|
|
26
28
|
'n' => 'newSecurityCode',
|
|
27
29
|
'v' => new_code.to_s
|
|
28
30
|
}]
|
|
29
|
-
send_command_and_collect(command_list, within: within)
|
|
31
|
+
send_command_and_collect(command_list, within: within)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def set_security_code!(...)
|
|
35
|
+
set_security_code(...).value!
|
|
30
36
|
end
|
|
31
37
|
|
|
32
38
|
# M0104 - Set the clock on the remote TLC. clock must respond to year/month/day/hour/min/sec.
|
|
33
39
|
def set_clock(clock, within:)
|
|
34
|
-
validate_ready 'set clock'
|
|
40
|
+
readiness = validate_ready 'set clock'
|
|
41
|
+
return readiness if readiness.failure?
|
|
42
|
+
|
|
35
43
|
raise 'TLC main component not found' unless main
|
|
36
44
|
|
|
37
|
-
send_command_and_collect(clock_command_list(clock), within: within)
|
|
45
|
+
send_command_and_collect(clock_command_list(clock), within: within)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def set_clock!(...)
|
|
49
|
+
set_clock(...).value!
|
|
38
50
|
end
|
|
39
51
|
|
|
40
52
|
private
|
|
@@ -6,6 +6,7 @@ module RSMP
|
|
|
6
6
|
include Proxy::Control
|
|
7
7
|
include Proxy::IO
|
|
8
8
|
include Proxy::Plans
|
|
9
|
+
include Proxy::PlansBang
|
|
9
10
|
include Proxy::Status
|
|
10
11
|
include Proxy::Detectors
|
|
11
12
|
include Proxy::System
|
|
@@ -32,7 +33,8 @@ module RSMP
|
|
|
32
33
|
end
|
|
33
34
|
|
|
34
35
|
def subscribe_to_timeplan
|
|
35
|
-
validate_ready 'subscribe to timeplan'
|
|
36
|
+
readiness = validate_ready 'subscribe to timeplan'
|
|
37
|
+
return readiness if readiness.failure?
|
|
36
38
|
|
|
37
39
|
status_list = [
|
|
38
40
|
{ 'sCI' => 'S0014', 'n' => 'status', 'uRt' => '0' },
|
|
@@ -45,6 +47,10 @@ module RSMP
|
|
|
45
47
|
subscribe_to_status status_list, component: main.c_id
|
|
46
48
|
end
|
|
47
49
|
|
|
50
|
+
def subscribe_to_timeplan!(...)
|
|
51
|
+
subscribe_to_timeplan(...).value!
|
|
52
|
+
end
|
|
53
|
+
|
|
48
54
|
def process_status_update(message)
|
|
49
55
|
status_values = message.attribute('sS')
|
|
50
56
|
return unless status_values
|
|
@@ -28,9 +28,9 @@ module RSMP
|
|
|
28
28
|
'TLC'
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
def
|
|
31
|
+
def start_auxiliary_tasks(parent)
|
|
32
32
|
super
|
|
33
|
-
start_tlc_timer
|
|
33
|
+
start_tlc_timer(parent: parent)
|
|
34
34
|
main.initiate_startup_sequence
|
|
35
35
|
end
|
|
36
36
|
|
|
@@ -82,11 +82,11 @@ module RSMP
|
|
|
82
82
|
end
|
|
83
83
|
end
|
|
84
84
|
|
|
85
|
-
def start_tlc_timer
|
|
85
|
+
def start_tlc_timer(parent:)
|
|
86
86
|
task_name = 'tlc timer'
|
|
87
87
|
log "Starting #{task_name} with interval #{@interval} seconds", level: :debug
|
|
88
88
|
|
|
89
|
-
@timer =
|
|
89
|
+
@timer = parent.async do |task|
|
|
90
90
|
task.annotate task_name
|
|
91
91
|
run_tlc_timer task
|
|
92
92
|
end
|
|
@@ -96,9 +96,6 @@ module RSMP
|
|
|
96
96
|
next_time = Time.now.to_f
|
|
97
97
|
loop do
|
|
98
98
|
timer(@clock.now)
|
|
99
|
-
rescue StandardError => e
|
|
100
|
-
distribute_error e, level: :internal
|
|
101
|
-
ensure
|
|
102
99
|
# adjust sleep duration to avoid drift. so wake up always happens on the
|
|
103
100
|
# same fractional second.
|
|
104
101
|
# note that Time.now is not monotonic. If the clock is changed,
|
|
@@ -108,7 +105,7 @@ module RSMP
|
|
|
108
105
|
# if the clock is changed, the wake up would then happen on a different
|
|
109
106
|
# fractional second
|
|
110
107
|
next_time += @interval
|
|
111
|
-
duration = next_time - Time.now.to_f
|
|
108
|
+
duration = [next_time - Time.now.to_f, 0].max
|
|
112
109
|
task.sleep duration
|
|
113
110
|
end
|
|
114
111
|
end
|
|
@@ -116,7 +113,7 @@ module RSMP
|
|
|
116
113
|
def stop_tlc_timer
|
|
117
114
|
return unless @timer
|
|
118
115
|
|
|
119
|
-
@timer.
|
|
116
|
+
@timer.cancel if @timer.running?
|
|
120
117
|
@timer = nil
|
|
121
118
|
end
|
|
122
119
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module RSMP
|
|
2
|
+
# The result of validating a message against one or more schemas.
|
|
3
|
+
Validation = Data.define(:violations) do
|
|
4
|
+
def initialize(violations: [])
|
|
5
|
+
raise ArgumentError, 'violations must be an Array' unless violations.is_a?(Array)
|
|
6
|
+
|
|
7
|
+
super(violations: violations.map { |violation| Array(violation).dup.freeze }.freeze)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def valid?
|
|
11
|
+
violations.empty?
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def invalid?
|
|
15
|
+
!valid?
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def message
|
|
19
|
+
violations.map { |item| item.reject { |part| part == '' } }.compact.join(', ').strip
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
data/lib/rsmp/version.rb
CHANGED
data/lib/rsmp.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
require 'yaml'
|
|
2
2
|
require 'socket'
|
|
3
3
|
require 'time'
|
|
4
|
+
require 'English'
|
|
4
5
|
require 'async'
|
|
5
6
|
require 'io/endpoint'
|
|
6
7
|
require 'io/endpoint/host_endpoint'
|
|
@@ -10,16 +11,28 @@ require 'json'
|
|
|
10
11
|
require 'securerandom'
|
|
11
12
|
require 'json_schemer'
|
|
12
13
|
require 'async/queue'
|
|
14
|
+
require 'async/barrier'
|
|
15
|
+
require 'async/promise'
|
|
13
16
|
require_relative 'rsmp/schema_error'
|
|
17
|
+
require_relative 'rsmp/helpers/clock'
|
|
18
|
+
require_relative 'rsmp/helpers/deep_merge'
|
|
19
|
+
require_relative 'rsmp/helpers/error'
|
|
20
|
+
require_relative 'rsmp/failure'
|
|
21
|
+
require_relative 'rsmp/result'
|
|
22
|
+
require_relative 'rsmp/validation'
|
|
23
|
+
require_relative 'rsmp/event'
|
|
24
|
+
require_relative 'rsmp/event_source'
|
|
25
|
+
require_relative 'rsmp/completion'
|
|
26
|
+
require_relative 'rsmp/termination'
|
|
27
|
+
require_relative 'rsmp/collection'
|
|
28
|
+
require_relative 'rsmp/exchange'
|
|
29
|
+
require_relative 'rsmp/delivery'
|
|
14
30
|
require_relative 'rsmp/schema'
|
|
15
31
|
require_relative 'rsmp/convert/import/yaml'
|
|
16
32
|
require_relative 'rsmp/convert/export/json_schema'
|
|
17
33
|
|
|
18
34
|
require_relative 'rsmp/status_list'
|
|
19
35
|
require_relative 'rsmp/command_list'
|
|
20
|
-
require_relative 'rsmp/helpers/clock'
|
|
21
|
-
require_relative 'rsmp/helpers/deep_merge'
|
|
22
|
-
require_relative 'rsmp/helpers/error'
|
|
23
36
|
require_relative 'rsmp/log/logging'
|
|
24
37
|
require_relative 'rsmp/log/archive'
|
|
25
38
|
require_relative 'rsmp/log/filtering'
|
|
@@ -35,7 +48,6 @@ require_relative 'rsmp/component/component_proxy'
|
|
|
35
48
|
require_relative 'rsmp/collect/distributor'
|
|
36
49
|
require_relative 'rsmp/collect/receiver'
|
|
37
50
|
require_relative 'rsmp/collect/queue'
|
|
38
|
-
require_relative 'rsmp/collect/collector/status'
|
|
39
51
|
require_relative 'rsmp/collect/collector/reporting'
|
|
40
52
|
require_relative 'rsmp/collect/collector/logging'
|
|
41
53
|
require_relative 'rsmp/collect/collector'
|
|
@@ -71,11 +83,13 @@ require_relative 'rsmp/proxy/modules/send'
|
|
|
71
83
|
require_relative 'rsmp/proxy/modules/receive'
|
|
72
84
|
require_relative 'rsmp/proxy/modules/versions'
|
|
73
85
|
require_relative 'rsmp/proxy/modules/tasks'
|
|
86
|
+
require_relative 'rsmp/proxy/modules/lifecycle'
|
|
74
87
|
require_relative 'rsmp/proxy/proxy'
|
|
75
88
|
require_relative 'rsmp/sxl/interface'
|
|
76
89
|
require_relative 'rsmp/sxl/supervisor_interface'
|
|
77
90
|
require_relative 'rsmp/sxl/site_interface'
|
|
78
91
|
require_relative 'rsmp/sxl/registry'
|
|
92
|
+
require_relative 'rsmp/sxl/processing'
|
|
79
93
|
require_relative 'rsmp/proxy/supervisor/modules/status_updates'
|
|
80
94
|
require_relative 'rsmp/proxy/supervisor/modules/status'
|
|
81
95
|
require_relative 'rsmp/proxy/supervisor/modules/commands'
|
|
@@ -108,6 +122,7 @@ require_relative 'rsmp/tlc/proxy/control'
|
|
|
108
122
|
require_relative 'rsmp/tlc/proxy/detectors'
|
|
109
123
|
require_relative 'rsmp/tlc/proxy/io'
|
|
110
124
|
require_relative 'rsmp/tlc/proxy/plans'
|
|
125
|
+
require_relative 'rsmp/tlc/proxy/plans_bang'
|
|
111
126
|
require_relative 'rsmp/tlc/proxy/status'
|
|
112
127
|
require_relative 'rsmp/tlc/proxy/system'
|
|
113
128
|
require_relative 'rsmp/tlc/supervisor_interface'
|