-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnode
More file actions
executable file
·395 lines (364 loc) · 10 KB
/
node
File metadata and controls
executable file
·395 lines (364 loc) · 10 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
#!/bin/bash
# Access cluster nodes for serial I/O or power cycle
# This program is used with the Cluster controller board to control up to 8 Rpi cluster nodes
# Version V2 - for use with V2 board (also works with V1, but power monitor unavailable)
#
# Board V1 used 74HC138/74HC251 for serial I/O, and 74HC259 for power enables
# fixed serial speed issue and delivered power enable persistance
# Problem: no power state monitoring for nodes (is the node on or off?)
#
# Board V2 added a second 74HC251 for direct monitoring of power enable lines.
#
# A 74HC138 (for TX) and 74HC251 (for RX) (de)multiplexers for fanout of TX and RX UART signals
# from Pi1 to nodes 2-8 (pi2 has fixed ttyAMA2 - ttyAMA10 to pi1)
# One x 74HC259 addressable latch, driving the Enable lines of the DC/DC
# converters powering the Pi boards. CLK and DATA lines on GPIO 17 and 18
# GPIO pins 2, 3 and 4 are address lines 0, 1 and 2 for above signals
# Serial1 pins from pi1 via (de)mulitplexers, to serial0 of cluster nodes
# (Board V2) Addition of power monitor using a second 74HC251 connected to the power enable
# outputs from the 74HC259, so as to sample the current power status of nodes.
# Output of power monitor is GPIO 27 (was serial enable in previous board versions)
# GPIO 2,3,4 are address select pins for I/O multiplexers
# pin 2 = bit 0
# pin 3 = bit 1
# pin 4 = bit 2
# GPIO 18 is power pin - active HIGH = POWEROFF!
# Power off signal is latched by GPIO 17 CLK pin pulsing low (active LOW)
# GPIO 17 is power latch Clk pin - high latches value, low enables Data to selected output
# GPIO 27 WAS serial enable (in V1), but now is INPUT from power monitor mpx.
serialport="/dev/ttyAMA0" # outgoing UART into demultiplexer board
baudrate=115200 # Baud rate set for node serial ports
interactive=1 # Interactive flag for power commands
# Setup function configures GPIO pins to drive multiplexers
# Initialises GPIO pins to node 0 (pi1) selected, with power ON and Clk DISABLED
#
setup () { # Set up GPIO pins if not already done
if [[ $(pinctrl get 17) != *op* ]]
then
pinctrl set 17 op dh # set Power Clk pin to output and HIGH (disable)
echo "Initialising GPIO pins" # echo acts as time delay for enable pin settling
pinctrl set 2,3,4,18 op dl # set Address and PowerOn pins to output and LOW
# default pins to 0, for address 000 and power 0 (ON)
pinctrl set 27 ip pd # GPIO27 is input (with pull-down)
echo "GPIO pins initialised"
fi
}
# Get selected node number from select pins and set global variable "selectednode"
#
nodenum() {
selectednode=1 # start at count of 1
if [[ $(pinctrl get 2) == *hi* ]]
then
selectednode=$((selectednode + 1))
fi
if [[ $(pinctrl get 3) == *hi* ]]
then
selectednode=$((selectednode + 2))
fi
if [[ $(pinctrl get 4) == *hi* ]]
then
selectednode=$((selectednode + 4))
fi
}
# Print out current state of GPIO pins
#
nodegpio () {
if [[ $(pinctrl get 17) == *op* ]]
then
echo "node select pins:"
pinctrl get 2,3,4 | cut -d ' ' -f 2,7
nodenum
echo "Selected node =" $selectednode # global variable retains selected node
echo "Power Enable pins:"
pinctrl get 17,18 | cut -d ' ' -f 1,6
if [[ $(pinctrl get 17) == *hi* ]]
then
echo "Power CLK High (Disabled)"
else
echo "Power CLK Low (ENABLED!)"
fi
if [[ $(pinctrl get 18) == *hi* ]]
then
echo "Power Data High (POWEROFF!)"
else
echo "Power Data Low (PowerOn)"
fi
echo
else
echo "GPIO pins not yet initialised"
echo -n "Initialise GPIO pins [y/N]? "
read reply
if [[ $reply == "Y" || $reply == "y" ]]
then
setup
nodegpio
else
echo "GPIO pins not initialised"
fi
fi
}
# Print currently selected node and power states for all nodes
#
nodestatus () {
nodenum
currentnode=$selectednode # save current selection for restore below
echo
for i in 1 2 3 4 5 6 7 8
do
nodeselect $i
echo -n "node $selectednode POWER is "
if [[ $(pinctrl get 27) == *hi* ]]
then
echo "OFF"
else
echo "ON"
fi
done
nodeselect $currentnode # restore previously selected node
echo "Currently selected node =" $selectednode
echo
}
# Set GPIO address pins of multiplexers to specified node
#
nodeselect () {
pinctrl set 17 dh # ensure power gate is DISABLED (high)
pinctrl set 18 dl # ensure power D pin is in ON state (low)
case $1 in
1) pinctrl set 2,3,4 dl
;;
2) pinctrl set 2 dh
pinctrl set 3,4 dl
;;
3) pinctrl set 2,4 dl
pinctrl set 3 dh
;;
4) pinctrl set 2,3 dh
pinctrl set 4 dl
;;
5) pinctrl set 2,3 dl
pinctrl set 4 dh
;;
6) pinctrl set 3 dl
pinctrl set 2,4 dh
;;
7) pinctrl set 2 dl
pinctrl set 3,4 dh
;;
8) pinctrl set 2,3,4 dh
;;
*) echo -e "\nInvalid node: \"$1\""
usage
;;
esac
nodenum # update global node number with new selection
}
# Print usage string
#
usage () {
echo -e "\nUsage: $scriptname <command> [<node number or range>]"
echo "Commands:
gpio
status
select n
connect n
poweroff [n | n-n | n,n,n... | \"all\"]
poweron [n | n-n | n,n,n... | \"all\"]
powercycle [n | n-n | n,n,n... | \"all\"]"
echo "n = Node number: 1 to 8"
echo
exit # after printing usage we always exit
}
# Power off selected node
#
setpoweroff () {
if [[ $(pinctrl get 27) == *hi* ]] # test actual status of power enable line
then
echo "Node $selectednode is already powered OFF"
else
if [[ $interactive == 1 ]]
then
echo -n "Press Return to power OFF node $selectednode "
read input
else
sleep 1
fi
pinctrl set 17 dh # ensure Clk disabled to start with
pinctrl set 18 dh # set power Data pin to POWER OFF
pinctrl set 17 dl # set power Clk pin to Enable
pinctrl set 17 dh # set power Clk pin to Latch
pinctrl set 18 dl # leave power Data pin in ON state
echo "Node $selectednode powered OFF"
fi
}
# Power on selected node
#
setpoweron () {
if [[ $(pinctrl get 27) == *hi* ]] # test actual status of power enable line
then
if [[ $interactive == 1 ]]
then
echo -n "Press Return to power ON node $selectednode and connect to serial "
read input
else
echo "Powering on node $selectednode"
fi
pinctrl set 18 dl # set power pin to POWER ON
pinctrl set 17 dl # set power Clk pin to Enable
pinctrl set 17 dh # set power Clk pin to Latch
sleep 1
if [[ $interactive == 1 ]]
then
sleep 1 # needed for pi firmware baud rate stability
minicom -D $serialport -b $baudrate
fi
else
echo "Node $selectednode is already powered ON"
fi
}
# Execute command in first argument
#
execute() {
case $1 in
"gpio") # Print current state of GPIO pins
nodegpio
;;
"status") # Print status of mux GPU pins
nodestatus
;;
"select") # Set GPIO pins to select specified node
echo Selected node: $selectednode
;;
"connect") # connect to serial port
minicom -D $serialport -b $baudrate
;;
"powercycle") # Power cycle node
setpoweroff
sleep 1
setpoweron
;;
"poweroff") # Power off node and exit (power state latched persistently)
setpoweroff
;;
"poweron") # Power on specified node
setpoweron
;;
"help")
usage
;;
*) # Default action - print usage
echo -e "\nUnknown command: \"$1\""
usage
;;
esac
}
# Noderange: interpret range of nodes to execute on
#
noderange() {
case ${#2} in # interpret based on length of arg 2
1)
nodeselect $2 # select node from passed argument
execute $1 # execute passed command on slected node
exit # all done, so don't drop to next code
;;
2)
echo "invalid node range"
usage # just 2 chars is illegal value
;;
3) # 3 chars in arg means a range has been specified (n-n)
range=$2 # use a named variable for range arg
if [[ $range == "all" ]] # "all" is a special case for arg 2
then
range="1-8" # convert to range notation
fi
readarray -d "-" -t array <<< "$range" # test for node range specification
if [[ ${#array[@]} >1 ]] # a range has been specified
then
arg1="${array[0]}"
arg2="${array[1]}"
if (( $arg1 < 1 || $arg1 > 8 || $arg2 < 1 || $arg2 > 8 || $arg1 >= $arg2 ))
then
echo "\"$range\" - invalid range"
usage
else
interactive=0 # turn off interactive for power commands
echo -n "really $1 nodes $range [y/N] "
read input
if [[ $input != "y" && $input != "Y" ]]
then
echo aborting!
exit
fi
for ((i=$arg1;i<=$arg2;i++))
do
nodeselect $i
execute $1
done
fi
exit # all done, so don't drop to next code
fi
;;
esac
# If we get here arg has 3 or more chars and must be a series (n,n,n...)
readarray -d "," -t array <<< "$2" # test for node series specification
if [[ ${#array[@]} >1 ]] # multiple nodes have been specified
then
for arg in "${array[@]}" # validate all numbers in the series
do
if (( $arg < 1 || $arg > 8 ))
then
echo invalid node numer in range
usage
fi
done
interactive=0 # turn off interactive for power commands
echo -n "really $1 nodes $2 [y/N] "
read input
if [[ $input != "y" && $input != "Y" ]]
then
echo aborting!
exit
fi
for arg in "${array[@]}"
do
nodeselect $arg
execute $1
done
exit # all done, so don't drop down to next code
fi
echo illegal range or node number # if we get here, no range or series specified
usage
}
#
# Program proper starts here:
#
scriptname=`basename $0` # needed for "usage" function
setup # ensure GPIO pins are initialised
case $# in # execute based on number of args passed
0) # no arguments passed
usage
;;
1) # just the command given
nodenum # set "selectednode" from current state of gpio pins
execute $1 # now execute the command passed as arg 1
;;
2) # node number given as argument
case $1 in # does a node number make sense for specified command
gpio|status)
echo "too many arguments for command \"$1\""
usage
;;
select|connect)
if (( ${#2} > 1 )) # range makes no sense for connect command
then
echo "specify only a single node for \"$1\" command"
usage
fi
;;
esac
noderange $1 $2 # interpret range of nodes to execute on
;;
*)
echo -e "\nToo many arguments"
usage
;;
esac