rsmp 0.5.6 → 0.6.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|