rsmp 0.8.3 → 0.8.4

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: f54121873905da2e5ffa4914f4f454fc4b59c7283e482b6b89b4035d686b7779
4
- data.tar.gz: 523d2e310ebec8f4df07592fcb501d91f604ba8ea1c4625482c7d8d011340a6f
3
+ metadata.gz: d6e0bddb9443fd704586251f92785f5ec4d703431d587047f8a2e835fcb48b9f
4
+ data.tar.gz: 81b56b1687ad356177b6277d58f6db4ed4d3f8fa8e59aa0fc626a90fcc03bb86
5
5
  SHA512:
6
- metadata.gz: 807d2283a18f4a9c4e45594d4ae85e75464cde3792eb941342a825e8765a00d21f7d541fac03191680e28eb7e4af4c6624cb6ce80486da191cf3bc2b3f2d6431
7
- data.tar.gz: 6adc50becc91e2deab2c8099808a492a2440d072188227147742bd51ec1310f8a1075e3bed72f2989581ba11125b9beeda8134704d8a42e131ac1dac9a76eca1
6
+ metadata.gz: d8ba189a5602f9ec1bc7f09e821231c2f5135dd163da82ffae48b9a9f62ac79ec8d4beb114e6112d41902fc1ca06ccff2a208863d00f05e51c9a83cafb68e33c
7
+ data.tar.gz: 4fd8b04217edb49b3c1b929ac3d585c60194207cdb8380be7693ee00b448a28fce90cc6e55621b6cee601d773f80c6780c0d7a3a31ee8606f62f23cfce0718f8
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rsmp (0.8.3)
4
+ rsmp (0.8.4)
5
5
  async (~> 1.29.1)
6
6
  async-io (~> 1.32.1)
7
7
  colorize (~> 0.8.1)
@@ -70,8 +70,8 @@ GEM
70
70
  cucumber-cucumber-expressions (~> 12.1, >= 12.1.1)
71
71
  cucumber-messages (~> 15.0, >= 15.0.0)
72
72
  diff-lcs (1.4.4)
73
- ecma-re-validator (0.3.0)
74
- regexp_parser (~> 2.0)
73
+ ecma-re-validator (0.4.0)
74
+ regexp_parser (~> 2.2)
75
75
  ffi (1.15.3)
76
76
  fiber-local (1.0.0)
77
77
  hana (1.3.7)
data/config/tlc.yaml CHANGED
@@ -20,17 +20,18 @@ signal_plans:
20
20
  dynamic_bands:
21
21
  1: 0
22
22
  2: 5
23
- states:
24
- A1: '123efg'
25
- A2: '123efg'
26
- B1: '123efg'
27
- B2: '123efg'
28
- 2:
29
23
  states:
30
24
  A1: '111NBB'
31
25
  A2: '11NBBB'
32
26
  B1: 'BBB11N'
33
27
  B2: 'BBB1NB'
28
+ 2:
29
+ states:
30
+ A1: 'NNNNBB'
31
+ A2: 'NNNNBN'
32
+ B1: 'BBNNNN'
33
+ B2: 'BNNNNN'
34
+ startup_sequence: 'efg'
34
35
  intervals:
35
36
  timer: 0.1
36
37
  watchdog: 0.1
@@ -48,3 +49,4 @@ log:
48
49
  level: false
49
50
  debug: true
50
51
  json: true
52
+ live_output: tmp/tlc.state
data/lib/rsmp/site.rb CHANGED
@@ -9,9 +9,9 @@ module RSMP
9
9
  attr_reader :rsmp_versions, :site_settings, :logger, :proxies
10
10
 
11
11
  def initialize options={}
12
+ super options
12
13
  initialize_components
13
14
  handle_site_settings options
14
- super options
15
15
  @proxies = []
16
16
  @sleep_condition = Async::Notification.new
17
17
  @proxies_condition = Async::Notification.new
@@ -6,25 +6,33 @@ module RSMP
6
6
  # plan is a string, with each character representing a signal phase at a particular second in the cycle
7
7
  def initialize node:, id:
8
8
  super node: node, id: id, grouped: false
9
- move 0
10
9
  end
11
10
 
12
- def get_state pos
11
+ def timer
12
+ @state = get_state
13
+ end
14
+
15
+ def get_state
16
+ return 'a' if node.main.dark_mode
17
+ return 'c' if node.main.yellow_flash
18
+
19
+ cycle_counter = node.main.cycle_counter
20
+
21
+ if node.main.startup_sequence_active
22
+ @state = node.main.startup_state || 'a'
23
+ end
24
+
13
25
  default = 'a' # phase a means disabled/dark
14
26
  plan = node.main.current_plan
15
27
  return default unless plan
16
28
  return default unless plan.states
17
29
  states = plan.states[c_id]
18
30
  return default unless states
19
- state = states[pos]
31
+ state = states[cycle_counter]
20
32
  return default unless state =~ /[a-hA-G0-9N-P]/ # valid signal group states
21
33
  state
22
34
  end
23
35
 
24
- def move pos
25
- @state = get_state pos
26
- end
27
-
28
36
  def handle_command command_code, arg
