rsmp 0.9.7 → 0.9.10

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: 9634c9a0b4e843d2f9d53f85023a51584a4686bea45aeb4cc74dbca7d63a117b
4
- data.tar.gz: 598c15d07dc9dd22bda5e4901e2537b902b675af9a88281c2dae9b494d41a52f
3
+ metadata.gz: f9afdedb545513c5574db59a28f07515866dbd34d8908767813275518ee590cd
4
+ data.tar.gz: e6fa96a531f450ce114601a57f91045ade415bb9317c5155a57a05054acf6481
5
5
  SHA512:
6
- metadata.gz: 990b18990bc24622bdceb84c9f19a247fb3c6e6cca82fb0a4019e1aa1da7f33503f182ebd4d7789ab890c4d9d51c83062f7f6ff8ab96681bc8cd98cc626418e8
7
- data.tar.gz: 20d4a23d38c6cce0ce46fe7def72d90a822627f51800a82d90c06f433e7104d3336a1c300ba6462038c641d08378980ceb794dc0ec54a91d36a17b21d1bf589a
6
+ metadata.gz: c3a2fbb33b4789e0cc0200156f759014eab17b51a23f78e486fd8fa67e54da1ac241bdd1c1b6c77ce0b0534d8447607b8806105433920ef7d00733183c2e67de
7
+ data.tar.gz: c6cf57cc0b98b54c541293283b7810de1ce218a3c22454d925db5727706b1d29793493d2cc0bff6f96e932c8dc6e9f5dffab005ebba79785617f9292c056575c
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rsmp (0.9.7)
4
+ rsmp (0.9.10)
5
5
  async (~> 1.29.1)
6
6
  async-io (~> 1.32.2)
7
7
  colorize (~> 0.8.1)
@@ -72,7 +72,7 @@ module RSMP
72
72
  else
73
73
  super message
74
74
  end
75
- rescue RSMP::RepeatedAlarmError, RSMP::RepeatedStatusError => e
75
+ rescue RSMP::RepeatedAlarmError, RSMP::RepeatedStatusError, RSMP::TimestampError => e
76
76
  str = "Rejected #{message.type} message,"
77
77
  dont_acknowledge message, str, "#{e}"
78
78
  notify_error e.exception("#{str}#{e.message} #{message.json}")
@@ -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
+
@@ -10,15 +10,22 @@ module RSMP
10
10
  :startup_sequence_active, :startup_sequence, :startup_sequence_pos
11
11
 
12
12
  def initialize node:, id:, cycle_time: 10, signal_plans:,
13
- startup_sequence:, live_output:nil, inputs:
13
+ startup_sequence:, live_output:nil, inputs:{}
14
14
  super node: node, id: id, grouped: true
15
15
  @signal_groups = []
16
16
  @detector_logics = []
17
17
  @plans = signal_plans
18
18
  @cycle_time = cycle_time
19
19
  @num_traffic_situations = 1
20
- @num_inputs = inputs['total']
21
- @input_programming = inputs['programming']
20
+
21
+ if inputs
22
+ num_inputs = inputs['total']
23
+ @input_programming = inputs['programming']
24
+ else
25
+ @input_programming = nil
26
+ end
27
+ @inputs = TLC::Inputs.new num_inputs || 8
28
+
22
29
  @startup_sequence = startup_sequence
23
30
  @live_output = live_output
24
31
  reset
@@ -41,25 +48,18 @@ module RSMP
41
48
 
42
49
  def reset
43
50
  reset_modes
44
-
45
51
  @cycle_counter = 0
46
52
  @plan = 1
47
53
  @intersection = 0
48
54
  @emergency_route = false
49
55
  @emergency_route_number = 0
50
56
  @traffic_situation = 0
51
-
52
- @inputs = '0'*@num_inputs
53
- @input_activations = '0'*@num_inputs
54
- @input_forced = '0'*@num_inputs
55
- @input_forced_values = '0'*@num_inputs
56
- @input_results = '0'*@num_inputs
57
-
58
57
  @day_time_table = {}
59
58
  @startup_sequence_active = false
60
59
  @startup_sequence_initiated_at = nil
61
60
  @startup_sequence_pos = 0
62
61
  @time_int = nil
62
+ @inputs.reset
63
63
  end
64
64
 
65
65
  def dark?
@@ -256,43 +256,34 @@ module RSMP
256
256
  end
257
257
  end
258
258
 
259
- def recompute_input idx
260
- if @input_forced[idx] == '1'
261
- @input_results[idx] = @input_forced_values[idx]
262
- elsif @input_activations[idx]=='1'
263
- @input_results[idx] = '1'
264
- else
265
- @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
+ else
268
+ log "Deactivating alarm #{alarm_code}, because input #{input} was deactivated", level: :info
269
+ end
266
270
  end
