Model Railroad System  2.2.1
C4TSMINI_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 : Mon Jul 13 12:42:15 2015
11 # Last Modified : <150820.1252>
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 package require CmriSupport;# require the Cmri Support package
44 package require snit;# require the SNIT OO framework
45 
46 snit::type C4TSMINI_Block {
47  ##
48  # @brief Block occupation detection using Circuits4Tracks Quad Occupancy Detectors and Azatrax SR4s
49  #
50  # @image html C4TSMINI_Block-thumb.png
51  # @image latex C4TSMINI_Block.png "Block detection with a Circuits4Tracks Quad Occupancy Detector and a Chubb SMINI card" width=5in
52  #
53  # Above is a simple diagram for using Circuits4Tracks Quad Occupancy
54  # Detectors for block occupation detection. A Circuits4Tracks Quad
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 Chubb SMINI board to connect a Circuits4Tracks Quad Occupancy Detectors
60  # to the computer via a serial interface.
61  #
62  # Typical usage:
63  #
64  #
65  # Four blocks in a loop:
66  #
67  # @code
68  # # Connect to the cmribus through a USB RS485 adapter at /dev/ttyUSB0
69  # CmriSupport::CmriNode openport /dev/ttyUSB0
70  # # SMINI board at address 0
71  # CmriSupport::CmriNode SMINI0 -type SMINI -address 0
72  # # The first four bits of the first port are wired to the Circuits4Tracks
73  # # Quad Occupancy Detector
74  # C4TSR4_Block block1 -nodeobj SMINI0 -port 0 -bit 0 -signalobj signal1
75  # C4TSR4_Block block2 -nodeobj SMINI0 -port 0 -bit 1 -signalobj signal2 -previousblock block1
76  # C4TSR4_Block block3 -nodeobj SMINI0 -port 0 -bit 2 -signalobj signal3 -previousblock block2
77  # C4TSR4_Block block4 -nodeobj SMINI0 -port 0 -bit 3 -signalobj signal4 -previousblock block3
78  # block1 configure -previousblock block4
79  # @endcode
80  # A Schematic of the layout would look like this:
81  # @image html 4circleblocks.png
82  # @image latex 4circleblocks.png "Four block circle" width=3in
83  # For the track work elements use "blockN occupiedp" for the track work
84  # elements' occupied command:
85  # eg Block1 would have 'block1 occupiedp' as its occupied command, that is
86  # its edit window would look like:
87  # @image html EditingBlock1.png
88  # @image latex EditingBlock1.png "Editing Block1" width=5in
89  # The other three blocks would be similar.
90  #
91  #
92  # Then in the Main Loop, you would have:
93  # @code
94  # while {true} {
95  # MainWindow ctcpanel invoke Block1
96  # MainWindow ctcpanel invoke Block2
97  # MainWindow ctcpanel invoke Block3
98  # MainWindow ctcpanel invoke Block4
99  # update;# Update display
100  # }
101  # @endcode
102  #
103  # @author Robert Heller \<heller\@deepsoft.com\>
104 
105  option -nodeobj -readonly yes -default {} -type ::CmriSupport::CmriNode
106  option -port -readonly yes -default 0 -type {snit::integer -min 0}
107  option -bit -readonly yes -default 0 -type {snit::integer -min 0 -max 7}
108  option -forwardsignalobj -readonly yes -default {}
109  option -reversesignalobj -readonly yes -default {}
110  option -previousblock -type C4TSMINI_Block -default {}
111  option -nextblock -type C4TSMINI_Block -default {}
112  option -direction -type {snit::enum -values {forward reverse}} -default forward
113  typemethod validate {object} {
114  ## Type validating code
115  # Raises an error if object is not either the empty string or a C4TSMINI_Block
116  # type.
117 
118  if {$object eq ""} {
119  return $object;# Empty or null objects are OK
120  } elseif {[catch {$object info type} itstype]} {
121  error "$object is not a $type";# object is not a SNIT type
122  } elseif {$itstype eq $type} {
123  return $object;# Object is of our type (Block)
124  } else {
125  error "$object is not a $type";# object is something else
126  }
127  }
128  component node
129  ## @privatesection SMINI node object
130  component forwardsignal
131  ## Signal object (typically a three color, one head block signal
132  component reversesignal
133  ## Signal object (typically a three color, one head block signal
134  variable isoccupied no
135  ## Saved occupation state.
136 
137 
138  constructor {args} {
139  ## @publicsection @brief Constructor: initialize the block object.
140  #
141  # Create a lowlevel node object and install it as a component.
142  # Install the blocks signal (created elsewhere).
143  #
144  # @param name Name of the block object
145  # @param ... Options:
146  # @arg -nodeobj This is the Cmri node for this block. This is a
147  # CmriNode object, defined in the Control Support package. This option
148  # is read-only and must be set at creation time.
149  # @arg -port The input port on the Cmri node. This is an integer
150  # greater or equal to 0. This option is read-only and can only be
151  # set at creation time. The default is 0.
152  # @arg -bit This defines the input bit on the input port for this
153  # block. This is an integer from 0 to 7 inclusive and is read-only
154  # and can only be set at creation time. The default is 0.
155  # @arg -forwardsignalobj This block's forward signal. This option is
156  # read-only and can only be set at creation time. The default is the
157  # empty string.
158  # @arg -reversesignalobj This block's reverse signal. This option is
159  # read-only and can only be set at creation time. The default is the
160  # empty string.
161  # @arg -previousblock Previous block (next block in reverse) -- used
162  # for 'propagating' signal aspects and must be a C4TSMINI_Block type
163  # object. The default is the empty string.
164  # @arg -nextblock Next block (previous block in reverse) -- used for
165  # 'propagating' signal aspects and must be a C4TSMINI_Block type
166  # object. The default is the empty string.
167  # @arg -direction Current running direction, either the word forward
168  # or reverse. The default is forward.
169  # @par
170 
171  ## Process any options
172  $self configurelist $args
173  # Install the node
174  set node [$self cget -nodeobj]
175  if {$node eq {}} {
176  error "The -nodeobj is required!"
177  }
178  # Install the signal component.
179  set forwardsignal [$self cget -forwardsignalobj]
180  set reversesignal [$self cget -reversesignalobj]
181  }
182  method occupiedp {} {
183  ## The occupiedp method returns yes or no (true or false) indicating
184  # block occupation.
185 
186  # First read the current sensor state.
187  set inputs [$node inputs]
188  set port [lindex $inputs [$self cget -port]]
189  set bit [expr {($port >> [$self cget -bit]) & 0x01}]
190  # The outputs of the OD are active negative, so we need to invert the
191  # logic.
192  set bit [expr {(~$bit) & 0x01}]
193  if {$bit == 1} {
194  if {$isoccupied} {
195  # Already entered the block.
196  return $isoccupied
197  } else {
198  # Just entered the block
199  set isoccupied yes
200  $self _entering
201  return $isoccupied
202  }
203  } else {
204  if {$isoccupied} {
205  # Just left the block
206  set isoccupied no
207  $self _exiting
208  return $isoccupied
209  } else {
210  # Block still unoccupied
211  return $isoccupied
212  }
213  }
214  }
215  method _entering {} {
216  ## @privatesection Method for entering a block.
217 
218  if {[$self cget -direction] eq "forward"} {
219  # Set a red (stop and proceed) aspect.
220  if {$forwardsignal ne ""} {$forwardsignal setaspect red}
221  # Now propagate the signal to the previous block (if any)
222  if {$options(-previousblock) ne {}} {
223  # Set a yellow (approach) aspect on the previous block.
224  $options(-previousblock) propagate yellow $self -direction forward
225  }
226  } else {
227  if {$reversesignal ne ""} {$reversesignal setaspect red}
228  # Now propagate the signal to the previous block (if any)
229  if {$options(-nextblock) ne {}} {
230  # Set a yellow (approach) aspect on the previous block.
231  $options(-nextblock) propagate yellow $self -direction reverse
232  }
233  }
234  }
235  method _exiting {} {
236  ## Method for exiting a block.
237 
238  # Nothing here -- could be used for any sort of exit handling.
239  }
240  method propagate {aspect from args} {
241  ## @publicsection Method used to propagate distant signal states back down the line.
242  # @param aspect The signal aspect that is being propagated.
243  # @param from The propagating block (not used).
244  # @param ... Options:
245  # @arg -direction The direction of the propagation.
246 
247  ## First process any options
248  $self configurelist $args
249  ## If we are already occupiedp, don't do anything else.
250  if {[$self occupiedp]} {return}
251  if {[$self cget -direction] eq "forward"} {
252  # Set signal aspect
253  if {$forwardsignal ne ""} {$forwardsignal setaspect $aspect}
254  # If the new aspect was yellow, propagate a green (clear) signal
255  if {$aspect eq "yellow"} {
256  if {$options(-previousblock) ne {}} {
257  $options(-previousblock) propagate green $self -direction forward
258  }
259  }
260  } else {
261  # Set signal aspect
262  if {$reversesignal ne ""} {$reversesignal setaspect $aspect}
263  # If the new aspect was yellow, propagate a green (clear) signal
264  if {$aspect eq "yellow"} {
265  if {$options(-nextblock) ne {}} {
266  $options(-nextblock) propagate green $self -direction reverse
267  }
268  }
269  }
270  }
271 }
272 
273 package provide C4TSMINI_Block 1.0
C4TSMINI_Block
Block occupation detection using Circuits4Tracks Quad Occupancy Detectors and Azatrax SR4s.
Definition: C4TSMINI_Block.tcl:62