rsmp 0.1.21 → 0.1.27

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.
@@ -20,7 +20,7 @@ module RSMP
20
20
  def handle_supervisor_settings options
21
21
  @supervisor_settings = {
22
22
  'port' => 12111,
23
- 'rsmp_versions' => ['3.1.1','3.1.2','3.1.3','3.1.4'],
23
+ 'rsmp_versions' => ['3.1.1','3.1.2','3.1.3','3.1.4','3.1.5'],
24
24
  'timer_interval' => 0.1,
25
25
  'watchdog_interval' => 1,
26
26
  'watchdog_timeout' => 2,
@@ -32,7 +32,9 @@ module RSMP
32
32
  'site_ready_timeout' => 1,
33
33
  'stop_after_first_session' => false,
34
34
  'sites' => {
35
- :any => {}
35
+ :any => {
36
+ 'sxl' => 'tlc'
37
+ }
36
38
  }
37
39
  }
38
40
 
@@ -47,17 +49,35 @@ module RSMP
47
49
  check_required_settings @supervisor_settings, required
48
50
 
49
51
  @rsmp_versions = @supervisor_settings["rsmp_versions"]
52
+
53
+ check_site_sxl_types
54
+ end
55
+
56
+ def check_site_sxl_types
57
+ @supervisor_settings['sites'].each do |ip,settings|
58
+ unless settings
59
+ raise RSMP::ConfigurationError.new("Configuration for site '#{ip}' is empty")
60
+ end
61
+ sxl = settings['sxl']
62
+ sxl = 'tlc' unless sxl # temporary fix until configs are updated
63
+ unless sxl
64
+ raise RSMP::ConfigurationError.new("Configuration error for site '#{ip}': No SXL specified")
65
+ end
66
+ RSMP::Schemer.find_schemas! sxl if sxl
67
+ rescue RSMP::Schemer::UnknownSchemaError => e
68
+ raise RSMP::ConfigurationError.new("Configuration error for site '#{ip}': #{e}")
69
+ end
50
70
  end
51
71
 
52
72
  def start_action
53
73
  @endpoint = Async::IO::Endpoint.tcp('0.0.0.0', @supervisor_settings["port"])
54
- @endpoint.accept do |socket|
74
+ @endpoint.accept do |socket| # creates async tasks
55
75
  handle_connection(socket)
76
+ rescue StandardError => e
77
+ notify_error e, level: :internal
56
78
  end
57
- rescue SystemCallError => e # all ERRNO errors
58
- log "Exception: #{e.to_s}", level: :error
59
79
  rescue StandardError => e
60
- log ["Exception: #{e.inspect}",e.backtrace].flatten.join("\n"), level: :error
80
+ notify_error e, level: :internal
61
81
  end
62
82
 
63
83
  def stop
@@ -74,16 +94,17 @@ module RSMP
74
94
  remote_hostname = socket.remote_address.ip_address
75
95
  remote_ip = socket.remote_address.ip_address
76
96
 
77
- info = {ip:remote_ip, port:remote_port, hostname:remote_hostname, now:RSMP.now_string()}
97
+ info = {ip:remote_ip, port:remote_port, hostname:remote_hostname, now:Clock.now}
78
98
  if accept? socket, info
79
99
  connect socket, info
80
100
  else
81
101
  reject socket, info
82
102
  end
83
- rescue SystemCallError => e # all ERRNO errors
84
- log "Exception: #{e.to_s}", level: :error
103
+ rescue ConnectionError => e
104
+ log "Rejected connection from #{remote_ip}, #{e.to_s}", level: :info
85
105
  rescue StandardError => e
86
- log "Exception: #{e}", exception: e, level: :error
106
+ log "Connection: #{e.to_s}", exception: e, level: :error
107
+ notify_error e, level: :internal
87
108
  ensure
88
109
  close socket, info
89
110
  end
@@ -91,7 +112,7 @@ module RSMP
91
112
  def starting
92
113
  log "Starting supervisor on port #{@supervisor_settings["port"]}",
93
114
  level: :info,
94
- timestamp: RSMP.now_object
115
+ timestamp: @clock.now
95
116
  end
96
117
 
97
118
  def accept? socket, info
@@ -115,11 +136,15 @@ module RSMP
115
136
  ip: info[:ip],
