rsmp 0.3.3 → 0.3.7

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: b124af129ad5b07b815b08abfa6b0642f5b2e3cc57b54face6c9c7eb907d7691
4
- data.tar.gz: 269c32fd8db76ea7960e92c652369de4f6de35d198848051ee6db742f4d64a30
3
+ metadata.gz: 63163e8e010e001deffd0bba691e343c028ae5edbf3a5c9022529d319c36035e
4
+ data.tar.gz: 07225c7538b514c3b74dbc307a432f32eb1fe839faaeef4483208206b29e103a
5
5
  SHA512:
6
- metadata.gz: af7adc670cb134befa1d6f0b05674dd2ff9f06f85690a907b55f510bf7b22d970251d8b971a64cc89c7fdd047208077521e32f7552437130b3ff3818b1458e4b
7
- data.tar.gz: 3cdf1087034a80e6b5539e398664ef5dba9308d94c1628339d7ec249563e6bd8211e15cc506b37ac31f4616ebb4d632d412b6c7fb785c2ba4e3b0a7082fa02d5
6
+ metadata.gz: 6eed25d057be1a6766b94d1127b41f498b4e3532bf5650d7c888321dfe48bafaf2af69ff2d871cc437fc44ae9286d898da2387bc2e267d451aca332d3695159f
7
+ data.tar.gz: 011f89ceb76bbfdc521ca0730c2d7f1c48663e4faf35576e4e72bee83831813745bc0ce0c45aab4201c1874f1ee21a5c1f6235dbab0c16feab1e3970acc56d3b
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rsmp (0.3.3)
4
+ rsmp (0.3.7)
5
5
  async (~> 1.29.1)
6
6
  async-io (~> 1.32.1)
7
7
  colorize (~> 0.8.1)
@@ -13,7 +13,7 @@ module RSMP
13
13
  :rest,
14
14
  :not_connected ]
15
15
 
16
- def initialize node:, id:, grouped:
16
+ def initialize node:, id:, grouped: false
17
17
  @c_id = id
18
18
  @node = node
19
19
  @grouped = grouped
@@ -57,9 +57,6 @@ module RSMP
57
57
  def aggregated_status_changed options={}
58
58
  @node.aggregated_status_changed self, options
59
59
  end
60
-
61
- def alarm code:, status:
62
- end
63
60
 
64
61
  def log str, options
65
62
  @node.log str, options
@@ -73,5 +70,18 @@ module RSMP
73
70
  raise UnknownStatus.new "Status #{status_code}/#{status_name} not implemented by #{self.class}"
74
71
  end
75
72
 
73
+ def handle_alarm message
74
+ code = message.attribute('aCId')
75
+ alarm = @alarms[code]
76
+ if alarm
77
+ if alarm.differ? message
78
+ @alarms[code] = alarm
79
+ else
80
+ raise RepeatedAlarmError.new("no changes from previous alarm #{alarm.m_id_short}")
81
+ end
82
+ else
83
+ @alarms[code] = message
84
+ end
85
+ end
76
86
  end
77
87
  end
@@ -38,10 +38,23 @@ module RSMP
38
38
  Component.new id:id, node: self, grouped: type=='main'
39
39
  end
40
40
 
41
- def find_component component_id
41
+ def infer_component_type component_id
42
+ Component
43
+ end
44
+
45
+ def find_component component_id, build: true
42
46
  component = @components[component_id]
43
- raise UnknownComponent.new("Component #{component_id} not found") unless component
44
- component
47
+ return component if component
48
+ if build
49
+ inferred = infer_component_type component_id
50
+ component = inferred.new node: self, id: component_id
51
+ @components[ component_id] = component
52
+ class_name = component.class.name.split('::').last
53
+ log "Inferred #{class_name} component #{component_id}", level: :info
54
+ component
55
+ else
56
+ raise UnknownComponent.new("Component #{component_id} not found") unless component
57
+ end
45
58
  end
