rsmp 0.45.0 → 0.45.2
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/.github/workflows/rubocop.yaml +1 -1
- data/.github/workflows/sus.yaml +1 -1
- data/.gitignore +0 -1
- data/AGENTS.md +57 -0
- data/CHANGELOG.md +12 -1
- data/Gemfile +0 -2
- data/Gemfile.lock +2 -80
- data/README.md +14 -35
- data/documentation/configuration.md +22 -21
- data/documentation/message_distribution.md +1 -2
- data/documentation/tasks.md +1 -2
- data/exe/rsmp +1 -2
- data/lib/rsmp/cli.rb +33 -3
- data/lib/rsmp/convert/export/json_schema/outputs.rb +18 -0
- data/lib/rsmp/convert/export/json_schema/values.rb +1 -1
- data/lib/rsmp/convert/export/json_schema.rb +14 -6
- data/lib/rsmp/schema/core_sxl_resolution.rb +69 -0
- data/lib/rsmp/schema/validation.rb +57 -0
- data/lib/rsmp/schema.rb +40 -67
- data/lib/rsmp/tlc/proxy/control.rb +5 -5
- data/lib/rsmp/tlc/proxy/detectors.rb +2 -2
- data/lib/rsmp/tlc/proxy/io.rb +4 -4
- data/lib/rsmp/tlc/proxy/plans.rb +8 -8
- data/lib/rsmp/tlc/proxy/system.rb +2 -2
- data/lib/rsmp/version.rb +1 -1
- data/schemas/tlc/1.0.10/rsmp.json +2 -1
- data/schemas/tlc/1.0.10/sxl.yaml +1 -0
- data/schemas/tlc/1.0.10/sxl_index.json +356 -0
- data/schemas/tlc/1.0.13/rsmp.json +2 -1
- data/schemas/tlc/1.0.13/sxl.yaml +1 -0
- data/schemas/tlc/1.0.13/sxl_index.json +436 -0
- data/schemas/tlc/1.0.14/rsmp.json +2 -1
- data/schemas/tlc/1.0.14/sxl.yaml +1 -0
- data/schemas/tlc/1.0.14/sxl_index.json +468 -0
- data/schemas/tlc/1.0.15/rsmp.json +2 -1
- data/schemas/tlc/1.0.15/sxl.yaml +1 -0
- data/schemas/tlc/1.0.15/sxl_index.json +508 -0
- data/schemas/tlc/1.0.7/rsmp.json +2 -1
- data/schemas/tlc/1.0.7/sxl.yaml +1 -0
- data/schemas/tlc/1.0.7/sxl_index.json +356 -0
- data/schemas/tlc/1.0.8/rsmp.json +2 -1
- data/schemas/tlc/1.0.8/sxl.yaml +1 -0
- data/schemas/tlc/1.0.8/sxl_index.json +356 -0
- data/schemas/tlc/1.0.9/rsmp.json +2 -1
- data/schemas/tlc/1.0.9/sxl.yaml +1 -0
- data/schemas/tlc/1.0.9/sxl_index.json +356 -0
- data/schemas/tlc/1.1.0/rsmp.json +2 -1
- data/schemas/tlc/1.1.0/sxl.yaml +1 -0
- data/schemas/tlc/1.1.0/sxl_index.json +572 -0
- data/schemas/tlc/1.2.0/rsmp.json +2 -1
- data/schemas/tlc/1.2.0/sxl.yaml +1 -0
- data/schemas/tlc/1.2.0/sxl_index.json +571 -0
- data/schemas/tlc/1.2.1/rsmp.json +2 -1
- data/schemas/tlc/1.2.1/sxl.yaml +1 -0
- data/schemas/tlc/1.2.1/sxl_index.json +571 -0
- data/schemas/tlc/1.3.0/defs/definitions.json +86 -25
- data/schemas/tlc/1.3.0/rsmp.json +2 -1
- data/schemas/tlc/1.3.0/statuses/S0024.json +2 -1
- data/schemas/tlc/1.3.0/sxl.yaml +1 -0
- data/schemas/tlc/1.3.0/sxl_index.json +578 -0
- metadata +15 -4
- data/.github/copilot-instructions.md +0 -33
- data/.rspec +0 -1
- data/cucumber.yml +0 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
module RSMP
|
|
2
|
+
# Provides JSON Schema validation for RSMP messages across core and SXL versions.
|
|
3
|
+
module Schema
|
|
4
|
+
def self.clear_core_sxl_schemas(type = nil, version = nil)
|
|
5
|
+
@core_sxl_schemas ||= {}
|
|
6
|
+
return @core_sxl_schemas.clear unless type
|
|
7
|
+
|
|
8
|
+
type = type.to_sym
|
|
9
|
+
@core_sxl_schemas.delete_if do |(cached_type, cached_version, _core_version), _schema|
|
|
10
|
+
cached_type == type && (!version || cached_version == version.to_s)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.schema_core_version(schemas)
|
|
15
|
+
schemas[:core] || schemas['core']
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.validate_resolved_sxl(message, resolved, schemas, options)
|
|
19
|
+
type, version = resolved
|
|
20
|
+
schema = find_core_sxl_schema! type, version, schema_core_version(schemas), options
|
|
21
|
+
validate_using_schema(message, schema)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.find_core_sxl_schema!(type, version, core_version, options = {})
|
|
25
|
+
raise ArgumentError, 'core version missing' unless core_version
|
|
26
|
+
|
|
27
|
+
version = sanitize_version(version.to_s) if options[:lenient]
|
|
28
|
+
core_version = sanitize_version(core_version.to_s) if options[:lenient]
|
|
29
|
+
find_schema! type, version
|
|
30
|
+
find_schema! :core, core_version
|
|
31
|
+
|
|
32
|
+
key = [type.to_sym, version.to_s, core_version.to_s]
|
|
33
|
+
@core_sxl_schemas ||= {}
|
|
34
|
+
@core_sxl_schemas[key] ||= build_core_sxl_schema(type, version, core_version)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.build_core_sxl_schema(type, version, core_version)
|
|
38
|
+
schema_path = @schema_paths&.dig(type.to_sym, version.to_s)
|
|
39
|
+
raise UnknownSchemaVersionError, "Unknown schema version #{type} #{version}" unless schema_path
|
|
40
|
+
|
|
41
|
+
file_path = File.join(schema_path, 'rsmp.json')
|
|
42
|
+
JSONSchemer.schema(
|
|
43
|
+
Pathname.new(file_path),
|
|
44
|
+
ref_resolver: core_sxl_ref_resolver(core_version)
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.core_sxl_ref_resolver(core_version)
|
|
49
|
+
proc do |uri|
|
|
50
|
+
if sxl_definitions_ref?(uri)
|
|
51
|
+
JSON.parse(File.read(core_definitions_path(core_version), encoding: 'UTF-8'))
|
|
52
|
+
else
|
|
53
|
+
JSONSchemer::FILE_URI_REF_RESOLVER.call(uri)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.sxl_definitions_ref?(uri)
|
|
59
|
+
uri.scheme == 'file' && uri.path.end_with?('/defs/definitions.json')
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def self.core_definitions_path(core_version)
|
|
63
|
+
path = File.join(schema_root_path, 'core', core_version.to_s, 'definitions.json')
|
|
64
|
+
return path if File.exist?(path)
|
|
65
|
+
|
|
66
|
+
raise UnknownSchemaVersionError, "Missing core definitions for RSMP #{core_version}"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
module RSMP
|
|
2
|
+
# Provides JSON Schema validation for RSMP messages across core and SXL versions.
|
|
3
|
+
module Schema
|
|
4
|
+
def self.core_message_type?(message)
|
|
5
|
+
type = message['type']
|
|
6
|
+
%w[
|
|
7
|
+
MessageAck
|
|
8
|
+
MessageNotAck
|
|
9
|
+
Version
|
|
10
|
+
ComponentList
|
|
11
|
+
AggregatedStatus
|
|
12
|
+
AggregatedStatusRequest
|
|
13
|
+
Watchdog
|
|
14
|
+
].include?(type)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.validate_core(message, schemas, options)
|
|
18
|
+
core_version = schemas[:core] || schemas['core']
|
|
19
|
+
raise ArgumentError, 'schemas must include core' unless core_version
|
|
20
|
+
|
|
21
|
+
schema = find_schema! :core, core_version, options
|
|
22
|
+
validate_using_schema(message, schema)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.validate_sxls(message, schemas, options)
|
|
26
|
+
sxl_schemas = schemas.reject { |type, _version| type.to_sym == :core }
|
|
27
|
+
return [] if sxl_schemas.empty? || core_message_type?(message)
|
|
28
|
+
|
|
29
|
+
resolved = resolve_sxl(message, schemas: schemas, **options)
|
|
30
|
+
return validate_resolved_sxl(message, resolved, schemas, options) if resolved
|
|
31
|
+
|
|
32
|
+
all_errors = []
|
|
33
|
+
sxl_schemas.each do |type, version|
|
|
34
|
+
schema = find_core_sxl_schema! type, version, schema_core_version(schemas), options
|
|
35
|
+
errors = validate_using_schema(message, schema)
|
|
36
|
+
return [] if errors.empty?
|
|
37
|
+
|
|
38
|
+
all_errors.concat errors
|
|
39
|
+
end
|
|
40
|
+
all_errors
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Core must pass. SXL-defined messages pass if at least one SXL schema passes.
|
|
44
|
+
def self.validate(message, schemas, options = {})
|
|
45
|
+
raise ArgumentError, 'message missing' unless message
|
|
46
|
+
raise ArgumentError, 'schemas missing' unless schemas
|
|
47
|
+
raise ArgumentError, 'schemas must be a Hash' unless schemas.is_a?(Hash)
|
|
48
|
+
raise ArgumentError, 'schemas cannot be empty' unless schemas.any?
|
|
49
|
+
|
|
50
|
+
errors = validate_core(message, schemas, options)
|
|
51
|
+
errors.concat validate_sxls(message, schemas, options) if errors.empty?
|
|
52
|
+
return nil if errors.empty?
|
|
53
|
+
|
|
54
|
+
errors
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
data/lib/rsmp/schema.rb
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
require 'json_schemer'
|
|
2
2
|
require 'json'
|
|
3
|
-
require 'yaml'
|
|
4
3
|
|
|
5
4
|
# RSMP (Road Side Message Protocol) schema validation library.
|
|
6
5
|
module RSMP
|
|
@@ -11,13 +10,19 @@ module RSMP
|
|
|
11
10
|
def self.setup
|
|
12
11
|
@schemas = {}
|
|
13
12
|
@schema_paths = {}
|
|
14
|
-
|
|
13
|
+
@sxl_indexes = {}
|
|
14
|
+
@core_sxl_schemas = {}
|
|
15
|
+
schemas_path = schema_root_path
|
|
15
16
|
Dir.glob("#{schemas_path}/*").select { |f| File.directory? f }.each do |type_path|
|
|
16
17
|
type = File.basename(type_path).to_sym
|
|
17
18
|
load_schema_type type, type_path
|
|
18
19
|
end
|
|
19
20
|
end
|
|
20
21
|
|
|
22
|
+
def self.schema_root_path
|
|
23
|
+
File.expand_path(File.join(__dir__, '..', '..', 'schemas'))
|
|
24
|
+
end
|
|
25
|
+
|
|
21
26
|
# load an schema from a folder. schemas are organized by version, and contain
|
|
22
27
|
# json schema files, with the entry point being rsmp.jspon, eg:
|
|
23
28
|
# tlc
|
|
@@ -35,6 +40,8 @@ module RSMP
|
|
|
35
40
|
@schemas[type] = {}
|
|
36
41
|
@schema_paths ||= {}
|
|
37
42
|
@schema_paths[type] = {}
|
|
43
|
+
clear_sxl_index(type)
|
|
44
|
+
clear_core_sxl_schemas(type)
|
|
38
45
|
schema_version_paths(type_path).each { |schema_path| load_schema_version(type, schema_path) }
|
|
39
46
|
end
|
|
40
47
|
|
|
@@ -53,6 +60,8 @@ module RSMP
|
|
|
53
60
|
|
|
54
61
|
@schemas[type][version] = JSONSchemer.schema(Pathname.new(file_path))
|
|
55
62
|
@schema_paths[type][version] = schema_path
|
|
63
|
+
clear_sxl_index(type, version)
|
|
64
|
+
clear_core_sxl_schemas(type, version)
|
|
56
65
|
end
|
|
57
66
|
|
|
58
67
|
# remove a schema type
|
|
@@ -60,6 +69,8 @@ module RSMP
|
|
|
60
69
|
type = type.to_sym
|
|
61
70
|
schemas.delete type
|
|
62
71
|
@schema_paths&.delete type
|
|
72
|
+
clear_sxl_index(type)
|
|
73
|
+
clear_core_sxl_schemas(type)
|
|
63
74
|
end
|
|
64
75
|
|
|
65
76
|
# get schemas types
|
|
@@ -195,14 +206,7 @@ module RSMP
|
|
|
195
206
|
version = sanitize_version version if options[:lenient]
|
|
196
207
|
find_schema! type, version
|
|
197
208
|
|
|
198
|
-
|
|
199
|
-
return {} unless path
|
|
200
|
-
|
|
201
|
-
yaml_path = File.join(path, 'sxl.yaml')
|
|
202
|
-
return YAML.load_file(yaml_path).fetch('meta', {}) if File.exist?(yaml_path)
|
|
203
|
-
|
|
204
|
-
json_path = File.join(path, 'rsmp.json')
|
|
205
|
-
File.exist?(json_path) ? JSON.parse(File.read(json_path)) : {}
|
|
209
|
+
sxl_index(type, version).fetch('meta', {})
|
|
206
210
|
end
|
|
207
211
|
|
|
208
212
|
def self.sxl_prefix(type, version, options = {})
|
|
@@ -211,82 +215,51 @@ module RSMP
|
|
|
211
215
|
|
|
212
216
|
# return a catalogue of statuses for a particular schema type and version
|
|
213
217
|
# returns a hash of { status_code_id_sym => [arg_name_sym, ...] }
|
|
214
|
-
# raises an error if the schema type/version is not found, or has no
|
|
218
|
+
# raises an error if the schema type/version is not found, or has no status catalogue
|
|
215
219
|
def self.status_catalogue(type, version)
|
|
216
220
|
sxl_catalogue(type, version, :statuses).transform_keys(&:to_sym).transform_values do |status|
|
|
217
|
-
(
|
|
221
|
+
status.fetch('arguments', []).map(&:to_sym)
|
|
218
222
|
end
|
|
219
223
|
end
|
|
220
224
|
|
|
221
225
|
def self.sxl_catalogue(type, version, kind)
|
|
222
226
|
find_schema! type, version
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
raise "No sxl.yaml for #{type} #{version}" unless yaml_path && File.exist?(yaml_path)
|
|
226
|
-
|
|
227
|
-
sxl = RSMP::Convert::Import::YAML.read(yaml_path)
|
|
228
|
-
sxl.fetch(kind)
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
def self.core_message_type?(message)
|
|
232
|
-
type = message['type']
|
|
233
|
-
%w[
|
|
234
|
-
MessageAck
|
|
235
|
-
MessageNotAck
|
|
236
|
-
Version
|
|
237
|
-
ComponentList
|
|
238
|
-
AggregatedStatus
|
|
239
|
-
AggregatedStatusRequest
|
|
240
|
-
Watchdog
|
|
241
|
-
].include?(type)
|
|
242
|
-
end
|
|
227
|
+
catalogue = sxl_index(type, version)[kind.to_s]
|
|
228
|
+
raise "No #{kind} catalogue for #{type} #{version}" unless catalogue
|
|
243
229
|
|
|
244
|
-
|
|
245
|
-
core_version = schemas[:core] || schemas['core']
|
|
246
|
-
raise ArgumentError, 'schemas must include core' unless core_version
|
|
247
|
-
|
|
248
|
-
schema = find_schema! :core, core_version, options
|
|
249
|
-
validate_using_schema(message, schema)
|
|
230
|
+
catalogue
|
|
250
231
|
end
|
|
251
232
|
|
|
252
|
-
def self.
|
|
253
|
-
|
|
254
|
-
return
|
|
233
|
+
def self.clear_sxl_index(type = nil, version = nil)
|
|
234
|
+
@sxl_indexes ||= {}
|
|
235
|
+
return @sxl_indexes.clear unless type
|
|
255
236
|
|
|
256
|
-
|
|
257
|
-
if
|
|
258
|
-
type, version
|
|
259
|
-
|
|
260
|
-
|
|
237
|
+
type = type.to_sym
|
|
238
|
+
if version
|
|
239
|
+
@sxl_indexes.delete([type, version.to_s])
|
|
240
|
+
else
|
|
241
|
+
@sxl_indexes.delete_if { |key, _value| key.first == type }
|
|
261
242
|
end
|
|
243
|
+
end
|
|
262
244
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
return [] if errors.empty?
|
|
268
|
-
|
|
269
|
-
all_errors.concat errors
|
|
270
|
-
end
|
|
271
|
-
all_errors
|
|
245
|
+
def self.sxl_index(type, version)
|
|
246
|
+
key = [type.to_sym, version.to_s]
|
|
247
|
+
@sxl_indexes ||= {}
|
|
248
|
+
@sxl_indexes[key] ||= load_sxl_index(type, version)
|
|
272
249
|
end
|
|
273
250
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
def self.validate(message, schemas, options = {})
|
|
278
|
-
raise ArgumentError, 'message missing' unless message
|
|
279
|
-
raise ArgumentError, 'schemas missing' unless schemas
|
|
280
|
-
raise ArgumentError, 'schemas must be a Hash' unless schemas.is_a?(Hash)
|
|
281
|
-
raise ArgumentError, 'schemas cannot be empty' unless schemas.any?
|
|
251
|
+
def self.load_sxl_index(type, version)
|
|
252
|
+
schema_path = @schema_paths&.dig(type.to_sym, version.to_s)
|
|
253
|
+
raise UnknownSchemaVersionError, "Unknown schema version #{type} #{version}" unless schema_path
|
|
282
254
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
return nil if errors.empty?
|
|
255
|
+
index_path = File.join(schema_path, 'sxl_index.json')
|
|
256
|
+
raise Error, "Missing SXL index #{index_path}" unless File.exist?(index_path)
|
|
286
257
|
|
|
287
|
-
|
|
258
|
+
JSON.parse(File.read(index_path, encoding: 'UTF-8'))
|
|
288
259
|
end
|
|
289
260
|
end
|
|
290
261
|
end
|
|
291
262
|
|
|
263
|
+
require_relative 'schema/core_sxl_resolution'
|
|
292
264
|
require_relative 'schema/message_resolution'
|
|
265
|
+
require_relative 'schema/validation'
|
|
@@ -4,7 +4,7 @@ module RSMP
|
|
|
4
4
|
# Command methods for operational control of a remote TLC.
|
|
5
5
|
# Covers functional position, emergency routes, I/O modes, signal group orders, and system settings.
|
|
6
6
|
module Control
|
|
7
|
-
# M0001
|
|
7
|
+
# M0001 - Set functional position (NormalControl, YellowFlash, Dark).
|
|
8
8
|
def set_functional_position(status, within:, timeout_minutes: 0)
|
|
9
9
|
validate_ready 'set functional position'
|
|
10
10
|
raise 'TLC main component not found' unless main
|
|
@@ -17,7 +17,7 @@ module RSMP
|
|
|
17
17
|
{ collector: collector }
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
# M0005
|
|
20
|
+
# M0005 - Set or clear an emergency route.
|
|
21
21
|
def set_emergency_route(route:, active:, within:)
|
|
22
22
|
validate_ready 'set emergency route'
|
|
23
23
|
raise 'TLC main component not found' unless main
|
|
@@ -45,7 +45,7 @@ module RSMP
|
|
|
45
45
|
send_command_and_collect(command_list, within: within).ok!
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
-
# M0007
|
|
48
|
+
# M0007 - Enable or disable fixed-time control.
|
|
49
49
|
def set_fixed_time(status, within:)
|
|
50
50
|
validate_ready 'set fixed time'
|
|
51
51
|
raise 'TLC main component not found' unless main
|
|
@@ -70,7 +70,7 @@ module RSMP
|
|
|
70
70
|
wait_for_status "fixed time #{status}", confirm_status, timeout: within
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
-
# M0003
|
|
73
|
+
# M0003 - Set traffic situation (activate a specific situation number).
|
|
74
74
|
def set_traffic_situation(situation, within:)
|
|
75
75
|
validate_ready 'set traffic situation'
|
|
76
76
|
raise 'TLC main component not found' unless main
|
|
@@ -99,7 +99,7 @@ module RSMP
|
|
|
99
99
|
wait_for_status "traffic situation #{situation}", confirm_status, timeout: within
|
|
100
100
|
end
|
|
101
101
|
|
|
102
|
-
# M0003
|
|
102
|
+
# M0003 - Clear the active traffic situation.
|
|
103
103
|
def unset_traffic_situation(within:)
|
|
104
104
|
validate_ready 'unset traffic situation'
|
|
105
105
|
raise 'TLC main component not found' unless main
|
|
@@ -4,7 +4,7 @@ module RSMP
|
|
|
4
4
|
# Command methods for operational control of a remote TLC.
|
|
5
5
|
# Covers functional position, emergency routes, I/O modes, signal group orders, and system settings.
|
|
6
6
|
module Detectors
|
|
7
|
-
# M0008
|
|
7
|
+
# M0008 - Force detector logic to a given mode and status.
|
|
8
8
|
# component_id must refer to the detector logic component, not main.
|
|
9
9
|
def force_detector_logic(component_id, status:, mode:, within:)
|
|
10
10
|
validate_ready 'force detector logic'
|
|
@@ -30,7 +30,7 @@ module RSMP
|
|
|
30
30
|
send_command_and_collect(command_list, component: component_id, within: within).ok!
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
# M0021
|
|
33
|
+
# M0021 - Set the trigger level for traffic counting.
|
|
34
34
|
def set_trigger_level(status, within:)
|
|
35
35
|
validate_ready 'set trigger level'
|
|
36
36
|
raise 'TLC main component not found' unless main
|
data/lib/rsmp/tlc/proxy/io.rb
CHANGED
|
@@ -4,7 +4,7 @@ module RSMP
|
|
|
4
4
|
# Command methods for I/O control of a remote TLC.
|
|
5
5
|
# Covers detector logic, input/output forcing and setting.
|
|
6
6
|
module IO
|
|
7
|
-
# M0006
|
|
7
|
+
# M0006 - Set a single input to a given status.
|
|
8
8
|
def set_input(input:, status:, within:)
|
|
9
9
|
validate_ready 'set input'
|
|
10
10
|
raise 'TLC main component not found' unless main
|
|
@@ -30,7 +30,7 @@ module RSMP
|
|
|
30
30
|
send_command_and_collect(command_list, within: within).ok!
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
# M0013
|
|
33
|
+
# M0013 - Set all inputs via a bit-pattern string.
|
|
34
34
|
def set_inputs(status, within:)
|
|
35
35
|
validate_ready 'set inputs'
|
|
36
36
|
raise 'TLC main component not found' unless main
|
|
@@ -51,7 +51,7 @@ module RSMP
|
|
|
51
51
|
send_command_and_collect(command_list, within: within).ok!
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
-
# M0019
|
|
54
|
+
# M0019 - Force an input to a given value.
|
|
55
55
|
def force_input(input:, status:, value:, within:)
|
|
56
56
|
validate_ready 'force input'
|
|
57
57
|
raise 'TLC main component not found' unless main
|
|
@@ -62,7 +62,7 @@ module RSMP
|
|
|
62
62
|
wait_for_status "force input #{input}", confirm_status, timeout: within
|
|
63
63
|
end
|
|
64
64
|
|
|
65
|
-
# M0020
|
|
65
|
+
# M0020 - Force an output to a given value.
|
|
66
66
|
def force_output(output:, status:, value:, within:)
|
|
67
67
|
validate_ready 'force output'
|
|
68
68
|
raise 'TLC main component not found' unless main
|
data/lib/rsmp/tlc/proxy/plans.rb
CHANGED
|
@@ -4,7 +4,7 @@ module RSMP
|
|
|
4
4
|
# Command methods for signal plans.
|
|
5
5
|
# Covers time plans, week/day tables, bands, offsets, and cycle times.
|
|
6
6
|
module Plans
|
|
7
|
-
# M0014
|
|
7
|
+
# M0014 - Set dynamic bands for a signal plan.
|
|
8
8
|
def set_dynamic_bands(plan:, status:, within:)
|
|
9
9
|
validate_ready 'set dynamic bands'
|
|
10
10
|
raise 'TLC main component not found' unless main
|
|
@@ -30,7 +30,7 @@ module RSMP
|
|
|
30
30
|
send_command_and_collect(command_list, within: within).ok!
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
# M0023
|
|
33
|
+
# M0023 - Set timeout for dynamic bands.
|
|
34
34
|
def set_dynamic_bands_timeout(status, within:)
|
|
35
35
|
validate_ready 'set dynamic bands timeout'
|
|
36
36
|
raise 'TLC main component not found' unless main
|
|
@@ -51,7 +51,7 @@ module RSMP
|
|
|
51
51
|
send_command_and_collect(command_list, within: within).ok!
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
-
# M0015
|
|
54
|
+
# M0015 - Set offset for a signal plan.
|
|
55
55
|
def set_offset(plan:, offset:, within:)
|
|
56
56
|
validate_ready 'set offset'
|
|
57
57
|
raise 'TLC main component not found' unless main
|
|
@@ -105,7 +105,7 @@ module RSMP
|
|
|
105
105
|
wait_for_status("timeplan #{plan_nr}", confirm_status, timeout: within)
|
|
106
106
|
end
|
|
107
107
|
|
|
108
|
-
# M0016
|
|
108
|
+
# M0016 - Set week table (mapping week days to traffic situations).
|
|
109
109
|
def set_week_table(status, within:)
|
|
110
110
|
validate_ready 'set week table'
|
|
111
111
|
raise 'TLC main component not found' unless main
|
|
@@ -126,7 +126,7 @@ module RSMP
|
|
|
126
126
|
send_command_and_collect(command_list, within:).ok!
|
|
127
127
|
end
|
|
128
128
|
|
|
129
|
-
# M0017
|
|
129
|
+
# M0017 - Set day table (mapping time periods to signal plans).
|
|
130
130
|
def set_day_table(status, within:)
|
|
131
131
|
validate_ready 'set day table'
|
|
132
132
|
raise 'TLC main component not found' unless main
|
|
@@ -147,7 +147,7 @@ module RSMP
|
|
|
147
147
|
send_command_and_collect(command_list, within:).ok!
|
|
148
148
|
end
|
|
149
149
|
|
|
150
|
-
# M0018
|
|
150
|
+
# M0018 - Set cycle time for a signal plan.
|
|
151
151
|
def set_cycle_time(plan:, cycle_time:, within:)
|
|
152
152
|
validate_ready 'set cycle time'
|
|
153
153
|
raise 'TLC main component not found' unless main
|
|
@@ -173,7 +173,7 @@ module RSMP
|
|
|
173
173
|
send_command_and_collect(command_list, within:).ok!
|
|
174
174
|
end
|
|
175
175
|
|
|
176
|
-
# M0010
|
|
176
|
+
# M0010 - Order signal start for a signal group component.
|
|
177
177
|
def order_signal_start(component_id, within:)
|
|
178
178
|
validate_ready 'order signal start'
|
|
179
179
|
|
|
@@ -193,7 +193,7 @@ module RSMP
|
|
|
193
193
|
send_command_and_collect(command_list, component: component_id, within:).ok!
|
|
194
194
|
end
|
|
195
195
|
|
|
196
|
-
# M0011
|
|
196
|
+
# M0011 - Order signal stop for a signal group component.
|
|
197
197
|
def order_signal_stop(component_id, within:)
|
|
198
198
|
validate_ready 'order signal stop'
|
|
199
199
|
|
|
@@ -4,7 +4,7 @@ module RSMP
|
|
|
4
4
|
# Command methods for operational control of a remote TLC.
|
|
5
5
|
# Covers functional position, emergency routes, I/O modes, signal group orders, and system settings.
|
|
6
6
|
module System
|
|
7
|
-
# M0103
|
|
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
10
|
validate_ready 'set security code'
|
|
@@ -29,7 +29,7 @@ module RSMP
|
|
|
29
29
|
send_command_and_collect(command_list, within: within).ok!
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
# M0104
|
|
32
|
+
# M0104 - Set the clock on the remote TLC. clock must respond to year/month/day/hour/min/sec.
|
|
33
33
|
def set_clock(clock, within:)
|
|
34
34
|
validate_ready 'set clock'
|
|
35
35
|
raise 'TLC main component not found' unless main
|
data/lib/rsmp/version.rb
CHANGED