The trouble with a headless device is that we don't know what it's doing unless we connect to it with ssh. Nor can we shut it down properly without giving a shutdown command via ssh.
We would at least like a couple of LEDs to indicate when it is running and to show whether we have a GPS timing lock. And a button to order a clean shutdown is fairly essential too. The alternative of just pulling the plug is not ideal. Having said that, nothing we are doing up to now is writing anything important to the disk. The only thing the radio system is writing are the log files /run/vtcard.log and /tmp/vttime.log and both of these directories are erased anyway when the system restarts. So, right now it is quite harmless to pull the plug. But later you'll be setting things up to record continuously to a USB memory stick and then a clean shutdown will be desirable.
Wiring the GPIO pins on the Pi to LEDs and buttons is easy. The LEDs will need each need a series resistor of 180 ohms, and a button will need a pull-up resistor - the value is not critical but something between 1k and 10k should do.
That's the easy bit. The hard bit is working out which GPIO pin is which. Try the command
cat /sys/class/gpio/gpiochip0/ngpio
This will come back with a number, such as 54. That's the number of 'logical' GPIO signals that the Pi has. Unfortunately there is no simple mapping of these 54 logical pins to the physical pin numbers of the GPIO header. The mapping depends on the particular model, generation, and revision of the Pi, and possibly on the day of the week and the weather too. Also, not all of the 54 logical pins are available for us to use - many are used internally within the Pi. Usually we can rely on six pins to be available for general use: logical pins gpio17, gpio18, gpio27, gpio22, gpio23, and gpio24. But the audio injector card uses gpio18 for its bitclock so we must leave that one alone.
On the Model 3 Pi which has a 40 pin header, these five logical GPIO lines map to the header pin numbers as follows:
Logical GPIO number Physical pin number 17 11 27 13 22 15 23 16 24 18 GND 14
There are others which can be used, but the above is all we need.
Each pin can be configured as an input or an output. There is very limited current which can be drawn from a GPIO output pin, it is said to be 16mA max. And the combined current of all outputs is not supposed to exceed about 50mA. Really they are intended to drive CMOS external logic, but we can get away with directly driving two or three LEDs if we limit the current with 180 ohm resistors.
To check this out, take a wire from header pin 11 via 180 ohms to the anode of an LED, and the cathode back to ground on header pin 14. The LED should initially be off.
Tell the system we want to use GPIO17 which is header pin 11.
echo 17 > /sys/class/gpio/export
and that we want GPIO17 to be an output
echo out > /sys/class/gpio/gpio17/direction
The echo command is the simplest command you can imagine, it just sends its argument to its standard output stream. By redirecting that output to a file, we use echo to stuff something into a file. Combine that with the fact that in Unix and Linux, nearly all devices are mapped to the filesystem so that I/O to or from a device is simply a matter of reading or writing the device file.
Now to set GPIO17 output to high state, do
echo 1 > /sys/class/gpio/gpio17/value
and the LED should light. And
echo 0 > /sys/class/gpio/gpio17/value
turns the LED off.
Inputs are just as easy. Just bear in mind that the input pins on the Pi are specially designed to self destruct if you apply even slightly over 3.3V to them. We're safe enough so long as we use the built-in 3.3V supply available on pin 1 of the header.
We'll use GPIO 24, header pin 18 for an input.
echo 24 > /sys/class/gpio/export echo in > /sys/class/gpio/gpio24/direction
Now wire a 1k resistor between 3.3V (header pin 1) and GPIO24 on pin 18. The command
cat /sys/class/gpio/gpio24/value
should come back with a '1' to indicate the input is high. Now wire a momentary pushbutton from header pin 18 to ground on header pin 14. Hold the button down and run the above cat command again (up arrow!), you should get a '0'.
Now we just need to prepare a short program, a shell script, which will monitor the operation of the radio and the GPS and drive some LEDs. It will also monitor the pushbutton and invoke a shutdown if it is pressed for a few seconds.
Using a text editor, create a file /root/monitor and paste the following into it.
#!/bin/bash # Set up GPIO17 and GPIO27 as outputs echo 17 > /sys/class/gpio/export 2> /dev/null echo out > /sys/class/gpio/gpio17/direction echo 27 > /sys/class/gpio/export 2> /dev/null echo out > /sys/class/gpio/gpio27/direction while : # Loop forever do # Test to see if @raw is present and with data. If so, then turn on # GPIO17, otherwise turn off GPIO17. if vtwait -t -e 0.2 @raw then echo 1 > /sys/class/gpio/gpio17/value else echo 0 > /sys/class/gpio/gpio17/value fi # Similarly, test to see if @timed is active. This will only be # active if vttime is seeing a good PPS. Set GPIO27 accordingly. if vtwait -t -e 0.2 @timed then echo 1 > /sys/class/gpio/gpio27/value else echo 0 > /sys/class/gpio/gpio27/value fi # Wait half a second sleep 0.5 done
The command vtwait -t -e 0.2 waits for up to 0.2 seconds to detect traffic on the buffer. Note the first line of the script,
#!/bin/bash
which should be right at the top of the file. This is called a shebang and tells the operating system which command interpreter (shell) is needed to execute your script, in this case the 'bash' shell which is the same one you've been typing commands into. There are many other shells available - some like bash are general purpose, others are for specific kinds of tasks such as text processing or number crunching or graphical user interface programming.
Make this text file into an executable script by doing
chmod +x /root/monitor
and run the monitor with
/root/monitor
Now if the radio system is running, both LEDs should be on. To give it a test, you can disconnect the PPS, or disconnect the GPS antenna. Then vttime will lose its PPS and after its 30 second holdover period, the LED attached to GPIO27 will turn off. Reconnect the GPS and it should come back on within a few seconds.
From another shell, stop the radio system with
systemctl stop radio.service
and within a second or two, both LEDs should turn off. Restart with
systemctl start radio.service
and after a minute or two, GPIO17 should turn its LED on, and a few seconds later GPIO27 should turn on.
Now to add some logic into your monitor script to notice when the button is held down for a couple of seconds and to start a shutdown.
Edit /root/monitor and add some new commands - which I've highlighted in blue-
#!/bin/bash # Set up GPIO17 and GPIO27 as outputs echo 17 > /sys/class/gpio/export 2> /dev/null echo out > /sys/class/gpio/gpio17/direction echo 27 > /sys/class/gpio/export 2> /dev/null echo out > /sys/class/gpio/gpio27/direction # Set up GPIO24 as input echo 24 > /sys/class/gpio/export 2> /dev/null echo in > /sys/class/gpio/gpio24/direction while : # Loop forever do # Test to see if @raw is present and with data. If so, then turn on # GPIO17, otherwise turn off GPIO17. if vtwait -t -e 0.2 @raw then echo 1 > /sys/class/gpio/gpio17/value else echo 0 > /sys/class/gpio/gpio17/value fi # Similarly, test to see if @timed is active. This will only be # active if vttime is seeing a good PPS. Set GPIO27 accordingly. if vtwait -t -e 0.2 @timed then echo 1 > /sys/class/gpio/gpio27/value else echo 0 > /sys/class/gpio/gpio27/value fi # See if the button is pressed for more than three seconds. Value is # pulled high by the resistor and low when the button is pushed. if [ $(cat /sys/class/gpio/gpio24/value) = 0 ] then sleep 3.0 if [ $(cat /sys/class/gpio/gpio24/value) = 0 ] then shutdown -h now fi fi # Wait half a second sleep 0.5 done
Save, then run the monitor again from the shell with
/root/monitor
Nothing should happen, then if you hold the button down long enough, the Pi should shut down.
If just remains to arrange things so that the monitor starts up automatically when the Pi boots, just like the radio programs. That means creating a service file for systemd, similar to the one done earlier for radio.
Edit a new file /etc/systemd/system/monitor.service and paste in the following:
[Unit] Description=Monitor program ConditionFileIsExecutable=/root/monitor [Service] Type=simple WorkingDirectory=/root ExecStart=/root/monitor User=root Group=root [Install] WantedBy=multi-user.target
Save the file and tell systemd to enable and start the service.
systemctl enable monitor.service systemctl start monitor.service
Now check the process table for the monitor program:
ps ax | grep monitor
and check that the shutdown button works and that the LEDs do the right thing when you restart the Pi.
Later you will think of other things to put in the monitor script. For example, using vtwait checks that data is flowing through the buffer, but it doesn't tell if the're a signal there. The data may just be a stream of zeros if the VLF antenna has fallen off. Commands can be added to test the amplitude of the signal to check that it is above some threshold.