rsmp 0.37.0 → 0.38.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/.devcontainer/devcontainer.json +22 -0
- data/.github/workflows/rubocop.yaml +17 -0
- data/.gitignore +5 -6
- data/.rubocop.yml +80 -0
- data/Gemfile +13 -1
- data/Gemfile.lock +34 -1
- data/Rakefile +3 -3
- data/lib/rsmp/cli.rb +147 -124
- data/lib/rsmp/collect/ack_collector.rb +8 -7
- data/lib/rsmp/collect/aggregated_status_collector.rb +4 -4
- data/lib/rsmp/collect/alarm_collector.rb +31 -23
- data/lib/rsmp/collect/alarm_matcher.rb +3 -3
- data/lib/rsmp/collect/collector/logging.rb +17 -0
- data/lib/rsmp/collect/collector/reporting.rb +44 -0
- data/lib/rsmp/collect/collector/status.rb +34 -0
- data/lib/rsmp/collect/collector.rb +69 -150
- data/lib/rsmp/collect/command_matcher.rb +19 -6
- data/lib/rsmp/collect/command_response_collector.rb +7 -7
- data/lib/rsmp/collect/distributor.rb +14 -11
- data/lib/rsmp/collect/filter.rb +31 -15
- data/lib/rsmp/collect/matcher.rb +7 -11
- data/lib/rsmp/collect/queue.rb +4 -4
- data/lib/rsmp/collect/receiver.rb +10 -12
- data/lib/rsmp/collect/state_collector.rb +116 -77
- data/lib/rsmp/collect/status_collector.rb +6 -6
- data/lib/rsmp/collect/status_matcher.rb +17 -7
- data/lib/rsmp/{alarm_state.rb → component/alarm_state.rb} +76 -37
- data/lib/rsmp/{component.rb → component/component.rb} +15 -15
- data/lib/rsmp/component/component_base.rb +89 -0
- data/lib/rsmp/component/component_proxy.rb +75 -0
- data/lib/rsmp/component/components.rb +63 -0
- data/lib/rsmp/convert/export/json_schema.rb +116 -110
- data/lib/rsmp/convert/import/yaml.rb +21 -18
- data/lib/rsmp/{rsmp.rb → helpers/clock.rb} +5 -6
- data/lib/rsmp/{deep_merge.rb → helpers/deep_merge.rb} +2 -1
- data/lib/rsmp/helpers/error.rb +71 -0
- data/lib/rsmp/{inspect.rb → helpers/inspect.rb} +6 -10
- data/lib/rsmp/log/archive.rb +98 -0
- data/lib/rsmp/log/colorization.rb +41 -0
- data/lib/rsmp/log/filtering.rb +54 -0
- data/lib/rsmp/log/logger.rb +206 -0
- data/lib/rsmp/{logging.rb → log/logging.rb} +5 -7
- data/lib/rsmp/message.rb +159 -148
- data/lib/rsmp/{node.rb → node/node.rb} +19 -17
- data/lib/rsmp/{protocol.rb → node/protocol.rb} +5 -3
- data/lib/rsmp/node/site/site.rb +195 -0
- data/lib/rsmp/node/supervisor/modules/configuration.rb +59 -0
- data/lib/rsmp/node/supervisor/modules/connection.rb +140 -0
- data/lib/rsmp/node/supervisor/modules/sites.rb +64 -0
- data/lib/rsmp/node/supervisor/supervisor.rb +72 -0
- data/lib/rsmp/{task.rb → node/task.rb} +12 -14
- data/lib/rsmp/proxy/modules/acknowledgements.rb +144 -0
- data/lib/rsmp/proxy/modules/receive.rb +119 -0
- data/lib/rsmp/proxy/modules/send.rb +76 -0
- data/lib/rsmp/proxy/modules/state.rb +25 -0
- data/lib/rsmp/proxy/modules/tasks.rb +105 -0
- data/lib/rsmp/proxy/modules/versions.rb +69 -0
- data/lib/rsmp/proxy/modules/watchdogs.rb +66 -0
- data/lib/rsmp/proxy/proxy.rb +199 -0
- data/lib/rsmp/proxy/site/modules/aggregated_status.rb +52 -0
- data/lib/rsmp/proxy/site/modules/alarms.rb +27 -0
- data/lib/rsmp/proxy/site/modules/commands.rb +31 -0
- data/lib/rsmp/proxy/site/modules/status.rb +110 -0
- data/lib/rsmp/proxy/site/site_proxy.rb +205 -0
- data/lib/rsmp/proxy/supervisor/modules/aggregated_status.rb +47 -0
- data/lib/rsmp/proxy/supervisor/modules/alarms.rb +73 -0
- data/lib/rsmp/proxy/supervisor/modules/commands.rb +53 -0
- data/lib/rsmp/proxy/supervisor/modules/status.rb +204 -0
- data/lib/rsmp/proxy/supervisor/supervisor_proxy.rb +178 -0
- data/lib/rsmp/tlc/detector_logic.rb +18 -34
- data/lib/rsmp/tlc/input_states.rb +126 -0
- data/lib/rsmp/tlc/modules/detector_logics.rb +50 -0
- data/lib/rsmp/tlc/modules/display.rb +78 -0
- data/lib/rsmp/tlc/modules/helpers.rb +41 -0
- data/lib/rsmp/tlc/modules/inputs.rb +173 -0
- data/lib/rsmp/tlc/modules/modes.rb +253 -0
- data/lib/rsmp/tlc/modules/outputs.rb +30 -0
- data/lib/rsmp/tlc/modules/plans.rb +218 -0
- data/lib/rsmp/tlc/modules/signal_groups.rb +109 -0
- data/lib/rsmp/tlc/modules/startup_sequence.rb +22 -0
- data/lib/rsmp/tlc/modules/system.rb +140 -0
- data/lib/rsmp/tlc/modules/traffic_data.rb +49 -0
- data/lib/rsmp/tlc/signal_group.rb +37 -41
- data/lib/rsmp/tlc/signal_plan.rb +14 -11
- data/lib/rsmp/tlc/signal_priority.rb +39 -35
- data/lib/rsmp/tlc/startup_sequence.rb +59 -0
- data/lib/rsmp/tlc/traffic_controller.rb +38 -1010
- data/lib/rsmp/tlc/traffic_controller_site.rb +58 -57
- data/lib/rsmp/version.rb +1 -1
- data/lib/rsmp.rb +82 -48
- data/rsmp.gemspec +24 -31
- metadata +79 -139
- data/lib/rsmp/archive.rb +0 -76
- data/lib/rsmp/collect/message_matchers.rb +0 -0
- data/lib/rsmp/component_base.rb +0 -87
- data/lib/rsmp/component_proxy.rb +0 -57
- data/lib/rsmp/components.rb +0 -65
- data/lib/rsmp/error.rb +0 -71
- data/lib/rsmp/logger.rb +0 -216
- data/lib/rsmp/proxy.rb +0 -693
- data/lib/rsmp/site.rb +0 -188
- data/lib/rsmp/site_proxy.rb +0 -389
- data/lib/rsmp/supervisor.rb +0 -302
- data/lib/rsmp/supervisor_proxy.rb +0 -510
- data/lib/rsmp/tlc/inputs.rb +0 -134
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
module RSMP
|
|
2
|
+
module TLC
|
|
3
|
+
module Modules
|
|
4
|
+
# System-level commands and status for traffic controllers
|
|
5
|
+
# Handles restart, emergency routes, security, clock, version, and configuration
|
|
6
|
+
module System
|
|
7
|
+
def clock
|
|
8
|
+
node.clock
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# M0004 - Restart traffic light controller
|
|
12
|
+
def handle_m0004(arg, _options = {})
|
|
13
|
+
@node.verify_security_code 2, arg['securityCode']
|
|
14
|
+
# don't restart immeediately, since we need to first send command response
|
|
15
|
+
# instead, defer an action, which will be handled by the TLC site
|
|
16
|
+
log 'Sheduling restart of TLC', level: :info
|
|
17
|
+
@node.defer :restart
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# M0103 - Set security code
|
|
21
|
+
def handle_m0103(arg, _options = {})
|
|
22
|
+
level = { 'Level1' => 1, 'Level2' => 2 }[arg['status']]
|
|
23
|
+
@node.change_security_code level, arg['oldSecurityCode'], arg['newSecurityCode']
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# M0104 - Set clock
|
|
27
|
+
def handle_m0104(arg, _options = {})
|
|
28
|
+
@node.verify_security_code 1, arg['securityCode']
|
|
29
|
+
time = Time.new(
|
|
30
|
+
arg['year'],
|
|
31
|
+
arg['month'],
|
|
32
|
+
arg['day'],
|
|
33
|
+
arg['hour'],
|
|
34
|
+
arg['minute'],
|
|
35
|
+
arg['second'],
|
|
36
|
+
'UTC'
|
|
37
|
+
)
|
|
38
|
+
clock.set time
|
|
39
|
+
log "Clock set to #{time}, (adjustment is #{clock.adjustment}s)", level: :info
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# S0005 - Traffic controller starting
|
|
43
|
+
def handle_s0005(_status_code, status_name = nil, _options = {})
|
|
44
|
+
case status_name
|
|
45
|
+
when 'status'
|
|
46
|
+
TrafficControllerSite.make_status @is_starting
|
|
47
|
+
when 'statusByIntersection' # from sxl 1.2.0
|
|
48
|
+
TrafficControllerSite.make_status([
|
|
49
|
+
{
|
|
50
|
+
'intersection' => '1',
|
|
51
|
+
'startup' => TrafficControllerSite.to_rmsp_bool(@is_starting)
|
|
52
|
+
}
|
|
53
|
+
])
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# S0095 - Version information
|
|
58
|
+
def handle_s0095(_status_code, status_name = nil, _options = {})
|
|
59
|
+
case status_name
|
|
60
|
+
when 'status'
|
|
61
|
+
TrafficControllerSite.make_status RSMP::VERSION
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# S0091 - Operator logged in/out OP-panel
|
|
66
|
+
def handle_s0091(_status_code, status_name = nil, _options = {})
|
|
67
|
+
case status_name
|
|
68
|
+
when 'user'
|
|
69
|
+
TrafficControllerSite.make_status 0
|
|
70
|
+
when 'username'
|
|
71
|
+
TrafficControllerSite.make_status ''
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# S0092 - Operator logged in/out web-interface
|
|
76
|
+
def handle_s0092(_status_code, status_name = nil, _options = {})
|
|
77
|
+
case status_name
|
|
78
|
+
when 'user'
|
|
79
|
+
TrafficControllerSite.make_status 0
|
|
80
|
+
when 'username'
|
|
81
|
+
TrafficControllerSite.make_status ''
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def datetime_components
|
|
86
|
+
{
|
|
87
|
+
'year' => [4, :year],
|
|
88
|
+
'month' => [2, :month],
|
|
89
|
+
'day' => [2, :day],
|
|
90
|
+
'hour' => [2, :hour],
|
|
91
|
+
'minute' => [2, :min],
|
|
92
|
+
'second' => [2, :sec]
|
|
93
|
+
}
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# S0096 - Current date and time
|
|
97
|
+
def handle_s0096(_status_code, status_name = nil, _options = {})
|
|
98
|
+
component = datetime_components[status_name]
|
|
99
|
+
return nil unless component
|
|
100
|
+
|
|
101
|
+
width, method = component
|
|
102
|
+
now = clock.now
|
|
103
|
+
TrafficControllerSite.make_status format_datetime_component(now.send(method), width)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
private
|
|
107
|
+
|
|
108
|
+
def format_datetime_component(value, width)
|
|
109
|
+
value.to_s.rjust(width, '0')
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# S0097 - Configuration checksum
|
|
113
|
+
def handle_s0097(_status_code, status_name = nil, _options = {})
|
|
114
|
+
case status_name
|
|
115
|
+
when 'checksum'
|
|
116
|
+
TrafficControllerSite.make_status '1'
|
|
117
|
+
when 'timestamp'
|
|
118
|
+
now = clock.to_s
|
|
119
|
+
TrafficControllerSite.make_status now
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# S0098 - Configuration data
|
|
124
|
+
def handle_s0098(_status_code, status_name = nil, _options = {})
|
|
125
|
+
settings = node.site_settings.slice('components', 'signal_plans', 'inputs', 'startup_sequence')
|
|
126
|
+
json = JSON.generate(settings)
|
|
127
|
+
case status_name
|
|
128
|
+
when 'config'
|
|
129
|
+
TrafficControllerSite.make_status json
|
|
130
|
+
when 'timestamp'
|
|
131
|
+
now = clock.to_s
|
|
132
|
+
TrafficControllerSite.make_status now
|
|
133
|
+
when 'version'
|
|
134
|
+
TrafficControllerSite.make_status Digest::MD5.hexdigest(json)
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module RSMP
|
|
2
|
+
module TLC
|
|
3
|
+
module Modules
|
|
4
|
+
# Traffic counting data collection for TLC
|
|
5
|
+
# Handles aggregate traffic counting status for all detectors
|
|
6
|
+
module TrafficData
|
|
7
|
+
# S0205 - Traffic Counting: Number of vehicles (aggregate)
|
|
8
|
+
def handle_s0205(_status_code, status_name = nil, _options = {})
|
|
9
|
+
case status_name
|
|
10
|
+
when 'start'
|
|
11
|
+
TrafficControllerSite.make_status clock.to_s
|
|
12
|
+
when 'vehicles'
|
|
13
|
+
TrafficControllerSite.make_status 0
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# S0206 - Traffic Counting: Vehicle speed (aggregate)
|
|
18
|
+
def handle_s0206(_status_code, status_name = nil, _options = {})
|
|
19
|
+
case status_name
|
|
20
|
+
when 'start'
|
|
21
|
+
TrafficControllerSite.make_status clock.to_s
|
|
22
|
+
when 'speed'
|
|
23
|
+
TrafficControllerSite.make_status 0
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# S0207 - Traffic Counting: Occupancy (aggregate)
|
|
28
|
+
def handle_s0207(_status_code, status_name = nil, _options = {})
|
|
29
|
+
case status_name
|
|
30
|
+
when 'start'
|
|
31
|
+
TrafficControllerSite.make_status clock.to_s
|
|
32
|
+
when 'occupancy'
|
|
33
|
+
TrafficControllerSite.make_status 0
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# S0208 - Traffic Counting: Number of vehicles by classification (aggregate)
|
|
38
|
+
def handle_s0208(_status_code, status_name = nil, _options = {})
|
|
39
|
+
case status_name
|
|
40
|
+
when 'start'
|
|
41
|
+
TrafficControllerSite.make_status clock.to_s
|
|
42
|
+
when 'P', 'PS', 'L', 'LS', 'B', 'SP', 'MC', 'C', 'F'
|
|
43
|
+
TrafficControllerSite.make_status 0
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -4,8 +4,8 @@ module RSMP
|
|
|
4
4
|
attr_reader :plan, :state
|
|
5
5
|
|
|
6
6
|
# plan is a string, with each character representing a signal phase at a particular second in the cycle
|
|
7
|
-
def initialize
|
|
8
|
-
super
|
|
7
|
+
def initialize(node:, id:)
|
|
8
|
+
super(node: node, id: id, grouped: false)
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def timer
|
|
@@ -15,82 +15,78 @@ module RSMP
|
|
|
15
15
|
def compute_state
|
|
16
16
|
return 'a' if node.main.dark?
|
|
17
17
|
return 'c' if node.main.yellow_flash?
|
|
18
|
+
return startup_state if node.main.startup_sequence.active?
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
compute_plan_state
|
|
21
|
+
end
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
def startup_state
|
|
24
|
+
node.main.startup_state || 'a'
|
|
25
|
+
end
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
def compute_plan_state
|
|
28
|
+
default = 'a' # phase a means disabled/dark
|
|
26
29
|
plan = node.main.current_plan
|
|
27
|
-
return default unless plan
|
|
28
|
-
return default unless plan.states
|
|
30
|
+
return default unless plan&.states
|
|
29
31
|
|
|
30
32
|
states = plan.states[c_id]
|
|
31
33
|
return default unless states
|
|
32
34
|
|
|
33
|
-
|
|
35
|
+
state_at_cycle_position(states, node.main.cycle_counter, default)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def state_at_cycle_position(states, cycle_counter, default)
|
|
39
|
+
counter = [cycle_counter, states.length - 1].min
|
|
34
40
|
state = states[counter]
|
|
35
|
-
return default unless state =~ /[a-hA-G0-9N-P]/
|
|
41
|
+
return default unless state =~ /[a-hA-G0-9N-P]/ # valid signal group states
|
|
42
|
+
|
|
36
43
|
state
|
|
37
44
|
end
|
|
38
45
|
|
|
39
|
-
def handle_command
|
|
46
|
+
def handle_command(command_code, arg, options = {})
|
|
40
47
|
case command_code
|
|
41
48
|
when 'M0010', 'M0011'
|
|
42
|
-
|
|
49
|
+
send("handle_#{command_code.downcase}", arg, options)
|
|
43
50
|
else
|
|
44
|
-
raise UnknownCommand
|
|
51
|
+
raise UnknownCommand, "Unknown command #{command_code}"
|
|
45
52
|
end
|
|
46
53
|
end
|
|
47
54
|
|
|
48
55
|
# Start of signal group. Orders a signal group to green
|
|
49
|
-
def handle_m0010
|
|
56
|
+
def handle_m0010(arg, _options = {})
|
|
50
57
|
@node.verify_security_code 2, arg['securityCode']
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
58
|
+
return unless TrafficControllerSite.from_rsmp_bool? arg['status']
|
|
59
|
+
|
|
60
|
+
log "Start signal group #{c_id}, go to green", level: :info
|
|
54
61
|
end
|
|
55
62
|
|
|
56
63
|
# Stop of signal group. Orders a signal group to red
|
|
57
|
-
def handle_m0011
|
|
64
|
+
def handle_m0011(arg, _options = {})
|
|
58
65
|
@node.verify_security_code 2, arg['securityCode']
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
66
|
+
return unless TrafficControllerSite.from_rsmp_bool? arg['status']
|
|
67
|
+
|
|
68
|
+
log "Stop signal group #{c_id}, go to red", level: :info
|
|
62
69
|
end
|
|
63
70
|
|
|
64
|
-
def get_status
|
|
71
|
+
def get_status(code, name = nil, _options = {})
|
|
65
72
|
case code
|
|
66
73
|
when 'S0025'
|
|
67
|
-
|
|
74
|
+
send("handle_#{code.downcase}", code, name)
|
|
68
75
|
else
|
|
69
|
-
raise InvalidMessage
|
|
76
|
+
raise InvalidMessage, "unknown status code #{code}"
|
|
70
77
|
end
|
|
71
78
|
end
|
|
72
79
|
|
|
73
|
-
def handle_s0025
|
|
80
|
+
def handle_s0025(_status_code, status_name = nil, _options = {})
|
|
74
81
|
now = @node.clock.to_s
|
|
75
82
|
case status_name
|
|
76
|
-
when 'minToGEstimate'
|
|
77
|
-
|
|
78
|
-
when 'maxToGEstimate'
|
|
79
|
-
TrafficControllerSite.make_status now
|
|
80
|
-
when 'likelyToGEstimate'
|
|
81
|
-
TrafficControllerSite.make_status now
|
|
82
|
-
when 'ToGConfidence'
|
|
83
|
-
TrafficControllerSite.make_status 0
|
|
84
|
-
when 'minToREstimate'
|
|
85
|
-
TrafficControllerSite.make_status now
|
|
86
|
-
when 'maxToREstimate'
|
|
87
|
-
TrafficControllerSite.make_status now
|
|
88
|
-
when 'likelyToREstimate'
|
|
83
|
+
when 'minToGEstimate', 'maxToGEstimate', 'likelyToGEstimate',
|
|
84
|
+
'minToREstimate', 'maxToREstimate', 'likelyToREstimate'
|
|
89
85
|
TrafficControllerSite.make_status now
|
|
90
|
-
when 'ToRConfidence'
|
|
86
|
+
when 'ToGConfidence', 'ToRConfidence'
|
|
91
87
|
TrafficControllerSite.make_status 0
|
|
92
88
|
end
|
|
93
89
|
end
|
|
94
90
|
end
|
|
95
91
|
end
|
|
96
|
-
end
|
|
92
|
+
end
|
data/lib/rsmp/tlc/signal_plan.rb
CHANGED
|
@@ -4,32 +4,35 @@ module RSMP
|
|
|
4
4
|
# A signal plan is a description of how all signal groups should change
|
|
5
5
|
# state over time.
|
|
6
6
|
class SignalPlan
|
|
7
|
-
attr_reader :
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
attr_reader :number, :states, :dynamic_bands, :cycle_time
|
|
8
|
+
|
|
9
|
+
def initialize(number:, cycle_time:, states:, dynamic_bands:)
|
|
10
|
+
@number = number
|
|
10
11
|
@states = states
|
|
11
12
|
@dynamic_bands = dynamic_bands || {}
|
|
12
13
|
@cycle_time = cycle_time
|
|
13
14
|
end
|
|
14
15
|
|
|
15
16
|
def dynamic_bands_string
|
|
16
|
-
str = @dynamic_bands.map { |band,value| "#{
|
|
17
|
+
str = @dynamic_bands.map { |band, value| "#{@number}-#{band}-#{value}" }.join(',')
|
|
17
18
|
return nil if str == ''
|
|
19
|
+
|
|
18
20
|
str
|
|
19
21
|
end
|
|
20
22
|
|
|
21
|
-
def set_band
|
|
22
|
-
@dynamic_bands[
|
|
23
|
+
def set_band(band, value)
|
|
24
|
+
@dynamic_bands[band.to_i] = value.to_i
|
|
23
25
|
end
|
|
24
26
|
|
|
25
|
-
def get_band
|
|
26
|
-
@dynamic_bands[
|
|
27
|
+
def get_band(band)
|
|
28
|
+
@dynamic_bands[band.to_i]
|
|
27
29
|
end
|
|
28
30
|
|
|
29
|
-
def
|
|
30
|
-
raise ArgumentError if cycle_time
|
|
31
|
+
def cycle_time=(cycle_time)
|
|
32
|
+
raise ArgumentError if cycle_time.negative?
|
|
33
|
+
|
|
31
34
|
@cycle_time = cycle_time
|
|
32
35
|
end
|
|
33
36
|
end
|
|
34
37
|
end
|
|
35
|
-
end
|
|
38
|
+
end
|
|
@@ -1,44 +1,48 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
module RSMP
|
|
2
|
+
module TLC
|
|
3
|
+
class SignalPriority
|
|
4
|
+
attr_reader :state, :node, :id, :level, :eta, :vehicle_type, :age, :updated
|
|
3
5
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
def initialize(node:, id:, level:, eta:, vehicle_type:)
|
|
7
|
+
@node = node
|
|
8
|
+
@id = id
|
|
9
|
+
@level = level
|
|
10
|
+
@eta = eta
|
|
11
|
+
@vehicle_type = vehicle_type
|
|
12
|
+
self.state = 'received'
|
|
13
|
+
end
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
def prune?
|
|
16
|
+
@state == 'stale' || @state == 'completed'
|
|
17
|
+
end
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
set_state 'completed'
|
|
20
|
-
end
|
|
21
|
-
end
|
|
19
|
+
def cancel
|
|
20
|
+
return unless @state == 'activated'
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
@updated = node.clock.now
|
|
26
|
-
@node.signal_priority_changed self, @state
|
|
27
|
-
end
|
|
22
|
+
self.state = 'completed'
|
|
23
|
+
end
|
|
28
24
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if @age >= 0.5
|
|
34
|
-
@node.log "Priority request #{@id} activated.", level: :info
|
|
35
|
-
set_state 'activated'
|
|
25
|
+
def state=(state)
|
|
26
|
+
@state = state
|
|
27
|
+
@updated = node.clock.now
|
|
28
|
+
@node.signal_priority_changed self, @state
|
|
36
29
|
end
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
@
|
|
40
|
-
|
|
30
|
+
|
|
31
|
+
def timer
|
|
32
|
+
@age = @node.clock.now - @updated
|
|
33
|
+
case @state
|
|
34
|
+
when 'received'
|
|
35
|
+
if @age >= 0.5
|
|
36
|
+
@node.log "Priority request #{@id} activated.", level: :info
|
|
37
|
+
self.state = 'activated'
|
|
38
|
+
end
|
|
39
|
+
when 'activated'
|
|
40
|
+
if @age >= 1
|
|
41
|
+
@node.log "Priority request #{@id} became stale.", level: :info
|
|
42
|
+
self.state = 'stale'
|
|
43
|
+
end
|
|
44
|
+
end
|
|
41
45
|
end
|
|
42
46
|
end
|
|
43
47
|
end
|
|
44
|
-
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module RSMP
|
|
2
|
+
module TLC
|
|
3
|
+
# Manages startup sequence state machine for traffic controllers
|
|
4
|
+
class StartupSequence
|
|
5
|
+
attr_reader :sequence, :position, :initiated_at
|
|
6
|
+
|
|
7
|
+
def initialize(sequence)
|
|
8
|
+
@sequence = sequence || []
|
|
9
|
+
@active = false
|
|
10
|
+
@initiated_at = nil
|
|
11
|
+
@position = nil
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def start
|
|
15
|
+
@active = true
|
|
16
|
+
@initiated_at = nil
|
|
17
|
+
@position = nil
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def stop
|
|
21
|
+
@active = false
|
|
22
|
+
@initiated_at = nil
|
|
23
|
+
@position = nil
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def active?
|
|
27
|
+
@active
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def complete?
|
|
31
|
+
return false unless @active
|
|
32
|
+
return false if @position.nil?
|
|
33
|
+
|
|
34
|
+
@position >= @sequence.size
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def current_state
|
|
38
|
+
return nil unless @active
|
|
39
|
+
return nil if @position.nil?
|
|
40
|
+
return nil if @position >= @sequence.size
|
|
41
|
+
|
|
42
|
+
@sequence[@position]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def advance
|
|
46
|
+
return unless @active
|
|
47
|
+
|
|
48
|
+
if @initiated_at.nil?
|
|
49
|
+
@initiated_at = Time.now.to_i + 1
|
|
50
|
+
@position = 0
|
|
51
|
+
else
|
|
52
|
+
@position = Time.now.to_i - @initiated_at
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
stop if complete?
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|