#!/bin/bash # There is no GPIO0 or GPIO1 # Zero padding means p_list[2] = GPIO2 p_list=("0" "0" "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") p_locs=(0 0 3 5 7 29 31 26 24 21 19 23 32 33 8 10 36 11 12 35 38 40 15 16 18 22 37 13) p_cache=(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) # Enabled/not p_dir=(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) # In/out p_stat=(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) # Powered/unpowered root=/sys/class/gpio p_id=0 # Pin ID p_en=0 # Pin enabled p_in=0 # Pin dir (in=1/out=0) messages=() # max 4 lines latestdatest="" ## Colors c_pre="\e[38;5;" c_default="${c_pre}15m" c_disabled="${c_pre}244m" c_dim="${c_pre}33m" c_off="${c_pre}202m" c_on="${c_pre}118m" c_in="${c_pre}45m" c_pink="${c_pre}207m" c_purple="${c_pre}141m" c_warn="${c_pre}11m" c_ok="${c_pre}10m" c_err="${c_pre}9m" rst="\e[0m" ## trap ctrlc INT function ctrlc() { tput cub 99 echo "`tput setaf 1`ctrl+c detected - exiting`tput sgr0`" tput cnorm exit 1 } function log() { upthedate local words="[ ${latestdatest} ] ${1}" local sev="$2" local logs=${#messages[@]} local maxlen=78 local logcolor="${c_default}" case $sev in err) logcolor="${c_err}";; warn) logcolor="${c_warn}";; ok) logcolor="${c_ok}";; esac if [ $logs -ge 4 ]; then # Prune first message # A loop would be smarter, but this is quicker messages[0]=${messages[1]} messages[1]=${messages[2]} messages[2]=${messages[3]} messages[3]="${logcolor}${words:0:$maxlen}${rst}" else messages[$logs]="${logcolor}${words:0:$maxlen}${rst}" fi } function upthedate(){ latestdatest=`date "+%_I:%M:%S %P"` } function showlogs() { local line=23 for i in `seq ${#messages[@]} -1 0`; do tput cup $line 2 tput el [ -z "${messages[$i]}" ] || echo -en "${messages[$i]}" let line=line-1 done } function hidelogs() { local line=22 for i in `seq 1 4`; do tput cup $line 0 tput el let line=line-1 done } function invalidpin(){ log "GPIO$1 is not a valid GPIO pin" "warn";showlogs } # Takes pin # Returns enabled y/n function checkpin() { p_id=$1 [[ "$p_id" == *"gpio"* ]] && p_id=${p_id:4} if [ -d $root/gpio${p_id} ]; then p_en=1 p_cache[$p_id]=1 if [[ `cat $root/gpio${p_id}/direction` == "in" ]]; then p_in=1 else p_in=0 p_stat[$p_id]=`cat $root/gpio${p_id}/value` fi p_dir[$p_id]=$p_in else zeroes $p_id fi } function zeroes(){ p_id=$1 p_en=0 p_in=0 p_cache[$p_id]=0 p_dir[$p_id]=0 p_stat[$p_id]=0 } function enablepin() { [ -z "$1" ] && return [[ $1 -gt 27 || $1 -lt 2 ]] && invalidpin $1 && return p_id=$1 if [ ${p_cache[$p_id]} -eq 1 ]; then log "Pin gpio$p_id is already enabled" "warn";showlogs return; fi echo $p_id > $root/export log "Enabling pin gpio$p_id" "ok";showlogs sleep .05;setpindir "$p_id" "o" } function disablepin() { [ -z "$1" ] && return [[ $1 -gt 27 || $1 -lt 2 ]] && invalidpin $1 && return p_id=$1 if [ ${p_cache[$p_id]} -eq 0 ]; then log "Pin gpio$p_id is already disabled" "warn";showlogs;return fi echo $p_id > $root/unexport zeroes $p_id log "Disabling pin gpio$p_id" "ok";showlogs } function turnonpin() { [ -z "$1" ] && return [[ $1 -gt 27 || $1 -lt 2 ]] && invalidpin $1 && return p_id=$1 if [ ! -d $root/gpio${p_id} ]; then log "Pin gpio$p_id is not enabled" "warn";showlogs;return fi if [ ${p_stat[$p_id]} -eq 1 ]; then log "Pin gpio$p_id is already powered" "warn";showlogs;return fi [[ ${p_cache[$p_id]} -eq 1 && ${p_dir[$p_id]} -eq 0 ]] && echo 1 > $root/gpio${p_id}/value log "Powering pin gpio$p_id" "ok";showlogs } function turnoffpin() { [ -z "$1" ] && return [[ $1 -gt 27 || $1 -lt 2 ]] && invalidpin $1 && return p_id=$1 if [ ! -d $root/gpio${p_id} ]; then log "Pin gpio$p_id is not enabled" "warn";showlogs;return fi if [ ${p_stat[$p_id]} -eq 0 ]; then log "Pin gpio$p_id is already off" "warn";showlogs;return fi [[ ${p_cache[$p_id]} -eq 1 && ${p_dir[$p_id]} -eq 0 ]] && echo 0 > $root/gpio${p_id}/value log "Unpowering pin gpio$p_id" "ok";showlogs } function setpindir() { [ -z "$1" ] && return;[ -z "$2" ] && return [[ $1 -gt 27 || $1 -lt 2 ]] && invalidpin $1 && return p_id=$1;p_dir=$2 if [ ! -d $root/gpio${p_id} ]; then log "Pin gpio$p_id is not enabled" "warn";showlogs;return fi case $p_dir in o) echo out > $root/gpio${p_id}/direction;log "Setting pin gpio$p_id as output" "ok";showlogs;; i) echo in > $root/gpio${p_id}/direction;log "Setting pin gpio$p_id as input" "ok";showlogs;; *) log "$p_dir is not a valid direction" "warn";showlogs;; esac } function refreshpins() { if [ ! -d $root ]; then tput rmcup;echo "`tput setaf 1`No gpio detected. Send help.`tput sgr0`";exit 1 fi for _pin in `ls $root`; do # Check for enabled pins if [[ "$_pin" == "gpio"* && "$_pin" != *"chip"* ]]; then checkpin $_pin fi done for _pin in ${p_list[@]}; do # Check for disabled pins if [ ${p_cache[$_pin]} -eq 1 ]; then [ -d $root/gpio${_pin} ] || zeroes $_pin fi done } function printkey() { tput cup 0 2 echo -en "Color key:" tput cup 0 16 echo -en "${c_disabled}pin disabled${rst}" tput cup 0 33 echo -en "${c_in}pin in${rst}" tput cup 0 45 echo -en "${c_on}pin out -> on${rst}" tput cup 0 63 echo -en "${c_default}pin out -> off${rst}" } function display() { tput sc printkey tput civis # tput cup down over tput cup 2 2 for i in `seq 0 ${#p_list[@]}`; do _p=${p_list[i]} [[ "$_p" == "0" || -z $_p ]] && continue [[ "$_p" == "15" ]] && tput cup 3 2 [ ${p_cache[i]} -eq 0 ] && _status=$c_disabled || _status=$c_default [[ ${p_cache[i]} -eq 1 && ${p_dir[i]} -eq 1 ]] && _status=$c_in [[ ${p_cache[i]} -eq 1 && ${p_dir[i]} -eq 0 && ${p_stat[i]} -eq 1 ]] && _status=$c_on echo -en "${_status}" [[ ${#_p} -lt 2 ]] && echo -n "[ $_p]" || echo -n "[$_p]" echo -en "${rst} " done echo tput rc } function printmenu() { tput civis local opts="$1" local oc="$2" local line=$3 tput cup $line 0 # https://stackoverflow.com/a/28104488 IFS=, menubottom=$line for opt in $opts; do tput cuf $oc echo "${opt}" let menubottom="menubottom+1" done unset IFS } function monitorpins() { local mon clearmenu 17 0 hidelogs tput cup 5 2 echo -en "${c_dim}Monitoring pins${rst}" tput cup 6 2 echo -en "${c_disabled}Press q to stop${rst}" #local loading=(". " ".. " "..." ".. ") local loading=(". " " . " " ." " . ") local lindex=0 while [[ "$mon" != "q" ]]; do echo -en "${c_disabled}${loading[$lindex]}${rst}" read -n1 -t1 -s mon refreshpins;display tput cup 6 17 let lindex=lindex+1 [ $lindex -ge ${#loading[@]} ] && lindex=0 done showlogs clearmenu 6 0 } function mainmenu() { tput civis tput cup 5 4 echo -e "${c_pink}-=-=-= Main Menu =-=-=-${rst}" _over=3 availablemainmenuoptions="e) enable pin,d) disable pin,p) power pin,u) unpower pin,i) set pin direction,r) refresh display,m) monitor gpio,h) help,q) quit" printmenu "$availablemainmenuoptions" "$_over" 7 mymenuspot=$menubottom let mymenuspot="mymenuspot+1" tput cup $mymenuspot $_over echo -n "> " tput el tput cnorm read -n1 mainmenuopt case $mainmenuopt in e) echo -en "${c_dim}nable${rst}";enablemenu;mainmenu;; d) echo -en "${c_dim}isable${rst}";disablemenu;mainmenu;; p) echo -en "${c_dim}ower${rst}";powermenu;mainmenu;; u) echo -en "${c_dim}npower${rst}";unpowermenu;mainmenu;; i) tput cub1;echo -en "${c_dim}d${rst}i${c_dim}rection${rst}";directmenu;mainmenu;; r) echo -en "${c_dim}efresh${rst}";refreshpins; display;mainmenu;; m) echo -en "${c_dim}onitor${rst}";monitorpins;mainmenu;; h) helppls;mainmenu;; q) tput rmcup;exit 0;; *) log "$mainmenuopt is not a valid menu choice" "warn";showlogs;mainmenu;; esac tput rmcup } function helppls(){ clearmenu 17 0;hidelogs;tput cup 0 0;tput el;tput civis tput cup 5 0;echo -en "\e[38;5;219m";tput rev echo -n " " echo -n "GPIO Monitor & Control Script" echo -n " " tput sgr0 tput cup 6 18;echo -en "${c_pink}-=-=-= Help menu and about this tool =-=-=-${rst}" tput cup 8 0 cat << EOF This tool was designed to be able to monitor and control, in real-time, the GPIO pins on my pi zero without needing to write a special python script for a quick test or check. The script functions as explained below: All menu options are single letters and are accepted without needing to press enter. The only time enter is required is when multiple characters may be necessary (e.g. entering a pin number). This program comes with no warranty and only interacts with the GPIO pins on the pi. Anything connected to those pins is not the responsibility of this script. Enjoy <3 EOF read -n1 -s tput cup 5 0;tput el tput cup 6 0;tput el clearmenu 18 0;hidelogs;showlogs;printkey } function clearmenu(){ tput civis local spot=5 local menu=0 [ -z $2 ] && menu=40 local max=$1 let max=max+1 [ $max -gt 19 ] && max=19 while [ $spot -lt $max ]; do tput cup $spot $menu tput el let spot=spot+1 done } function gpiodisclaimer() { local offset=$1;local alpha;local beta let alpha=8+offset let beta=9+offset tput cup $alpha 40;echo -en "This is the GPIO# not the physical" tput cup $beta 40;echo -en "pin location." } function enablemenu() { tput cup 5 40 echo -en "${c_purple}-=-=-= Enable Pin =-=-=-${rst}" tput cup 7 40;echo -en "Enter the pin ID you wish to enable." gpiodisclaimer tput cup 11 40;echo -n "> " tput cnorm read enpin enablepin $enpin clearmenu 11;refreshpins;display } function disablemenu() { tput cup 5 40 echo -en "${c_purple}-=-=-= Disable Pin =-=-=-${rst}" tput cup 7 40;echo -en "Enter the pin ID you wish to disable." gpiodisclaimer tput cup 11 40;echo -n "> " tput cnorm read dispin disablepin $dispin clearmenu 11;refreshpins;display } function powermenu() { tput cup 5 40 echo -en "${c_purple}-=-=-= Power Pin =-=-=-${rst}" tput cup 7 40;echo -en "Enter the pin ID you wish to turn on." gpiodisclaimer tput cup 11 40;echo -n "> " tput cnorm read powapin turnonpin $powapin clearmenu 11;refreshpins;display } function unpowermenu() { tput cup 5 40 echo -en "${c_purple}-=-=-= Unpower Pin =-=-=-${rst}" tput cup 7 40;echo -en "Enter the pin ID you wish to turn off." gpiodisclaimer tput cup 11 40;echo -n "> " tput cnorm read powapin turnoffpin $powapin clearmenu 11;refreshpins;display } function directmenu() { tput cup 5 40 echo -en "${c_purple}-=-=-= Change Direction =-=-=-${rst}" # | LAST tput cup 7 40;echo -en "Enter the pin ID you wish to set the" tput cup 8 40;echo -en "direction of. This is the GPIO# not" tput cup 9 40;echo -en "the physical pin location." tput cup 11 40;echo -n "> " tput cnorm read dirpin clearmenu 11 tput cup 5 40 echo -en "${c_purple}-=-=-= Change Direction =-=-=-${rst}" # | LAST tput cup 7 40;echo -en "Enter the direction you would like this" tput cup 8 40;echo -en "pin to go in." tput cup 10 40;echo -n "o) output" tput cup 11 40;echo -n "i) input" tput cup 13 40;echo -n "> " tput cnorm read -n1 dirdir setpindir $dirpin $dirdir clearmenu 13;refreshpins;display } tput smcup refreshpins display mainmenu