rsmp 0.1.19 → 0.1.31

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -80,7 +88,11 @@ module RSMP
80
88
  end
81
89
 
82
90
  def format_signal_group_status
83
- @signal_groups.map { |group| group.state }.join
91
+ if @yellow_flash
92
+ 'c' * @signal_groups.size
93
+ else
94
+ @signal_groups.map { |group| group.state }.join
95
+ end
84
96
  end
85
97
 
86
98
  def handle_command command_code, arg
@@ -125,18 +137,29 @@ module RSMP
125
137
 
126
138
  def handle_m0005 arg
127
139
  @node.verify_security_code 2, arg['securityCode']
128
- @emergency_route = arg['status'] == 'True'
140
+ @emergency_route = (arg['status'] == 'True')
129
141
  @emergency_route_number = arg['emergencyroute'].to_i
142
+
143
+ if @emergency_route
144
+ log "Switching to emergency route #{@emergency_route_number}", level: :info
145
+ else
146
+ log "Switching off emergency route", level: :info
147
+ end
130
148
  end
131
149
 
132
150
  def handle_m0006 arg
133
151
  @node.verify_security_code 2, arg['securityCode']
134
152
  input = arg['input'].to_i
135
153
  idx = input - 1
136
- return unless idx>=0 && input<@num_inputs
154
+ return unless idx>=0 && input<@num_inputs # TODO should NotAck
137
155
  @input_activations[idx] = (arg['status']=='True' ? '1' : '0')
138
156
  result = @input_activations[idx]=='1' || @inputs[idx]=='1'
139
157
  @input_results[idx] = (result ? '1' : '0')
158
+ if @input_activations[idx]
159
+ log "Activate input #{idx}", level: :info
160
+ else
161
+ log "Deactivate input #{idx}", level: :info
162
+ end
140
163
  end
141
164
 
142
165
  def handle_m0007 arg
@@ -191,6 +214,17 @@ module RSMP
191
214
 
192
215
  def handle_m0104 arg
193
216
  @node.verify_security_code 1, arg['securityCode']
217
+ time = Time.new(
218
+ arg['year'],
219
+ arg['month'],
220
+ arg['day'],
221
+ arg['hour'],
222
+ arg['minute'],
223
+ arg['second'],
224
+ 'UTC'
225
+ )
226
+ @node.clock.set time
227
+ log "Clock set to #{time}, (adjustment is #{@node.clock.adjustment}s)", level: :info
194
228
  end
195
229
 
196
230
  def set_input i, value
@@ -203,8 +237,13 @@ module RSMP
203
237
  end
204
238
 
205
239
  def switch_plan plan
206
- log "Switching to plan #{plan}", level: :info
207
- @plan = plan.to_i
240
+ plan_nr = plan.to_i
241
+ if plan_nr == 0
242
+ log "Switching to plan selection by time table", level: :info
243
+ else
244
+ log "Switching to plan #{plan_nr}", level: :info
245
+ end
246
+ @plan = plan_nr
208
247
  end
209
248
 
210
249
  def switch_mode mode
@@ -502,35 +541,37 @@ module RSMP
502
541
  end
503
542
 
504
543
  def handle_s0096 status_code, status_name=nil
544
+ now = clock.now
505
545
  case status_name
506
546
  when 'year'
507
- RSMP::Tlc.make_status RSMP.now_object.year.to_s.rjust(4, "0")
547
+ RSMP::Tlc.make_status now.year.to_s.rjust(4, "0")
508
548
  when 'month'
509
- RSMP::Tlc.make_status RSMP.now_object.month.to_s.rjust(2, "0")
549
+ RSMP::Tlc.make_status now.month.to_s.rjust(2, "0")
510
550
  when 'day'
511
- RSMP::Tlc.make_status RSMP.now_object.day.to_s.rjust(2, "0")
551
+ RSMP::Tlc.make_status now.day.to_s.rjust(2, "0")
512
552
  when 'hour'
513
- RSMP::Tlc.make_status RSMP.now_object.hour.to_s.rjust(2, "0")
553
+ RSMP::Tlc.make_status now.hour.to_s.rjust(2, "0")
514
554
  when 'minute'
515
- RSMP::Tlc.make_status RSMP.now_object.min.to_s.rjust(2, "0")
555
+ RSMP::Tlc.make_status now.min.to_s.rjust(2, "0")
516
556
  when 'second'
517
- RSMP::Tlc.make_status RSMP.now_object.sec.to_s.rjust(2, "0")
557
+ RSMP::Tlc.make_status now.sec.to_s.rjust(2, "0")
518
558
  end