116
137
  port: info[:port],
117
138
  level: :info,
118
- timestamp: RSMP.now_object
139
+ timestamp: Clock.now
140
+
141
+ settings = ip_to_site_settings info[:ip]
142
+ raise ConnectionError.new('unknown ip not allowed') unless settings
119
143
 
120
- settings = @supervisor_settings['sites'][info[:ip]] || @supervisor_settings['sites'][:any]
121
144
  proxy = build_proxy({
122
145
  supervisor: self,
146
+ ip: info[:ip],
147
+ port: info[:port],
123
148
  task: @task,
124
149
  settings: settings,
125
150
  socket: socket,
@@ -146,9 +171,9 @@ module RSMP
146
171
 
147
172
  def close socket, info
148
173
  if info
149
- log "Connection to #{format_ip_and_port(info)} closed", ip: info[:ip], level: :info, timestamp: RSMP.now_object
174
+ log "Connection to #{format_ip_and_port(info)} closed", ip: info[:ip], level: :info, timestamp: Clock.now
150
175
  else
151
- log "Connection closed", level: :info, timestamp: RSMP.now_object
176
+ log "Connection closed", level: :info, timestamp: Clock.now
152
177
  end
153
178
 
154
179
  socket.close
@@ -170,13 +195,13 @@ module RSMP
170
195
  return site if site
171
196
  wait_for(@site_id_condition,timeout) { find_site site_id }
172
197
  rescue Async::TimeoutError
173
- nil
198
+ raise RSMP::TimeoutError.new "Site '#{site_id}'' did not connect within #{timeout}s"
174
199
  end
175
200
 
176
201
  def wait_for_site_disconnect site_id, timeout
177
202
  wait_for(@site_id_condition,timeout) { true unless find_site site_id }
178
203
  rescue Async::TimeoutError
179
- false
204
+ raise RSMP::TimeoutError.new "Site '#{site_id}'' did not disconnect within #{timeout}s"
180
205
  end
181
206
 
182
207
  def check_site_id site_id
@@ -185,7 +210,7 @@ module RSMP
185
210
  end
186
211
 
187
212
  def check_site_already_connected site_id
188
- raise FatalError.new "Site #{site_id} already connected" if find_site(site_id)
213
+ raise FatalError.new "Site '#{site_id}'' already connected" if find_site(site_id)
189
214
  end
190
215
 
191
216
  def find_allowed_site_setting site_id
@@ -198,6 +223,10 @@ module RSMP
198
223
  raise FatalError.new "site id #{site_id} rejected"
199
224
  end
200
225
 
226
+ def ip_to_site_settings ip
227
+ @supervisor_settings['sites'][ip] || @supervisor_settings['sites'][:any]
228
+ end
229
+
201
230
  def aggregated_status_changed site_proxy, component
202
231
  end
203
232
 
@@ -49,12 +49,12 @@ module RSMP
49
49
  @endpoint = Async::IO::Endpoint.tcp(@ip, @port)
50
50
  @socket = @endpoint.connect
51
51
  @stream = Async::IO::Stream.new(@socket)
52
- @protocol = Async::IO::Protocol::Line.new(@stream,RSMP::WRAPPING_DELIMITER) # rsmp messages are json terminated with a form-feed
52
+ @protocol = Async::IO::Protocol::Line.new(@stream,WRAPPING_DELIMITER) # rsmp messages are json terminated with a form-feed
53
53
  end
54
54
 
55
55
  def connection_complete
56
56
  super
57
- log "Connection to supervisor established", level: :info
57
+ log "Connection to supervisor established, using core #{@rsmp_version}, #{sxl} #{sxl_version}", level: :info
58
58
  start_watchdog
59
59
  end
60
60
 
@@ -65,6 +65,8 @@ module RSMP
65
65
  when StatusUpdate
66
66
  when AggregatedStatus
67
67
  will_not_handle message
68
+ when AggregatedStatusRequest
69
+ process_aggregated_status_request message
68
70
  when CommandRequest
69
71
  process_command_request message
70
72
  when CommandResponse
@@ -123,7 +125,7 @@ module RSMP
123
125
 
124
126
  def send_aggregated_status component
125
127
  message = AggregatedStatus.new({
126
- "aSTS" => RSMP.now_string,
128
+ "aSTS" => clock.to_s,
127
129
  "cId" => component.c_id,
128
130
  "fP" => 'NormalControl',
129
131
  "fS" => nil,
@@ -161,6 +163,14 @@ module RSMP
161
163
  sorted
162
164
  end
163
165
 
166
+ def process_aggregated_status_request message
167
+ log "Received #{message.type}", message: message, level: :log
168
+ component_id = message.attributes["cId"]
169
+ component = @site.find_component component_id
170
+ acknowledge message
171
+ send_aggregated_status component
172
+ end
173
+
164
174
  def process_command_request message
165
175
  log "Received #{message.type}", message: message, level: :log
166
176
  component_id = message.attributes["cId"]
@@ -177,7 +187,7 @@ module RSMP
177
187
  end
178
188
  response = CommandResponse.new({
179
189
  "cId"=>component_id,
180
- "cTS"=>RSMP.now_string,
190
+ "cTS"=>clock.to_s,
181
191
  "rvs"=>rvs
182
192
  })
183
193
  acknowledge message
@@ -194,7 +204,7 @@ module RSMP
194
204
  end
195
205
  response = StatusResponse.new({
196
206
  "cId"=>component_id,
197
- "sTs"=>RSMP.now_string,
207
+ "sTs"=>clock.to_s,
198
208
  "sS"=>sS,
199
209
  "mId" => options[:m_id]
200
210
  })
@@ -221,7 +231,7 @@ module RSMP
221
231
  update_list[component] ||= {}
222
232
 
223
233
  subs = @status_subscriptions[component]
224
- now = RSMP::now_object
234
+ now = Time.now # internal timestamp
225
235
 
226
236
  message.attributes["sS"].each do |arg|
227
237
  sCI = arg["sCI"]
@@ -310,12 +320,10 @@ module RSMP
310
320
  end
311
321
  end
312
322
  send_status_updates update_list
313
- rescue StandardError => e
314
- log ["Status update exception: #{e}",e.backtrace].flatten.join("\n"), level: :error
315
323
  end
316
324
 
317
325
  def send_status_updates update_list
318
- now = RSMP.now_string
326
+ now = clock.to_s
319
327
  update_list.each_pair do |component_id,by_code|
320
328
  component = @site.find_component component_id
321
329
  sS = []
@@ -343,7 +351,7 @@ module RSMP
343
351
 
344
352
  def send_alarm
345
353
  message = Alarm.new({
346
- "aSTS"=>RSMP.now_string,
354
+ "aSTS"=>clock.to_s,
347
355
  "fP"=>nil,
348
356
  "fS"=>nil,
349
357
  "se"=>@site.aggregated_status_bools
data/lib/rsmp/tlc.rb CHANGED
@@ -13,7 +13,6 @@ module RSMP
13
13
  @cycle_time = cycle_time
14
14
  @num_traffic_situations = 1
15
15
  @num_inputs = 8
16
-
17
16
  reset
18
17
  end
19
18
 
@@ -41,6 +40,11 @@ module RSMP
41
40
  @input_results = '0'*@num_inputs
42
41
  end
43
42
 
43
+ def clock
44
+ node.clock
45
+ end
46
+
47
+
44
48
  def add_signal_group group
45
49
  @signal_groups << group
46
50
  end
@@ -48,8 +52,12 @@ module RSMP
48
52
  def add_detector_logic logic
49
53
  @detector_logics << logic
50
54
  end
55
+
51
56
  def timer now
52
- pos = now.to_i % @cycle_time
57
+ # TODO
58
+ # We should use a monotone timer, to avoid jumps
59
+ # in case the user sets the system time
60
+ pos = Time.now.to_i % @cycle_time
53
61
  if pos != @pos
54
62
  @pos = pos
55
63
  move pos
@@ -202,6 +210,17 @@ module RSMP
202
210
 
203
211
  def handle_m0104 arg
204
212
  @node.verify_security_code 1, arg['securityCode']
213
+ time = Time.new(
214
+ arg['year'],
215
+ arg['month'],
216
+ arg['day'],
217
+ arg['hour'],
218
+ arg['minute'],
219
+ arg['second'],
220
+ 'UTC'
221
+ )
222
+ @node.clock.set time
223
+ log "Clock set to #{time}, (adjustment is #{@node.clock.adjustment}s)", level: :info
205
224
  end
206
225
 
207
226
  def set_input i, value
@@ -518,35 +537,37 @@ module RSMP
518
537
  end
519
538
 
520
539
  def handle_s0096 status_code, status_name=nil
540
+ now = clock.now
521
541
  case status_name
522
542
  when 'year'
523
- RSMP::Tlc.make_status RSMP.now_object.year.to_s.rjust(4, "0")
543
+ RSMP::Tlc.make_status now.year.to_s.rjust(4, "0")
524
544
  when 'month'
525
- RSMP::Tlc.make_status RSMP.now_object.month.to_s.rjust(2, "0")
545
+ RSMP::Tlc.make_status now.month.to_s.rjust(2, "0")
526
546
  when 'day'
527
- RSMP::Tlc.make_status RSMP.now_object.day.to_s.rjust(2, "0")
547
+ RSMP::Tlc.make_status now.day.to_s.rjust(2, "0")
528
548
  when 'hour'
529
- RSMP::Tlc.make_status RSMP.now_object.hour.to_s.rjust(2, "0")
549
+ RSMP::Tlc.make_status now.hour.to_s.rjust(2, "0")
530
550
  when 'minute'
531
- RSMP::Tlc.make_status RSMP.now_object.min.to_s.rjust(2, "0")
551
+ RSMP::Tlc.make_status now.min.to_s.rjust(2, "0")
532
552
  when 'second'
533
- RSMP::Tlc.make_status RSMP.now_object.sec.to_s.rjust(2, "0")
553
+ RSMP::Tlc.make_status now.sec.to_s.rjust(2, "0")
534
554
  end
535
555
  end
536
556
 
537
557
  def handle_s0097 status_code, status_name=nil
538
558
  case status_name
539
- when 'version'
540
- RSMP::Tlc.make_status '1'
541
- when 'hash'
559
+ when 'checksum'
542
560
  RSMP::Tlc.make_status '1'
561
+ when 'timestamp'
562
+ now = @node.clock.to_s
563
+ RSMP::Tlc.make_status now
543
564
  end
544
565
  end
545
566
 
546
567
  def handle_s0205 status_code, status_name=nil
547
568
  case status_name
548
569
  when 'start'
549
- RSMP::Tlc.make_status RSMP.now_string
570
+ RSMP::Tlc.make_status clock.to_s
550
571
  when 'vehicles'
551
572
  RSMP::Tlc.make_status 0
552
573
  end
@@ -555,7 +576,7 @@ module RSMP
555
576
  def handle_s0206 status_code, status_name=nil
556
577
  case status_name
557
578
  when 'start'
558
- RSMP::Tlc.make_status RSMP.now_string
579
+ RSMP::Tlc.make_status clock.to_s
559
580
  when 'speed'
560
581
  RSMP::Tlc.make_status 0
561
582
  end
@@ -564,7 +585,7 @@ module RSMP
564
585
  def handle_s0207 status_code, status_name=nil
565
586
  case status_name
566
587
  when 'start'
567
- RSMP::Tlc.make_status RSMP.now_string
588
+ RSMP::Tlc.make_status clock.to_s
568
589
  when 'occupancy'
569
590
  RSMP::Tlc.make_status 0
570
591
  end
@@ -573,7 +594,7 @@ module RSMP
573
594
  def handle_s0208 status_code, status_name=nil
574
595
  case status_name
575
596
  when 'start'
576
- RSMP::Tlc.make_status RSMP.now_string
597
+ RSMP::Tlc.make_status clock.to_s
577
598
  when 'P'
578
599
  RSMP::Tlc.make_status 0
579
600
  when 'PS'
@@ -653,21 +674,22 @@ module RSMP
653
674
  end
654
675
 
655
676
  def handle_s0025 status_code, status_name=nil
677
+ now = @node.clock.to_s
656
678
  case status_name
657
679
  when 'minToGEstimate'
658
- RSMP::Tlc.make_status RSMP.now_string
680
+ RSMP::Tlc.make_status now
659
681
  when 'maxToGEstimate'
660
- RSMP::Tlc.make_status RSMP.now_string
682
+ RSMP::Tlc.make_status now
661
683
  when 'likelyToGEstimate'
662
- RSMP::Tlc.make_status RSMP.now_string
684
+ RSMP::Tlc.make_status now
663
685
  when 'ToGConfidence'
664
686
  RSMP::Tlc.make_status 0
665
687
  when 'minToREstimate'
666
- RSMP::Tlc.make_status RSMP.now_string
688
+ RSMP::Tlc.make_status now
667
689
  when 'maxToREstimate'
668
- RSMP::Tlc.make_status RSMP.now_string
690
+ RSMP::Tlc.make_status now
669
691
  when 'likelyToREstimate'
670
- RSMP::Tlc.make_status RSMP.now_string
692
+ RSMP::Tlc.make_status now
671
693
  when 'ToRConfidence'
672
694
  RSMP::Tlc.make_status 0
673
695
  end
@@ -695,7 +717,7 @@ module RSMP
695
717
  def handle_s0201 status_code, status_name=nil
696
718
  case status_name
697
719
  when 'starttime'
698
- RSMP::Tlc.make_status RSMP.now_string
720
+ RSMP::Tlc.make_status @node.clock.to_s
699
721
  when 'vehicles'
700
722
  RSMP::Tlc.make_status 0
701
723
  end
@@ -704,7 +726,7 @@ module RSMP
704
726
  def handle_s0202 status_code, status_name=nil
705
727
  case status_name
706
728
  when 'starttime'
707
- RSMP::Tlc.make_status RSMP.now_string
729
+ RSMP::Tlc.make_status @node.clock.to_s
708
730
  when 'speed'
709
731
  RSMP::Tlc.make_status 0
710
732
  end
@@ -713,7 +735,7 @@ module RSMP
713
735
  def handle_s0203 status_code, status_name=nil
714
736
  case status_name
715
737
  when 'starttime'
716
- RSMP::Tlc.make_status RSMP.now_string
738
+ RSMP::Tlc.make_status @node.clock.to_s
717
739
  when 'occupancy'
718
740
  RSMP::Tlc.make_status 0
719
741
  end
@@ -722,7 +744,7 @@ module RSMP
722
744
  def handle_s0204 status_code, status_name=nil
723
745
  case status_name
724
746
  when 'starttime'
725
- RSMP::Tlc.make_status RSMP.now_string
747
+ RSMP::Tlc.make_status @node.clock.to_s
726
748
  when 'P'
727
749
  RSMP::Tlc.make_status 0
728
750
  when 'PS'
@@ -767,6 +789,7 @@ module RSMP
767
789
  end
768
790
 
769
791
  class Tlc < Site
792
+ attr_accessor :main
770
793
  def initialize options={}
771
794
  super options
772
795
  @sxl = 'traffic_light_controller'
@@ -806,22 +829,21 @@ module RSMP
806
829
  next_time = Time.now.to_f
807
830
  loop do
808
831
  begin
809
- now = RSMP.now_object
810
- timer(now)
832
+ timer(@clock.now)
811
833
  rescue EOFError => e
812
- log "TLC timer: Connection closed: #{e}", level: :warning
834
+ log "Connection closed: #{e}", level: :warning
813
835
  rescue IOError => e
814
- log "TLC timer: IOError", level: :warning
836
+ log "IOError", level: :warning
815
837
  rescue Errno::ECONNRESET
816
- log "TLC timer: Connection reset by peer", level: :warning
838
+ log "Connection reset by peer", level: :warning
817
839
  rescue Errno::EPIPE => e
818
- log "TLC timer: Broken pipe", level: :warning
840
+ log "Broken pipe", level: :warning
819
841
  rescue StandardError => e
820
- log "TLC timer: #{e}", level: :debug
842
+ notify_error e, level: :internal
821
843
  ensure
822
844
  # adjust sleep duration to avoid drift. so wake up always happens on the
823
845
  # same fractional second.
824
- # note that Time.now is not monotonic. If the clock si changed,
846
+ # note that Time.now is not monotonic. If the clock is changed,
825
847
  # either manaully or via NTP, the sleep interval might jump.
826
848
  # an alternative is to use ::Process.clock_gettime(::Process::CLOCK_MONOTONIC),
827
849
  # to get the current time. this ensures a constant interval, but