267
271
  end
268
272
 
269
273
  def handle_m0006 arg
270
274
  @node.verify_security_code 2, arg['securityCode']
271
275
  input = arg['input'].to_i
272
- unless input>0 && input<=@num_inputs
273
- raise MessageRejected.new("Input #{idx} is invalid, must be in the range 1-#{@num_inputs}")
274
- end
275
- idx = input - 1
276
- @input_activations[idx] = bool_string_to_digit arg['status']
277
- recompute_input idx
278
- activate = @input_activations[idx] == '1'
279
- if activate
276
+ status = string_to_bool arg['status']
277
+ unless input>=1 && input<=@inputs.size
278
+ raise MessageRejected.new("Input must be in the range 1-#{@inputs.size}")
279
+ end
280
+ if status
280
281
  log "Activating input #{input}", level: :info
281
282
  else
282
283
  log "Deactivating input #{input}", level: :info
283
284
  end
284
-
285
- if @input_programming
286
- actions = @input_programming[input]
287
- if actions && actions['raise']
288
- alarm_code = actions['raise']
289
- if activate
290
- log "Activating alarm #{alarm_code}, due to input #{input} programming", level: :info
291
- else
292
- log "Deactivating alarm #{alarm_code}, due to input #{input} programming", level: :info
293
- end
294
- end
295
- end
285
+ change = @inputs.set input, status
286
+ input_logic input, change if change != nil
296
287
  end
297
288
 
298
289
  def handle_m0007 arg
@@ -354,6 +345,17 @@ module RSMP
354
345
  @node.verify_security_code 2, arg['securityCode']
355
346
  end
356
347
 
348
+ def string_to_bool bool_str
349
+ case bool_str
350
+ when 'True'
351
+ true
352
+ when 'False'
353
+ false
354
+ else
355
+ raise RSMP::MessageRejected.new "Invalid boolean '#{bool}', must be 'True' or 'False'"
356
+ end
357
+ end
358
+
357
359
  def bool_string_to_digit bool
358
360
  case bool
359
361
  when 'True'
@@ -372,21 +374,18 @@ module RSMP
372
374
  def handle_m0019 arg
373
375
  @node.verify_security_code 2, arg['securityCode']
374
376
  input = arg['input'].to_i
375
- idx = input - 1
376
- unless idx>=0 && input<@num_inputs # TODO should NotAck
377
- log "Can't force input #{idx+1}, only have #{@num_inputs} inputs", level: :warning
378
- return
379
- end
380
- @input_forced[idx] = bool_string_to_digit arg['status']
381
- if @input_forced[idx]
382
- @input_forced_values[idx] = bool_string_to_digit arg['inputValue']
383
- end
384
- recompute_input idx
385
- if @input_forced[idx]
386
- log "Forcing input #{idx+1} to #{@input_forced_values[idx]}, #{@input_results}", level: :info
377
+ force = string_to_bool arg['status']
378
+ forced_value = string_to_bool arg['inputValue']
379
+ unless input>=1 && input<=@inputs.size
380
+ raise MessageRejected.new("Input must be in the range 1-#{@inputs.size}")
381
+ end
382
+ if force
383
+ log "Forcing input #{input} to #{forced_value}", level: :info
387
384
  else
388
- log "Releasing input #{idx+1}", level: :info
385
+ log "Releasing input #{input}", level: :info
389
386
  end
387
+ change = @inputs.set_forcing input, force, forced_value
388
+ input_logic input, change if change != nil
390
389
  end
391
390
 
392
391
  def handle_m0020 arg
@@ -496,7 +495,7 @@ module RSMP
496
495
  def handle_s0003 status_code, status_name=nil
497
496
  case status_name
498
497
  when 'inputstatus'
499
- TrafficControllerSite.make_status @input_results
498
+ TrafficControllerSite.make_status @inputs.actual_string
500
499
  when 'extendedinputstatus'
501
500
  TrafficControllerSite.make_status 0.to_s
502
501
  end
@@ -698,7 +697,7 @@ module RSMP
698
697
  def handle_s0029 status_code, status_name=nil
699
698
  case status_name
700
699
  when 'status'
701
- TrafficControllerSite.make_status @input_forced
700
+ TrafficControllerSite.make_status @inputs.forced_string
702
701
  end
703
702
  end
704
703
 
data/lib/rsmp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module RSMP
2
- VERSION = "0.9.7"
2
+ VERSION = "0.9.10"
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.7
4
+ version: 0.9.10
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