rsmp 0.9.9 → 0.10.1

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: 71af49e549129bf32f9137a2799c91b43ba19e5e7adb15f777a181919c19dbd0
4
- data.tar.gz: 15c8f8c96ed3838f0b0b948b5d0e9be895ec965a9f651a529a44b214426242ec
3
+ metadata.gz: 58dea443fbf263b26902f047bc4b9127add5b43eea514be23e8f1c1354b34686
4
+ data.tar.gz: be065deb840d556e81194ca9862616d48fb5be475167899c155295a1b2276a5d
5
5
  SHA512:
6
- metadata.gz: 33206373986495e8c8d9871c83d465d2961db86c2713e0056eb1e5a0fb6f153dc506c05f549bc52f6963f7aeb7e1b7f78f387b479893babe8f0d77cd0efbffe3
7
- data.tar.gz: 125e125b49bb0a5d99234d8aa4bac4a3107de077fb7adc55a1e70cbf0544c0b163355cfac4a94eeae1e412b8951e4f5fab8d2846187e2d7479c626e0adf81530
6
+ metadata.gz: 594fc45b7d42a0ad33c23ac2789c0b090a72afa5fb5355a9543586272f5623f4ea58a37265bd79c74c3cb0efe3e07d731265ca01c56188eb62084f1694ee3e09
7
+ data.tar.gz: aac8c6bc88b8498139232e2c131626f7d9e1663aeea1c85fbce579b499d21a4bc40ebbcb064281b34009dd413d3a79a1a4191f2c771ae3fa5253180317fa8436
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rsmp (0.9.9)
4
+ rsmp (0.10.1)
5
5
  async (~> 1.29.1)
6
6
  async-io (~> 1.32.2)
7
7
  colorize (~> 0.8.1)
data/config/tlc.yaml CHANGED
@@ -15,6 +15,7 @@ components:
15
15
  B2:
16
16
  detector_logic:
17
17
  DL1:
18
+ DL2:
18
19
  signal_plans:
19
20
  1:
20
21
  dynamic_bands:
@@ -77,6 +77,7 @@ module RSMP
77
77
  raise UnknownStatus.new "Status #{status_code}/#{status_name} not implemented by #{self.class}"
78
78
  end
79
79
 
80
+ # handle incoming alarm
80
81
  def handle_alarm message
81
82
  code = message.attribute('aCId')
82
83
  previous = @alarms[code]
@@ -92,6 +93,27 @@ module RSMP
92
93
  @alarms[code] = message
93
94
  end
94
95
 
96
+ # set alarm
97
+ def send_alarm code:, status:
98
+ # TODO
99
+ # we need to manage the state of alarms internally (an ALarm class probably),
100
+ # and handle request from the supervisor to suspend and resume alarms etc.
101
+ # when this state changes, we then send an alarm message
102
+ alarm = Alarm.new(
103
+ 'cId' => c_id,
104
+ 'aTs' => @node.clock.to_s,
105
+ 'aCId' => code,
106
+ 'aSp' => 'Issue',
107
+ 'ack' => 'Acknowledged',
108
+ 'sS' => 'notSuspended',
109
+ 'aS' => status,
110
+ 'cat' => 'D',
111
+ 'pri' => '2',
112
+ 'rvs' => []
113
+ )
114
+ @node.alarm_changed self, alarm
115
+ end
116
+
95
117
  # Handle an incoming status respone, by storing the values
96
118
  def handle_status_response message
97
119
  store_status message, check_repeated: false
data/lib/rsmp/site.rb CHANGED
@@ -93,6 +93,12 @@ module RSMP
93
93
  end
94
94
  end
95
95
 
96
+ def alarm_changed component, alarm
97
+ @proxies.each do |proxy|
98
+ proxy.send_alarm component, alarm if proxy.ready?
99
+ end
100
+ end
101
+
96
102
  def connect_to_supervisor task, supervisor_settings
