rsmp 0.40.0 → 0.41.0
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 +645 -3
- data/Gemfile.lock +12 -12
- data/config/supervisor.yaml +1 -1
- data/documentation/configuration.md +67 -1
- data/lib/rsmp/cli.rb +2 -2
- data/lib/rsmp/helpers/inspect.rb +1 -1
- data/lib/rsmp/node/supervisor/modules/configuration.rb +10 -8
- data/lib/rsmp/node/supervisor/modules/connection.rb +14 -5
- data/lib/rsmp/node/supervisor/supervisor.rb +7 -0
- data/lib/rsmp/options/schemas/supervisor.json +6 -3
- data/lib/rsmp/options/schemas/supervisor_site.json +46 -0
- data/lib/rsmp/options/schemas/traffic_controller_site.json +3 -2
- data/lib/rsmp/options/supervisor_options.rb +4 -2
- data/lib/rsmp/proxy/proxy.rb +1 -0
- data/lib/rsmp/proxy/site/modules/alarms.rb +58 -0
- data/lib/rsmp/proxy/site/modules/status.rb +9 -0
- data/lib/rsmp/proxy/site/site_proxy.rb +12 -7
- data/lib/rsmp/tlc/modules/inputs.rb +30 -1
- data/lib/rsmp/tlc/proxy/control.rb +158 -0
- data/lib/rsmp/tlc/proxy/detectors.rb +58 -0
- data/lib/rsmp/tlc/proxy/io.rb +119 -0
- data/lib/rsmp/tlc/proxy/plans.rb +226 -0
- data/lib/rsmp/tlc/proxy/status.rb +120 -0
- data/lib/rsmp/tlc/proxy/system.rb +58 -0
- data/lib/rsmp/tlc/traffic_controller_proxy.rb +143 -0
- data/lib/rsmp/tlc/traffic_controller_site.rb +10 -1
- data/lib/rsmp/version.rb +1 -1
- data/lib/rsmp.rb +7 -1
- data/rsmp.gemspec +1 -1
- metadata +11 -4
- data/lib/rsmp/convert/export/json_schema.rb +0 -214
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module RSMP
|
|
2
|
+
module TLC
|
|
3
|
+
module Proxy
|
|
4
|
+
# Command methods for operational control of a remote TLC.
|
|
5
|
+
# Covers functional position, emergency routes, I/O modes, signal group orders, and system settings.
|
|
6
|
+
module Detectors
|
|
7
|
+
# M0008 — Force detector logic to a given mode and status.
|
|
8
|
+
# component_id must refer to the detector logic component, not main.
|
|
9
|
+
def force_detector_logic(component_id, status:, mode:, options: {})
|
|
10
|
+
validate_ready 'force detector logic'
|
|
11
|
+
|
|
12
|
+
security_code = security_code_for(2)
|
|
13
|
+
|
|
14
|
+
command_list = [{
|
|
15
|
+
'cCI' => 'M0008',
|
|
16
|
+
'cO' => 'setForceDetectorLogic',
|
|
17
|
+
'n' => 'status',
|
|
18
|
+
'v' => status.to_s
|
|
19
|
+
}, {
|
|
20
|
+
'cCI' => 'M0008',
|
|
21
|
+
'cO' => 'setForceDetectorLogic',
|
|
22
|
+
'n' => 'securityCode',
|
|
23
|
+
'v' => security_code.to_s
|
|
24
|
+
}, {
|
|
25
|
+
'cCI' => 'M0008',
|
|
26
|
+
'cO' => 'setForceDetectorLogic',
|
|
27
|
+
'n' => 'mode',
|
|
28
|
+
'v' => mode.to_s
|
|
29
|
+
}]
|
|
30
|
+
|
|
31
|
+
send_command_with_confirm component_id, command_list, options, "force detector logic #{component_id}", nil
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# M0021 — Set the trigger level for traffic counting.
|
|
35
|
+
def set_trigger_level(status, options: {})
|
|
36
|
+
validate_ready 'set trigger level'
|
|
37
|
+
raise 'TLC main component not found' unless main
|
|
38
|
+
|
|
39
|
+
security_code = security_code_for(2)
|
|
40
|
+
|
|
41
|
+
command_list = [{
|
|
42
|
+
'cCI' => 'M0021',
|
|
43
|
+
'cO' => 'setLevel',
|
|
44
|
+
'n' => 'status',
|
|
45
|
+
'v' => status.to_s
|
|
46
|
+
}, {
|
|
47
|
+
'cCI' => 'M0021',
|
|
48
|
+
'cO' => 'setLevel',
|
|
49
|
+
'n' => 'securityCode',
|
|
50
|
+
'v' => security_code.to_s
|
|
51
|
+
}]
|
|
52
|
+
|
|
53
|
+
send_command_with_confirm main.c_id, command_list, options, "trigger level #{status}", nil
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
module RSMP
|
|
2
|
+
module TLC
|
|
3
|
+
module Proxy
|
|
4
|
+
# Command methods for I/O control of a remote TLC.
|
|
5
|
+
# Covers detector logic, input/output forcing and setting.
|
|
6
|
+
module IO
|
|
7
|
+
# M0006 — Set a single input to a given status.
|
|
8
|
+
def set_input(input:, status:, options: {})
|
|
9
|
+
validate_ready 'set input'
|
|
10
|
+
raise 'TLC main component not found' unless main
|
|
11
|
+
|
|
12
|
+
security_code = security_code_for(2)
|
|
13
|
+
|
|
14
|
+
command_list = [{
|
|
15
|
+
'cCI' => 'M0006',
|
|
16
|
+
'cO' => 'setInput',
|
|
17
|
+
'n' => 'status',
|
|
18
|
+
'v' => status.to_s
|
|
19
|
+
}, {
|
|
20
|
+
'cCI' => 'M0006',
|
|
21
|
+
'cO' => 'setInput',
|
|
22
|
+
'n' => 'securityCode',
|
|
23
|
+
'v' => security_code.to_s
|
|
24
|
+
}, {
|
|
25
|
+
'cCI' => 'M0006',
|
|
26
|
+
'cO' => 'setInput',
|
|
27
|
+
'n' => 'input',
|
|
28
|
+
'v' => input.to_s
|
|
29
|
+
}]
|
|
30
|
+
|
|
31
|
+
send_command_with_confirm main.c_id, command_list, options, "input #{input} set to #{status}", nil
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# M0013 — Set all inputs via a bit-pattern string.
|
|
35
|
+
def set_inputs(status, options: {})
|
|
36
|
+
validate_ready 'set inputs'
|
|
37
|
+
raise 'TLC main component not found' unless main
|
|
38
|
+
|
|
39
|
+
security_code = security_code_for(2)
|
|
40
|
+
|
|
41
|
+
command_list = [{
|
|
42
|
+
'cCI' => 'M0013',
|
|
43
|
+
'cO' => 'setInputs',
|
|
44
|
+
'n' => 'status',
|
|
45
|
+
'v' => status.to_s
|
|
46
|
+
}, {
|
|
47
|
+
'cCI' => 'M0013',
|
|
48
|
+
'cO' => 'setInputs',
|
|
49
|
+
'n' => 'securityCode',
|
|
50
|
+
'v' => security_code.to_s
|
|
51
|
+
}]
|
|
52
|
+
|
|
53
|
+
send_command_with_confirm main.c_id, command_list, options, "inputs #{status}", nil
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# M0019 — Force an input to a given value.
|
|
57
|
+
def force_input(input:, status:, value:, options: {})
|
|
58
|
+
validate_ready 'force input'
|
|
59
|
+
raise 'TLC main component not found' unless main
|
|
60
|
+
|
|
61
|
+
command_list = force_input_command_list(input, status, value)
|
|
62
|
+
confirm_status = force_input_confirm_status(input, status, value)
|
|
63
|
+
send_command_with_confirm main.c_id, command_list, options, "force input #{input}", confirm_status
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# M0020 — Force an output to a given value.
|
|
67
|
+
def force_output(output:, status:, value:, options: {})
|
|
68
|
+
validate_ready 'force output'
|
|
69
|
+
raise 'TLC main component not found' unless main
|
|
70
|
+
|
|
71
|
+
security_code = security_code_for(2)
|
|
72
|
+
|
|
73
|
+
command_list = [{
|
|
74
|
+
'cCI' => 'M0020',
|
|
75
|
+
'cO' => 'setOutput',
|
|
76
|
+
'n' => 'status',
|
|
77
|
+
'v' => status.to_s
|
|
78
|
+
}, {
|
|
79
|
+
'cCI' => 'M0020',
|
|
80
|
+
'cO' => 'setOutput',
|
|
81
|
+
'n' => 'securityCode',
|
|
82
|
+
'v' => security_code.to_s
|
|
83
|
+
}, {
|
|
84
|
+
'cCI' => 'M0020',
|
|
85
|
+
'cO' => 'setOutput',
|
|
86
|
+
'n' => 'output',
|
|
87
|
+
'v' => output.to_s
|
|
88
|
+
}, {
|
|
89
|
+
'cCI' => 'M0020',
|
|
90
|
+
'cO' => 'setOutput',
|
|
91
|
+
'n' => 'outputValue',
|
|
92
|
+
'v' => value.to_s
|
|
93
|
+
}]
|
|
94
|
+
|
|
95
|
+
send_command_with_confirm main.c_id, command_list, options, "force output #{output}", nil
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
private
|
|
99
|
+
|
|
100
|
+
def force_input_command_list(input, status, value)
|
|
101
|
+
security_code = security_code_for(2)
|
|
102
|
+
[
|
|
103
|
+
{ 'cCI' => 'M0019', 'cO' => 'setInput', 'n' => 'status', 'v' => status.to_s },
|
|
104
|
+
{ 'cCI' => 'M0019', 'cO' => 'setInput', 'n' => 'securityCode', 'v' => security_code.to_s },
|
|
105
|
+
{ 'cCI' => 'M0019', 'cO' => 'setInput', 'n' => 'input', 'v' => input.to_s },
|
|
106
|
+
{ 'cCI' => 'M0019', 'cO' => 'setInput', 'n' => 'inputValue', 'v' => value.to_s }
|
|
107
|
+
]
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def force_input_confirm_status(input, status, value)
|
|
111
|
+
[
|
|
112
|
+
{ 'sCI' => 'S0029', 'n' => 'status', 's' => /^.{#{input.to_i - 1}}#{status == 'True' ? '1' : '0'}/ },
|
|
113
|
+
{ 'sCI' => 'S0003', 'n' => 'inputstatus', 's' => /^.{#{input.to_i - 1}}#{value == 'True' ? '1' : '0'}/ }
|
|
114
|
+
]
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
module RSMP
|
|
2
|
+
module TLC
|
|
3
|
+
module Proxy
|
|
4
|
+
# Command methods for signal plans.
|
|
5
|
+
# Covers time plans, week/day tables, bands, offsets, and cycle times.
|
|
6
|
+
module Plans
|
|
7
|
+
# M0014 — Set dynamic bands for a signal plan.
|
|
8
|
+
def set_dynamic_bands(plan:, status:, options: {})
|
|
9
|
+
validate_ready 'set dynamic bands'
|
|
10
|
+
raise 'TLC main component not found' unless main
|
|
11
|
+
|
|
12
|
+
security_code = security_code_for(2)
|
|
13
|
+
|
|
14
|
+
command_list = [{
|
|
15
|
+
'cCI' => 'M0014',
|
|
16
|
+
'cO' => 'setCommands',
|
|
17
|
+
'n' => 'status',
|
|
18
|
+
'v' => status.to_s
|
|
19
|
+
}, {
|
|
20
|
+
'cCI' => 'M0014',
|
|
21
|
+
'cO' => 'setCommands',
|
|
22
|
+
'n' => 'securityCode',
|
|
23
|
+
'v' => security_code.to_s
|
|
24
|
+
}, {
|
|
25
|
+
'cCI' => 'M0014',
|
|
26
|
+
'cO' => 'setCommands',
|
|
27
|
+
'n' => 'plan',
|
|
28
|
+
'v' => plan.to_s
|
|
29
|
+
}]
|
|
30
|
+
|
|
31
|
+
send_command_with_confirm main.c_id, command_list, options, "dynamic bands plan #{plan}", nil
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# M0023 — Set timeout for dynamic bands.
|
|
35
|
+
def set_dynamic_bands_timeout(status, options: {})
|
|
36
|
+
validate_ready 'set dynamic bands timeout'
|
|
37
|
+
raise 'TLC main component not found' unless main
|
|
38
|
+
|
|
39
|
+
security_code = security_code_for(2)
|
|
40
|
+
|
|
41
|
+
command_list = [{
|
|
42
|
+
'cCI' => 'M0023',
|
|
43
|
+
'cO' => 'setTimeout',
|
|
44
|
+
'n' => 'status',
|
|
45
|
+
'v' => status.to_s
|
|
46
|
+
}, {
|
|
47
|
+
'cCI' => 'M0023',
|
|
48
|
+
'cO' => 'setTimeout',
|
|
49
|
+
'n' => 'securityCode',
|
|
50
|
+
'v' => security_code.to_s
|
|
51
|
+
}]
|
|
52
|
+
|
|
53
|
+
send_command_with_confirm main.c_id, command_list, options, "dynamic bands timeout #{status}", nil
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# M0015 — Set offset for a signal plan.
|
|
57
|
+
def set_offset(plan:, offset:, options: {})
|
|
58
|
+
validate_ready 'set offset'
|
|
59
|
+
raise 'TLC main component not found' unless main
|
|
60
|
+
|
|
61
|
+
security_code = security_code_for(2)
|
|
62
|
+
|
|
63
|
+
command_list = [{
|
|
64
|
+
'cCI' => 'M0015',
|
|
65
|
+
'cO' => 'setOffset',
|
|
66
|
+
'n' => 'status',
|
|
67
|
+
'v' => offset.to_s
|
|
68
|
+
}, {
|
|
69
|
+
'cCI' => 'M0015',
|
|
70
|
+
'cO' => 'setOffset',
|
|
71
|
+
'n' => 'securityCode',
|
|
72
|
+
'v' => security_code.to_s
|
|
73
|
+
}, {
|
|
74
|
+
'cCI' => 'M0015',
|
|
75
|
+
'cO' => 'setOffset',
|
|
76
|
+
'n' => 'plan',
|
|
77
|
+
'v' => plan.to_s
|
|
78
|
+
}]
|
|
79
|
+
|
|
80
|
+
send_command_with_confirm main.c_id, command_list, options, "offset plan #{plan} to #{offset}", nil
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Set the timeplan (signal plan) on the remote TLC.
|
|
84
|
+
def set_timeplan(plan_nr, options: {})
|
|
85
|
+
validate_ready 'set timeplan'
|
|
86
|
+
raise 'TLC main component not found' unless main
|
|
87
|
+
|
|
88
|
+
security_code = security_code_for(2)
|
|
89
|
+
|
|
90
|
+
command_list = [{
|
|
91
|
+
'cCI' => 'M0002',
|
|
92
|
+
'cO' => 'setPlan',
|
|
93
|
+
'n' => 'status',
|
|
94
|
+
'v' => 'True'
|
|
95
|
+
}, {
|
|
96
|
+
'cCI' => 'M0002',
|
|
97
|
+
'cO' => 'setPlan',
|
|
98
|
+
'n' => 'securityCode',
|
|
99
|
+
'v' => security_code.to_s
|
|
100
|
+
}, {
|
|
101
|
+
'cCI' => 'M0002',
|
|
102
|
+
'cO' => 'setPlan',
|
|
103
|
+
'n' => 'timeplan',
|
|
104
|
+
'v' => plan_nr.to_s
|
|
105
|
+
}]
|
|
106
|
+
|
|
107
|
+
confirm_status = [{ 'sCI' => 'S0014', 'n' => 'status', 's' => plan_nr.to_s }]
|
|
108
|
+
send_command_with_confirm main.c_id, command_list, options, "timeplan #{plan_nr}", confirm_status
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# M0016 — Set week table (mapping week days to traffic situations).
|
|
112
|
+
def set_week_table(status, options: {})
|
|
113
|
+
validate_ready 'set week table'
|
|
114
|
+
raise 'TLC main component not found' unless main
|
|
115
|
+
|
|
116
|
+
security_code = security_code_for(2)
|
|
117
|
+
|
|
118
|
+
command_list = [{
|
|
119
|
+
'cCI' => 'M0016',
|
|
120
|
+
'cO' => 'setWeekTable',
|
|
121
|
+
'n' => 'status',
|
|
122
|
+
'v' => status.to_s
|
|
123
|
+
}, {
|
|
124
|
+
'cCI' => 'M0016',
|
|
125
|
+
'cO' => 'setWeekTable',
|
|
126
|
+
'n' => 'securityCode',
|
|
127
|
+
'v' => security_code.to_s
|
|
128
|
+
}]
|
|
129
|
+
|
|
130
|
+
send_command_with_confirm main.c_id, command_list, options, 'week table', nil
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# M0017 — Set day table (mapping time periods to signal plans).
|
|
134
|
+
def set_day_table(status, options: {})
|
|
135
|
+
validate_ready 'set day table'
|
|
136
|
+
raise 'TLC main component not found' unless main
|
|
137
|
+
|
|
138
|
+
security_code = security_code_for(2)
|
|
139
|
+
|
|
140
|
+
command_list = [{
|
|
141
|
+
'cCI' => 'M0017',
|
|
142
|
+
'cO' => 'setDayTable',
|
|
143
|
+
'n' => 'status',
|
|
144
|
+
'v' => status.to_s
|
|
145
|
+
}, {
|
|
146
|
+
'cCI' => 'M0017',
|
|
147
|
+
'cO' => 'setDayTable',
|
|
148
|
+
'n' => 'securityCode',
|
|
149
|
+
'v' => security_code.to_s
|
|
150
|
+
}]
|
|
151
|
+
|
|
152
|
+
send_command_with_confirm main.c_id, command_list, options, 'day table', nil
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# M0018 — Set cycle time for a signal plan.
|
|
156
|
+
def set_cycle_time(plan:, cycle_time:, options: {})
|
|
157
|
+
validate_ready 'set cycle time'
|
|
158
|
+
raise 'TLC main component not found' unless main
|
|
159
|
+
|
|
160
|
+
security_code = security_code_for(2)
|
|
161
|
+
|
|
162
|
+
command_list = [{
|
|
163
|
+
'cCI' => 'M0018',
|
|
164
|
+
'cO' => 'setCycleTime',
|
|
165
|
+
'n' => 'status',
|
|
166
|
+
'v' => cycle_time.to_s
|
|
167
|
+
}, {
|
|
168
|
+
'cCI' => 'M0018',
|
|
169
|
+
'cO' => 'setCycleTime',
|
|
170
|
+
'n' => 'securityCode',
|
|
171
|
+
'v' => security_code.to_s
|
|
172
|
+
}, {
|
|
173
|
+
'cCI' => 'M0018',
|
|
174
|
+
'cO' => 'setCycleTime',
|
|
175
|
+
'n' => 'plan',
|
|
176
|
+
'v' => plan.to_s
|
|
177
|
+
}]
|
|
178
|
+
|
|
179
|
+
send_command_with_confirm main.c_id, command_list, options, "cycle time plan #{plan} to #{cycle_time}", nil
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# M0010 — Order signal start for a signal group component.
|
|
183
|
+
def order_signal_start(component_id, options: {})
|
|
184
|
+
validate_ready 'order signal start'
|
|
185
|
+
|
|
186
|
+
security_code = security_code_for(2)
|
|
187
|
+
|
|
188
|
+
command_list = [{
|
|
189
|
+
'cCI' => 'M0010',
|
|
190
|
+
'cO' => 'setStart',
|
|
191
|
+
'n' => 'status',
|
|
192
|
+
'v' => 'True'
|
|
193
|
+
}, {
|
|
194
|
+
'cCI' => 'M0010',
|
|
195
|
+
'cO' => 'setStart',
|
|
196
|
+
'n' => 'securityCode',
|
|
197
|
+
'v' => security_code.to_s
|
|
198
|
+
}]
|
|
199
|
+
|
|
200
|
+
send_command_with_confirm component_id, command_list, options, "signal start #{component_id}", nil
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# M0011 — Order signal stop for a signal group component.
|
|
204
|
+
def order_signal_stop(component_id, options: {})
|
|
205
|
+
validate_ready 'order signal stop'
|
|
206
|
+
|
|
207
|
+
security_code = security_code_for(2)
|
|
208
|
+
|
|
209
|
+
command_list = [{
|
|
210
|
+
'cCI' => 'M0011',
|
|
211
|
+
'cO' => 'setStop',
|
|
212
|
+
'n' => 'status',
|
|
213
|
+
'v' => 'True'
|
|
214
|
+
}, {
|
|
215
|
+
'cCI' => 'M0011',
|
|
216
|
+
'cO' => 'setStop',
|
|
217
|
+
'n' => 'securityCode',
|
|
218
|
+
'v' => security_code.to_s
|
|
219
|
+
}]
|
|
220
|
+
|
|
221
|
+
send_command_with_confirm component_id, command_list, options, "signal stop #{component_id}", nil
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
module RSMP
|
|
2
|
+
module TLC
|
|
3
|
+
module Proxy
|
|
4
|
+
# Status reading and waiting methods for a remote TLC.
|
|
5
|
+
# Covers status subscriptions, group waits, and plan/band reading.
|
|
6
|
+
module Status
|
|
7
|
+
# Fetch the current signal plan from the remote TLC.
|
|
8
|
+
def fetch_signal_plan(options: {})
|
|
9
|
+
validate_ready 'fetch signal plan'
|
|
10
|
+
|
|
11
|
+
status_list = [{
|
|
12
|
+
'sCI' => 'S0014',
|
|
13
|
+
'n' => 'status'
|
|
14
|
+
}, {
|
|
15
|
+
'sCI' => 'S0014',
|
|
16
|
+
'n' => 'source'
|
|
17
|
+
}]
|
|
18
|
+
|
|
19
|
+
request_status main.c_id, status_list, @timeouts.merge(options)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Subscribe to one or more statuses and wait until they match the expected values.
|
|
23
|
+
# Raises RSMP::TimeoutError if the values don't match within the timeout.
|
|
24
|
+
#
|
|
25
|
+
# status_list items: { 'sCI' => ..., 'n' => ..., 's' => <expected value or Regexp> }
|
|
26
|
+
# component_id defaults to the main TLC component.
|
|
27
|
+
# timeout defaults to @timeouts['command'].
|
|
28
|
+
def wait_for_status(description, status_list, update_rate: 0, timeout: nil, component_id: nil)
|
|
29
|
+
validate_ready 'wait for status'
|
|
30
|
+
component_id ||= main.c_id
|
|
31
|
+
timeout ||= @timeouts['command']
|
|
32
|
+
|
|
33
|
+
subscribe_list = status_list.map do |item|
|
|
34
|
+
entry = item.merge('uRt' => update_rate.to_s)
|
|
35
|
+
entry = entry.merge('sOc' => true) if use_soc?
|
|
36
|
+
entry
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
log "Wait for #{description}", level: :debug
|
|
40
|
+
|
|
41
|
+
begin
|
|
42
|
+
subscribe_to_status component_id, subscribe_list, collect!: { timeout: timeout }
|
|
43
|
+
ensure
|
|
44
|
+
unsubscribe_list = status_list.map { |item| item.slice('sCI', 'n') }
|
|
45
|
+
unsubscribe_to_status component_id, unsubscribe_list
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Wait for all signal groups to match state (as regex string, e.g. 'c' for yellow flash).
|
|
50
|
+
def wait_for_groups(state, timeout:)
|
|
51
|
+
regex = /^#{state}+$/
|
|
52
|
+
wait_for_status(
|
|
53
|
+
"all groups to reach state #{state}",
|
|
54
|
+
[{ 'sCI' => 'S0001', 'n' => 'signalgroupstatus', 's' => regex }],
|
|
55
|
+
timeout: timeout
|
|
56
|
+
)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Wait for the TLC to return to normal control mode (functional position NormalControl,
|
|
60
|
+
# yellow flash off, startup mode off).
|
|
61
|
+
def wait_for_normal_control(timeout: nil)
|
|
62
|
+
wait_for_status(
|
|
63
|
+
'normal control on, yellow flash off, startup mode off',
|
|
64
|
+
[
|
|
65
|
+
{ 'sCI' => 'S0007', 'n' => 'status', 's' => /^True(,True)*$/ },
|
|
66
|
+
{ 'sCI' => 'S0011', 'n' => 'status', 's' => /^False(,False)*$/ },
|
|
67
|
+
{ 'sCI' => 'S0005', 'n' => 'status', 's' => 'False' }
|
|
68
|
+
],
|
|
69
|
+
timeout: timeout
|
|
70
|
+
)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Read cycle times for all plans via S0028.
|
|
74
|
+
# Returns a hash of plan_nr (Integer) => cycle_time (Integer, seconds).
|
|
75
|
+
def read_cycle_times(options: {})
|
|
76
|
+
validate_ready 'read cycle times'
|
|
77
|
+
timeout = options[:timeout] || @timeouts['status_response']
|
|
78
|
+
result = request_status main.c_id,
|
|
79
|
+
[{ 'sCI' => 'S0028', 'n' => 'status' }],
|
|
80
|
+
collect!: { timeout: timeout }
|
|
81
|
+
result[:collector].messages.first.attributes['sS'].first['s'].split(',').to_h do |item|
|
|
82
|
+
item.split('-').map(&:to_i)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Read the current signal plan number via S0014.
|
|
87
|
+
# Returns the plan number as an Integer.
|
|
88
|
+
def read_current_plan(options: {})
|
|
89
|
+
validate_ready 'read current plan'
|
|
90
|
+
timeout = options[:timeout] || @timeouts['status_response']
|
|
91
|
+
result = request_status main.c_id,
|
|
92
|
+
[{ 'sCI' => 'S0014', 'n' => 'status' }],
|
|
93
|
+
collect!: { timeout: timeout }
|
|
94
|
+
result[:collector].messages.first.attributes['sS'].first['s'].to_i
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Read the value of a single dynamic band for a given plan and band index via S0023.
|
|
98
|
+
# Returns the band value as an Integer, or nil if not found.
|
|
99
|
+
def read_dynamic_band(plan:, band:, options: {})
|
|
100
|
+
validate_ready 'read dynamic band'
|
|
101
|
+
timeout = options[:timeout] || @timeouts['status_response']
|
|
102
|
+
result = request_status main.c_id,
|
|
103
|
+
[{ 'sCI' => 'S0023', 'n' => 'status' }],
|
|
104
|
+
collect!: { timeout: timeout }
|
|
105
|
+
extract_band_value(result, plan, band)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
private
|
|
109
|
+
|
|
110
|
+
def extract_band_value(result, plan, band)
|
|
111
|
+
result[:collector].messages.first.attributes['sS'].first['s'].split(',').each do |item|
|
|
112
|
+
some_plan, some_band, value = item.split('-')
|
|
113
|
+
return value.to_i if some_plan.to_i == plan.to_i && some_band.to_i == band.to_i
|
|
114
|
+
end
|
|
115
|
+
nil
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module RSMP
|
|
2
|
+
module TLC
|
|
3
|
+
module Proxy
|
|
4
|
+
# Command methods for operational control of a remote TLC.
|
|
5
|
+
# Covers functional position, emergency routes, I/O modes, signal group orders, and system settings.
|
|
6
|
+
module System
|
|
7
|
+
# M0103 — Change security code for a given level.
|
|
8
|
+
# Does not use security_code_for since the codes are passed explicitly.
|
|
9
|
+
def set_security_code(level:, old_code:, new_code:, options: {})
|
|
10
|
+
validate_ready 'set security code'
|
|
11
|
+
raise 'TLC main component not found' unless main
|
|
12
|
+
|
|
13
|
+
command_list = [{
|
|
14
|
+
'cCI' => 'M0103',
|
|
15
|
+
'cO' => 'setSecurityCode',
|
|
16
|
+
'n' => 'status',
|
|
17
|
+
'v' => level.to_s
|
|
18
|
+
}, {
|
|
19
|
+
'cCI' => 'M0103',
|
|
20
|
+
'cO' => 'setSecurityCode',
|
|
21
|
+
'n' => 'oldSecurityCode',
|
|
22
|
+
'v' => old_code.to_s
|
|
23
|
+
}, {
|
|
24
|
+
'cCI' => 'M0103',
|
|
25
|
+
'cO' => 'setSecurityCode',
|
|
26
|
+
'n' => 'newSecurityCode',
|
|
27
|
+
'v' => new_code.to_s
|
|
28
|
+
}]
|
|
29
|
+
|
|
30
|
+
send_command_with_confirm main.c_id, command_list, options, "security code level #{level}", nil
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# M0104 — Set the clock on the remote TLC. clock must respond to year/month/day/hour/min/sec.
|
|
34
|
+
def set_clock(clock, options: {})
|
|
35
|
+
validate_ready 'set clock'
|
|
36
|
+
raise 'TLC main component not found' unless main
|
|
37
|
+
|
|
38
|
+
send_command_with_confirm main.c_id, clock_command_list(clock), options, 'clock', nil
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def clock_command_list(clock)
|
|
44
|
+
security_code = security_code_for(1)
|
|
45
|
+
[
|
|
46
|
+
{ 'cCI' => 'M0104', 'cO' => 'setDate', 'n' => 'securityCode', 'v' => security_code.to_s },
|
|
47
|
+
{ 'cCI' => 'M0104', 'cO' => 'setDate', 'n' => 'year', 'v' => clock.year.to_s },
|
|
48
|
+
{ 'cCI' => 'M0104', 'cO' => 'setDate', 'n' => 'month', 'v' => clock.month.to_s },
|
|
49
|
+
{ 'cCI' => 'M0104', 'cO' => 'setDate', 'n' => 'day', 'v' => clock.day.to_s },
|
|
50
|
+
{ 'cCI' => 'M0104', 'cO' => 'setDate', 'n' => 'hour', 'v' => clock.hour.to_s },
|
|
51
|
+
{ 'cCI' => 'M0104', 'cO' => 'setDate', 'n' => 'minute', 'v' => clock.min.to_s },
|
|
52
|
+
{ 'cCI' => 'M0104', 'cO' => 'setDate', 'n' => 'second', 'v' => clock.sec.to_s }
|
|
53
|
+
]
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|