Skip to content

Instantly share code, notes, and snippets.

@jigpu
Created December 19, 2020 20:11
Show Gist options
  • Save jigpu/71fe9205dc2b465a6b7fc35c13cf06c5 to your computer and use it in GitHub Desktop.
Save jigpu/71fe9205dc2b465a6b7fc35c13cf06c5 to your computer and use it in GitHub Desktop.
Raspberry Pi Bluetooth Watchdog / Reset
#!/bin/sh
# Force a reset of the Bluetooth interface if it freezes up.
#
# https://github.com/raspberrypi/linux/issues/2832#issuecomment-597001597
if test $(id -u) -ne 0; then
echo "This script must be run as root."
exit 1
fi
killall hciattach
sleep 2
if grep -a Zero /proc/device-tree/model; then
raspi-gpio set 45 op dl
sleep 1
raspi-gpio set 45 op dh
else
/opt/vc/bin/vcmailbox 0x38041 8 8 128 0
sleep 1
/opt/vc/bin/vcmailbox 0x38041 8 8 128 1
fi
sleep 4
btuart
[Unit]
Description=Montor and reset the Bluetooth interface if it dies
[Service]
Type=simple
ExecStart=/usr/local/bin/btwatchdog.sh
[Install]
WantedBy=multi-user.target
#!/usr/bin/env bash
# Monitor the Bluetooth clock for hiccups. If we see it act
# strangely (e.g. get stuck at 0 or jump by a large amount)
# for some reason, trigger a reset
#
# Relies on the presence of /usr/local/bin/btreset.sh
# May be run as a systemd service with btwatchdog.service
function gettime {
printf "%d\n" $(hcitool clock | awk '/Clock/{print $2}')
}
function difftime {
CLOCK_MAXIMUM=536870912
OLD=$1
NEW=$2
DELTA=$((${2} - ${1}))
if [[ ${DELTA} -lt 0 ]]; then
DELTA=$((${DELTA} + ${CLOCK_MAXIMUM}))
fi
echo ${DELTA}
}
function clock2sec {
CLOCK_RATE=3200
TIME=$1
echo $((${TIME} / ${CLOCK_RATE}))
}
SLEEP_SECONDS=10
FAIL_COUNT=0
TIME_NOW=$(gettime)
while true; do
sleep ${SLEEP_SECONDS}
TIME_OLD=${TIME_NOW}
# Check how much time elapsed on the BT clock
TIME_NOW=$(gettime)
DELTA_T=$(difftime "${TIME_OLD}" "${TIME_NOW}")
DELTA_S=$(clock2sec "${DELTA_T}")
# If no time passed, something is wrong...
if [[ "${DELTA_S}" -eq 0 || "${DELTA_S}" -gt $((2*${SLEEP_SECONDS})) ]]; then
FAIL_COUNT=$((${FAIL_COUNT} + 1))
echo "Encountered failure ${FAIL_COUNT}"
elif [[ "${FAIL_COUNT}" -gt 0 ]]; then
echo "Clock started back up. Resetting failure count."
FAIL_COUNT=0
fi
# If we keep hitting failures, just reset the
# device and hope it fixes itself.
if [[ "${FAIL_COUNT}" -ge 5 ]]; then
echo "Resetting device."
/usr/local/bin/btreset.sh
FAIL_COUNT=0
fi
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment