rsmp 0.1.19 → 0.1.31

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.
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