519
559
  end
520
560
 
521
561
  def handle_s0097 status_code, status_name=nil
522
562
  case status_name
523
- when 'version'
524
- RSMP::Tlc.make_status '1'
525
- when 'hash'
563
+ when 'checksum'
526
564
  RSMP::Tlc.make_status '1'
565
+ when 'timestamp'
566
+ now = @node.clock.to_s
567
+ RSMP::Tlc.make_status now
527
568
  end
528
569
  end
529
570
 
530
571
  def handle_s0205 status_code, status_name=nil
531
572
  case status_name
532
573
  when 'start'
533
- RSMP::Tlc.make_status RSMP.now_string
574
+ RSMP::Tlc.make_status clock.to_s
534
575
  when 'vehicles'
535
576
  RSMP::Tlc.make_status 0
536
577
  end
@@ -539,7 +580,7 @@ module RSMP
539
580
  def handle_s0206 status_code, status_name=nil
540
581
  case status_name
541
582
  when 'start'
542
- RSMP::Tlc.make_status RSMP.now_string
583
+ RSMP::Tlc.make_status clock.to_s
543
584
  when 'speed'
544
585
  RSMP::Tlc.make_status 0
545
586
  end
@@ -548,7 +589,7 @@ module RSMP
548
589
  def handle_s0207 status_code, status_name=nil
549
590
  case status_name
550
591
  when 'start'
551
- RSMP::Tlc.make_status RSMP.now_string
592
+ RSMP::Tlc.make_status clock.to_s
552
593
  when 'occupancy'
553
594
  RSMP::Tlc.make_status 0
554
595
  end
@@ -557,7 +598,7 @@ module RSMP
557
598
  def handle_s0208 status_code, status_name=nil
558
599
  case status_name
559
600
  when 'start'
560
- RSMP::Tlc.make_status RSMP.now_string
601
+ RSMP::Tlc.make_status clock.to_s
561
602
  when 'P'
562
603
  RSMP::Tlc.make_status 0
563
604
  when 'PS'
@@ -637,21 +678,22 @@ module RSMP
637
678
  end
638
679
 
639
680
  def handle_s0025 status_code, status_name=nil
681
+ now = @node.clock.to_s
640
682
  case status_name
641
683
  when 'minToGEstimate'
642
- RSMP::Tlc.make_status RSMP.now_string
684
+ RSMP::Tlc.make_status now
643
685
  when 'maxToGEstimate'
644
- RSMP::Tlc.make_status RSMP.now_string
686
+ RSMP::Tlc.make_status now
645
687
  when 'likelyToGEstimate'
646
- RSMP::Tlc.make_status RSMP.now_string
688
+ RSMP::Tlc.make_status now
647
689
  when 'ToGConfidence'
648
690
  RSMP::Tlc.make_status 0
649
691
  when 'minToREstimate'
650
- RSMP::Tlc.make_status RSMP.now_string
692
+ RSMP::Tlc.make_status now
651
693
  when 'maxToREstimate'
652
- RSMP::Tlc.make_status RSMP.now_string
694
+ RSMP::Tlc.make_status now
653
695
  when 'likelyToREstimate'
654
- RSMP::Tlc.make_status RSMP.now_string
696
+ RSMP::Tlc.make_status now
655
697
  when 'ToRConfidence'
656
698
  RSMP::Tlc.make_status 0
657
699
  end
@@ -679,7 +721,7 @@ module RSMP
679
721
  def handle_s0201 status_code, status_name=nil
680
722
  case status_name
681
723
  when 'starttime'
682
- RSMP::Tlc.make_status RSMP.now_string
724
+ RSMP::Tlc.make_status @node.clock.to_s
683
725
  when 'vehicles'
684
726
  RSMP::Tlc.make_status 0
685
727
  end
@@ -688,7 +730,7 @@ module RSMP
688
730
  def handle_s0202 status_code, status_name=nil
689
731
  case status_name
690
732
  when 'starttime'
691
- RSMP::Tlc.make_status RSMP.now_string
733
+ RSMP::Tlc.make_status @node.clock.to_s
692
734
  when 'speed'
693
735
  RSMP::Tlc.make_status 0
694
736
  end
@@ -697,7 +739,7 @@ module RSMP
697
739
  def handle_s0203 status_code, status_name=nil
698
740
  case status_name
699
741
  when 'starttime'
700
- RSMP::Tlc.make_status RSMP.now_string
742
+ RSMP::Tlc.make_status @node.clock.to_s
701
743
  when 'occupancy'