29
37
  case command_code
30
38
  when 'M0010', 'M0011'
@@ -5,9 +5,12 @@ module RSMP
5
5
  # and keeps track of signal plans, detector logics, inputs, etc. which do
6
6
  # not have dedicated components.
7
7
  class TrafficController < Component
8
- attr_reader :pos, :cycle_time, :plan
8
+ attr_reader :pos, :cycle_time, :plan, :cycle_counter,
9
+ :yellow_flash, :dark_mode,
10
+ :startup_sequence_active, :startup_sequence, :startup_sequence_pos
9
11
 
10
- def initialize node:, id:, cycle_time: 10, signal_plans:
12
+ def initialize node:, id:, cycle_time: 10, signal_plans:,
13
+ startup_sequence:, live_output:nil
11
14
  super node: node, id: id, grouped: true
12
15
  @signal_groups = []
13
16
  @detector_logics = []
@@ -15,13 +18,15 @@ module RSMP
15
18
  @cycle_time = cycle_time
16
19
  @num_traffic_situations = 1
17
20
  @num_inputs = 8
21
+ @startup_sequence = startup_sequence
22
+ @live_output = live_output
18
23
  reset
19
24
  end
20
25
 
21
26
  def reset
22
- @pos = 0
23
- @plan = 0
24
- @dark_mode = false
27
+ @cycle_counter = 0
28
+ @plan = 1
29
+ @dark_mode = true
25
30
  @yellow_flash = false
26
31
  @booting = false
27
32
  @control_mode = 'control'
@@ -40,6 +45,12 @@ module RSMP
40
45
  @inputs = '0'*@num_inputs
41
46
  @input_activations = '0'*@num_inputs
42
47
  @input_results = '0'*@num_inputs
48
+
49
+ @day_time_table = {}
50
+ @startup_sequence_active = false
51
+ @startup_sequence_initiated_at = nil
52
+ @startup_sequence_pos = 0
53
+ @time_int = nil
43
54
  end
44
55
 
45
56
  def clock
@@ -64,46 +75,83 @@ module RSMP
64
75
  end
65
76
 
66
77
  def timer now
67
- # TODO
68
- # We should use a monotone timer, to avoid jumps
69
- # in case the user sets the system time
70
- pos = Time.now.to_i % @cycle_time
71
- if pos != @pos
72
- @pos = pos
73
- move pos
74
- end
78
+ # TODO use monotone timer, to avoid jumps in case the user sets the system time
79
+ @signal_groups.each { |group| group.timer }
80
+ time = Time.now.to_i
81
+ return if time == @time_int
82
+ @time_int = time
83
+ move_cycle_counter
84
+ move_startup_sequence if @startup_sequence_active
85
+ output_states
86
+ end
87
+
88
+ def move_cycle_counter
89
+ counter = Time.now.to_i % @cycle_time
90
+ @cycle_counter = counter
91
+ end
92
+
93
+ def startup_state
94
+ return unless @startup_sequence_active
95
+ return unless @startup_sequence_pos
96
+ @startup_sequence[ @startup_sequence_pos ]
75
97
  end
76
98
 
77
- def move pos
78
- @signal_groups.each do |group|
79
- group.move pos
99
+ def initiate_startup_sequence
100
+ log "Initiating startup sequence", level: :info
101
+ @startup_sequence_active = true
102
+ @startup_sequence_initiated_at = nil
103
+ @startup_sequence_pos = nil
104
+ end
105
+
106
+ def end_startup_sequence
107
+ @startup_sequence_active = false
108
+ @startup_sequence_initiated_at = nil
109
+ @startup_sequence_pos = nil
110
+
111
+ @yellow_flash = false
112
+ @dark_mode = false
113
+ end
114
+
115
+ def move_startup_sequence
116
+ was = @startup_sequence_pos
117
+ if @startup_sequence_initiated_at == nil
118
+ @startup_sequence_initiated_at = Time.now.to_i + 1
119
+ @startup_sequence_pos = 0
120
+ else
121
+ @startup_sequence_pos = Time.now.to_i - @startup_sequence_initiated_at
122
+ end
123
+ if @startup_sequence_pos >= @startup_sequence.size
124
+ end_startup_sequence
80
125
  end
81
- #output_states
82
126
  end
83
127
 
84
128
  def output_states
129
+ return unless @live_output
85
130
  str = @signal_groups.map do |group|
86
131
  s = "#{group.c_id}:#{group.state}"
87
132
  if group.state =~ /^[1-9]$/
88
133
  s.colorize(:green)
89
134
  elsif group.state =~ /^[NOP]$/
90
135
  s.colorize(:yellow)
91
- elsif group.state =~ /^[a]$/
92
- s.colorize(color: :black)
136
+ elsif group.state =~ /^[ae]$/
137
+ s.colorize(:black)
138
+ elsif group.state =~ /^[f]$/
139
+ s.colorize(:yellow)
140
+ elsif group.state =~ /^[g]$/
141
+ s.colorize(:red)
93
142
  else
94
143
  s.colorize(:red)