46
59
 
47
60
  end
data/lib/rsmp/error.rb CHANGED
@@ -52,4 +52,7 @@ module RSMP
52
52
 
53
53
  class ConfigurationError < Error
54
54
  end
55
+
56
+ class RepeatedAlarmError < Error
57
+ end
55
58
  end
data/lib/rsmp/message.rb CHANGED
@@ -36,7 +36,7 @@ module RSMP
36
36
  when "Watchdog"
37
37
  message = Watchdog.new attributes
38
38
  when "Alarm"
39
- message = Alarm.new attributes
39
+ message = self.build_alarm attributes
40
40
  when "CommandRequest"
41
41
  message = CommandRequest.new attributes
42
42
  when "CommandResponse"
@@ -59,6 +59,23 @@ module RSMP
59
59
  message
60
60
  end
61
61
 
62
+ def self.build_alarm attributes
63
+ case attributes["aSp"]
64
+ when 'Issue'
65
+ AlarmIssue.new attributes
66
+ when 'Request'
67
+ AlarmRequest.new attributes
68
+ when 'Acknowledge'
69
+ AlarmAcknowledged.new attributes
70
+ when 'Suspend'
71
+ AlarmSuspend.new attributes
72
+ when 'Resume'
73
+ AlarmResume.new attributes
74
+ else
75
+ Alarm.new attributes
76
+ end
77
+ end
78
+
62
79
  def type
63
80
  @attributes["type"]
64
81
  end
@@ -191,26 +208,64 @@ module RSMP
191
208
  def initialize attributes = {}
192
209
  super({
193
210
  "type" => "Alarm",
211
+ "ntsOId" => '',
212
+ "xNId" => '',
213
+ "xACId" => '',
214
+ "xNACId" => ''
194
215
  }.merge attributes)
195
216
  end
217
+
218
+ def differ? from
219
+ %w{aSp aCId ack aS sS aTs cat pri}.each do |key|
220
+ return true if attribute(key).downcase != from.attribute(key).downcase
221
+ end
222
+ return true if attribute('rvs') != from.attribute('rvs')
223
+ false
224
+ end
196
225
  end
197
226
 
198
- class AlarmRequest < Message
227
+ class AlarmIssue < Alarm
199
228
  def initialize attributes = {}
200
229
  super({
201
- "type" => "Alarm",
230
+ "aSp" => "Issue",
202
231
  }.merge attributes)
203
232
  end
204
233
  end
205
234
 
206
- class AlarmAcknowledged < Message
235
+ class AlarmRequest < Alarm
207
236
  def initialize attributes = {}
208
237
  super({
209
- "type" => "Alarm",
238
+ "aSp" => "Request",
239
+ }.merge attributes)
240
+ end
241
+ end
242
+
243
+ class AlarmAcknowledged < Alarm
244
+ def initialize attributes = {}
245
+ super({
246
+ "aSp" => "Acknowledge",
210
247
  }.merge attributes)
211
248
  end
212
249
  end
213
250
 
251
+ class AlarmSuspend < Alarm
252
+ def initialize attributes = {}
253
+ super({
254
+ "aSp" => "Suspend",
255
+ }.merge attributes)
256
+ end
257
+ end
258
+
259
+ class AlarmResume < Alarm
260
+ def initialize attributes = {}
261
+ super({
262
+ "aSp" => "Resume",
263
+ }.merge attributes)
264
+ end
265
+ end
266
+
267
+
268
+
214
269
  class Watchdog < Message
215
270
  def initialize attributes = {}
216
271
  super({
data/lib/rsmp/proxy.rb CHANGED
@@ -73,6 +73,11 @@ module RSMP
73
73
  @state == :ready
74
74
  end
75
75
 
76
+ def connected?
77
+ @state == :starting || @state == :ready
78
+ end
79
+
80
+
76
81
  def start
77
82
  set_state :starting
78
83
  end
@@ -118,7 +123,6 @@ module RSMP
118
123
  task.annotate "reader"
119
124
  @stream ||= Async::IO::Stream.new(@socket)
120
125
  @protocol ||= Async::IO::Protocol::Line.new(@stream,WRAPPING_DELIMITER) # rsmp messages are json terminated with a form-feed
121
-
122
126
  while json = @protocol.read_line
123
127
  beginning = Time.now
124
128
  message = process_packet json
@@ -267,12 +271,13 @@ module RSMP
267
271
  end
268
272
 
269
273
  def send_message message, reason=nil, validate: true
274
+ raise NotReady unless connected?
270
275
  raise IOError unless @protocol
271
276
  message.direction = :out
272
277
  message.generate_json
273
278
  message.validate get_schemas unless validate==false
274
- expect_acknowledgement message
275
279
  @protocol.write_lines message.json
280
+ expect_acknowledgement message
276
281
  notify message
277
282
  log_send message, reason
278
283
  rescue EOFError, IOError
@@ -303,10 +308,11 @@ module RSMP
303
308
  end
304
309
 
305
310
  def should_validate_ingoing_message? message
306
- return false unless @site_settings
311
+ return true unless @site_settings
307
312
  skip = @site_settings.dig('skip_validation')
308
- return true unless skip && skip.include?(message.class.to_s)
309
- false
313
+ return true unless skip
314
+ klass = message.class.name.split('::').last
315
+ !skip.include?(klass)
310
316
  end
311
317
 
312
318
  def process_packet json
data/lib/rsmp/site.rb CHANGED
@@ -83,7 +83,7 @@ module RSMP
83
83
 
84
84
  def aggregated_status_changed component, options={}
85
85
  @proxies.each do |proxy|
86
- proxy.send_aggregated_status component, options
86
+ proxy.send_aggregated_status component, options if proxy.ready?
87
87
  end
88
88
  end
89
89
 
@@ -125,17 +125,11 @@ module RSMP
125
125
  se = message.attribute("se")
126
126
  validate_aggregated_status(message,se) == false
127
127
  c_id = message.attributes["cId"]
128
- component = @components[c_id]
129
- if component == nil
130
- if @site_settings == nil || @site_settings['components'] == nil
131
- component = build_component(id:c_id, type:nil)
132
- @components[c_id] = component
133
- log "Adding component #{c_id} to site #{@site_id}", level: :info
134
- else
135
- reason = "component #{c_id} not found"
136
- dont_acknowledge message, "Ignoring #{message.type}:", reason
137
- return
138
- end
128
+ component = find_component c_id
129
+ unless component
130
+ reason = "component #{c_id} not found"
131
+ dont_acknowledge message, "Ignoring #{message.type}:", reason
132
+ return
139
133
  end
140
134
 
141
135
  component.set_aggregated_status_bools se
@@ -148,11 +142,17 @@ module RSMP
148
142
  end
149
143
 
150
144
  def process_alarm message
145
+ component = find_component message.attribute("cId")
146
+ status = ["ack","aS","sS"].map { |key| message.attribute(key) }.join(',')
147
+ component.handle_alarm message
151
148
  alarm_code = message.attribute("aCId")
152
149
  asp = message.attribute("aSp")
153
- status = ["ack","aS","sS"].map { |key| message.attribute(key) }.join(',')
154
150
  log "Received #{message.type}, #{alarm_code} #{asp} [#{status}]", message: message, level: :log
155
151
  acknowledge message
152
+ rescue RSMP::RepeatedAlarmError => e
153
+ str = "Rejected #{message.type} message, "
154
+ dont_acknowledge message, str, "#{e}"
155
+ notify_error e.exception("#{str}#{e.message} #{message.json}")
156
156
  end
157
157
 
158
158
  def version_acknowledged
@@ -241,13 +241,8 @@ module RSMP
241
241
 
242
242
  def send_alarm_acknowledgement component, alarm_code, options={}
243
243
  message = RSMP::AlarmAcknowledged.new({
244
- "ntsOId" => '',
245
- "xNId" => '',
246
244
  "cId" => component,
247
245
  "aCId" => alarm_code,
248
- "xACId" => '',
249
- "xNACId" => '',
250
- "aSp" => 'Acknowledge'
251
246
  })
252
247
  send_message message, validate: options[:validate]
253
248
  message
@@ -363,16 +363,6 @@ module RSMP
363
363
  end
364
364
  end
365
365
 
366
- def send_alarm
367
- message = Alarm.new({
368
- "aSTS"=>clock.to_s,
369
- "fP"=>nil,
370
- "fS"=>nil,
371
- "se"=>@site.aggregated_status_bools
372
- })
373
- send_message message
374
- end
375
-
376
366
  def sxl_version
377
367
  @site_settings['sxl_version']
378
368
  end
data/lib/rsmp/tlc.rb CHANGED
@@ -5,7 +5,7 @@ module RSMP
5
5
  class TrafficController < Component
6
6
  attr_reader :pos, :cycle_time
7
7
 
8
- def initialize node:, id:, cycle_time:
8
+ def initialize node:, id:, cycle_time: 10
9
9
  super node: node, id: id, grouped: true
10
10
  @signal_groups = []
11
11
  @detector_logics = []
@@ -625,13 +625,15 @@ module RSMP
625
625
  class SignalGroup < Component
626
626
  attr_reader :plan, :state
627
627
 
628
- def initialize node:, id:, plan:
628
+ # plan is a string, with each character representing a signal phase at a particular second in the cycle
629
+ def initialize node:, id:, plan: nil
629
630
  super node: node, id: id, grouped: false
630
631
  @plan = plan
631
632
  move 0
632
633
  end
633
634
 
634
635
  def get_state pos
636
+ return 'a' unless @plan # if no plan, use phase a, which means disabled/dark
635
637
  if pos > @plan.length
636
638
  '.'
637
639
  else
data/lib/rsmp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module RSMP
2
- VERSION = "0.3.3"
2
+ VERSION = "0.3.7"
3
3
  end
data/lib/rsmp.rb CHANGED
@@ -18,7 +18,6 @@ require 'rsmp/node'
18
18
  require 'rsmp/supervisor'
19
19
  require 'rsmp/components'
20
20
  require 'rsmp/notifier'
21
-
22
21
  require 'rsmp/listener'
23
22
  require 'rsmp/collector'
24
23
  require 'rsmp/matcher'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rsmp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.3.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Emil Tin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-10-18 00:00:00.000000000 Z
11
+ date: 2021-10-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async
@@ -203,7 +203,6 @@ files:
203
203
  - documentation/message_distribution.md
204
204
  - exe/rsmp
205
205
  - lib/rsmp.rb
206
- - lib/rsmp/alarm.rb
207
206
  - lib/rsmp/archive.rb
208
207
  - lib/rsmp/cli.rb
209
208
  - lib/rsmp/collector.rb
@@ -255,7 +254,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
255
254
  - !ruby/object:Gem::Version
256
255
  version: '0'
257
256
  requirements: []
258
- rubygems_version: 3.2.15
257
+ rubygems_version: 3.2.26
259
258
  signing_key:
260
259
  specification_version: 4
261
260
  summary: RoadSide Message Protocol (RSMP) library.
data/lib/rsmp/alarm.rb DELETED
@@ -1,15 +0,0 @@
1
- # RSMP Alarm. Manages the various states an alarm can be in.
2
-
3
- module RSMP
4
- class Alarm
5
-
6
- def initialize code: code, blocked: blocked=false, suspended: suspended=false, acknowledged: acknowledged=false
7
- @code = code
8
- @code = code
9
- @blocked = blocked
10
- @suspended = suspended
11
- @acknowledged = acknowledged
12
- end
13
-
14
- end
15
- end