97
103
  proxy = build_proxy({
98
104
  site: self,
@@ -172,6 +172,12 @@ module RSMP
172
172
  end
173
173
  end
174
174
 
175
+ def send_alarm component, alarm, options={}
176
+ send_and_optionally_collect alarm, options do |collect_options|
177
+ Collector.new self, collect_options.merge(task:@task, type: 'MessageAck')
178
+ end
179
+ end
180
+
175
181
  def process_aggregated_status message
176
182
  se = message.attribute("se")
177
183
  validate_aggregated_status(message,se) == false
@@ -0,0 +1,134 @@
1
+ module RSMP
2
+ module TLC
3
+ # class that maintains the state of TLC inputs
4
+ # indexing is 1-based since that's how the RSMP messages are specified
5
+ class Inputs
6
+ attr_reader :size
7
+
8
+ def initialize size
9
+ @size = size
10
+ reset
11
+ end
12
+
13
+ def reset
14
+ string_size = @size+1
15
+ @value = '0'*string_size
16
+ @forced = '0'*string_size
17
+ @forced_value = '0'*string_size
18
+ @actual = '0'*string_size
19
+ end
20
+
21
+ def set input, value
22
+ check_input input
23
+ report_change(input) do
24
+ @value[input] = to_digit value
25
+ update_actual input
26
+ end
27
+ end
28
+
29
+ def set_forcing input, force=true, forced_value=true
30
+ check_input input
31
+ report_change(input) do
32
+ @forced[input] = to_digit force
33
+ @forced_value[input] = to_digit forced_value
34
+ update_actual input
35
+ end
36
+ end
37
+
38
+ def force input, forced_value=true
39
+ report_change(input) do
40
+ set_forcing input, true, forced_value
41
+ end
42
+ end
43
+
44
+ def release input
45
+ report_change(input) do
46
+ set_forcing input, false, false
47
+ end
48
+ end
49
+
50
+ def value input
51
+ check_input input
52
+ from_digit @value[input]
53
+ end
54
+
55
+ def forced? input
56
+ check_input input
57
+ from_digit @forced[input]
58
+ end
59
+
60
+ def forced_value input
61
+ check_input input
62
+ from_digit @forced_value[input]
63
+ end
64
+
65
+ def actual input
66
+ check_input input
67
+ from_digit @actual[input]
68
+ end
69
+
70
+ def report input
71
+ {
72
+ value: value(input),
73
+ forced: forced?(input),
74
+ forced_value: forced_value(input),
75
+ actual:actual(input)
76
+ }
77
+ end
78
+
79
+ def value_string
80
+ @value[1..-1]
81
+ end
82
+
83
+ def value_string
84
+ @value[1..-1]
85
+ end
86
+
87
+ def forced_string
88
+ @forced[1..-1]
89
+ end
90
+
91
+ def forced_value_string
92
+ @forced[1..-1]
93
+ end
94
+
95
+ def actual_string
96
+ @actual[1..-1]
97
+ end
98
+
99
+ protected
100
+
101
+ def check_input input
102
+ raise ArgumentError.new("Input index #{input} must be in the range 1-#{@size}") if input<1 || input>@size
103
+ end
104
+
105
+ def from_digit input
106
+ input == '1'
107
+ end
108
+
109
+ def to_digit input
110
+ input ? '1' : '0'
111
+ end
112
+
113
+ def update_actual input
114
+ if from_digit @forced[input]
115
+ @actual[input] = @forced_value[input]
116
+ else
117
+ @actual[input] = @value[input]
118
+ end
119
+ end
120
+
121
+ def report_change input, &block
122
+ before = @actual[input]
123
+ yield
124
+ if @actual[input] != before
125
+ from_digit @actual[input]
126
+ else
127
+ nil
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
133
+
134
+
@@ -19,12 +19,12 @@ module RSMP
19
19
  @num_traffic_situations = 1
20
20
 
21
21
  if inputs
22
- @num_inputs = inputs['total'] || 8
22
+ num_inputs = inputs['total']
23
23
  @input_programming = inputs['programming']
24
24
  else
25
- @num_inputs = 8
26
25
  @input_programming = nil
27
26
  end
27
+ @inputs = TLC::Inputs.new num_inputs || 8
28
28
 
29
29
  @startup_sequence = startup_sequence
30
30
  @live_output = live_output
@@ -48,25 +48,18 @@ module RSMP
48
48
 
49
49
  def reset
50
50
  reset_modes
51
-
52
51
  @cycle_counter = 0
53
52
  @plan = 1
54
53
  @intersection = 0
55
54
  @emergency_route = false
56
55
  @emergency_route_number = 0
57
56
  @traffic_situation = 0
58
-
59
- @inputs = '0'*@num_inputs
60
- @input_activations = '0'*@num_inputs
61
- @input_forced = '0'*@num_inputs
62
- @input_forced_values = '0'*@num_inputs
63
- @input_results = '0'*@num_inputs
64
-
65
57
  @day_time_table = {}
66
58
  @startup_sequence_active = false
67
59
  @startup_sequence_initiated_at = nil
68
60
  @startup_sequence_pos = 0
69
61
  @time_int = nil
62
+ @inputs.reset
70
63
  end
71
64
 
72
65
  def dark?
@@ -263,43 +256,36 @@ module RSMP
263
256
  end
264
257
  end
265
258
 
266
- def recompute_input idx
267
- if @input_forced[idx] == '1'
268
- @input_results[idx] = @input_forced_values[idx]
269
- elsif @input_activations[idx]=='1'
270
- @input_results[idx] = '1'
271
- else
272
- @input_results[idx] = bool_to_digit( @inputs[idx]=='1' )
259
+ def input_logic input, change
260
+ return unless @input_programming && change != nil
261
+ actions = @input_programming[input]
262
+ return unless actions
263
+ if actions['raise']
264
+ alarm_code = actions['raise']
265
+ if change
266
+ log "Activating alarm #{alarm_code}, because input #{input} was activated", level: :info
267
+ send_alarm code:alarm_code, status:'Active'
268
+ else
269
+ log "Deactivating alarm #{alarm_code}, because input #{input} was deactivated", level: :info
270
+ send_alarm code:alarm_code, status:'inActive'
271
+ end
273
272
  end
274
273
  end
275
274
 
276
275
  def handle_m0006 arg
277
276
  @node.verify_security_code 2, arg['securityCode']
278
277
  input = arg['input'].to_i
279
- unless input>0 && input<=@num_inputs
280
- raise MessageRejected.new("Input #{idx} is invalid, must be in the range 1-#{@num_inputs}")
281
- end
282
- idx = input - 1
283
- @input_activations[idx] = bool_string_to_digit arg['status']
284
- recompute_input idx
285
- activate = @input_activations[idx] == '1'
286
- if activate
278
+ status = string_to_bool arg['status']
279
+ unless input>=1 && input<=@inputs.size
280
+ raise MessageRejected.new("Input must be in the range 1-#{@inputs.size}")
281
+ end
282
+ if status
287
283
  log "Activating input #{input}", level: :info
288
284
  else
289
285
  log "Deactivating input #{input}", level: :info
290
286
  end
291
-
292
- if @input_programming
293
- actions = @input_programming[input]
294
- if actions && actions['raise']
295
- alarm_code = actions['raise']
296
- if activate
297
- log "Activating alarm #{alarm_code}, due to input #{input} programming", level: :info
298
- else
299
- log "Deactivating alarm #{alarm_code}, due to input #{input} programming", level: :info
300
- end
301
- end
302
- end
287
+ change = @inputs.set input, status
288
+ input_logic input, change if change != nil
303
289
  end
304
290
 
305
291
  def handle_m0007 arg
@@ -361,6 +347,17 @@ module RSMP
361
347
  @node.verify_security_code 2, arg['securityCode']
362
348
  end
363
349
 
350
+ def string_to_bool bool_str
351
+ case bool_str
352
+ when 'True'
353
+ true
354
+ when 'False'
355
+ false
356
+ else
357
+ raise RSMP::MessageRejected.new "Invalid boolean '#{bool}', must be 'True' or 'False'"
358
+ end
359
+ end
360
+
364
361
  def bool_string_to_digit bool
365
362
  case bool
366
363
  when 'True'
@@ -379,20 +376,18 @@ module RSMP
379
376
  def handle_m0019 arg
380
377
  @node.verify_security_code 2, arg['securityCode']
381
378
  input = arg['input'].to_i
382
- idx = input - 1
383
- unless input>0 && input<=@num_inputs
384
- raise MessageRejected.new("Can't force input #{input}, only have #{@num_inputs} inputs")
385
- end
386
- @input_forced[idx] = bool_string_to_digit arg['status']
387
- if @input_forced[idx]
388
- @input_forced_values[idx] = bool_string_to_digit arg['inputValue']
379
+ force = string_to_bool arg['status']
380
+ forced_value = string_to_bool arg['inputValue']
381
+ unless input>=1 && input<=@inputs.size
382
+ raise MessageRejected.new("Input must be in the range 1-#{@inputs.size}")
389
383
  end
390
- recompute_input idx
391
- if @input_forced[idx]
392
- log "Forcing input #{input} to #{@input_forced_values[idx]}", level: :info
384
+ if force
385
+ log "Forcing input #{input} to #{forced_value}", level: :info
393
386
  else
394
387
  log "Releasing input #{input}", level: :info
395
388
  end
389
+ change = @inputs.set_forcing input, force, forced_value
390
+ input_logic input, change if change != nil
396
391
  end
397
392
 
398
393
  def handle_m0020 arg
@@ -502,7 +497,7 @@ module RSMP
502
497
  def handle_s0003 status_code, status_name=nil
503
498
  case status_name
504
499
  when 'inputstatus'
505
- TrafficControllerSite.make_status @input_results
500
+ TrafficControllerSite.make_status @inputs.actual_string
506
501
  when 'extendedinputstatus'
507
502
  TrafficControllerSite.make_status 0.to_s
508
503
  end
@@ -704,7 +699,7 @@ module RSMP
704
699
  def handle_s0029 status_code, status_name=nil
705
700
  case status_name
706
701
  when 'status'
707
- TrafficControllerSite.make_status @input_forced
702
+ TrafficControllerSite.make_status @inputs.forced_string
708
703
  end
709
704
  end
710
705
 
data/lib/rsmp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module RSMP
2
- VERSION = "0.9.9"
2
+ VERSION = "0.10.1"
3
3
  end
data/lib/rsmp.rb CHANGED
@@ -44,6 +44,7 @@ require 'rsmp/tlc/traffic_controller'
44
44
  require 'rsmp/tlc/detector_logic'
45
45
  require 'rsmp/tlc/signal_group'
46
46
  require 'rsmp/tlc/signal_plan'
47
+ require 'rsmp/tlc/inputs'
47
48
 
48
49
  require 'rsmp/convert/import/yaml'
49
50
  require 'rsmp/convert/export/json_schema'
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.9.9
4
+ version: 0.10.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Emil Tin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-03-10 00:00:00.000000000 Z
11
+ date: 2022-03-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async
@@ -243,6 +243,7 @@ files:
243
243
  - lib/rsmp/supervisor_proxy.rb
244
244
  - lib/rsmp/task.rb
245
245
  - lib/rsmp/tlc/detector_logic.rb
246
+ - lib/rsmp/tlc/inputs.rb
246
247
  - lib/rsmp/tlc/signal_group.rb
247
248
  - lib/rsmp/tlc/signal_plan.rb
248
249
  - lib/rsmp/tlc/traffic_controller.rb