95
144
  end
96
145
  end.join ' '
97
146
  plan = "P#{@plan}"
98
- print "#{plan.rjust(4)} #{pos.to_s.rjust(4)} #{str}\r"
147
+
148
+ File.open @live_output, 'w' do |file|
149
+ file.puts "#{plan.rjust(4)} #{pos.to_s.rjust(4)} #{str}\r"
150
+ end
99
151
  end
100
152
 
101
153
  def format_signal_group_status
102
- if @yellow_flash
103
- 'c' * @signal_groups.size
104
- else
105
- @signal_groups.map { |group| group.state }.join
106
- end
154
+ @signal_groups.map { |group| group.state }.join
107
155
  end
108
156
 
109
157
  def handle_command command_code, arg
@@ -214,6 +262,18 @@ module RSMP
214
262
 
215
263
  def handle_m0017 arg
216
264
  @node.verify_security_code 2, arg['securityCode']
265
+ arg['status'].split(',').each do |item|
266
+ elems = item.split('-')
267
+ nr = elems[0].to_i
268
+ plan = elems[1].to_i
269
+ hour = elems[2].to_i
270
+ min = elems[3].to_i
271
+ if nr<0 || nr>12
272
+ raise InvalidMessage.new "time table id must be between 0 and 12, got #{nr}"
273
+ end
274
+ #p "nr: #{nr}, plan #{plan} at #{hour}:#{min}"
275
+ @day_time_table[nr] = {plan: plan, hour: hour, min:min}
276
+ end
217
277
  end
218
278
 
219
279
  def handle_m0018 arg
@@ -276,6 +336,7 @@ module RSMP
276
336
  log "Switching to mode #{mode}", level: :info
277
337
  case mode
278
338
  when 'NormalControl'
339
+ initiate_startup_sequence if @yellow_flash || @dark_mode
279
340
  @yellow_flash = false
280
341
  @dark_mode = false
281
342
  when 'YellowFlash'
@@ -308,9 +369,9 @@ module RSMP
308
369
  when 'signalgroupstatus'
309
370
  TrafficControllerSite.make_status format_signal_group_status
310
371
  when 'cyclecounter'
311
- TrafficControllerSite.make_status @pos.to_s
372
+ TrafficControllerSite.make_status @cycle_counter.to_s
312
373
  when 'basecyclecounter'
313
- TrafficControllerSite.make_status @pos.to_s
374
+ TrafficControllerSite.make_status @cycle_counter.to_s
314
375
  when 'stage'
315
376
  TrafficControllerSite.make_status 0.to_s
316
377
  end
@@ -511,7 +572,10 @@ module RSMP
511
572
  def handle_s0027 status_code, status_name=nil
512
573
  case status_name
513
574
  when 'status'
514
- TrafficControllerSite.make_status '00-00-00-00'
575
+ status = @day_time_table.map do |i,item|
576
+ "#{i}-#{item[:plan]}-#{item[:hour]}-#{item[:min]}"
577
+ end.join(',')
578
+ TrafficControllerSite.make_status status
515
579
  end
516
580
  end
517
581
 
@@ -5,11 +5,16 @@ module RSMP
5
5
  attr_accessor :main, :signal_plans
6
6
 
7
7
  def initialize options={}
8
+ # setup options before calling super initializer,
9
+ # since build of components depend on options
8
10
  @sxl = 'traffic_light_controller'
9
11
  @security_codes = options[:site_settings]['security_codes']
10
12
  @interval = options[:site_settings].dig('intervals','timer') || 1
13
+ @startup_sequence = options[:site_settings]['startup_sequence'] || 'efg'
11
14
  build_plans options[:site_settings].dig('signal_plans')
15
+
12
16
  super options
17
+
13
18
  unless @main
14
19
  raise ConfigurationError.new "TLC must have a main component"
15
20
  end
@@ -37,7 +42,9 @@ module RSMP
37
42
  when 'main'
38
43
  @main = TrafficController.new node: self, id: id,
39
44
  cycle_time: settings['cycle_time'],
40
- signal_plans: @signal_plans
45
+ startup_sequence: @startup_sequence,
46
+ signal_plans: @signal_plans,
47
+ live_output: @site_settings['live_output']
41
48
  when 'signal_group'
42
49
  group = SignalGroup.new node: self, id: id
43
50
  @main.add_signal_group group
@@ -52,6 +59,7 @@ module RSMP
52
59
  def start_action
53
60
  super
54
61
  start_timer
62
+ @main.initiate_startup_sequence
55
63
  end
56
64
 
57
65
  def start_timer
@@ -134,6 +142,7 @@ module RSMP
134
142
  when :restart
135
143
  log "Restarting TLC", level: :info
136
144
  restart
145
+ initiate_startup_sequence
137
146
  end
138
147
  end
139
148
  end
data/lib/rsmp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module RSMP
2
- VERSION = "0.8.3"
2
+ VERSION = "0.8.4"
3
3
  end
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.8.3
4
+ version: 0.8.4
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-01-11 00:00:00.000000000 Z
11
+ date: 2022-01-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async