Model Railroad System  2.2.2
Model RR signals with an Arduino
SignalDriverMax72xx_Host.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 : Sun Mar 1 10:42:54 2015
11 # Last Modified : <150728.1017>
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 snit
44 
45 snit::type SignalDriverMax72xx {
46  ## SignalDriverMax72xx is a Snit type (OO class) that implements the host
47  # interface to the SignalDriverMax72xx program running on an Arduino.
48  # It provides an abstraction of the serial port interface that controls
49  # signals multiplexed by the MAX72xx chip.
50  # This version assumes a that there is only one SignalDriverMax72xx driver
51  # boards (1 to 8 signals, numbered 0 through 7) connected to the Arduino.
52  # This version assumes that only these aspects are valid (case folded):
53  #
54  # g_r (Green over Red -- Clear)
55  # y_r (Yellow over Red -- Approach)
56  # r_r (Red over Red -- [Absolute] Stop)
57  # r_g (Red over Green -- Slow Clear)
58  # r_y (Red over Yellow -- Approach Limited)
59  # dark (all lights off)
60  #
61 
62  typecomponent validateaspects
63  ## @private Validation type for aspects.
64  typecomponent validatesignalnums
65  ## @private Validation type for signal numbers.
66  typeconstructor {
67  ## Initialize the validation typecomponents.
68  set validateaspects [snit::enum %%AUTO%% -values {g_r y_r r_r r_g r_y
69  dark}]
70  set validatesignalnums [snit::integer %%AUTO%% -min 0 -max 7]
71  }
72  typemethod validate {object} {
73  ## Type validation typemethod
74  # @param object An object to be validated.
75 
76  if {[catch {$object info type} thetype]} {
77  error "Not a valid $type object: $object"
78  } elseif {$thetype ne $type} {
79  error "Not a valid $type object: $object"
80  } else {
81  return $object
82  }
83  }
84 
85  variable portfd {}
86  ## @private Variable to hold the port fd
87 
88  #* option for the portname
89  option -portname -readonly yes -default /dev/ttyACM0
90  constructor {args} {
91  ## Constructor: open the port, configure it, set a readable file event,
92  # and prime the port.
93  # @param name The name of the object to be created.
94  # @param ... Options:
95  # @arg -portname The name of the USB Serial port connecting to the Uno.
96 
97  set options(-portname) [from args -portname]
98  set portfd [open $options(-portname) w+]
99  fconfigure $portfd -mode 115200,n,8,2 -blocking no -buffering none \
100  -handshake none -translation {crlf cr}
101  fileevent $portfd readable [mymethod _ReadPort]
102  puts $portfd {}
103  }
104 
105  variable _ready no
106  ## @private Variable to hold ready (for a command) state
107 
108  method _ReadPort {} {
109  ## @private Method to gobble from the Arduino
110  foreach {in out} [fconfigure $portfd -queue] {break}
111  if {$in > 0} {
112  set buffer [read $portfd $in]
113  if {[string range $buffer end-1 end] eq ">>"} {
114  set _ready yes
115  } else {
116  set _ready no
117  }
118  }
119  }
120 
121  method dark {} {
122  ## Method to turn off all LEDs
123 
124  # Wait for a prompt.
125  if {!$_ready} {
126  vwait [myvar _ready]
127  }
128  set _ready no
129  # Send the command
130  puts $portfd "D"
131  }
132 
133  method set {signo aspect} {
134  ## Method to set the aspect for one signal
135  # @param signo Signal number
136  # @param aspect The desired aspect
137 
138  # Validate the aspect
139  $validateaspects validate [string tolower $aspect]
140  # Validate the signal number
141  $validatesignalnums validate $signo
142  # Wait for a prompt.
143  if {!$_ready} {
144  vwait [myvar _ready]
145  }
146  # Form command
147  set cmd [format {S %d %s} $signo $aspect]
148  set _ready no
149  # Send the command
150  puts $portfd "$cmd"
151  }
152 
153  destructor {
154  ## Destructor: close the port.
155  catch {close $portfd}
156  }
157 }
158 
159 package provide SignalDriverMax72xx_Host 1.0