C.H.I.P. program to blink status LED and shut down when reset if briefly pressed.
I want there to be NO barriers to using this code, so I am releasing it to the public domain. But "public domain" does not have an internationally agreed upon definition, so I use CC0:
To the extent possible under law, the contributors to this project have waived all copyright and related or neighboring rights to this work. In other words, you can use this code for any purpose without any restrictions. This work is published from: United States. The project home is https://github.com/fordsfords/blink/tree/gh-pages
To contact me, Steve Ford, project owner, you can find my email address at http://geeky-boy.com. Can't see it? Keep looking.
The "C.H.I.P." single-board computer runs Linux. As a result, it should be shut down gracefully, not abruptly (e.g. by removing power). But CHIP is often used as an embedded system without any user interface. In those cases, it can be difficult to know if it has successfully booted, and is difficult to trigger a graceful shutdown. The "blink" program solves both problems.
At CHIP boot time, blink can indicate successful boot by blinking an LED (CHIP's status LED and/or an external GPIO output).
Blink can shut down CHIP gracefully through any of several configurable triggers, including button press, battery charge level, and temperature.
In addition, blink can enter a warning state based on configurable warning thresholds for battery and temperature. When in warning state, the LED is blinked faster, and each warning can be configured to trigger a GPIO output.
You can find blink on github. See:
- User documentation (this README): https://github.com/fordsfords/blink/tree/gh-pages
Note: the "gh-pages" branch is considered to be the current stable release. The "master" branch is the development cutting edge.
These instructions assume you are in a shell prompt on CHIP.
Prerequisites. If you plan on blinking CHIP's status LED, and/or monitoring the reset button and/or battery, you will need the "i2c-tools" package, installable like this:
sudo apt-get install i2c-tools
If you plan to use GPIO inputs and/or outputs, you will need "gpio_sh" package, installable like this:
sudo wget -O /usr/local/bin/gpio.sh http://fordsfords.github.io/gpio_sh/gpio.sh
(See https://github.com/fordsfords/gpio_sh/tree/gh-pages for details of "gpio_sh".)
If you have an earlier version of blink running, kill it:
sudo service blink stop
If that returns a failure, enter:
sudo kill `cat /tmp/blink.pid`
Get the project files onto CHIP:
sudo wget -O /usr/local/bin/blink.sh http://fordsfords.github.io/blink/blink.sh sudo chmod +x /usr/local/bin/blink.sh sudo wget -O /etc/systemd/system/blink.service http://fordsfords.github.io/blink/blink.service sudo systemctl enable /etc/systemd/system/blink.service
If installing blink for the first time, get the configuration file:
sudo wget -O /usr/local/etc/blink.cfg http://fordsfords.github.io/blink/blink.cfg
If upgrading blink and have a configuration file, you can skip that step.
Now test it:
sudo service blink start
After a few seconds watching the blinking LED, briefly press the reset button and watch CHIP shut down. Restart CHIP, and when it has completed its reboot, watch the status LED start to blink again.
grep blink /var/log/syslog
Blink can monitor up to 4 conditions in any combination:
- Short press of reset button.
- A configured GPIO input reading a configured value (e.g. an external button).
- The AXP209 temperature exceeding a configured threshold.
- The battery charge level dropping below a configured threshold (only applies if CHIP is running only on battery; an external power source will suppress battery monitoring).
While blink is running, it can be configured to blink either CHIP's status LED, or an external LED connected to a GPIO output (or both).
For temperature and battery monitoring, here are actually two configurable thresholds available: a warning threshold and a shutdown threshold. There is also a configurable warning GPIO output. For example, the temperature warning GPIO could turn on a fan, and the battery warning GPIO could be used to enter a reduced power mode by removing power to a non-critical external device.
Note that if blink shuts CHIP down due to low battery, it will not be possible to boot CHIP successfully without connecting to a power supply. If you try, blink will immediately detect low battery and will shut down before the system is fully booted. Similarly, if blink shuts CHIP down due to high temperature, you must let CHIP cool before you can boot it.
Since blink is a service, you can manually stop it with:
sudo service blink stop
Edit the file /usr/local/etc/blink.cfg it should look like this:
# blink.cfg -- version 24-Jul-2016 # Configuration for /usr/local/bin/blink.sh which is normally # installed as a service started at bootup. # See https://github.com/fordsfords/blink/tree/gh-pages BLINK_STATUS=1 # Blink CHIP's status LED. #BLINK_GPIO=XIO_P7 # Blink a GPIO. MON_RESET=1 # Monitor reset button for short press. #MON_GPIO=XIO_P4 # Shutdown when this GPIO is triggered. #MON_GPIO_VALUE=0 # The value read from MON_GPIO that initiates shutdown. #MON_BATTERY=7 # When battery percentage is below this, shut down. #WARN_BATTERY=9 # When battery percentage is below this, assert warning. #WARN_BATTERY_GPIO=XIO_P5 # When battery warning, activate this GPIO. #WARN_BATTERY_GPIO_VALUE=0 # Warning value to write to WARN_BATTERY_GPIO. #MON_TEMPERATURE=800 # Shutdown temperature in tenths of a degree C. #WARN_TEMPERATURE=750 # Warning temperature in tenths of a degree C. #WARN_TEMPERATURE_GPIO=XIO_P6 # When temperature warning, activate this GPIO. #WARN_TEMPERATURE_GPIO_VALUE=0 # Warning value to write to #WARN_TEMPERATURE_GPIO.
The hash sign (#) represents a comment. Most lines are commented, so their functions do not apply. I.e. the above (default) configuration only blinks CHIP's status LED and only monitors the reset button for short press. You can enable a function by uncommenting it (remove the hash signs). Or you can comment lines (add the hash) to disable a function.
Do not add any spaces before or after the equals sign.
For example, to skip all blinking of LEDs, and only monitor the battery, writing "1" to GPIO CSID0 when the battery drops below 10%, and shutting down when the battery drops below 5%:
#BLINK_STATUS=1 # Blink CHIP's status LED. #BLINK_GPIO=XIO_P7 # Blink a GPIO. #MON_RESET=1 # Monitor reset button for short press. #MON_GPIO=XIO_P4 # Shutdown when this GPIO is triggered. #MON_GPIO_VALUE=0 # The value read from MON_GPIO that initiates shutdown. MON_BATTERY=5 # When battery percentage is below this, shut down. WARN_BATTERY=10 # When battery percentage is below this, assert warning. WARN_BATTERY_GPIO=CSID0 # When battery warning, activate this GPIO. WARN_BATTERY_GPIO_VALUE=1 # Warning value to write to WARN_BATTERY_GPIO. #MON_TEMPERATURE=800 # Shutdown temperature in tenths of a degree C. #WARN_TEMPERATURE=750 # Warning temperature in tenths of a degree C. #WARN_TEMPERATURE_GPIO=XIO_P6 # When temperature warning, activate this GPIO. #WARN_TEMPERATURE_GPIO_VALUE=0 # Warning value to write to #WARN_TEMPERATURE_GPIO.
Blink logs informational (and maybe error) messages to /var/log/daemon.log
There is an older C version of blink which uses a GPIO line instead of the reset button. Given that the reset button is much better, I don't anticipate the C program will be of interest except perhaps as a simple example of a C program accessing the GPIO lines.
As long as the status LED continues to blink, you know that your CHIP is still running. But if you are running some useful application, the blinking LED does not necessarily give you a good indication of the overall health of your system. Basically, blink shows that the OS is still running, but your application may have crashed.
There are often ways of automatically monitoring the health of applications. At a crude level, you can periodically run the "ps" command and at least make sure the process itself is still running. Even better would be to be able to "poke" the application in some way to produce an expected result (like maybe sending it a signal and writing the application to write a message to a log file). You could build this capability into blink, and if it detects a failure, change the blink rate of the LED (like to 3 pulses per second). This still won't tell you what is wrong, but at least it narrows things down a bit.
The battery charge level is susceptible to "bit bobble", i.e. it can cycle between two values fairly rapidly. The CHIP temperature measurement can vary randomly within about a .9 degree range. To avoid rapid cycling of the warning state, blink adds hysteresis to the warning thresholds. For example, if CHIP's temperature exceeds the warning threshold, the temperature warning state is entered. If the temperature then starts to fall, it must fall to 1.1 degrees lower then the warning threshold to exit the warning state.
Added temperature monitoring, and also added warning levels. Re-wrote the code pretty much from scratch.
Fixed a tight loop when battery not being monitored.
Removed writes to blink.log. Fixed another "unary operator expected" bug.
Changed logging to go to syslog. Changed PID file to /run/blink.pid Some doc improvements.
Fixed small bug that caused "chip blink.sh: /usr/local/bin/blink.sh:
line 169: [: -eq: unary operator expected".
Added ability initiate shutdown based on monitoring a GPIO input pin and/or battery charge level. Added ability to blink a GPIO output pin. Added log file to /var/log.
Changed service type from "forked", which was both misspelled AND the wrong choice, to "simple". Also added spaces after the "-O" of wget to be more familliar.
Corrected typo. Added version ID to blink script. (Version ID is the release date.)
Checked for short button press properly (masking the correct bit).
Got rid of sleep 10. Added "blink.service" to start as system service instead of cron job. Also re-added the /tmp/blink.pid file.
Created shell script which accesses reset button instead of GPIO line.
Merged in Efreak's ontime/offtime
Added binary executable to package. Updated quickstart to use it. Made a few more improvements to documentation. Also changed the 1 second sleep to 1 million microseconds to make it easier to use a faster blink rate. Also added /tmp/blink.pid file.