Last active
June 15, 2025 04:15
-
-
Save Geofferey/f329280729a469cb44cfa711ba9651ff to your computer and use it in GitHub Desktop.
Grabs location data from gps_cli utility available on Novatel Hotspots and Similar and converts to CoT for use with ATAK input
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 | |
PATH=/data/bin:/bin:/sbin:/usr/bin:/usr/sbin:/opt/nvtl/bin:/opt/nvtl/data/branding/bin | |
LD_LIBRARY_PATH=/opt/nvtl/lib:/opt/nvtl/data/branding/lib | |
SCRIPT=$(basename "$0") | |
CURRENT_PID=$$ | |
DNS_REC_HOST="" | |
gps_cli set_privacy 1 >> /dev/null 2>&1 | |
gps_cli gps_start >> /dev/null 2>&1 | |
if ! [ -d /data/bin ]; then | |
mkdir /data/bin | |
fi | |
if ! [ -e /data/bin/git-bins ]; then | |
wget --directory-prefix=/data/bin/ https://gist.githubusercontent.com/Geofferey/39db654c2916c95d2fe30e6abbc464b0/raw/git-bins | |
chmod +x /data/bin/git-bins | |
fi | |
if ! [ -e /data/bin/s6-dnstxt ]; then | |
git-bins s6-dnstxt | |
fi | |
if ! [ -e /data/bin/netcat ]; then | |
git-bins netcat | |
fi | |
if ! [ -e /data/bin/bc ]; then | |
git-bins bc | |
fi | |
DNS_TXT_HOST=$(s6-dnstxt host."${DNS_REC_HOST}" | txtdec) | |
#DNS_TXT_HOST=$(s6-dnstxt host."${DNS_REC_HOST}" | cut -d '"' -f2) | |
DNS_TXT_PORT=$(s6-dnstxt port."${DNS_REC_HOST}" | txtdec) | |
#DNS_TXT_PORT=$(s6-dnstxt port."${DNS_REC_HOST}" | cut -d '"' -f2) | |
if [ -z "${1}" ] || [ -z "${2}" ]; then | |
HOST=${DNS_TXT_HOST} | |
PORT=${DNS_TXT_PORT} | |
else | |
HOST="${1}" | |
PORT="${2}" | |
fi | |
if [ -n "${INTERVAL}" ]; then | |
BASE_INTERVAL="${INTERVAL}" | |
elif [ -z "${INTERVAL}" ]; then | |
BASE_INTERVAL=$(s6-dnstxt interval."${DNS_REC_HOST}" | txtdec) | |
C2_INTERVAL="1" | |
else | |
INTERVAL=60 | |
fi | |
# Kill previous copies | |
for PID in $(pgrep -f "${SCRIPT}"); do | |
if [ "${PID}" != "${CURRENT_PID}" ]; then | |
kill "${PID}" >> /dev/null 2>&1 | |
sleep 10 | |
fi | |
done | |
DEFAULT_TYPE="\"a-n-G-E-S\"" | |
START_TIME="\"$(date -u +"%Y-%m-%dT%H:%M:%SZ")\"" | |
ICCID="\"$(modem2_cli sim_get_iccid | grep -w "iccid :" | cut -d ' ' -f3)\"" | |
IMSI="\"$(modem2_cli get_imsi | grep -w "imsi :" | cut -d ':' -f2 | cut -d ' ' -f2)\"" | |
TYPE=${TYPE:-$DEFAULT_TYPE} | |
echo "${HOST} ${PORT}" | |
if [ -z "${UDP}" ]; then | |
coproc NETCAT { netcat ${HOST} ${PORT}; } | |
else | |
coproc NETCAT { nc -u "${HOST}" "${PORT}"; } | |
fi | |
if [ -z "${NETCAT_PID}" ]; then | |
echo "Failed to create TCP connection to $HOST:$PORT" | |
exit 1 | |
fi | |
trap 'echo "Caught termination signal, cleaning up..."; kill ${NETCAT_PID} 2>/dev/null; exit 0' SIGINT SIGTERM | |
# Haversine formula (km) | |
haversine() { | |
local lat1=$1 lon1=$2 lat2=$3 lon2=$4 R=6371 | |
lat1=$(echo "$lat1 * 0.0174533" | bc -l) | |
lon1=$(echo "$lon1 * 0.0174533" | bc -l) | |
lat2=$(echo "$lat2 * 0.0174533" | bc -l) | |
lon2=$(echo "$lon2 * 0.0174533" | bc -l) | |
local dlat=$(echo "$lat2 - $lat1" | bc -l) | |
local dlon=$(echo "$lon2 - $lon1" | bc -l) | |
local a=$(echo "s($dlat/2)^2 + c($lat1)*c($lat2)*s($dlon/2)^2" | bc -l) | |
local c=$(echo "2*a(1)*a(sqrt($a)/sqrt(1-$a))" | bc -l) | |
echo "$(echo "$R * $c" | bc -l)" | |
} | |
# Loop init | |
INTERVAL=${BASE_INTERVAL} | |
FIRSTSHOT="" | |
PREV_LAT="" | |
PREV_LON="" | |
PREV_TIME="" | |
IDLE_COUNT=0 | |
IDLE_THRESH=10 | |
while true; do | |
if ! [ -z "C2_INTERVAL" ]; then | |
BASE_INTERVAL=$(s6-dnstxt interval."${DNS_REC_HOST}" | txtdec) | |
fi | |
now_ts=$(date +%s) | |
CURRENT_TIME="\"$(date -u +"%Y-%m-%dT%H:%M:%SZ")\"" | |
STALE_TIME="\"$(date -u -d "@$((now_ts + 600))" +"%Y-%m-%dT%H:%M:%SZ")\"" | |
GPS_OUTPUT=$(gps_cli get_last_fix) | |
LATITUDE="\"$(echo "$GPS_OUTPUT" | grep latitude: | cut -d '[' -f2 | cut -d ']' -f1 | tr -d ' ')\"" | |
LONGITUDE="\"$(echo "$GPS_OUTPUT" | grep longitude: | cut -d '[' -f2 | cut -d ']' -f1 | tr -d ' ')\"" | |
HAE="\"$(echo "$GPS_OUTPUT" | grep -w "alt_ellipsoid:" | cut -d '[' -f2 | cut -d ']' -f1)\"" | |
CE="\"$(echo "$GPS_OUTPUT" | grep -w "horiz_unc_cir:" | cut -d '[' -f2 | cut -d ']' -f1)\"" | |
LE="\"$(echo "$GPS_OUTPUT" | grep -w "vertical_unc:" | cut -d '[' -f2 | cut -d ']' -f1)\"" | |
#COURSE="\"$(echo "$GPS_OUTPUT" | grep -w "heading:" | cut -d '[' -f2 | cut -d ']' -f1)\"" | |
LAT_RAW=$(echo "${LATITUDE}" | tr -d '"') | |
LON_RAW=$(echo "${LONGITUDE}" | tr -d '"') | |
if [ -n "${PREV_LAT}" ] && [ -n "${PREV_LON}" ] && [ -n "${PREV_TIME}" ]; then | |
TIME_DIFF=$(echo "$(date +%s) - ${PREV_TIME}" | bc) | |
if [ "${TIME_DIFF}" -gt 0 ]; then | |
DISTANCE=$(haversine "${PREV_LAT}" "${PREV_LON}" "${LAT_RAW}" "${LON_RAW}") | |
SPEED_KMH=$(echo "${DISTANCE} / ${TIME_DIFF} * 3600" | bc -l) | |
# reset idle count on movement | |
if [ "$(echo "${SPEED_KMH} > 6" | bc -l)" -eq 1 ]; then | |
IDLE_COUNT=0 | |
else | |
IDLE_COUNT=$((IDLE_COUNT + 1)) | |
fi | |
# dynamic interval thresholds | |
if [ "$(echo "${SPEED_KMH} > 60" | bc -l)" -eq 1 ]; then | |
INTERVAL=0.1 | |
elif [ "$(echo "${SPEED_KMH} > 40" | bc -l)" -eq 1 ]; then | |
INTERVAL=3 | |
elif [ "$(echo "${SPEED_KMH} > 6" | bc -l)" -eq 1 ]; then | |
INTERVAL=5 | |
else | |
# back-off: only use base interval after threshold | |
if [ ${IDLE_COUNT} -ge ${IDLE_THRESH} ]; then | |
INTERVAL=${BASE_INTERVAL} | |
fi | |
fi | |
fi | |
fi | |
PREV_LAT=${LAT_RAW} | |
PREV_LON=${LON_RAW} | |
PREV_TIME=$(date +%s) | |
XML="<event version=\"2.0\" uid=${ICCID} type=${TYPE} time=${CURRENT_TIME} start=${START_TIME} stale=${STALE_TIME} how=\"m-g\"><point lat=${LATITUDE} lon=${LONGITUDE} hae=${HAE} ce=${CE} le=${LE}/><detail><contact callsign=${IMSI}/></detail></event>" | |
if [ -z "${FIRSTSHOT}" ]; then | |
printf "%s" "$XML" >&"${NETCAT[1]}" | |
sleep 1 | |
fi | |
FIRSTSHOT=1 | |
if [ -n "${DEBUG}" ]; then | |
echo -e " | |
${XML} | |
" | |
fi | |
if ! printf "%s" "${XML}" >&"${NETCAT[1]}"; then | |
if ! [ -z ${1} ]; then | |
${SCRIPT} ${1} ${2} & | |
exit 1 | |
else | |
${SCRIPT} & | |
exit 1 | |
fi | |
fi | |
if [ -n "${ONESHOT}" ]; then | |
break | |
fi | |
if [ "${INTERVAL}" -eq "${BASE_INTERVAL}" ] && [ ! -z "${POWERSAVE}" ]; then | |
gps_cli enable_powersave_mode 1 >> /dev/null 2>&1 | |
gps_cli set_privacy 0 >> /dev/null 2>&1 | |
fi | |
gps_cli enable_powersave_mode 1 >> /dev/null 2>&1 | |
sleep "${INTERVAL}" | |
gps_cli set_privacy 1 >> /dev/null 2>&1 & | |
sleep 0.1 | |
gps_cli gps_start >> /dev/null 2>&1 & | |
sleep 0.1 | |
gps_cli enable_powersave_mode 0 >> /dev/null 2>&1 & | |
done | |
exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment