rsmp 0.3.3 → 0.3.7

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 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