1 #*****************************************************************************
5 # Object Name : $RCSfile$
6 # Revision : $Revision$
9 # Created By : Robert Heller
10 # Created : Sat Aug 1 09:57:53 2015
11 # Last Modified : <150801.1029>
19 #*****************************************************************************
21 # Copyright (C) 2015 Robert Heller D/B/A Deepwoods Software
23 # Wendell, MA 01379-9728
25 # This program is free software; you can redistribute it and/or modify
26 # it under the terms of the GNU General Public License as published by
27 # the Free Software Foundation; either version 2 of the License, or
28 # (at your option) any later version.
30 # This program is distributed in the hope that it will be useful,
31 # but WITHOUT ANY WARRANTY; without even the implied warranty of
32 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 # GNU General Public License for more details.
35 # You should have received a copy of the GNU General Public License
36 # along with this program; if not, write to the Free Software
37 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
41 #*****************************************************************************
44 package require CTIAcela;# require the CTIAcela
package
45 package require snit;# require the SNIT OO framework
49 # @brief Block occupation detection using Circuits4Tracks Quad Occupancy Detector and a CTI Train Brain
51 # @image html C4TTB_Block-thumb.png
52 # @image latex C4TTB_Block.png "Block detection with a Circuits4Tracks Quad Occupancy Detector and a Train Brain" width=5in
54 # Above is a simple diagram for using Circuits4Tracks Quad Occupancy
55 # Occupancy board has four current sensors. One wires one side of the
56 # track power (either DCC or DC) to a common rail and the other side
57 # through the Circuits4Tracks Quad Occupancy Detector to rails isolated
58 # with gaps (possibly with insulating rail joiners). This code uses
59 # a CTI Train Brain to connect a Circuits4Tracks Quad Occupancy Detectors
60 # to the computer via a CTI Acela computer interface.
65 # Four blocks in a loop:
68 # # Connect to the CTI Acela via USB the serial interface at /dev/ttyACM0
69 # ctiacela::CTIAcela acela /dev/ttyACM0
70 # # The first four bits of the first Train Brain are wired to the Circuits4Tracks
71 # # Quad Occupancy Detector
72 # C4TTB_Block block1 -acelaobj acela -address 0 -signalobj signal1
73 # C4TTB_Block block2 -acelaobj acela -address 1 -signalobj signal2 -previousblock block1
74 # C4TTB_Block block3 -acelaobj acela -address 2 -signalobj signal3 -previousblock block2
75 # C4TTB_Block block4 -acelaobj acela -address 3 -signalobj signal4 -previousblock block3
76 # block1 configure -previousblock block4
78 # A Schematic of the layout would look like this:
79 # @image html 4circleblocks.png
80 # @image latex 4circleblocks.png "Four block circle" width=3in
81 # For the track work elements use "blockN occupiedp" for the track work
82 # elements' occupied command:
83 # eg Block1 would have 'block1 occupiedp' as its occupied command, that is
84 # its edit window would look like:
85 # @image html EditingBlock1.png
86 # @image latex EditingBlock1.png "Editing Block1" width=5in
87 # The other three blocks would be similar.
90 # Then in the Main Loop, you would have:
93 # MainWindow ctcpanel invoke Block1
94 # MainWindow ctcpanel invoke Block2
95 # MainWindow ctcpanel invoke Block3
96 # MainWindow ctcpanel invoke Block4
97 # update;# Update display
101 # @author Robert Heller \<heller\@deepsoft.com\>
104 option -acelaobj -readonly yes -
default {} -type ::ctiacela::CTIAcela
105 option -address -readonly yes -
default 0 -type ::ctiacela::addresstype
106 option -forwardsignalobj -readonly yes -
default {}
107 option -reversesignalobj -readonly yes -
default {}
108 option -previousblock -type
C4TTB_Block -
default {}
110 option -direction -type {snit::enum -values {forward reverse}} -
default forward
111 typemethod validate {
object} {
112 ## Type validating code
113 # Raises an error if object is not either the empty string or a C4TTB_Block
117 return $object;# Empty or
null objects are OK
118 } elseif {[
catch {$object info type} itstype]} {
119 error
"$object is not a $type";#
object is not a SNIT type
120 } elseif {$itstype eq $type} {
121 return $object;# Object is of our type (Block)
123 error
"$object is not a $type";#
object is something
else
127 ## @private Acela object
128 component forwardsignal
129 ## @private Signal object (typically a three color, one head block signal
130 component reversesignal
131 ## @private Signal object (typically a three color, one head block signal
132 variable isoccupied no
133 ## @private Saved occupation state.
136 ## @brief Constructor: initialize the block object.
138 # Install an CTIAcela object as a component created elsewhere).
139 # Install the blocks signal (created elsewhere).
141 # @param name Name of the block object
142 # @param ... Options:
143 # @arg -acelaobj This is the CTIAcela object.
144 # This option is read-only and must be set at creation time.
145 # @arg -address The address of the sensor bit for this block.
146 # This is an integer from 0 to 65535 inclusive. This option is
147 # read-only and can only be set at creation time. The default is 0.
148 # @arg -forwardsignalobj This block's forward signal. This option is
149 # read-only and can only be set at creation time. The default is the
151 # @arg -reversesignalobj This block's reverse signal. This option is
152 # read-only and can only be set at creation time. The default is the
154 # @arg -previousblock Previous block (next block in reverse) -- used
155 # for 'propagating' signal aspects and must be a C4TTB_Block type
156 # object. The default is the empty string.
157 # @arg -nextblock Next block (previous block in reverse) -- used for
158 # 'propagating' signal aspects and must be a C4TTB_Block type object.
159 # The default is the empty string.
160 # @arg -direction Current running direction, either the word forward
161 # or reverse. The default is forward.
164 ## Process any options
165 $self configurelist $args
166 set acela [$self cget -acelaobj]
168 error
"The -acelaobj is required!"
170 # Install the signal component.
171 set forwardsignal [$self cget -forwardsignalobj]
172 set reversesignal [$self cget -reversesignalobj]
174 method occupiedp {} {
175 ## The occupiedp method returns yes or no (true or false) indicating
178 # First read the current sensor state.
179 set bit [$acela Read [$self cget -address]]
182 # Already entered the block.
185 # Just entered the block
192 # Just left the block
197 # Block still unoccupied
202 method _entering {} {
203 ## @privatesection Method for entering a block.
205 if {[$self cget -direction] eq
"forward"} {
206 # Set a red (stop and proceed) aspect.
207 if {$forwardsignal ne
""} {$forwardsignal setaspect red}
208 # Now propagate the signal to the previous block (if any)
209 if {$options(-previousblock) ne {}} {
210 # Set a yellow (approach) aspect on the previous block.
211 $options(-previousblock) propagate yellow $self -direction forward
214 if {$reversesignal ne
""} {$reversesignal setaspect red}
215 # Now propagate the signal to the previous block (if any)
216 if {$options(-nextblock) ne {}} {
217 # Set a yellow (approach) aspect on the previous block.
218 $options(-nextblock) propagate yellow $self -direction reverse
223 ## Method for exiting a block.
225 # Nothing here -- could be used for any sort of exit handling.
227 method propagate {aspect from args} {
228 ## @publicsection Method used to propagate distant signal states back down the line.
229 # @param aspect The signal aspect that is being propagated.
230 # @param from The propagating block (not used).
231 # @param ... Options:
232 # @arg -direction The direction of the propagation.
234 ## First process any options
235 $self configurelist $args
236 ## If we are already occupiedp, don't do anything else.
237 if {[$self occupiedp]} {
return}
238 if {[$self cget -direction] eq
"forward"} {
240 if {$forwardsignal ne
""} {$forwardsignal setaspect $aspect}
241 # If the new aspect was yellow, propagate a green (clear) signal
242 if {$aspect eq
"yellow"} {
243 if {$options(-previousblock) ne {}} {
244 $options(-previousblock) propagate green $self -direction forward
249 if {$reversesignal ne
""} {$reversesignal setaspect $aspect}
250 # If the new aspect was yellow, propagate a green (clear) signal
251 if {$aspect eq
"yellow"} {
252 if {$options(-nextblock) ne {}} {
253 $options(-nextblock) propagate green $self -direction reverse
260 package provide C4TTB_Block 1.0