702
744
  RSMP::Tlc.make_status 0
703
745
  end
@@ -706,7 +748,7 @@ module RSMP
706
748
  def handle_s0204 status_code, status_name=nil
707
749
  case status_name
708
750
  when 'starttime'
709
- RSMP::Tlc.make_status RSMP.now_string
751
+ RSMP::Tlc.make_status @node.clock.to_s
710
752
  when 'P'
711
753
  RSMP::Tlc.make_status 0
712
754
  when 'PS'
@@ -751,6 +793,7 @@ module RSMP
751
793
  end
752
794
 
753
795
  class Tlc < Site
796
+ attr_accessor :main
754
797
  def initialize options={}
755
798
  super options
756
799
  @sxl = 'traffic_light_controller'
@@ -790,22 +833,21 @@ module RSMP
790
833
  next_time = Time.now.to_f
791
834
  loop do
792
835
  begin
793
- now = RSMP.now_object
794
- timer(now)
836
+ timer(@clock.now)
795
837
  rescue EOFError => e
796
- log "TLC timer: Connection closed: #{e}", level: :warning
838
+ log "Connection closed: #{e}", level: :warning
797
839
  rescue IOError => e
798
- log "TLC timer: IOError", level: :warning
840
+ log "IOError", level: :warning
799
841
  rescue Errno::ECONNRESET
800
- log "TLC timer: Connection reset by peer", level: :warning
842
+ log "Connection reset by peer", level: :warning
801
843
  rescue Errno::EPIPE => e
802
- log "TLC timer: Broken pipe", level: :warning
844
+ log "Broken pipe", level: :warning
803
845
  rescue StandardError => e
804
- log "TLC timer: #{e}", level: :debug
846
+ notify_error e, level: :internal
805
847
  ensure
806
848
  # adjust sleep duration to avoid drift. so wake up always happens on the
807
849
  # same fractional second.
808
- # note that Time.now is not monotonic. If the clock si changed,
850
+ # note that Time.now is not monotonic. If the clock is changed,
809
851
  # either manaully or via NTP, the sleep interval might jump.
810
852
  # an alternative is to use ::Process.clock_gettime(::Process::CLOCK_MONOTONIC),
811
853
  # to get the current time. this ensures a constant interval, but
data/lib/rsmp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module RSMP
2
- VERSION = "0.1.19"
2
+ VERSION = "0.1.31"
3
3
  end
data/lib/rsmp/wait.rb CHANGED
@@ -1,163 +1,16 @@
1
- # Helper for waiting for an Async condition using a block
2
-
3
1
  module RSMP
4
2
  module Wait
5
-
3
+ # wait for an async condition to signal, then yield to block
4
+ # if block returns true we're done. otherwise, wait again
6
5
  def wait_for condition, timeout, &block
7
- raise RuntimeError.new("Can't wait for state because task is stopped") unless @task.running?
6
+ raise RuntimeError.new("Can't wait for condition because task is not running") unless @task.running?
8
7
  @task.with_timeout(timeout) do
9
- while task.running? do
8
+ while @task.running? do
10
9
  value = condition.wait
11
10
  result = yield value
12
11
  return result if result # return result of check, if not nil
13
12
  end
14
13
  end
15
14
  end
