rsmp 0.5.6 → 0.6.3
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 +2 -2
- data/config/supervisor.yaml +1 -8
- data/config/tlc.yaml +17 -12
- data/lib/rsmp/archive.rb +2 -2
- data/lib/rsmp/cli.rb +1 -1
- data/lib/rsmp/component.rb +2 -2
- data/lib/rsmp/components.rb +6 -3
- data/lib/rsmp/error.rb +3 -0
- data/lib/rsmp/logger.rb +10 -10
- data/lib/rsmp/logging.rb +1 -1
- data/lib/rsmp/node.rb +9 -0
- data/lib/rsmp/proxy.rb +9 -6
- data/lib/rsmp/supervisor.rb +1 -0
- data/lib/rsmp/tlc/detector_logic.rb +101 -0
- data/lib/rsmp/tlc/signal_group.rb +85 -0
- data/lib/rsmp/tlc/signal_plan.rb +29 -0
- data/lib/rsmp/tlc/traffic_controller.rb +652 -0
- data/lib/rsmp/tlc/traffic_controller_site.rb +136 -0
- data/lib/rsmp/version.rb +1 -1
- data/lib/rsmp.rb +5 -1
- metadata +8 -4
- data/lib/rsmp/tlc.rb +0 -920
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4072d3e93ef2223bfc9ac2cb1a1e34b3668456e52a622a2b6f059087dd442c2e
|
4
|
+
data.tar.gz: 37603275646789fec0db5ec4c85baf731bebe6786693e6ad57eae7be3b3c29ed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 84a5e06ed20c8cb3331cf13ebd9bfc8d2baaf6c81ec14d67e83900d198153d86b89aeb09485f87afa9ef5c2aa7ca4469caa190a745dc9936caedc31bbb14d5a5
|
7
|
+
data.tar.gz: 9aa602447f391353632bf59fccd2ca48ab2eea492913cab875614c50279c362f04ebbf89559d1ea6a72878ef22e632a29160379b682356e8411568710a9d8525
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rsmp (0.
|
4
|
+
rsmp (0.6.3)
|
5
5
|
async (~> 1.29.1)
|
6
6
|
async-io (~> 1.32.1)
|
7
7
|
colorize (~> 0.8.1)
|
@@ -96,7 +96,7 @@ GEM
|
|
96
96
|
thread_safe
|
97
97
|
rake (13.0.3)
|
98
98
|
regexp_parser (2.1.1)
|
99
|
-
rsmp_schemer (0.3.
|
99
|
+
rsmp_schemer (0.3.2)
|
100
100
|
json_schemer (~> 0.2.18)
|
101
101
|
rspec (3.10.0)
|
102
102
|
rspec-core (~> 3.10.0)
|
data/config/supervisor.yaml
CHANGED
@@ -8,16 +8,9 @@ guest:
|
|
8
8
|
watchdog: 0.2
|
9
9
|
acknowledgement: 0.2
|
10
10
|
log:
|
11
|
-
active: true
|
12
|
-
color: true
|
13
|
-
timestamp: true
|
14
|
-
id: true
|
15
|
-
component: true
|
16
|
-
ip: false
|
17
11
|
port: true
|
18
12
|
site_id: 9
|
19
|
-
|
20
|
-
text: true
|
13
|
+
component: 2
|
21
14
|
direction: false
|
22
15
|
level: false
|
23
16
|
debug: true
|
data/config/tlc.yaml
CHANGED
@@ -10,15 +10,27 @@ components:
|
|
10
10
|
cycle_time: 6
|
11
11
|
signal_group:
|
12
12
|
A1:
|
13
|
-
plan: '11NBBB'
|
14
13
|
A2:
|
15
|
-
plan: '1NBBBB'
|
16
14
|
B1:
|
17
|
-
plan: 'BBB11N'
|
18
15
|
B2:
|
19
|
-
plan: 'BBB1NB'
|
20
16
|
detector_logic:
|
21
17
|
DL1:
|
18
|
+
signal_plans:
|
19
|
+
1:
|
20
|
+
dynamic_bands:
|
21
|
+
1: 0
|
22
|
+
2: 5
|
23
|
+
states:
|
24
|
+
A1: '11NBBB'
|
25
|
+
A2: '1NBBBB'
|
26
|
+
B1: 'BBB11N'
|
27
|
+
B2: 'BBB1NB'
|
28
|
+
2:
|
29
|
+
states:
|
30
|
+
A1: '111NBB'
|
31
|
+
A2: '11NBBB'
|
32
|
+
B1: 'BBB11N'
|
33
|
+
B2: 'BBB1NB'
|
22
34
|
intervals:
|
23
35
|
timer: 0.1
|
24
36
|
watchdog: 0.1
|
@@ -30,18 +42,11 @@ security_codes:
|
|
30
42
|
1: '1111'
|
31
43
|
2: '2222'
|
32
44
|
log:
|
33
|
-
active: true
|
34
|
-
color: true
|
35
|
-
timestamp: true
|
36
|
-
id: true
|
37
|
-
component_id: true
|
38
45
|
ip: false
|
39
46
|
site_id: 9
|
40
|
-
|
47
|
+
component: 2
|
41
48
|
level: false
|
42
49
|
debug: true
|
43
|
-
text: true
|
44
|
-
direction: false
|
45
50
|
json: true
|
46
51
|
acknowledgements: false
|
47
52
|
watchdogs: false
|
data/lib/rsmp/archive.rb
CHANGED
@@ -21,11 +21,11 @@ module RSMP
|
|
21
21
|
def self.prepare_item item
|
22
22
|
raise ArgumentError unless item.is_a? Hash
|
23
23
|
|
24
|
-
cleaned = item.select { |k,v| [:author,:level,:ip,:port,:site_id,:
|
24
|
+
cleaned = item.select { |k,v| [:author,:level,:ip,:port,:site_id,:component,:text,:message,:exception].include? k }
|
25
25
|
cleaned[:timestamp] = Clock.now
|
26
26
|
if item[:message]
|
27
27
|
cleaned[:direction] = item[:message].direction
|
28
|
-
cleaned[:
|
28
|
+
cleaned[:component] = item[:message].attributes['cId']
|
29
29
|
end
|
30
30
|
|
31
31
|
cleaned
|
data/lib/rsmp/cli.rb
CHANGED
data/lib/rsmp/component.rb
CHANGED
@@ -65,7 +65,8 @@ module RSMP
|
|
65
65
|
end
|
66
66
|
|
67
67
|
def log str, options
|
68
|
-
|
68
|
+
default = { component: c_id}
|
69
|
+
@node.log str, default.merge(options)
|
69
70
|
end
|
70
71
|
|
71
72
|
def handle_command command_code, arg
|
@@ -118,7 +119,6 @@ module RSMP
|
|
118
119
|
@statuses[sCI][n] ||= {}
|
119
120
|
@statuses[sCI][n][:initial] = true
|
120
121
|
end
|
121
|
-
#pp @subscribes
|
122
122
|
end
|
123
123
|
|
124
124
|
# Our proxy unsubscribed to status updates.
|
data/lib/rsmp/components.rb
CHANGED
@@ -15,8 +15,10 @@ module RSMP
|
|
15
15
|
return unless settings
|
16
16
|
check_main_component settings
|
17
17
|
settings.each_pair do |type,components_by_type|
|
18
|
-
components_by_type
|
19
|
-
|
18
|
+
if components_by_type
|
19
|
+
components_by_type.each_pair do |id,settings|
|
20
|
+
@components[id] = build_component(id:id, type:type, settings:settings)
|
21
|
+
end
|
20
22
|
end
|
21
23
|
end
|
22
24
|
end
|
@@ -50,7 +52,8 @@ module RSMP
|
|
50
52
|
component = inferred.new node: self, id: component_id
|
51
53
|
@components[ component_id] = component
|
52
54
|
class_name = component.class.name.split('::').last
|
53
|
-
|
55
|
+
class_name << " compoent" unless class_name == 'Component'
|
56
|
+
log "Inferred #{class_name} #{component_id}", level: :debug
|
54
57
|
component
|
55
58
|
else
|
56
59
|
raise UnknownComponent.new("Component #{component_id} not found") unless component
|
data/lib/rsmp/error.rb
CHANGED
data/lib/rsmp/logger.rb
CHANGED
@@ -5,7 +5,7 @@ module RSMP
|
|
5
5
|
|
6
6
|
def initialize settings={}
|
7
7
|
defaults = {
|
8
|
-
'active'=>
|
8
|
+
'active'=>true,
|
9
9
|
'path'=>nil,
|
10
10
|
'stream'=>nil,
|
11
11
|
'color'=>true,
|
@@ -13,6 +13,7 @@ module RSMP
|
|
13
13
|
'statistics'=>false,
|
14
14
|
'hide_ip_and_port' => false,
|
15
15
|
'acknowledgements' => false,
|
16
|
+
'watchdogs' => false,
|
16
17
|
'json'=>false,
|
17
18
|
'tabs'=>'-',
|
18
19
|
|
@@ -23,11 +24,10 @@ module RSMP
|
|
23
24
|
'ip'=>false,
|
24
25
|
'port'=>false,
|
25
26
|
'site_id'=>true,
|
26
|
-
'component_id'=>true,
|
27
27
|
'direction'=>false,
|
28
28
|
'level'=>false,
|
29
|
-
'id'=>
|
30
|
-
'
|
29
|
+
'id'=>true,
|
30
|
+
'text'=>true,
|
31
31
|
}
|
32
32
|
|
33
33
|
default_lengths = {
|
@@ -37,8 +37,8 @@ module RSMP
|
|
37
37
|
'ip'=>22,
|
38
38
|
'port'=>5,
|
39
39
|
'site_id'=>19,
|
40
|
-
'
|
41
|
-
'direction'=>
|
40
|
+
'component'=>19,
|
41
|
+
'direction'=>3,
|
42
42
|
'level'=>7,
|
43
43
|
'id'=>4,
|
44
44
|
}
|
@@ -189,15 +189,15 @@ module RSMP
|
|
189
189
|
build_part( parts, item, :ip )
|
190
190
|
build_part( parts, item, :port )
|
191
191
|
build_part( parts, item, :site_id )
|
192
|
-
build_part( parts, item, :
|
193
|
-
build_part( parts, item, :direction ) { |part| {in:"
|
192
|
+
build_part( parts, item, :component )
|
193
|
+
build_part( parts, item, :direction ) { |part| {in:"In",out:"Out"}[part] }
|
194
194
|
build_part( parts, item, :level ) { |part| part.capitalize }
|
195
195
|
build_part( parts, item, :id ) { Logger.shorten_message_id(item[:message].m_id,4) if item[:message] }
|
196
|
-
build_part( parts, item, :
|
196
|
+
build_part( parts, item, :text )
|
197
197
|
build_part( parts, item, :json ) { item[:message].json if item[:message] }
|
198
198
|
build_part( parts, item, :exception ) { |e| [e.class,e.backtrace].flatten.join("\n") }
|
199
199
|
|
200
|
-
parts.join(' ').chomp(@settings['tabs']).rstrip
|
200
|
+
parts.join(' ').chomp(@settings['tabs'].to_s).rstrip
|
201
201
|
end
|
202
202
|
end
|
203
203
|
end
|
data/lib/rsmp/logging.rb
CHANGED
@@ -15,7 +15,7 @@ module RSMP
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def log str, options={}
|
18
|
-
default = {
|
18
|
+
default = { text:str, level: :log, author: author, ip: @ip, port: @port }
|
19
19
|
prepared = RSMP::Archive.prepare_item default.merge(options)
|
20
20
|
@archive.add prepared
|
21
21
|
@logger.log prepared
|
data/lib/rsmp/node.rb
CHANGED
@@ -14,9 +14,18 @@ module RSMP
|
|
14
14
|
@deferred = []
|
15
15
|
@clock = Clock.new
|
16
16
|
@error_queue = Async::Queue.new
|
17
|
+
@ignore_errors = []
|
18
|
+
end
|
19
|
+
|
20
|
+
def ignore_errors classes, &block
|
21
|
+
was, @ignore_errors = @ignore_errors, [classes].flatten
|
22
|
+
yield
|
23
|
+
ensure
|
24
|
+
@ignore_errors = was
|
17
25
|
end
|
18
26
|
|
19
27
|
def notify_error e, options={}
|
28
|
+
return if @ignore_errors.find { |klass| e.is_a? klass }
|
20
29
|
if options[:level] == :internal
|
21
30
|
log ["#{e.to_s} in task: #{Async::Task.current.to_s}",e.backtrace].flatten.join("\n"), level: :error
|
22
31
|
end
|
data/lib/rsmp/proxy.rb
CHANGED
@@ -86,7 +86,7 @@ module RSMP
|
|
86
86
|
return if @state == :stopped
|
87
87
|
set_state :stopping
|
88
88
|
stop_tasks
|
89
|
-
notify_error
|
89
|
+
notify_error DisonnectError.new("Connection was closed")
|
90
90
|
ensure
|
91
91
|
close_socket
|
92
92
|
clear
|
@@ -348,20 +348,23 @@ module RSMP
|
|
348
348
|
# cannot send NotAcknowledged for a malformed message since we can't read it, just ignore it
|
349
349
|
nil
|
350
350
|
rescue SchemaError, RSMP::Schemer::Error => e
|
351
|
-
|
351
|
+
reason = "schema errors: #{e.message}"
|
352
|
+
str = "Received invalid #{message.type}, #{reason}"
|
352
353
|
log str, message: message, level: :warning
|
353
354
|
notify_error e.exception(str), message: message
|
354
|
-
dont_acknowledge message, str
|
355
|
+
dont_acknowledge message, str, reason
|
355
356
|
message
|
356
357
|
rescue InvalidMessage => e
|
357
|
-
|
358
|
+
reason = "#{e.message}"
|
359
|
+
str = "Received invalid #{message.type},"
|
358
360
|
notify_error e.exception("#{str} #{message.json}"), message: message
|
359
|
-
dont_acknowledge message, str
|
361
|
+
dont_acknowledge message, str, reason
|
360
362
|
message
|
361
363
|
rescue FatalError => e
|
364
|
+
reason = e.message
|
362
365
|
str = "Rejected #{message.type},"
|
363
366
|
notify_error e.exception(str), message: message
|
364
|
-
dont_acknowledge message, str,
|
367
|
+
dont_acknowledge message, str, reason
|
365
368
|
stop
|
366
369
|
message
|
367
370
|
ensure
|
data/lib/rsmp/supervisor.rb
CHANGED
@@ -0,0 +1,101 @@
|
|
1
|
+
module RSMP
|
2
|
+
module TLC
|
3
|
+
class DetectorLogic < Component
|
4
|
+
attr_reader :forced, :value
|
5
|
+
|
6
|
+
def initialize node:, id:
|
7
|
+
super node: node, id: id, grouped: false
|
8
|
+
@forced = 0
|
9
|
+
@value = 0
|
10
|
+
end
|
11
|
+
|
12
|
+
def get_status code, name=nil
|
13
|
+
case code
|
14
|
+
when 'S0201', 'S0202', 'S0203', 'S0204'
|
15
|
+
return send("handle_#{code.downcase}", code, name)
|
16
|
+
else
|
17
|
+
raise InvalidMessage.new "unknown status code #{code}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def handle_s0201 status_code, status_name=nil
|
22
|
+
case status_name
|
23
|
+
when 'starttime'
|
24
|
+
TrafficControllerSite.make_status @node.clock.to_s
|
25
|
+
when 'vehicles'
|
26
|
+
TrafficControllerSite.make_status 0
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def handle_s0202 status_code, status_name=nil
|
31
|
+
case status_name
|
32
|
+
when 'starttime'
|
33
|
+
TrafficControllerSite.make_status @node.clock.to_s
|
34
|
+
when 'speed'
|
35
|
+
TrafficControllerSite.make_status 0
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def handle_s0203 status_code, status_name=nil
|
40
|
+
case status_name
|
41
|
+
when 'starttime'
|
42
|
+
TrafficControllerSite.make_status @node.clock.to_s
|
43
|
+
when 'occupancy'
|
44
|
+
TrafficControllerSite.make_status 0
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def handle_s0204 status_code, status_name=nil
|
49
|
+
case status_name
|
50
|
+
when 'starttime'
|
51
|
+
TrafficControllerSite.make_status @node.clock.to_s
|
52
|
+
when 'P'
|
53
|
+
TrafficControllerSite.make_status 0
|
54
|
+
when 'PS'
|
55
|
+
TrafficControllerSite.make_status 0
|
56
|
+
when 'L'
|
57
|
+
TrafficControllerSite.make_status 0
|
58
|
+
when 'LS'
|
59
|
+
TrafficControllerSite.make_status 0
|
60
|
+
when 'B'
|
61
|
+
TrafficControllerSite.make_status 0
|
62
|
+
when 'SP'
|
63
|
+
TrafficControllerSite.make_status 0
|
64
|
+
when 'MC'
|
65
|
+
TrafficControllerSite.make_status 0
|
66
|
+
when 'C'
|
67
|
+
TrafficControllerSite.make_status 0
|
68
|
+
when 'F'
|
69
|
+
TrafficControllerSite.make_status 0
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def handle_command command_code, arg
|
74
|
+
case command_code
|
75
|
+
when 'M0008'
|
76
|
+
handle_m0008 arg
|
77
|
+
else
|
78
|
+
raise UnknownCommand.new "Unknown command #{command_code}"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def handle_m0008 arg
|
83
|
+
@node.verify_security_code 2, arg['securityCode']
|
84
|
+
status = arg['status']=='True'
|
85
|
+
mode = arg['mode']=='True'
|
86
|
+
force_detector_logic status, mode
|
87
|
+
arg
|
88
|
+
end
|
89
|
+
|
90
|
+
def force_detector_logic forced, value
|
91
|
+
@forced = forced
|
92
|
+
@value = value
|
93
|
+
if @forced
|
94
|
+
log "Forcing to #{value}", level: :info
|
95
|
+
else
|
96
|
+
log "Releasing", level: :info
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module RSMP
|
2
|
+
module TLC
|
3
|
+
class SignalGroup < Component
|
4
|
+
attr_reader :plan, :state
|
5
|
+
|
6
|
+
# plan is a string, with each character representing a signal phase at a particular second in the cycle
|
7
|
+
def initialize node:, id:
|
8
|
+
super node: node, id: id, grouped: false
|
9
|
+
move 0
|
10
|
+
end
|
11
|
+
|
12
|
+
def get_state pos
|
13
|
+
default = 'a' # phase a means disabled/dark
|
14
|
+
plan = node.main.current_plan
|
15
|
+
return default unless plan
|
16
|
+
return default unless plan.states
|
17
|
+
states = plan.states[c_id]
|
18
|
+
return default unless states
|
19
|
+
state =states[pos]
|
20
|
+
return default unless state =~ /[a-hA-G0-9N-P]/ # valid signal group states
|
21
|
+
state
|
22
|
+
end
|
23
|
+
|
24
|
+
def move pos
|
25
|
+
@state = get_state pos
|
26
|
+
end
|
27
|
+
|
28
|
+
def handle_command command_code, arg
|
29
|
+
case command_code
|
30
|
+
when 'M0010', 'M0011'
|
31
|
+
return send("handle_#{command_code.downcase}", arg)
|
32
|
+
else
|
33
|
+
raise UnknownCommand.new "Unknown command #{command_code}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Start of signal group. Orders a signal group to green
|
38
|
+
def handle_m0010 arg
|
39
|
+
@node.verify_security_code 2, arg['securityCode']
|
40
|
+
if TrafficControllerSite.from_rsmp_bool arg['status']
|
41
|
+
log "Start signal group #{c_id}, go to green", level: :info
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Stop of signal group. Orders a signal group to red
|
46
|
+
def handle_m0011 arg
|
47
|
+
@node.verify_security_code 2, arg['securityCode']
|
48
|
+
if TrafficControllerSite.from_rsmp_bool arg['status']
|
49
|
+
log "Stop signal group #{c_id}, go to red", level: :info
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def get_status code, name=nil
|
54
|
+
case code
|
55
|
+
when 'S0025'
|
56
|
+
return send("handle_#{code.downcase}", code, name)
|
57
|
+
else
|
58
|
+
raise InvalidMessage.new "unknown status code #{code}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def handle_s0025 status_code, status_name=nil
|
63
|
+
now = @node.clock.to_s
|
64
|
+
case status_name
|
65
|
+
when 'minToGEstimate'
|
66
|
+
TrafficControllerSite.make_status now
|
67
|
+
when 'maxToGEstimate'
|
68
|
+
TrafficControllerSite.make_status now
|
69
|
+
when 'likelyToGEstimate'
|
70
|
+
TrafficControllerSite.make_status now
|
71
|
+
when 'ToGConfidence'
|
72
|
+
TrafficControllerSite.make_status 0
|
73
|
+
when 'minToREstimate'
|
74
|
+
TrafficControllerSite.make_status now
|
75
|
+
when 'maxToREstimate'
|
76
|
+
TrafficControllerSite.make_status now
|
77
|
+
when 'likelyToREstimate'
|
78
|
+
TrafficControllerSite.make_status now
|
79
|
+
when 'ToRConfidence'
|
80
|
+
TrafficControllerSite.make_status 0
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module RSMP
|
2
|
+
module TLC
|
3
|
+
# A Traffic Light Controller Signal Plan.
|
4
|
+
# A signal plan is a description of how all signal groups should change
|
5
|
+
# state over time.
|
6
|
+
class SignalPlan
|
7
|
+
attr_reader :nr, :states, :dynamic_bands
|
8
|
+
def initialize nr:, states:, dynamic_bands:
|
9
|
+
@nr = nr
|
10
|
+
@states = states
|
11
|
+
@dynamic_bands = dynamic_bands || {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def dynamic_bands_string
|
15
|
+
str = @dynamic_bands.map { |band,value| "#{nr}-#{band}-#{value}" }.join(',')
|
16
|
+
return nil if str == ''
|
17
|
+
str
|
18
|
+
end
|
19
|
+
|
20
|
+
def set_band band, value
|
21
|
+
@dynamic_bands[ band.to_i ] = value.to_i
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_band band
|
25
|
+
@dynamic_bands[ band.to_i ]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|