rsmp 0.6.1 → 0.6.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 99c851e6110d58148d2e4875f65340d6427a3a674908ae95397025bc380491bc
4
- data.tar.gz: 9aa3d5570819e3b20e84542ee3b6ef6bb5d8a17afae964394f14f7e6eda88e2d
3
+ metadata.gz: 7ffe9f097053c9814ad119cbd6a01192cd20c02d3ca1fffa6269dbdf534f419b
4
+ data.tar.gz: 9848398d419a76f16fa8eb1f527d4c6b055b17886a5ee689b7607c891103d5a1
5
5
  SHA512:
6
- metadata.gz: c54182fe42fd77bc9f23b7a7ea116807d92e8c9c02a62ae91da1460373ec695f390f98ebe6d6dcb8e2c72487f861f0ab12bd947e1271942b7a0fba2916b7dbff
7
- data.tar.gz: 5510c69befdc20d5091c16709c5d9b70a7a226773aad37b69fe1699c8cc86443b1196c8d348e0996ec5da8b8a94b1b3b3f2db8c0bcbedaa2ac979797d5b2e535
6
+ metadata.gz: d974b915cbc32bee428cc7f39a1e26134c6db34f72590ad9bd67400ad71ce831037a82341601369aa6582c1e4b5ecf8d4e6f8c3249a4375716bc877ca1cc7cec
7
+ data.tar.gz: 301eb51aecb05c57fc3395f3a06df33846e24fdd863db2ff65e81e9fc1b7c23c4e6b40e508b15a3ec0c92e87595ce78317773cfca6e13ec72ca9609d037cb1f1
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rsmp (0.6.1)
4
+ rsmp (0.6.5)
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.1)
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/README.md CHANGED
@@ -125,7 +125,7 @@ This will output messages form both the site and the supervisor, ordered chronol
125
125
  ```console
126
126
  RN+SU0001 Starting supervisor RN+SU0001 on port 12111
127
127
  RN+SI0001 Starting site RN+SI0001
128
- RN+SI0001 Connecting to superviser at 127.0.0.1:12111
128
+ RN+SI0001 Connecting to supervisor at 127.0.0.1:12111
129
129
  RN+SI0001 <-- f8c7 Sent Version
130
130
  RN+SU0001 Site connected from 127.0.0.1:53500
131
131
  RN+SU0001 RN+SI0001 --> f8c7 Received Version message for sites [RN+SI0001] using RSMP 3.1.4
@@ -156,7 +156,7 @@ The ```site``` command will start an RSMP site, which will try to connect to one
156
156
  ```console
157
157
  % rsmp site
158
158
  2019-11-11 12:22:00 UTC Starting site RN+SI0001
159
- 2019-11-11 12:22:00 UTC Connecting to superviser at 127.0.0.1:12111
159
+ 2019-11-11 12:22:00 UTC Connecting to supervisor at 127.0.0.1:12111
160
160
  2019-11-11 12:22:00 UTC <-- 792f Sent Version
161
161
  2019-11-11 12:22:00 UTC RN+SU0001 --> e70e Received Version message, using RSMP 3.1.4
162
162
  2019-11-11 12:22:00 UTC RN+SU0001 Connection to supervisor established
@@ -8,15 +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
- component: true
15
- ip: false
16
11
  port: true
17
12
  site_id: 9
18
- component_id: 3
19
- text: true
13
+ component: 2
20
14
  direction: false
21
15
  level: false
22
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,17 +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
- component_id: true
37
45
  ip: false
38
46
  site_id: 9
39
- component: 3
47
+ component: 2
40
48
  level: false
41
49
  debug: true
42
- text: true
43
- direction: false
44
50
  json: true
45
51
  acknowledgements: false
46
52
  watchdogs: false
data/lib/rsmp/archive.rb CHANGED
@@ -21,7 +21,7 @@ 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,:component,:str,:message,:exception].include? k }
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
data/lib/rsmp/cli.rb CHANGED
@@ -51,7 +51,7 @@ module RSMP
51
51
  if options[:type]
52
52
  case options[:type]
53
53
  when 'tlc'
54
- site_class = RSMP::Tlc
54
+ site_class = RSMP::TLC::TrafficControllerSite
55
55
  else
56
56
  site_class = RSMP::Site
57
57
  end
@@ -65,7 +65,8 @@ module RSMP
65
65
  end
66
66
 
67
67
  def log str, options
68
- @node.log str, options
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
@@ -78,16 +79,17 @@ module RSMP
78
79
 
79
80
  def handle_alarm message
80
81
  code = message.attribute('aCId')
81
- alarm = @alarms[code]
82
- if alarm
83
- if alarm.differ? message
84
- @alarms[code] = alarm
85
- else
86
- raise RepeatedAlarmError.new("no changes from previous alarm #{alarm.m_id_short}")
82
+ previous = @alarms[code]
83
+ if previous
84
+ unless message.differ?(previous)
85
+ raise RepeatedAlarmError.new("no changes from previous alarm #{previous.m_id_short}")
86
+ end
87
+ if Time.parse(message.attribute('aTs')) < Time.parse(previous.attribute('aTs'))
88
+ raise RepeatedAlarmError.new("timestamp is earlier than previous alarm #{previous.m_id_short}")
87
89
  end
88
- else
89
- @alarms[code] = message
90
90
  end
91
+ ensure
92
+ @alarms[code] = message
91
93
  end
92
94
 
93
95
  # Handle an incoming status respone, by storing the values