16
-
17
- def capture_status_updates_or_responses task, type, options, m_id
18
- task.annotate "wait for status update/response"
19
- want = convert_status_list options[:status_list]
20
- result = {}
21
- # wait for a status update
22
- item = @archive.capture(task,options.merge({
23
- type: [type,'MessageNotAck'],
24
- num: 1
25
- })) do |item|
26
- message = item[:message]
27
- if message.is_a?(MessageNotAck) && message.attribute('oMId') == m_id
28
- # set result to an exception, but don't raise it.
29
- # this will be returned by the task and stored as the task result
30
- # when the parent task call wait() on the task, the exception
31
- # will be raised in the parent task, and caught by rspec.
32
- # rspec will then show the error and record the test as failed
33
- m_id_short = RSMP::Message.shorten_m_id m_id, 8
34
- result = RSMP::MessageRejected.new "Status request #{m_id_short} was rejected: #{message.attribute('rea')}"
35
- next true # done, no more messages wanted
36
- end
37
- found = []
38
- # look through querues
39
- want.each_with_index do |query,i|
40
- # look through status items in message
41
- item[:message].attributes['sS'].each do |input|
42
- ok = status_match? query, input
43
- if ok
44
- result[query] = input
45
- found << i # record which queries where matched succesfully
46
- end
47
- end
48
- end
49
- # remove queries that where matched
50
- found.sort.reverse.each do |i|
51
- want.delete_at i
52
- end
53
- want.empty? # any queries left to match?
54
- end
55
- result
56
- rescue Async::TimeoutError
57
- type_str = {'StatusUpdate'=>'update', 'StatusResponse'=>'response'}[type]
58
- raise RSMP::TimeoutError.new "Did not received status #{type_str} in reply to #{m_id} within #{options[:timeout]}s"
59
- end
60
-
61
- def wait_for_status_updates_or_responses parent_task, type, options={}, &block
62
- raise ArgumentError.new("component argument is missing") unless options[:component]
63
- raise ArgumentError.new("status_list argument is missing") unless options[:status_list]
64
- m_id = RSMP::Message.make_m_id # make message id so we can start waiting for it
65
-
66
- # wait for command responses in an async task
67
- task = parent_task.async do |task|
68
- capture_status_updates_or_responses task, type, options, m_id
69
- end
70
-
71
- # call block, it should send command request using the given m_id
72
- yield m_id
73
-
74
- # wait for the response and return it, raise exception if NotAck received, it it timed out
75
- task.wait
76
- end
77
-
78
- def wait_for_status_updates parent_task, options={}, &block
79
- wait_for_status_updates_or_responses parent_task, 'StatusUpdate', options, &block
80
- end
81
-
82
- def wait_for_status_responses parent_task, options={}, &block
83
- wait_for_status_updates_or_responses parent_task, 'StatusResponse', options, &block
84
- end
85
-
86
- def process_command_response message
87
- log "Received #{message.type}", message: message, level: :log
88
- acknowledge message
89
- end
90
-
91
- def command_match? query, item
92
- return false if query[:sCI] && query[:sCI] != item['sCI']
93
- return false if query[:n] && query[:n] != item['n']
94
- if query[:s].is_a? Regexp
95
- return false if query[:v] && item['v'] !~ query[:v]
96
- else
97
- return false if query[:v] && item['v'] != query[:v]
98
- end
99
- true
100
- end
101
-
102
- def capture_command_responses parent_task, type, options, m_id
103
- task.annotate "wait for command response"
104
- want = options[:command_list].clone
105
- result = {}
106
- item = @archive.capture(parent_task,options.merge({
107
- type: [type,'MessageNotAck'],
108
- num: 1
109
- })) do |item|
110
- message = item[:message]
111
- if message.is_a?(MessageNotAck) && message.attribute('oMId') == m_id
112
- # and message.attribute('oMId')==m_id
113
- # set result to an exception, but don't raise it.
114
- # this will be returned by the task and stored as the task result
115
- # when the parent task call wait() on the task, the exception
116
- # will be raised in the parent task, and caught by rspec.
117
- # rspec will then show the error and record the test as failed
118
- m_id_short = RSMP::Message.shorten_m_id m_id, 8
119
- result = RSMP::MessageRejected.new "Command request #{m_id_short} was rejected: #{message.attribute('rea')}"
120
- next true # done, no more messages wanted
121
- end
122
-
123
- found = []
124
- # look through querues
125
- want.each_with_index do |query,i|
126
- # look through items in message
127
- item[:message].attributes['rvs'].each do |input|
128
- ok = command_match? query, input
129
- if ok
130
- result[query] = input
131
- found << i # record which queries where matched succesfully
132
- end
133
- end
134
- end
135
- # remove queries that where matched
136
- found.sort.reverse.each do |i|
137
- want.delete_at i
138
- end
139
- want.empty? # any queries left to match?
140
- end
141
- result
142
- rescue Async::TimeoutError
143
- raise RSMP::TimeoutError.new "Did not receive command response to #{m_id} within #{options[:timeout]}s"
144
- end
145
-
146
- def wait_for_command_responses parent_task, options={}, &block
147
- raise ArgumentError.new("component argument is missing") unless options[:component]
148
- raise ArgumentError.new("command_list argument is missing") unless options[:command_list]
149
- m_id = RSMP::Message.make_m_id # make message id so we can start waiting for it
150
-
151
- # wait for command responses in an async task
152
- task = parent_task.async do |task|
153
- capture_command_responses task, 'CommandResponse', options, m_id
154
- end
155
-
156
- # call block, it should send command request using the given m_id
157
- yield m_id
158
-
159
- # wait for the response and return it, raise exception if NotAck received, it it timed out
160
- task.wait
161
- end
162
15
  end
163
16
  end