Last active
February 27, 2024 05:06
-
-
Save fastcat/5708253 to your computer and use it in GitHub Desktop.
Shell script to make it easy to control an Adafruit USB+Serial backpack (http://www.adafruit.com/products/784) from other shell scripts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
dev=/dev/serial/by-id/usb-239a_Adafruit_Industries-if00 | |
# prefix byte for all commands | |
pfx='\xfe' | |
# named commands, associative array, start as just the hex chars | |
declare -A cmd=( | |
[on]=42\\xff # macro for below | |
[on2]=42 # +1 # arg ignored | |
[off]=46 | |
[brightness]=99 # +1 | |
# [savebrightness]=98 # +1 # same as brightness | |
[contrast]=50 # +1 | |
# [savecontrast]=91 # +1 # same as contrast | |
[autoscroll]=51 | |
[noautoscroll]=52 | |
[clear]=58 | |
# splash=40+32 | |
[movecursor]=47 # +2 | |
[gohome]=48 | |
[cursorback]=4c | |
[cursorforward]=4d | |
[underlineon]=4a | |
[underlineoff]=4b | |
[blockon]=53 | |
[blockoff]=54 | |
[color]=d0 # +3 | |
# color macros | |
# led primaries | |
[white]=d0\\xff\\xff\\xff | |
[red]=d0\\xff\\x00\\x00 | |
[green]=d0\\x00\\xff\\x00 | |
[blue]=d0\\x00\\x00\\xff | |
# cmy(k) "primaries", roughly color balanced due to led brightness differences | |
[yellow]=d0\\xff\\x80\\x00 | |
[cyan]=d0\\x00\\xc0\\xff | |
[magenta]=d0\\xff\\x00\\x80 | |
# other saturated simple combos | |
# full saturation red+green is just a different shade of yellow, slightly greenish | |
[teal]=d0\\x00\\xff\\xff | |
[purple]=d0\\xff\\x00\\xff | |
# hack | |
[black]=d0\\x00\\x00\\x00 | |
# size=d1+2 | |
[customchar]=4e | |
# savecustom=c1+1+1+8 | |
# loadcustom=c0+1 | |
# gpiooff=56+1 | |
# gpioon=57+1 | |
# gpiostart=c3+1 | |
# autolinewrapon=43 # not supp because "not useful" | |
# autolinewrapoff=44 # not supp because "not useful" | |
) | |
declare -A cmdargs=( | |
[on2]=1 | |
[brightness]=1 | |
[contrast]=1 | |
[movecursor]=2 | |
[color]=3 | |
[customchar]=9 # 1 spot + 8 data bytes (bitmask for each row) | |
) | |
for c in "${!cmd[@]}" ; do | |
# all these commands are prefixed | |
cmd["$c"]="${pfx}\\x${cmd[$c]}" | |
done | |
# non-prefixed commands | |
cmd[nl]='\n' | |
# "fonts" for slots 1-8 | |
# processed as decimal format from https://www.quinapalus.com/hd44780udg.html | |
declare -a font_hfill=( | |
"16,16,16,16,16,16,16,16" | |
"24,24,24,24,24,24,24,24" | |
"28,28,28,28,28,28,28,28" | |
"30,30,30,30,30,30,30,30" | |
"31,31,31,31,31,31,31,31" | |
) | |
declare -a font_vfill=( | |
"00,00,00,00,00,00,00,31" | |
"00,00,00,00,00,00,31,31" | |
"00,00,00,00,00,31,31,31" | |
"00,00,00,00,31,31,31,31" | |
"00,00,00,31,31,31,31,31" | |
"00,00,31,31,31,31,31,31" | |
"00,31,31,31,31,31,31,31" | |
"31,31,31,31,31,31,31,31" | |
) | |
declare -a font_loadbars=( | |
# 5 entries | |
"${font_hfill[@]}" | |
# 3 "multiplier" blocks | |
"31,31,31,31,31,17,17,31" | |
"31,31,31,17,17,17,17,31" | |
"31,17,17,17,17,17,17,31" | |
) | |
printfx1() { | |
value="$1" | |
if [ $value -eq 0 ]; then | |
value=1 | |
fi | |
printf %02x $value | |
} | |
# printf format string... | |
out= | |
# ... and printf arguments | |
declare -a outargs=() | |
okempty=no | |
#set -x | |
while [ $# -gt 0 ]; do | |
i="$1" | |
shift | |
c="${i#-}" | |
if [ "$c" = "$i" ]; then | |
out+="%s" | |
#TODO: support incoming hex | |
outargs+=("$i") | |
elif [ "${cmd["$c"]+xxx}" ]; then | |
out+="${cmd["$c"]}" | |
if [ "${cmdargs["$c"]+xxx}" ]; then | |
if [ $# -lt ${cmdargs["$c"]} ]; then | |
echo "Not enough args to '$c'" 1>&2 | |
exit 1 | |
fi | |
for ((a=0;a<${cmdargs["$c"]};++a)); do | |
out+="\\x$(printfx1 "$1")" | |
shift | |
done | |
fi | |
elif [ "$c" = "msg" ]; then | |
out+="%s" | |
#TODO: support incoming hex | |
outargs+=("$1") | |
shift | |
elif [ "$c" = "hex" ]; then | |
out+="\\x$1" | |
shift | |
elif [ "$c" = "font" ]; then | |
declare -n fvar="font_$1" | |
shift | |
for ((j=0;j<${#fvar[@]};++j)); do | |
# font entries are 0-7, but bash can't hold 0 in a string | |
out+="${cmd[customchar]}\\x$j" | |
for r in ${fvar[$j]//,/ } ; do | |
out+="\\x$(printfx1 $r)" | |
done | |
done | |
elif [ "$c" = "loadbar" ]; then | |
n="$1" | |
shift | |
declare -a lavgargs=() | |
lavg=$(cut -d. -f1 < /proc/loadavg) | |
lavgt=$(cat /proc/loadavg | cut -d. -f2 | cut -c 1) | |
loffset=0 | |
nn="$n" | |
while [ $lavg -gt $n -a $nn -ge 5 ]; do | |
loffset=$((loffset + 5)) | |
lavg=$((lavg - 5)) | |
# 5, 10, 15 each are one char | |
n=$((nn - (loffset + 14)/15)) | |
done | |
while [ $loffset -gt 0 ]; do | |
if [ $loffset -ge 15 ]; then | |
out+='\x7' | |
loffset=$((loffset - 15)) | |
elif [ $loffset -eq 10 ]; then | |
out+='\x6' | |
loffset=$((loffset - 10)) | |
elif [ $loffset -eq 5 ]; then | |
out+='\x5' | |
loffset=$((loffset - 5)) | |
else | |
echo "WTF?!" 1>&2 | |
exit 1 | |
fi | |
done | |
for ((j=0;j<$n;++j)); do | |
if [ $lavg -lt $j ]; then | |
out+=' ' | |
elif [ $lavg -gt $j ]; then | |
out+='\x4' | |
elif [ $lavgt -ge 8 ]; then | |
out+='\x3' | |
elif [ $lavgt -ge 6 ]; then | |
out+='\x2' | |
elif [ $lavgt -ge 4 ]; then | |
out+='\x1' | |
elif [ $lavgt -ge 2 ]; then | |
out+='\x0' | |
else | |
out+=' ' | |
fi | |
done | |
elif [ "$c" = "help" ]; then | |
echo "Usage: $(basename "$0") [-cmd|message]..." | |
echo "Commands:" | |
for k in "${!cmd[@]}" ; do | |
a=${cmdargs["$k"]} | |
if [ -z "$a" ]; then | |
echo " $k" | |
else | |
echo " $k ($a args)" | |
fi | |
done | |
echo " -msg <message>" | |
echo " -help" | |
echo " -testdev" | |
echo " -hex <hexchar>" | |
echo " -font <name>" | |
exit 0 | |
elif [ "$c" = "testdev" ]; then | |
okempty=yes | |
if [ ! -e "$dev" ]; then | |
exit 1 | |
fi | |
elif [ "$c" = "powermode" ]; then | |
okempty=yes | |
if [ ! -e "$dev" ]; then | |
exit 1 | |
fi | |
devshortname=$(basename $(realpath "$dev")) | |
sysbase=/sys/class/tty/$devshortname/device/ | |
powermodechanged=no | |
for sysp in $(find $sysbase -type f -path '**/power/control') ; do | |
[ "$(<$sysp)" != "on" ] || continue | |
echo "set power $sysp on" | |
echo on | sudo sponge $sysp | |
powermodechanged=yes | |
done | |
# if it was in suspend mode, it generally needs a reset to work again | |
if [ "$powermodechanged" = "yes" ]; then | |
sudo usbreset 239a:0001 | |
for sysp in $(find $sysbase -type f -path '**/power/control') ; do | |
[ "$(<$sysp)" != "on" ] || continue | |
echo "set power $sysp on" | |
echo on | sudo sponge $sysp | |
powermodechanged=yes | |
done | |
fi | |
else | |
echo "Unrecognized argument '$i'" 1>&2 | |
exit 1 | |
fi | |
done | |
#set +x | |
if [ -z "$out" ]; then | |
if [ "$okempty" != "yes" ]; then | |
echo "Gimme some args" 1>&2 | |
exit 1 | |
else | |
exit 0 | |
fi | |
fi | |
#printf "$out" "${outargs[@]}" | hd | |
printf "$out" "${outargs[@]}" > $dev |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Unit] | |
Description=LCD Clock | |
[Service] | |
Type=simple | |
Environment="PATH=/usr/lib/ccache:%h/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games" | |
ExecStart=%h/bin/lcdclock.sh | |
Restart=on-failure | |
[Install] | |
WantedBy=default.target |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
if [ ! -t 0 -a -z "$DIDSETSID" -a -z "$INVOCATION_ID" ]; then | |
export DIDSETSID=1 | |
exec setsid nohup "$0" "$@" </dev/null &>/dev/null | |
exit 1 | |
fi | |
#set -x | |
lcd="$(dirname "$(realpath "$0")")"/lcd.sh | |
# don't hold open dirs or such | |
cd / | |
# line just wraps via careful counting | |
format="+%b %d %H:%M:%S" | |
export lockfile=/run/user/$UID/lcdclock.lock | |
ltouch= | |
cleanup() { | |
"$lcd" -clear -white -brightness 255 -off | |
if [ -n "$ltouch" ]; then | |
kill $ltouch | |
fi | |
} | |
if ! lockfile-create --use-pid --retry 0 --lock-name $lockfile &>/dev/null ; then | |
[ ! -t 0 ] || echo "Cannot get lock" | |
exit 1 | |
fi | |
lfpid=$BASHPID | |
trap cleanup EXIT | |
lockfile-touch --lock-name $lockfile & | |
ltouch=$! | |
sleep= | |
#shorthost="${HOSTNAME:-$(hostname -s)}" | |
#shorthost="$(printf "%-7s" "${shorthost:0:7}")" | |
for ((i=1;;++i)); do | |
[ "$sleep" ] && sleep $sleep | |
# don't stomp on other lcd usage | |
if false ; then | |
sleep=10 | |
i=0 | |
continue | |
fi | |
sleep=0.25 | |
if [ $i -eq 1 -o $i -gt 300 ]; then | |
[ $i -gt 1 ] && i=0 | |
# reset lcd after stolen or every 5 minutes in case it's messed up | |
# if this fails, retry lcd cleanup on next round | |
"$lcd" -testdev -clear -on -white -brightness 3 -powermode -font loadbars || { | |
i=0 | |
continue | |
} | |
fi | |
lcd.sh -testdev -gohome -msg "$(date "$format")" -loadbar 16 || i=0 | |
if [ $((i % 4)) -eq 0 ] && ! lockfile-check --use-pid --lock-name $lockfile || [ "$(<$lockfile)" != "$lfpid" ] ; then | |
[ ! -t 0 ] || echo "Another instance stole our lock!" | |
exit 1 | |
fi | |
done |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
bmax=3 | |
gmod=60 | |
ymod=30 | |
rmod=15 | |
gmax=$gmod | |
ymax=$((gmod + ymod)) | |
zero=$(date +%s) | |
lnow=-1 | |
lnows=-1 | |
lcolor=null | |
fmod=0 | |
while true ; do | |
now=$(($(date +%s) - zero)) | |
if [ $now -lt $gmax ]; then | |
color=green | |
mod=$gmod | |
elif [ $now -lt $ymax ]; then | |
color=yellow | |
mod=$ymod | |
else | |
color=red | |
mod=$rmod | |
fi | |
nows=$((now % mod)) | |
bmod=$((fmod % 2)) | |
if [ $nows -eq 0 -a $lnows -ne $nows ]; then | |
[ $lcolor = null ] || echo | |
echo -n "$color " | |
lcolor=$color | |
fi | |
if [ $nows -lt $bmax ]; then | |
if [ $bmod -eq 0 ] ; then | |
lcd.sh -$color -brightness 255 | |
else | |
lcd.sh -white -brightness 3 | |
fi | |
elif [ $nows -eq $bmax ]; then | |
lcd.sh -white -brightness 3 | |
fi | |
if [ $lnow -ne $now ]; then | |
p=. | |
else | |
p= | |
fi | |
if read -t 0.3 -p "$p" ; then | |
zero=$(date +%s) | |
fmod=0 | |
else | |
let fmod+=1 | |
fi | |
lnow=$now | |
lnows=$nows | |
done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment