Model Railroad System  2.2.2
C4TTB_Block.tcl
1 #*****************************************************************************
2 #
3 # System :
4 # Module :
5 # Object Name : $RCSfile$
6 # Revision : $Revision$
7 # Date : $Date$
8 # Author : $Author$
9 # Created By : Robert Heller
10 # Created : Sat Aug 1 09:57:53 2015
11 # Last Modified : <150801.1029>
12 #
13 # Description
14 #
15 # Notes
16 #
17 # History
18 #
19 #*****************************************************************************
20 #
21 # Copyright (C) 2015 Robert Heller D/B/A Deepwoods Software
22 # 51 Locke Hill Road
23 # Wendell, MA 01379-9728
24 #
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.
29 #
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.
34 #
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.
38 #
39 #
40 #
41 #*****************************************************************************
42 
43 
44 package require CTIAcela;# require the CTIAcela package
45 package require snit;# require the SNIT OO framework
46 
47 snit::type C4TTB_Block {
48  ##
49  # @brief Block occupation detection using Circuits4Tracks Quad Occupancy Detector and a CTI Train Brain
50  #
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
53  #
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.
61  #
62  #
63  # Typical usage:
64  #
65  # Four blocks in a loop:
66  #
67  # @code
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
77  # @endcode
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.
88  #
89  #
90  # Then in the Main Loop, you would have:
91  # @code
92  # while {true} {
93  # MainWindow ctcpanel invoke Block1
94  # MainWindow ctcpanel invoke Block2
95  # MainWindow ctcpanel invoke Block3
96  # MainWindow ctcpanel invoke Block4
97  # update;# Update display
98  # }
99  # @endcode
100  #
101  # @author Robert Heller \<heller\@deepsoft.com\>
102 
103 
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 {}
109  option -nextblock -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
114  # type.
115 
116  if {$object eq ""} {
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)
122  } else {
123  error "$object is not a $type";# object is something else
124  }
125  }
126  component acela
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.
134 
135  constructor {args} {
136  ## @brief Constructor: initialize the block object.
137  #
138  # Install an CTIAcela object as a component created elsewhere).
139  # Install the blocks signal (created elsewhere).
140  #
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
150  # empty string.
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
153  # empty string.
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.
162  # @par
163 
164  ## Process any options
165  $self configurelist $args
166  set acela [$self cget -acelaobj]
167  if {$acela eq {}} {
168  error "The -acelaobj is required!"
169  }
170  # Install the signal component.
171  set forwardsignal [$self cget -forwardsignalobj]
172  set reversesignal [$self cget -reversesignalobj]
173  }
174  method occupiedp {} {
175  ## The occupiedp method returns yes or no (true or false) indicating
176  # block occupation.
177 
178  # First read the current sensor state.
179  set bit [$acela Read [$self cget -address]]
180  if {$bit == 1} {
181  if {$isoccupied} {
182  # Already entered the block.
183  return $isoccupied
184  } else {
185  # Just entered the block
186  set isoccupied yes
187  $self _entering
188  return $isoccupied
189  }
190  } else {
191  if {$isoccupied} {
192  # Just left the block
193  set isoccupied no
194  $self _exiting
195  return $isoccupied
196  } else {
197  # Block still unoccupied
198  return $isoccupied
199  }
200  }
201  }
202  method _entering {} {
203  ## @privatesection Method for entering a block.
204 
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
212  }
213  } else {
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
219  }
220  }
221  }
222  method _exiting {} {
223  ## Method for exiting a block.
224 
225  # Nothing here -- could be used for any sort of exit handling.
226  }
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.
233 
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"} {
239  # Set signal aspect
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
245  }
246  }
247  } else {
248  # Set signal aspect
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
254  }
255  }
256  }
257  }
258 }
259 
260 package provide C4TTB_Block 1.0
261 
Block occupation detection using Circuits4Tracks Quad Occupancy Detector and a CTI Train Brain.
Definition: C4TTB_Block.tcl:59