@@ -118,7 +120,6 @@ module RSMP
118
120
  @statuses[sCI][n] ||= {}
119
121
  @statuses[sCI][n][:initial] = true
120
122
  end
121
- #pp @subscribes
122
123
  end
123
124
 
124
125
  # Our proxy unsubscribed to status updates.
@@ -52,7 +52,8 @@ module RSMP
52
52
  component = inferred.new node: self, id: component_id
53
53
  @components[ component_id] = component
54
54
  class_name = component.class.name.split('::').last
55
- log "Inferred #{class_name} component #{component_id}", level: :info
55
+ class_name << " compoent" unless class_name == 'Component'
56
+ log "Inferred #{class_name} #{component_id}", level: :debug
56
57
  component
57
58
  else
58
59
  raise UnknownComponent.new("Component #{component_id} not found") unless component
data/lib/rsmp/error.rb CHANGED
@@ -64,4 +64,7 @@ module RSMP
64
64
 
65
65
  class RepeatedStatusError < Error
66
66
  end
67
+
68
+ class TimestampError < Error
69
+ end
67
70
  end
data/lib/rsmp/logger.rb CHANGED
@@ -5,7 +5,7 @@ module RSMP
5
5
 
6
6
  def initialize settings={}
7
7
  defaults = {
8
- 'active'=>false,
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
 
@@ -27,7 +28,7 @@ module RSMP
27
28
  'direction'=>false,
28
29
  'level'=>false,
29
30
  'id'=>true,
30
- 'str'=>true,
31
+ 'text'=>true,
31
32
  }
32
33
 
33
34
  default_lengths = {
@@ -38,7 +39,7 @@ module RSMP
38
39
  'port'=>5,
39
40
  'site_id'=>19,
40
41
  'component'=>19,
41
- 'direction'=>4,
42
+ 'direction'=>3,
42
43
  'level'=>7,
43
44
  'id'=>4,
44
45
  }
@@ -189,15 +190,15 @@ module RSMP
189
190
  build_part( parts, item, :ip )
190
191
  build_part( parts, item, :port )
191
192
  build_part( parts, item, :site_id )
192
- build_part( parts, item, :component_id )
193
- build_part( parts, item, :direction ) { |part| {in:"-->",out:"<--"}[part] }
193
+ build_part( parts, item, :component )
194
+ build_part( parts, item, :direction ) { |part| {in:"In",out:"Out"}[part] }
194
195
  build_part( parts, item, :level ) { |part| part.capitalize }
195
196
  build_part( parts, item, :id ) { Logger.shorten_message_id(item[:message].m_id,4) if item[:message] }
196
- build_part( parts, item, :str )
197
+ build_part( parts, item, :text )
197
198
  build_part( parts, item, :json ) { item[:message].json if item[:message] }
198
199
  build_part( parts, item, :exception ) { |e| [e.class,e.backtrace].flatten.join("\n") }
199
200
 
200
- parts.join(' ').chomp(@settings['tabs']).rstrip
201
+ parts.join(' ').chomp(@settings['tabs'].to_s).rstrip
201
202
  end
202
203
  end
203
204
  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 = { str:str, level: :log, author: author, ip: @ip, port: @port }
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/message.rb CHANGED
@@ -126,7 +126,7 @@ module RSMP
126
126
  end
127
127
 
128
128
  def initialize attributes = {}
129
- @timestamp = Time.now # this timestamp is for internal use, and does not the clock
129
+ @timestamp = Time.now # this timestamp is for internal use, and does not use the clock
130
130
  # in the node, which can be set by an rsmp supervisor
131
131
 
132
132
  @attributes = { "mType"=> "rSMsg" }.merge attributes
data/lib/rsmp/proxy.rb CHANGED
@@ -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
- str = "Received invalid #{message.type}, schema errors: #{e.message}"
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
- str = "Received", "invalid #{message.type}, #{e.message}"
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, "#{e.message}"
367
+ dont_acknowledge message, str, reason
365
368
  stop
366
369
  message
367
370
  ensure
@@ -23,15 +23,22 @@ module RSMP
23
23
  end
24
24
 
25
25
  def start
26
- log "Connecting to superviser at #{@ip}:#{@port}", level: :info
26
+ log "Connecting to supervisor at #{@ip}:#{@port}", level: :info
27
27
  super
28
28
  connect
29
29
  @logger.unmute @ip, @port
30
- log "Connected to superviser at #{@ip}:#{@port}", level: :info
30
+ log "Connected to supervisor at #{@ip}:#{@port}", level: :info
31
31
  start_reader
32
32
  send_version @site_settings['site_id'], @site_settings["rsmp_versions"]
33
- rescue Errno::ECONNREFUSED
34
- log "No connection to supervisor at #{@ip}:#{@port}", level: :error
33
+ rescue SystemCallError => e
34
+ log "Could not connect to supervisor at #{@ip}:#{@port}: Errno #{e.errno} #{e}", level: :error
35
+ retry_notice
36
+ rescue StandardError => e
37
+ log "Error while connecting to supervisor at #{@ip}:#{@port}: #{e}", level: :error
38
+ retry_notice
39
+ end
40
+
41
+ def retry_notice
35
42
  unless @site.site_settings['intervals']['reconnect'] == :no
36
43
  log "Will try to reconnect again every #{@site.site_settings['intervals']['reconnect']} seconds..", level: :info
37
44
  @logger.mute @ip, @port
@@ -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