#!/bin/sh
# Alpine 5G Router – modem status via AT commands (AT_COMMANDS_REFERENCE.md)
# Outputs JSON. Used by Web GUI /api/status.
# Rev: 3  (see REVISION in repo root)

CONFIG="/etc/5g-router.conf"
AT_PORT="${AT_PORT:-/dev/ttyUSB1}"
AT_LOCK="/var/lock/5g-at.lock"
[ -f "$CONFIG" ] && . "$CONFIG" || true

# Acquire exclusive lock on AT port to avoid conflicts with connect-5g.sh
exec 9>"$AT_LOCK"
flock -w 10 9 || { echo '{"error":"AT port busy"}'; exit 1; }

get_at() {
    _cmd="$1"
    _wait="${2:-1}"
    timeout $((_wait + 2)) sh -c "
        [ -c \"$AT_PORT\" ] || exit 1
        cat $AT_PORT 2>/dev/null &
        _p=\$!
        sleep 0.3
        echo -e '${_cmd}\r' > $AT_PORT
        sleep $_wait
        kill \$_p 2>/dev/null
    " 2>/dev/null
}

json_str() { printf '"%s"' "$(echo "$1" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\r//g' | tr '\n' ' ')"; }

# Probe port: send AT, return 0 if we see OK
try_at_port() {
    _port="$1"
    [ ! -c "$_port" ] && return 1
    _out=$(timeout 4 sh -c "
        cat $_port 2>/dev/null &
        _p=\$!
        sleep 0.3
        echo -e 'AT\r' > $_port
        sleep 1
        kill \$_p 2>/dev/null
    " 2>/dev/null)
    echo "$_out" | grep -q 'OK' && return 0 || return 1
}

# Use configured port if it exists and is a char device; else try common Fibocom AT ports
if [ ! -c "$AT_PORT" ]; then
    for p in /dev/ttyUSB0 /dev/ttyUSB1 /dev/ttyUSB2; do
        if try_at_port "$p"; then
            AT_PORT="$p"
            break
        fi
    done
fi

[ ! -c "$AT_PORT" ] && echo '{}' && exit 0

# Disable command echo so we get only response lines (ATE0); avoids parsing "AT+CGMI" as manufacturer
get_at "ATE0" 1 >/dev/null 2>&1
sleep 0.2

# Query AT commands (reference: AT_COMMANDS_REFERENCE.md)
r_cgmi=$(get_at "AT+CGMI" 1)
r_cgmm=$(get_at "AT+CGMM" 1)
r_cgmr=$(get_at "AT+CGMR" 1)
r_cgsn=$(get_at "AT+CGSN" 1)
r_csq=$(get_at "AT+CSQ" 1)
r_creg=$(get_at "AT+CREG?" 1)
r_cereg=$(get_at "AT+CEREG?" 1)
r_usbmode=$(get_at "AT+GTUSBMODE?" 1)
r_ccid=$(get_at "AT+CCID" 1)
r_cops=$(get_at "AT+COPS?" 1)
r_cgpaddr=$(get_at "AT+CGPADDR=1" 1)

# Parse (skip echoed command lines: lines starting with AT or +)
manufacturer=$(echo "$r_cgmi" | grep -vE '^AT|^\+' | grep -oE '^[A-Za-z0-9 ].*' | head -1 | sed 's/\r$//; s/^ *//; s/ *$//')
model=$(echo "$r_cgmm" | grep -vE '^AT|^\+' | grep -oE '^[A-Za-z0-9\-].*' | head -1 | sed 's/\r$//; s/^ *//; s/ *$//')
revision=$(echo "$r_cgmr" | grep -vE '^(AT|OK|\+)' | head -1 | sed 's/\r$//; s/^ *//; s/ *$//')
imei=$(echo "$r_cgsn" | grep -oE '[0-9]{15}' | head -1)
csq=$(echo "$r_csq" | grep "+CSQ:" | grep -oE '[0-9]+' | head -1)
creg=$(echo "$r_creg" | grep "+CREG:" | head -1)
cereg=$(echo "$r_cereg" | grep "+CEREG:" | head -1)
usb_mode=$(echo "$r_usbmode" | grep "+GTUSBMODE:" | grep -oE '[0-9]+' | head -1)
iccid=$(echo "$r_ccid" | grep "+CCID:" | sed 's/+CCID:[[:space:]]*//; s/\r$//; s/"//g' | head -1)
cops=$(echo "$r_cops" | grep "+COPS:" | sed 's/+COPS:[[:space:]]*//; s/\r$//' | head -1)
modem_ip=$(echo "$r_cgpaddr" | grep "+CGPADDR:" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -1)

# Registration: CREG 0,1 = registered home, 0,5 = registered roaming; CEREG same
creg_status=""
case "$creg" in *",1"*) creg_status="registered_home";; *",5"*) creg_status="registered_roaming";; *",2"*) creg_status="searching";; *",0"*) creg_status="not_registered";; *) creg_status="unknown";; esac
cereg_status=""
case "$cereg" in *",1"*) cereg_status="registered_home";; *",5"*) cereg_status="registered_roaming";; *",2"*) cereg_status="searching";; *",0"*) cereg_status="not_registered";; *) cereg_status="unknown";; esac

# Operator name from +COPS: 0,0,"Vodafone",7
operator_name=$(echo "$cops" | sed -n 's/.*"\([^"]*\)".*/\1/p')

# Build JSON (no jq)
printf '{\n'
printf '  "at_port": '; json_str "$AT_PORT"; printf ',\n'
printf '  "manufacturer": '; json_str "${manufacturer:-}"; printf ',\n'
printf '  "model": '; json_str "${model:-}"; printf ',\n'
printf '  "revision": '; json_str "${revision:-}"; printf ',\n'
printf '  "imei": '; json_str "${imei:-}"; printf ',\n'
printf '  "signal_csq": %s,\n' "${csq:-null}"
printf '  "creg_status": '; json_str "$creg_status"; printf ',\n'
printf '  "cereg_status": '; json_str "$cereg_status"; printf ',\n'
printf '  "usb_mode": '; json_str "${usb_mode:-}"; printf ',\n'
printf '  "iccid": '; json_str "${iccid:-}"; printf ',\n'
printf '  "operator": '; json_str "${operator_name:-}"; printf ',\n'
printf '  "modem_ip": '; json_str "${modem_ip:-}"; printf '\n'
printf '}\n'
