rsmp 0.6.2 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
data/lib/rsmp/tlc.rb DELETED
@@ -1,920 +0,0 @@
1
- # Simulates a Traffic Light Controller
2
-
3
- module RSMP
4
-
5
- class TrafficController < Component
6
- attr_reader :pos, :cycle_time
7
-
8
- def initialize node:, id:, cycle_time: 10
9
- super node: node, id: id, grouped: true
10
- @signal_groups = []
11
- @detector_logics = []
12
- @plans = []
13
- @cycle_time = cycle_time
14
- @num_traffic_situations = 1
15
- @num_inputs = 8
16
- reset
17
- end
18
-
19
- def reset
20
- @pos = 0
21
- @plan = 0
22
- @dark_mode = false
23
- @yellow_flash = false
24
- @booting = false
25
- @control_mode = 'control'
26
- @police_key = 0
27
- @intersection = 0
28
- @is_starting = false
29
- @emergency_route = false
30
- @emergency_route_number = 0
31
- @traffic_situation = 0
32
- @manual_control = false
33
- @fixed_time_control = false
34
- @isolated_control = false
35
- @yellow_flash = false
36
- @all_red = false
37
-
38
- @inputs = '0'*@num_inputs
39
- @input_activations = '0'*@num_inputs
40
- @input_results = '0'*@num_inputs
41
- end
42
-
43
- def clock
44
- node.clock
45
- end
46
-
47
-
48
- def add_signal_group group
49
- @signal_groups << group
50
- end
51
-
52
- def add_detector_logic logic
53
- @detector_logics << logic
54
- end
55
-
56
- def timer now
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
61
- if pos != @pos
62
- @pos = pos
63
- move pos
64
- end
65
- end
66
-
67
- def move pos
68
- @signal_groups.each do |group|
69
- group.move pos
70
- end
71
- if pos == 0
72
- aggregated_status_changed
73
- end
74
- end
75
-
76
- def output_states
77
- str = @signal_groups.map do |group|
78
- s = "#{group.c_id}:#{group.state}"
79
- if group.state =~ /^[1-9]$/
80
- s.colorize(:green)
81
- elsif group.state =~ /^[NOP]$/
82
- s.colorize(:yellow)
83
- else
84
- s.colorize(:red)
85
- end
86
- end.join ' '
87
- print "\t#{pos.to_s.ljust(3)} #{str}\r"
88
- end
89
-
90
- def format_signal_group_status
91
- if @yellow_flash
92
- 'c' * @signal_groups.size
93
- else
94
- @signal_groups.map { |group| group.state }.join
95
- end
96
- end
97
-
98
- def handle_command command_code, arg
99
- case command_code
100
- when 'M0001', 'M0002', 'M0003', 'M0004', 'M0005', 'M0006', 'M0007',
101
- 'M0012', 'M0013', 'M0014', 'M0015', 'M0016', 'M0017', 'M0018',
102
- 'M0019', 'M0020', 'M0021', 'M0022',
103
- 'M0103', 'M0104'
104
-
105
- return send("handle_#{command_code.downcase}", arg)
106
- else
107
- raise UnknownCommand.new "Unknown command #{command_code}"
108
- end
109
- end
110
-
111
- def handle_m0001 arg
112
- @node.verify_security_code 2, arg['securityCode']
113
- switch_mode arg['status']
114
- end
115
-
116
- def handle_m0002 arg
117
- @node.verify_security_code 2, arg['securityCode']
118
- if RSMP::Tlc.from_rsmp_bool(arg['status'])
119
- switch_plan arg['timeplan']
120
- else
121
- switch_plan 0 # TODO use clock/calender
122
- end
123
- end
124
-
125
- def handle_m0003 arg
126
- @node.verify_security_code 2, arg['securityCode']
127
- @traffic_situation = arg['traficsituation'].to_i
128
- end
129
-
130
- def handle_m0004 arg
131
- @node.verify_security_code 2, arg['securityCode']
132
- # don't restart immeediately, since we need to first send command response
133
- # instead, defer an action, which will be handled by the TLC site
134
- log "Sheduling restart of TLC", level: :info
135
- @node.defer :restart
136
- end
137
-
138
- def handle_m0005 arg
139
- @node.verify_security_code 2, arg['securityCode']
140
- @emergency_route = (arg['status'] == 'True')
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
148
- end
149
-
150
- def handle_m0006 arg
151
- @node.verify_security_code 2, arg['securityCode']
152
- input = arg['input'].to_i
153
- idx = input - 1
154
- return unless idx>=0 && input<@num_inputs # TODO should NotAck
155
- @input_activations[idx] = (arg['status']=='True' ? '1' : '0')
156
- result = @input_activations[idx]=='1' || @inputs[idx]=='1'
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
163
- end
164
-
165
- def handle_m0007 arg
166
- @node.verify_security_code 2, arg['securityCode']
167
- set_fixed_time_control arg['status']
168
- end
169
-
170
- def handle_m0012 arg
171
- @node.verify_security_code 2, arg['securityCode']
172
- end
173
-
174
- def handle_m0013 arg
175
- @node.verify_security_code 2, arg['securityCode']
176
- end
177
-
178
- def handle_m0014 arg
179
- @node.verify_security_code 2, arg['securityCode']
180
- end
181
-
182
- def handle_m0015 arg
183
- @node.verify_security_code 2, arg['securityCode']
184
- end
185
-
186
- def handle_m0016 arg
187
- @node.verify_security_code 2, arg['securityCode']
188
- end
189
-
190
- def handle_m0017 arg
191
- @node.verify_security_code 2, arg['securityCode']
192
- end
193
-
194
- def handle_m0018 arg
195
- @node.verify_security_code 2, arg['securityCode']
196
- end
197
-
198
- def handle_m0019 arg
199
- @node.verify_security_code 2, arg['securityCode']
200
- end
201
-
202
- def handle_m0020 arg
203
- @node.verify_security_code 2, arg['securityCode']
204
- end
205
-
206
- def handle_m0021 arg
207
- @node.verify_security_code 2, arg['securityCode']
208
- end
209
-
210
- def handle_m0103 arg
211
- level = {'Level1'=>1,'Level2'=>2}[arg['status']]
212
- @node.change_security_code level, arg['oldSecurityCode'], arg['newSecurityCode']
213
- end
214
-
215
- def handle_m0104 arg
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
228
- end
229
-
230
- def set_input i, value
231
- return unless i>=0 && i<@num_inputs
232
- @inputs[i] = (arg['value'] ? '1' : '0')
233
- end
234
-
235
- def set_fixed_time_control status
236
- @fixed_time_control = status
237
- end
238
-
239
- def switch_plan plan
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
247
- end
248
-
249
- def switch_mode mode
250
- log "Switching to mode #{mode}", level: :info
251
- case mode
252
- when 'NormalControl'
253
- @yellow_flash = false
254
- @dark_mode = false
255
- when 'YellowFlash'
256
- @yellow_flash = true
257
- @dark_mode = false
258
- when 'Dark'
259
- @yellow_flash = false
260
- @dark_mode = true
261
- end
262
- mode
263
- end
264
-
265
- def get_status code, name=nil
266
- case code
267
- when 'S0001', 'S0002', 'S0003', 'S0004', 'S0005', 'S0006', 'S0007',
268
- 'S0008', 'S0009', 'S0010', 'S0011', 'S0012', 'S0013', 'S0014',
269
- 'S0015', 'S0016', 'S0017', 'S0018', 'S0019', 'S0020', 'S0021',
270
- 'S0022', 'S0023', 'S0024', 'S0026', 'S0027', 'S0028',
271
- 'S0029', 'S0030', 'S0031',
272
- 'S0091', 'S0092', 'S0095', 'S0096', 'S0097',
273
- 'S0205', 'S0206', 'S0207', 'S0208'
274
- return send("handle_#{code.downcase}", code, name)
275
- else
276
- raise InvalidMessage.new "unknown status code #{code}"
277
- end
278
- end
279
-
280
- def handle_s0001 status_code, status_name=nil
281
- case status_name
282
- when 'signalgroupstatus'
283
- RSMP::Tlc.make_status format_signal_group_status
284
- when 'cyclecounter'
285
- RSMP::Tlc.make_status @pos.to_s
286
- when 'basecyclecounter'
287
- RSMP::Tlc.make_status @pos.to_s
288
- when 'stage'
289
- RSMP::Tlc.make_status 0.to_s
290
- end
291
- end
292
-
293
- def handle_s0002 status_code, status_name=nil
294
- case status_name
295
- when 'detectorlogicstatus'
296
- RSMP::Tlc.make_status @detector_logics.map { |dl| dl.value ? '1' : '0' }.join
297
- end
298
- end
299
-
300
- def handle_s0003 status_code, status_name=nil
301
- case status_name
302
- when 'inputstatus'
303
- RSMP::Tlc.make_status @input_results
304
- when 'extendedinputstatus'
305
- RSMP::Tlc.make_status 0.to_s
306
- end
307
- end
308
-
309
- def handle_s0004 status_code, status_name=nil
310
- case status_name
311
- when 'outputstatus'
312
- RSMP::Tlc.make_status 0
313
- when 'extendedoutputstatus'
314
- RSMP::Tlc.make_status 0
315
- end
316
- end
317
-
318
- def handle_s0005 status_code, status_name=nil
319
- case status_name
320
- when 'status'
321
- RSMP::Tlc.make_status @is_starting
322
- end
323
- end
324
-
325
- def handle_s0006 status_code, status_name=nil
326
- case status_name
327
- when 'status'
328
- RSMP::Tlc.make_status @emergency_route
329
- when 'emergencystage'
330
- RSMP::Tlc.make_status @emergency_route_number
331
- end
332
- end
333
-
334
- def handle_s0007 status_code, status_name=nil
335
- case status_name
336
- when 'intersection'
337
- RSMP::Tlc.make_status @intersection
338
- when 'status'
339
- RSMP::Tlc.make_status !@dark_mode
340
- end
341
- end
342
-
343
- def handle_s0008 status_code, status_name=nil
344
- case status_name
345
- when 'intersection'
346
- RSMP::Tlc.make_status @intersection
347
- when 'status'
348
- RSMP::Tlc.make_status @manual_control
349
- end
350
- end
351
-
352
- def handle_s0009 status_code, status_name=nil
353
- case status_name
354
- when 'intersection'
355
- RSMP::Tlc.make_status @intersection
356
- when 'status'
357
- RSMP::Tlc.make_status @fixed_time_control
358
- end
359
- end
360
-
361
- def handle_s0010 status_code, status_name=nil
362
- case status_name
363
- when 'intersection'
364
- RSMP::Tlc.make_status @intersection
365
- when 'status'
366
- RSMP::Tlc.make_status @isolated_control
367
- end
368
- end
369
-
370
- def handle_s0011 status_code, status_name=nil
371
- case status_name
372
- when 'intersection'
373
- RSMP::Tlc.make_status @intersection
374
- when 'status'
375
- RSMP::Tlc.make_status @yellow_flash
376
- end
377
- end
378
-
379
- def handle_s0012 status_code, status_name=nil
380
- case status_name
381
- when 'intersection'
382
- RSMP::Tlc.make_status @intersection
383
- when 'status'
384
- RSMP::Tlc.make_status @all_red
385
- end
386
- end
387
-
388
- def handle_s0013 status_code, status_name=nil
389
- case status_name
390
- when 'intersection'
391
- RSMP::Tlc.make_status @intersection
392
- when 'status'
393
- RSMP::Tlc.make_status @police_key
394
- end
395
- end
396
-
397
- def handle_s0014 status_code, status_name=nil
398
- case status_name
399
- when 'status'
400
- RSMP::Tlc.make_status @plan
401
- end
402
- end
403
-
404
- def handle_s0015 status_code, status_name=nil
405
- case status_name
406
- when 'status'
407
- RSMP::Tlc.make_status @traffic_situation
408
- end
409
- end
410
-
411
- def handle_s0016 status_code, status_name=nil
412
- case status_name
413
- when 'number'
414
- RSMP::Tlc.make_status @detector_logics.size
415
- end
416
- end
417
-
418
- def handle_s0017 status_code, status_name=nil
419
- case status_name
420
- when 'number'
421
- RSMP::Tlc.make_status @signal_groups.size
422
- end
423
- end
424
-
425
- def handle_s0018 status_code, status_name=nil
426
- case status_name
427
- when 'number'
428
- RSMP::Tlc.make_status @plans.size
429
- end
430
- end
431
-
432
- def handle_s0019 status_code, status_name=nil
433
- case status_name
434
- when 'number'
435
- RSMP::Tlc.make_status @num_traffic_situations
436
- end
437
- end
438
-
439
- def handle_s0020 status_code, status_name=nil
440
- case status_name
441
- when 'intersection'
442
- RSMP::Tlc.make_status @intersection
443
- when 'controlmode'
444
- RSMP::Tlc.make_status @control_mode
445
- end
446
- end
447
-
448
- def handle_s0021 status_code, status_name=nil
449
- case status_name
450
- when 'detectorlogics'
451
- RSMP::Tlc.make_status @detector_logics.map { |logic| logic.forced=='True' ? '1' : '0'}.join
452
- end
453
- end
454
-
455
- def handle_s0022 status_code, status_name=nil
456
- case status_name
457
- when 'status'
458
- RSMP::Tlc.make_status '1'
459
- end
460
- end
461
-
462
- def handle_s0023 status_code, status_name=nil
463
- case status_name
464
- when 'status'
465
- RSMP::Tlc.make_status '1-1-0'
466
- end
467
- end
468
-
469
- def handle_s0024 status_code, status_name=nil
470
- case status_name
471
- when 'status'
472
- RSMP::Tlc.make_status '1-0'
473
- end
474
- end
475
-
476
- def handle_s0026 status_code, status_name=nil
477
- case status_name
478
- when 'status'
479
- RSMP::Tlc.make_status '0-00'
480
- end
481
- end
482
-
483
- def handle_s0027 status_code, status_name=nil
484
- case status_name
485
- when 'status'
486
- RSMP::Tlc.make_status '00-00-00-00'
487
- end
488
- end
489
-
490
- def handle_s0028 status_code, status_name=nil
491
- case status_name
492
- when 'status'
493
- RSMP::Tlc.make_status '00-00'
494
- end
495
- end
496
-
497
- def handle_s0029 status_code, status_name=nil
498
- case status_name
499
- when 'status'
500
- RSMP::Tlc.make_status ''
501
- end
502
- end
503
-
504
- def handle_s0030 status_code, status_name=nil
505
- case status_name
506
- when 'status'
507
- RSMP::Tlc.make_status ''
508
- end
509
- end
510
-
511
- def handle_s0031 status_code, status_name=nil
512
- case status_name
513
- when 'status'
514
- RSMP::Tlc.make_status ''
515
- end
516
- end
517
-
518
- def handle_s0091 status_code, status_name=nil
519
- case status_name
520
- when 'user'
521
- RSMP::Tlc.make_status 'nobody'
522
- when 'status'
523
- RSMP::Tlc.make_status 'logout'
524
- end
525
- end
526
-
527
- def handle_s0092 status_code, status_name=nil
528
- case status_name
529
- when 'user'
530
- RSMP::Tlc.make_status 'nobody'
531
- when 'status'
532
- RSMP::Tlc.make_status 'logout'
533
- end
534
- end
535
-
536
- def handle_s0095 status_code, status_name=nil
537
- case status_name
538
- when 'status'
539
- RSMP::Tlc.make_status RSMP::VERSION
540
- end
541
- end
542
-
543
- def handle_s0096 status_code, status_name=nil
544
- now = clock.now
545
- case status_name
546
- when 'year'
547
- RSMP::Tlc.make_status now.year.to_s.rjust(4, "0")
548
- when 'month'
549
- RSMP::Tlc.make_status now.month.to_s.rjust(2, "0")
550
- when 'day'
551
- RSMP::Tlc.make_status now.day.to_s.rjust(2, "0")
552
- when 'hour'
553
- RSMP::Tlc.make_status now.hour.to_s.rjust(2, "0")
554
- when 'minute'
555
- RSMP::Tlc.make_status now.min.to_s.rjust(2, "0")
556
- when 'second'
557
- RSMP::Tlc.make_status now.sec.to_s.rjust(2, "0")
558
- end
559
- end
560
-
561
- def handle_s0097 status_code, status_name=nil
562
- case status_name
563
- when 'checksum'
564
- RSMP::Tlc.make_status '1'
565
- when 'timestamp'
566
- now = @node.clock.to_s
567
- RSMP::Tlc.make_status now
568
- end
569
- end
570
-
571
- def handle_s0205 status_code, status_name=nil
572
- case status_name
573
- when 'start'
574
- RSMP::Tlc.make_status clock.to_s
575
- when 'vehicles'
576
- RSMP::Tlc.make_status 0
577
- end
578
- end
579
-
580
- def handle_s0206 status_code, status_name=nil
581
- case status_name
582
- when 'start'
583
- RSMP::Tlc.make_status clock.to_s
584
- when 'speed'
585
- RSMP::Tlc.make_status 0
586
- end
587
- end
588
-
589
- def handle_s0207 status_code, status_name=nil
590
- case status_name
591
- when 'start'
592
- RSMP::Tlc.make_status clock.to_s
593
- when 'occupancy'
594
- RSMP::Tlc.make_status 0
595
- end
596
- end
597
-
598
- def handle_s0208 status_code, status_name=nil
599
- case status_name
600
- when 'start'
601
- RSMP::Tlc.make_status clock.to_s
602
- when 'P'
603
- RSMP::Tlc.make_status 0
604
- when 'PS'
605
- RSMP::Tlc.make_status 0
606
- when 'L'
607
- RSMP::Tlc.make_status 0
608
- when 'LS'
609
- RSMP::Tlc.make_status 0
610
- when 'B'
611
- RSMP::Tlc.make_status 0
612
- when 'SP'
613
- RSMP::Tlc.make_status 0
614
- when 'MC'
615
- RSMP::Tlc.make_status 0
616
- when 'C'
617
- RSMP::Tlc.make_status 0
618
- when 'F'
619
- RSMP::Tlc.make_status 0
620
- end
621
- end
622
-
623
- end
624
-
625
- class SignalGroup < Component
626
- attr_reader :plan, :state
627
-
628
- # plan is a string, with each character representing a signal phase at a particular second in the cycle
629
- def initialize node:, id:, plan: nil
630
- super node: node, id: id, grouped: false
631
- @plan = plan
632
- move 0
633
- end
634
-
635
- def get_state pos
636
- return 'a' unless @plan # if no plan, use phase a, which means disabled/dark
637
- if pos > @plan.length
638
- '.'
639
- else
640
- @plan[pos]
641
- end
642
- end
643
-
644
- def move pos
645
- @state = get_state pos
646
- end
647
-
648
- def handle_command command_code, arg
649
- case command_code
650
- when 'M0010', 'M0011'
651
- return send("handle_#{command_code.downcase}", arg)
652
- else
653
- raise UnknownCommand.new "Unknown command #{command_code}"
654
- end
655
- end
656
-
657
- # Start of signal group. Orders a signal group to green
658
- def handle_m0010 arg
659
- @node.verify_security_code 2, arg['securityCode']
660
- if RSMP::Tlc.from_rsmp_bool arg['status']
661
- log "Start signal group #{c_id}, go to green", level: :info
662
- end
663
- end
664
-
665
- # Stop of signal group. Orders a signal group to red
666
- def handle_m0011 arg
667
- @node.verify_security_code 2, arg['securityCode']
668
- if RSMP::Tlc.from_rsmp_bool arg['status']
669
- log "Stop signal group #{c_id}, go to red", level: :info
670
- end
671
- end
672
-
673
- def get_status code, name=nil
674
- case code
675
- when 'S0025'
676
- return send("handle_#{code.downcase}", code, name)
677
- else
678
- raise InvalidMessage.new "unknown status code #{code}"
679
- end
680
- end
681
-
682
- def handle_s0025 status_code, status_name=nil
683
- now = @node.clock.to_s
684
- case status_name
685
- when 'minToGEstimate'
686
- RSMP::Tlc.make_status now
687
- when 'maxToGEstimate'
688
- RSMP::Tlc.make_status now
689
- when 'likelyToGEstimate'
690
- RSMP::Tlc.make_status now
691
- when 'ToGConfidence'
692
- RSMP::Tlc.make_status 0
693
- when 'minToREstimate'
694
- RSMP::Tlc.make_status now
695
- when 'maxToREstimate'
696
- RSMP::Tlc.make_status now
697
- when 'likelyToREstimate'
698
- RSMP::Tlc.make_status now
699
- when 'ToRConfidence'
700
- RSMP::Tlc.make_status 0
701
- end
702
- end
703
- end
704
-
705
- class DetectorLogic < Component
706
- attr_reader :forced, :value
707
-
708
- def initialize node:, id:
709
- super node: node, id: id, grouped: false
710
- @forced = 0
711
- @value = 0
712
- end
713
-
714
- def get_status code, name=nil
715
- case code
716
- when 'S0201', 'S0202', 'S0203', 'S0204'
717
- return send("handle_#{code.downcase}", code, name)
718
- else
719
- raise InvalidMessage.new "unknown status code #{code}"
720
- end
721
- end
722
-
723
- def handle_s0201 status_code, status_name=nil
724
- case status_name
725
- when 'starttime'
726
- RSMP::Tlc.make_status @node.clock.to_s
727
- when 'vehicles'
728
- RSMP::Tlc.make_status 0
729
- end
730
- end
731
-
732
- def handle_s0202 status_code, status_name=nil
733
- case status_name
734
- when 'starttime'
735
- RSMP::Tlc.make_status @node.clock.to_s
736
- when 'speed'
737
- RSMP::Tlc.make_status 0
738
- end
739
- end
740
-
741
- def handle_s0203 status_code, status_name=nil
742
- case status_name
743
- when 'starttime'
744
- RSMP::Tlc.make_status @node.clock.to_s
745
- when 'occupancy'
746
- RSMP::Tlc.make_status 0
747
- end
748
- end
749
-
750
- def handle_s0204 status_code, status_name=nil
751
- case status_name
752
- when 'starttime'
753
- RSMP::Tlc.make_status @node.clock.to_s
754
- when 'P'
755
- RSMP::Tlc.make_status 0
756
- when 'PS'
757
- RSMP::Tlc.make_status 0
758
- when 'L'
759
- RSMP::Tlc.make_status 0
760
- when 'LS'
761
- RSMP::Tlc.make_status 0
762
- when 'B'
763
- RSMP::Tlc.make_status 0
764
- when 'SP'
765
- RSMP::Tlc.make_status 0
766
- when 'MC'
767
- RSMP::Tlc.make_status 0
768
- when 'C'
769
- RSMP::Tlc.make_status 0
770
- when 'F'
771
- RSMP::Tlc.make_status 0
772
- end
773
- end
774
-
775
- def handle_command command_code, arg
776
- case command_code
777
- when 'M0008'
778
- handle_m0008 arg
779
- else
780
- raise UnknownCommand.new "Unknown command #{command_code}"
781
- end
782
- end
783
-
784
- def handle_m0008 arg
785
- @node.verify_security_code 2, arg['securityCode']
786
- status = arg['status']=='True'
787
- mode = arg['mode']=='True'
788
- force_detector_logic status, mode
789
- arg
790
- end
791
-
792
- def force_detector_logic forced, value
793
- @forced = forced
794
- @value = value
795
- if @forced
796
- log "Forcing to #{value}", level: :info
797
- else
798
- log "Releasing", level: :info
799
- end
800
- end
801
-
802
- end
803
-
804
- class Tlc < Site
805
- attr_accessor :main
806
- def initialize options={}
807
- super options
808
- @sxl = 'traffic_light_controller'
809
- @security_codes = options[:site_settings]['security_codes']
810
- @interval = options[:site_settings].dig('intervals','timer') || 1
811
- unless @main
812
- raise ConfigurationError.new "TLC must have a main component"
813
- end
814
- end
815
-
816
- def build_component id:, type:, settings:{}
817
- component = case type
818
- when 'main'
819
- @main = TrafficController.new node: self, id: id, cycle_time: settings['cycle_time']
820
- when 'signal_group'
821
- group = SignalGroup.new node: self, id: id, plan: settings['plan']
822
- @main.add_signal_group group
823
- group
824
- when 'detector_logic'
825
- logic = DetectorLogic.new node: self, id: id
826
- @main.add_detector_logic logic
827
- logic
828
- end
829
- end
830
-
831
- def start_action
832
- super
833
- start_timer
834
- end
835
-
836
- def start_timer
837
- task_name = "tlc timer"
838
- log "Starting #{task_name} with interval #{@interval} seconds", level: :debug
839
-
840
- @timer = @task.async do |task|
841
- task.annotate task_name
842
- next_time = Time.now.to_f
843
- loop do
844
- begin
845
- timer(@clock.now)
846
- rescue EOFError => e
847
- log "Connection closed: #{e}", level: :warning
848
- rescue IOError => e
849
- log "IOError", level: :warning
850
- rescue Errno::ECONNRESET
851
- log "Connection reset by peer", level: :warning
852
- rescue Errno::EPIPE => e
853
- log "Broken pipe", level: :warning
854
- rescue StandardError => e
855
- notify_error e, level: :internal
856
- ensure
857
- # adjust sleep duration to avoid drift. so wake up always happens on the
858
- # same fractional second.
859
- # note that Time.now is not monotonic. If the clock is changed,
860
- # either manaully or via NTP, the sleep interval might jump.
861
- # an alternative is to use ::Process.clock_gettime(::Process::CLOCK_MONOTONIC),
862
- # to get the current time. this ensures a constant interval, but
863
- # if the clock is changed, the wake up would then happen on a different
864
- # fractional second
865
- next_time += @interval
866
- duration = next_time - Time.now.to_f
867
- task.sleep duration
868
- end
869
- end
870
- end
871
- end
872
-
873
- def timer now
874
- return unless @main
875
- @main.timer now
876
- end
877
-
878
- def verify_security_code level, code
879
- raise ArgumentError.new("Level must be 1-2, got #{level}") unless (1..2).include?(level)
880
- if @security_codes[level] != code
881
- raise MessageRejected.new("Wrong security code for level #{level}")
882
- end
883
- end
884
-
885
- def change_security_code level, old_code, new_code
886
- verify_security_code level, old_code
887
- @security_codes[level] = new_code
888
- end
889
-
890
- def self.to_rmsp_bool bool
891
- if bool
892
- 'True'
893
- else
894
- 'False'
895
- end
896
- end
897
-
898
- def self.from_rsmp_bool str
899
- str == 'True'
900
- end
901
-
902
- def self.make_status value, q='recent'
903
- case value
904
- when true, false
905
- return to_rmsp_bool(value), q
906
- else
907
- return value, q
908
- end
909
- end
910
-
911
- def do_deferred item
912
- case item
913
- when :restart
914
- log "Restarting TLC", level: :info
915
- restart
916
- end
917
- end
918
-
919
- end
920
- end