Add web GUI, docs, scripts, and 5G router config
- Web app (Flask): status, config, firewall, logs, users, restart - Docs: AT commands, deploy, DNS, quickstart, web GUI - Scripts: connect, deploy, diag, healthcheck, modem-status, speedtest, status, troubleshoot - Init and iptables: 5g-router, 5g-webgui, rules.v4 - CHANGELOG, TODO, REVISION; config and README updates
This commit is contained in:
168
scripts/connect-5g.sh
Normal file
168
scripts/connect-5g.sh
Normal file
@@ -0,0 +1,168 @@
|
||||
#!/bin/sh
|
||||
# Alpine 5G Router – connection script (run by 5g-router service or manually)
|
||||
# Uses /etc/5g-router.conf if present. Supports watchdog and failover.
|
||||
# Rev: 2 (see REVISION in repo root)
|
||||
|
||||
set -e
|
||||
|
||||
CONFIG="/etc/5g-router.conf"
|
||||
LOG_FILE="/var/log/5g-router.log"
|
||||
|
||||
# Defaults
|
||||
AT_PORT="/dev/ttyUSB1"
|
||||
APN="internet"
|
||||
WAN_IF="eth1"
|
||||
LAN_IF="eth0.100"
|
||||
FAILOVER_ENABLED="no"
|
||||
FAILOVER_IF="eth0"
|
||||
FAILOVER_METRIC="202"
|
||||
WATCHDOG_INTERVAL="0"
|
||||
LOG_SIGNAL="yes"
|
||||
WEAK_SIGNAL_CSQ="10"
|
||||
|
||||
[ -f "$CONFIG" ] && . "$CONFIG"
|
||||
|
||||
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE" 2>/dev/null || echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"; }
|
||||
|
||||
# Fix broken /dev/ttyUSB* node (if it is a regular file instead of char device - e.g. after modem reconnect)
|
||||
fix_ttyusb_if_needed() {
|
||||
case "$AT_PORT" in
|
||||
/dev/ttyUSB[0-9]*) ;;
|
||||
*) return 0 ;;
|
||||
esac
|
||||
[ ! -e "$AT_PORT" ] && return 0
|
||||
if [ -f "$AT_PORT" ] && [ ! -c "$AT_PORT" ]; then
|
||||
_num="${AT_PORT#/dev/ttyUSB}"
|
||||
log "Fixing $AT_PORT (was regular file, recreating as char device)"
|
||||
rm -f "$AT_PORT"
|
||||
mknod "$AT_PORT" c 188 "$_num"
|
||||
chmod 660 "$AT_PORT"
|
||||
chown root:dialout "$AT_PORT" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
get_at_response() {
|
||||
_cmd="$1"
|
||||
_wait="${2:-2}"
|
||||
timeout $((_wait + 4)) sh -c "
|
||||
cat $AT_PORT 2>/dev/null &
|
||||
_pid=\$!
|
||||
sleep 0.5
|
||||
echo \"${_cmd}\r\" > $AT_PORT
|
||||
sleep $_wait
|
||||
kill \$_pid 2>/dev/null
|
||||
" 2>&1
|
||||
}
|
||||
|
||||
wait_for_modem() {
|
||||
log "Waiting for modem AT port..."
|
||||
for _i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
|
||||
fix_ttyusb_if_needed
|
||||
if [ -c "$AT_PORT" ]; then
|
||||
log "Modem AT port available"
|
||||
return 0
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
log "Modem AT port not available"
|
||||
return 1
|
||||
}
|
||||
|
||||
check_usb_mode() {
|
||||
if lsusb 2>/dev/null | grep -q "0e8d:7127"; then
|
||||
log "WARN: Modem is in Mode 41 (7127). AT commands may not work. Reboot or power-cycle modem."
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
do_connect() {
|
||||
# eth1 (RNDIS) does NOT provide DHCP. We get IP (and DNS) only via AT commands
|
||||
# and configure the interface manually. Do not run dhclient on eth1.
|
||||
check_usb_mode || return 1
|
||||
# Modem can take 3–5s to respond after boot; use 5s so service (started at boot) gets OK
|
||||
get_at_response "AT" 5 | grep -q "OK" || { log "AT not OK (try longer wait or different AT port)"; return 1; }
|
||||
|
||||
# Signal (optional log)
|
||||
_resp=$(get_at_response "AT+CSQ" 1)
|
||||
_csq=$(echo "$_resp" | grep "+CSQ:" | grep -oE '[0-9]+' | head -1)
|
||||
[ -n "$_csq" ] && [ "$LOG_SIGNAL" = "yes" ] && echo "$(date -Iseconds) CSQ=$_csq" >> "$LOG_FILE" 2>/dev/null || true
|
||||
[ -n "$_csq" ] && [ -n "$WEAK_SIGNAL_CSQ" ] && [ "$WEAK_SIGNAL_CSQ" -gt 0 ] && [ "$_csq" -lt "$WEAK_SIGNAL_CSQ" ] && log "WARN weak signal CSQ=$_csq"
|
||||
|
||||
log "Configuring APN: $APN"
|
||||
get_at_response "AT+CGDCONT=1,\"IP\",\"$APN\"" 2 | grep -q "OK" || true
|
||||
log "Activating PDP context..."
|
||||
get_at_response "AT+CGACT=1,1" 3 | grep -qE "(OK|CGEV)" || true
|
||||
|
||||
_ip=""
|
||||
for _retry in 1 2 3 4 5; do
|
||||
_resp=$(get_at_response "AT+CGPADDR=1" 2)
|
||||
_ip=$(echo "$_resp" | grep "+CGPADDR:" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -1)
|
||||
[ -n "$_ip" ] && break
|
||||
[ $_retry -lt 5 ] && log "No IP yet, retry $_retry/5 in 3s..." && sleep 3
|
||||
done
|
||||
[ -z "$_ip" ] && log "Could not get modem IP (check signal/registration: AT+CSQ, AT+CEREG?)" && return 1
|
||||
|
||||
# Get DNS from modem (AT+CGCONTRDP=1); modem does not provide DHCP, only IP/DNS via AT
|
||||
_dns1=""; _dns2=""
|
||||
_contrdp=$(get_at_response "AT+CGCONTRDP=1" 2)
|
||||
_allips=""
|
||||
for _a in $(echo "$_contrdp" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+'); do
|
||||
[ "$_a" = "$_ip" ] && continue
|
||||
_allips="${_allips} ${_a}"
|
||||
done
|
||||
for _a in $_allips; do [ -z "$_a" ] && continue; _dns2="$_dns1"; _dns1="$_a"; done
|
||||
[ -z "$_dns1" ] && [ -n "$DNS_SERVERS" ] && _dns1=$(echo "$DNS_SERVERS" | cut -d',' -f1 | tr -d ' ') && _dns2=$(echo "$DNS_SERVERS" | cut -d',' -f2 | tr -d ' ')
|
||||
if [ -n "$_dns1" ]; then
|
||||
: > /etc/resolv.conf
|
||||
echo "nameserver $_dns1" >> /etc/resolv.conf
|
||||
[ -n "$_dns2" ] && echo "nameserver $_dns2" >> /etc/resolv.conf
|
||||
log "DNS set (from modem or config)"
|
||||
fi
|
||||
|
||||
log "Configuring $WAN_IF with IP $_ip (no DHCP - from AT+CGPADDR=1)"
|
||||
ip link set "$WAN_IF" up 2>/dev/null || true
|
||||
ip addr flush dev "$WAN_IF" 2>/dev/null || true
|
||||
ip addr add "$_ip/32" dev "$WAN_IF"
|
||||
ip route add default dev "$WAN_IF" metric 50 2>/dev/null || true
|
||||
log "Interface configured"
|
||||
|
||||
log "Setting up NAT..."
|
||||
echo 1 > /proc/sys/net/ipv4/ip_forward
|
||||
iptables -t nat -C POSTROUTING -o "$WAN_IF" -j MASQUERADE 2>/dev/null || iptables -t nat -A POSTROUTING -o "$WAN_IF" -j MASQUERADE
|
||||
iptables -C FORWARD -i "$LAN_IF" -o "$WAN_IF" -j ACCEPT 2>/dev/null || iptables -A FORWARD -i "$LAN_IF" -o "$WAN_IF" -j ACCEPT
|
||||
iptables -C FORWARD -i "$WAN_IF" -o "$LAN_IF" -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || iptables -A FORWARD -i "$WAN_IF" -o "$LAN_IF" -m state --state RELATED,ESTABLISHED -j ACCEPT
|
||||
log "NAT configured"
|
||||
return 0
|
||||
}
|
||||
|
||||
do_failover() {
|
||||
[ "$FAILOVER_ENABLED" != "yes" ] && return 0
|
||||
# Ensure there is a default route via failover interface (higher metric so 5G wins when up)
|
||||
ip route add default dev "$FAILOVER_IF" metric "$FAILOVER_METRIC" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# Main
|
||||
run_once() {
|
||||
wait_for_modem || { do_failover; return 1; }
|
||||
if do_connect; then
|
||||
log "5G connection successful!"
|
||||
return 0
|
||||
else
|
||||
do_failover
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
if [ -n "$WATCHDOG_INTERVAL" ] && [ "$WATCHDOG_INTERVAL" -gt 0 ]; then
|
||||
log "Starting 5G connection (watchdog every ${WATCHDOG_INTERVAL}s)..."
|
||||
while true; do
|
||||
run_once || true
|
||||
sleep "$WATCHDOG_INTERVAL"
|
||||
done
|
||||
else
|
||||
log "Starting 5G connection..."
|
||||
run_once || true
|
||||
log "Holding process for service (stop with: service 5g-router stop)."
|
||||
exec sleep infinity
|
||||
fi
|
||||
47
scripts/deploy.sh
Executable file
47
scripts/deploy.sh
Executable file
@@ -0,0 +1,47 @@
|
||||
#!/bin/sh
|
||||
# Alpine 5G Router – deploy/update device from this repo
|
||||
# Run from repo root: ./scripts/deploy.sh [user@host]
|
||||
# Or: TARGET=root@192.168.1.1 ./scripts/deploy.sh
|
||||
#
|
||||
# Copies etc/, scripts/, web/, configure_fm350_5g.sh to the device,
|
||||
# runs install.sh there, then restarts 5g-router and 5g-webgui.
|
||||
|
||||
set -e
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
TARGET="${1:-${TARGET:-root@10.130.60.121}}"
|
||||
REMOTE_DIR="/tmp/Alpine_5G"
|
||||
SSH_OPTS="${SSH_OPTS:--o ConnectTimeout=10}"
|
||||
|
||||
echo "Deploying Alpine 5G Router to $TARGET"
|
||||
echo " Repo root: $ROOT"
|
||||
echo " Remote dir: $REMOTE_DIR"
|
||||
echo ""
|
||||
|
||||
# Copy files to device
|
||||
echo "[1/3] Copying files to $TARGET:$REMOTE_DIR ..."
|
||||
ssh $SSH_OPTS "$TARGET" "mkdir -p $REMOTE_DIR"
|
||||
scp $SSH_OPTS -r "$ROOT/etc" "$ROOT/scripts" "$ROOT/configure_fm350_5g.sh" "$TARGET:$REMOTE_DIR/"
|
||||
if [ -d "$ROOT/web" ] && [ -f "$ROOT/web/app.py" ]; then
|
||||
scp $SSH_OPTS -r "$ROOT/web" "$TARGET:$REMOTE_DIR/"
|
||||
fi
|
||||
echo " Done."
|
||||
echo ""
|
||||
|
||||
# Run install on device
|
||||
echo "[2/3] Running install.sh on device ..."
|
||||
ssh $SSH_OPTS "$TARGET" "cd $REMOTE_DIR && chmod +x scripts/*.sh 2>/dev/null; chmod +x etc/init.d/* 2>/dev/null; ./scripts/install.sh"
|
||||
echo ""
|
||||
|
||||
# Restart services to pick up changes
|
||||
echo "[3/3] Restarting services ..."
|
||||
ssh $SSH_OPTS "$TARGET" "
|
||||
service 5g-router restart 2>/dev/null || true
|
||||
service 5g-webgui restart 2>/dev/null || true
|
||||
echo ' Done.'
|
||||
"
|
||||
|
||||
echo ""
|
||||
echo "Deployment complete. Device: $TARGET"
|
||||
echo " Web GUI: http://<device-ip>:5000"
|
||||
echo " SSH: ssh $TARGET"
|
||||
92
scripts/diag-at-port.sh
Normal file
92
scripts/diag-at-port.sh
Normal file
@@ -0,0 +1,92 @@
|
||||
#!/bin/sh
|
||||
# Alpine 5G Router – AT port diagnostic (run on device to debug “No modem AT data”)
|
||||
# Rev: 1 (see REVISION in repo root)
|
||||
# Usage: ./diag-at-port.sh or /usr/local/bin/diag-at-port.sh
|
||||
|
||||
CONFIG="/etc/5g-router.conf"
|
||||
AT_PORT="${AT_PORT:-/dev/ttyUSB1}"
|
||||
[ -f "$CONFIG" ] && . "$CONFIG"
|
||||
|
||||
echo "=== Alpine 5G Router – AT port diagnostic ==="
|
||||
echo ""
|
||||
|
||||
# 1) User and permissions
|
||||
echo "--- User & groups ---"
|
||||
echo "User: $(id -un) (uid=$(id -u) gid=$(id -g))"
|
||||
echo "Groups: $(id -Gn)"
|
||||
if id -Gn | grep -q dialout; then
|
||||
echo "dialout: YES (can access serial ports)"
|
||||
else
|
||||
echo "dialout: NO – add user to dialout: adduser <user> dialout"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 2) Serial devices
|
||||
echo "--- Serial devices ---"
|
||||
for d in /dev/ttyUSB* /dev/ttyACM*; do
|
||||
[ -e "$d" ] || continue
|
||||
ls -la "$d" 2>/dev/null
|
||||
done
|
||||
if ! ls /dev/ttyUSB* /dev/ttyACM* 2>/dev/null | grep -q .; then
|
||||
echo "No /dev/ttyUSB* or /dev/ttyACM* found. Modem may not be in USB mode 40 or not bound."
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 3) Modem USB
|
||||
echo "--- Modem (lsusb) ---"
|
||||
lsusb 2>/dev/null | grep -i fibocom || echo "No Fibocom device in lsusb"
|
||||
lsusb 2>/dev/null | grep -i "0e8d" || true
|
||||
echo ""
|
||||
|
||||
# 4) Config
|
||||
echo "--- Config ---"
|
||||
echo "AT_PORT from config: $AT_PORT"
|
||||
if [ -c "$AT_PORT" ]; then
|
||||
echo " -> exists and is a character device"
|
||||
else
|
||||
echo " -> missing or not a character device"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 5) Raw AT probe on each ttyUSB
|
||||
echo "--- Raw AT probe (send AT, show response) ---"
|
||||
for port in /dev/ttyUSB0 /dev/ttyUSB1 /dev/ttyUSB2 /dev/ttyUSB3; do
|
||||
[ -c "$port" ] || continue
|
||||
echo "Port $port:"
|
||||
out=$(timeout 4 sh -c "
|
||||
cat $port 2>/dev/null &
|
||||
_p=\$!
|
||||
sleep 0.3
|
||||
echo -e 'AT\r' > $port 2>/dev/null
|
||||
sleep 1
|
||||
kill \$_p 2>/dev/null
|
||||
" 2>/dev/null)
|
||||
if echo "$out" | grep -q 'OK'; then
|
||||
echo " -> OK (modem responded)"
|
||||
else
|
||||
echo " -> no OK in response (raw below)"
|
||||
fi
|
||||
echo "$out" | head -5 | sed 's/^/ /'
|
||||
echo ""
|
||||
done
|
||||
if ! ls /dev/ttyUSB* 2>/dev/null | grep -q .; then
|
||||
echo "No ttyUSB devices to probe."
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 6) modem-status-at.sh if present
|
||||
echo "--- modem-status-at.sh ---"
|
||||
if [ -x "/usr/local/bin/modem-status-at.sh" ]; then
|
||||
echo "Running: /usr/local/bin/modem-status-at.sh"
|
||||
out=$(timeout 20 /usr/local/bin/modem-status-at.sh 2>&1)
|
||||
code=$?
|
||||
echo "Exit code: $code"
|
||||
echo "$out" | head -15
|
||||
if [ "$code" != 0 ] || echo "$out" | grep -q '^{}$'; then
|
||||
echo "... (no modem JSON or script failed)"
|
||||
fi
|
||||
else
|
||||
echo "Not found at /usr/local/bin/modem-status-at.sh (install with scripts/install.sh)"
|
||||
fi
|
||||
echo ""
|
||||
echo "=== End diagnostic ==="
|
||||
131
scripts/diag-modem-up.sh
Normal file
131
scripts/diag-modem-up.sh
Normal file
@@ -0,0 +1,131 @@
|
||||
#!/bin/sh
|
||||
# Alpine 5G Router – modem/WAN diagnostic (run on device to debug “modem not up”)
|
||||
# Rev: 1 (see REVISION in repo root)
|
||||
# Usage: ./diag-modem-up.sh or /usr/local/bin/diag-modem-up.sh
|
||||
|
||||
CONFIG="/etc/5g-router.conf"
|
||||
WAN_IF="${WAN_IF:-eth1}"
|
||||
AT_PORT="${AT_PORT:-/dev/ttyUSB1}"
|
||||
LOG_FILE="/var/log/5g-router.log"
|
||||
[ -f "$CONFIG" ] && . "$CONFIG"
|
||||
|
||||
echo "=== Alpine 5G Router – modem/WAN diagnostic ==="
|
||||
echo ""
|
||||
|
||||
# 1) Service
|
||||
echo "--- 5g-router service ---"
|
||||
if command -v rc-service >/dev/null 2>&1; then
|
||||
rc-service 5g-router status 2>&1 || true
|
||||
else
|
||||
echo "OpenRC not found; service status skipped"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 2) Config
|
||||
echo "--- Config ($CONFIG) ---"
|
||||
if [ -f "$CONFIG" ]; then
|
||||
echo "WAN_IF=$WAN_IF AT_PORT=$AT_PORT"
|
||||
grep -E '^APN=|^WAN_IF=|^AT_PORT=' "$CONFIG" 2>/dev/null || true
|
||||
else
|
||||
echo "Config file not found (using defaults)"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 3) Modem USB
|
||||
echo "--- Modem (lsusb) ---"
|
||||
MODEM_LINE=$(lsusb 2>/dev/null | grep -i fibocom || lsusb 2>/dev/null | grep "0e8d" || true)
|
||||
if [ -n "$MODEM_LINE" ]; then
|
||||
echo "$MODEM_LINE"
|
||||
if echo "$MODEM_LINE" | grep -q "7127"; then
|
||||
echo " -> Mode 41 (0e8d:7127): AT port may not work; use Mode 40 (0e8d:7126)"
|
||||
elif echo "$MODEM_LINE" | grep -q "7126"; then
|
||||
echo " -> Mode 40 (RNDIS): AT port should be available"
|
||||
fi
|
||||
else
|
||||
echo "No Fibocom / 0e8d device – modem not seen by USB"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 4) WAN interface
|
||||
echo "--- WAN interface ($WAN_IF) ---"
|
||||
if ip link show "$WAN_IF" >/dev/null 2>&1; then
|
||||
ip link show "$WAN_IF"
|
||||
WAN_STATE=$(ip link show "$WAN_IF" 2>/dev/null | grep -oE 'state [A-Z]+' | awk '{print $2}')
|
||||
WAN_IP=$(ip -4 addr show "$WAN_IF" 2>/dev/null | grep -oE 'inet [0-9.]+' | awk '{print $2}')
|
||||
echo " State: $WAN_STATE IP: ${WAN_IP:-none}"
|
||||
if [ "$WAN_STATE" = "DOWN" ]; then
|
||||
echo " -> Interface is DOWN (connect-5g.sh may have failed or not run)"
|
||||
fi
|
||||
if [ -z "$WAN_IP" ]; then
|
||||
echo " -> No IP (PDP not activated or modem did not assign address)"
|
||||
fi
|
||||
else
|
||||
echo " Interface $WAN_IF does not exist (wrong name or modem not bound?)"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 5) Default route
|
||||
echo "--- Default route ---"
|
||||
DEFAULT=$(ip route show default 2>/dev/null | head -1)
|
||||
if [ -n "$DEFAULT" ]; then
|
||||
echo "$DEFAULT"
|
||||
DEF_DEV=$(echo "$DEFAULT" | awk '{print $3}')
|
||||
if [ "$DEF_DEV" != "$WAN_IF" ]; then
|
||||
echo " -> Default is via $DEF_DEV, not $WAN_IF (5G may be down or failover active)"
|
||||
fi
|
||||
else
|
||||
echo " No default route"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 6) AT port
|
||||
echo "--- AT port ($AT_PORT) ---"
|
||||
if [ -c "$AT_PORT" ]; then
|
||||
echo " Exists (character device)"
|
||||
out=$(timeout 4 sh -c "
|
||||
cat $AT_PORT 2>/dev/null &
|
||||
_p=\$!
|
||||
sleep 0.3
|
||||
echo -e 'AT\r' > $AT_PORT 2>/dev/null
|
||||
sleep 1
|
||||
kill \$_p 2>/dev/null
|
||||
" 2>/dev/null)
|
||||
if echo "$out" | grep -q 'OK'; then
|
||||
echo " AT response: OK"
|
||||
else
|
||||
echo " AT response: no OK (raw: $(echo "$out" | head -1))"
|
||||
fi
|
||||
else
|
||||
echo " Not available (missing or not a char device) – connect-5g.sh waits for this"
|
||||
for p in /dev/ttyUSB0 /dev/ttyUSB1 /dev/ttyUSB2; do
|
||||
[ -c "$p" ] && echo " Found: $p"
|
||||
done
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 7) Last log lines
|
||||
echo "--- Last 20 lines of $LOG_FILE ---"
|
||||
if [ -f "$LOG_FILE" ]; then
|
||||
tail -20 "$LOG_FILE" 2>/dev/null | sed 's/^/ /'
|
||||
else
|
||||
echo " Log file not found"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 8) Connectivity
|
||||
echo "--- Connectivity (ping 8.8.8.8) ---"
|
||||
if ping -c 1 -W 3 8.8.8.8 >/dev/null 2>&1; then
|
||||
echo " Reachable (modem/route may be OK)"
|
||||
else
|
||||
echo " Not reachable (WAN down or no default via 5G)"
|
||||
fi
|
||||
echo ""
|
||||
echo "=== End diagnostic ==="
|
||||
echo ""
|
||||
echo "Typical fixes:"
|
||||
echo " - Modem not in lsusb: power-cycle modem or USB; check cable"
|
||||
echo " - Mode 41 (7127): reboot modem or run AT+GTUSBMODE=40 then AT+CFUN=1,1"
|
||||
echo " - AT port missing: wait for modem to expose ttyUSB (can take 30s after boot)"
|
||||
echo " - AT no OK: wrong port – set AT_PORT in $CONFIG (e.g. /dev/ttyUSB0)"
|
||||
echo " - No modem IP: check APN in $CONFIG; check SIM/network registration"
|
||||
echo " - Start connection: service 5g-router start or /usr/local/bin/connect-5g.sh"
|
||||
44
scripts/healthcheck-5g.sh
Normal file
44
scripts/healthcheck-5g.sh
Normal file
@@ -0,0 +1,44 @@
|
||||
#!/bin/sh
|
||||
# Alpine 5G Router – health check for monitoring (Nagios, Uptime Kuma, etc.)
|
||||
# Exit 0 = OK, 1 = 5G down or no connectivity
|
||||
# Usage: healthcheck-5g.sh [--ping-only]
|
||||
# Rev: 1 (see REVISION in repo root)
|
||||
|
||||
CONFIG="/etc/5g-router.conf"
|
||||
WAN_IF="${WAN_IF:-eth1}"
|
||||
[ -f "$CONFIG" ] && . "$CONFIG"
|
||||
|
||||
PING_TARGET="${PING_TARGET:-8.8.8.8}"
|
||||
|
||||
# Check default route goes via 5G
|
||||
def_if=$(ip route show default 2>/dev/null | awk '{print $5}' | head -1)
|
||||
if [ "$def_if" != "$WAN_IF" ]; then
|
||||
echo "CRITICAL: default route not via $WAN_IF (got: $def_if)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check WAN has an address
|
||||
wan_ip=$(ip -4 addr show "$WAN_IF" 2>/dev/null | grep -oE 'inet [0-9.]+' | awk '{print $2}')
|
||||
if [ -z "$wan_ip" ]; then
|
||||
echo "CRITICAL: no IP on $WAN_IF"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$1" = "--ping-only" ]; then
|
||||
if ping -c 1 -W 3 "$PING_TARGET" >/dev/null 2>&1; then
|
||||
echo "OK: ping $PING_TARGET"
|
||||
exit 0
|
||||
else
|
||||
echo "CRITICAL: ping $PING_TARGET failed"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Full check: route + ping
|
||||
if ping -c 2 -W 5 "$PING_TARGET" >/dev/null 2>&1; then
|
||||
echo "OK: 5G up, ping $PING_TARGET"
|
||||
exit 0
|
||||
else
|
||||
echo "CRITICAL: 5G route OK but ping $PING_TARGET failed"
|
||||
exit 1
|
||||
fi
|
||||
88
scripts/install.sh
Normal file
88
scripts/install.sh
Normal file
@@ -0,0 +1,88 @@
|
||||
#!/bin/sh
|
||||
# Alpine 5G Router – install/deploy scripts and config to this device
|
||||
# Run from repo root: ./scripts/install.sh
|
||||
# Or from scripts/: ./install.sh (uses script dir to find repo root)
|
||||
# Rev: 1 (see REVISION in repo root)
|
||||
|
||||
set -e
|
||||
|
||||
# Repo root (directory containing etc/ and scripts/)
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
ETC="$ROOT/etc"
|
||||
SCRIPTS="$ROOT/scripts"
|
||||
BIN="/usr/local/bin"
|
||||
INITD="/etc/init.d"
|
||||
IPTABLES_SAVE="/etc/iptables"
|
||||
CONFIG="/etc/5g-router.conf"
|
||||
CONFIG_EXAMPLE="$ETC/5g-router.conf.example"
|
||||
LOG_DIR="/var/log"
|
||||
|
||||
echo "Installing Alpine 5G Router from $ROOT"
|
||||
|
||||
# Config: copy example if no config exists
|
||||
if [ ! -f "$CONFIG" ]; then
|
||||
cp "$CONFIG_EXAMPLE" "$CONFIG"
|
||||
echo "Created $CONFIG – please edit APN and interfaces if needed."
|
||||
else
|
||||
echo "Keeping existing $CONFIG"
|
||||
fi
|
||||
|
||||
# Scripts
|
||||
install -m 755 "$SCRIPTS/connect-5g.sh" "$BIN/connect-5g.sh"
|
||||
install -m 755 "$SCRIPTS/status-5g.sh" "$BIN/status-5g.sh"
|
||||
install -m 755 "$SCRIPTS/modem-status-at.sh" "$BIN/modem-status-at.sh"
|
||||
install -m 755 "$SCRIPTS/healthcheck-5g.sh" "$BIN/healthcheck-5g.sh"
|
||||
install -m 755 "$SCRIPTS/speedtest-5g.sh" "$BIN/speedtest-5g.sh"
|
||||
install -m 755 "$SCRIPTS/rotate-5g-log.sh" "$BIN/rotate-5g-log.sh"
|
||||
install -m 755 "$SCRIPTS/diag-at-port.sh" "$BIN/diag-at-port.sh"
|
||||
install -m 755 "$SCRIPTS/diag-modem-up.sh" "$BIN/diag-modem-up.sh"
|
||||
install -m 755 "$SCRIPTS/troubleshoot-5g.sh" "$BIN/troubleshoot-5g.sh"
|
||||
echo "Installed scripts to $BIN"
|
||||
|
||||
# Optional: configure_fm350_5g.sh for manual runs
|
||||
if [ -f "$ROOT/configure_fm350_5g.sh" ]; then
|
||||
install -m 755 "$ROOT/configure_fm350_5g.sh" "$BIN/configure_fm350_5g.sh"
|
||||
echo "Installed configure_fm350_5g.sh"
|
||||
fi
|
||||
|
||||
# OpenRC service
|
||||
install -m 755 "$ETC/init.d/5g-router" "$INITD/5g-router"
|
||||
echo "Installed $INITD/5g-router"
|
||||
|
||||
# iptables rules (restore at boot – ensure iptables-restore service exists)
|
||||
mkdir -p "$IPTABLES_SAVE"
|
||||
install -m 644 "$ETC/iptables/rules.v4" "$IPTABLES_SAVE/rules.v4"
|
||||
echo "Installed $IPTABLES_SAVE/rules.v4"
|
||||
if [ -d /etc/init.d ] && [ ! -f /etc/init.d/iptables-restore ]; then
|
||||
echo "Tip: enable iptables restore at boot: rc-update add iptables-restore"
|
||||
fi
|
||||
|
||||
# Log file
|
||||
touch "$LOG_DIR/5g-router.log" 2>/dev/null && chmod 644 "$LOG_DIR/5g-router.log" || true
|
||||
touch "$LOG_DIR/speedtest-5g.log" 2>/dev/null && chmod 644 "$LOG_DIR/speedtest-5g.log" || true
|
||||
|
||||
# Enable 5g-router at boot
|
||||
if command -v rc-update >/dev/null 2>&1; then
|
||||
rc-update add 5g-router default 2>/dev/null || true
|
||||
echo "Added 5g-router to default runlevel"
|
||||
fi
|
||||
|
||||
# Web GUI (optional)
|
||||
WEBGUI_SRC="$ROOT/web"
|
||||
WEBGUI_DEST="/usr/local/share/5g-webgui"
|
||||
if [ -d "$WEBGUI_SRC" ] && [ -f "$WEBGUI_SRC/app.py" ]; then
|
||||
mkdir -p "$WEBGUI_DEST"
|
||||
cp -r "$WEBGUI_SRC"/* "$WEBGUI_DEST/"
|
||||
chmod 755 "$WEBGUI_DEST/run.sh" 2>/dev/null || true
|
||||
install -m 755 "$ETC/init.d/5g-webgui" "$INITD/5g-webgui"
|
||||
echo "Installed Web GUI at $WEBGUI_DEST. Enable with: rc-update add 5g-webgui default"
|
||||
echo " Then: apk add python3 py3-flask && service 5g-webgui start"
|
||||
echo " Login at http://<device-ip>:5000 (default: admin/admin, support/support – change passwords)"
|
||||
else
|
||||
echo "Web GUI source not found; skipping."
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Done. Edit $CONFIG if needed, then: service 5g-router start"
|
||||
echo "Or run once: $BIN/connect-5g.sh"
|
||||
echo "Status: $BIN/status-5g.sh"
|
||||
105
scripts/modem-status-at.sh
Normal file
105
scripts/modem-status-at.sh
Normal file
@@ -0,0 +1,105 @@
|
||||
#!/bin/sh
|
||||
# Alpine 5G Router – modem status via AT commands (AT_COMMANDS_REFERENCE.md)
|
||||
# Outputs JSON. Used by Web GUI /api/status.
|
||||
# Rev: 2 (see REVISION in repo root)
|
||||
|
||||
CONFIG="/etc/5g-router.conf"
|
||||
AT_PORT="${AT_PORT:-/dev/ttyUSB1}"
|
||||
[ -f "$CONFIG" ] && . "$CONFIG"
|
||||
|
||||
get_at() {
|
||||
_cmd="$1"
|
||||
_wait="${2:-1}"
|
||||
timeout $((_wait + 2)) sh -c "
|
||||
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'
|
||||
21
scripts/rotate-5g-log.sh
Normal file
21
scripts/rotate-5g-log.sh
Normal file
@@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
# Rotate /var/log/5g-router.log (keep last 5 copies, max 1MB each)
|
||||
# Run from cron daily: 0 3 * * * /usr/local/bin/rotate-5g-log.sh
|
||||
# Alpine does not ship logrotate by default; this is a minimal alternative.
|
||||
# Rev: 1 (see REVISION in repo root)
|
||||
|
||||
LOG="/var/log/5g-router.log"
|
||||
MAXSIZE=$((1024 * 1024)) # 1MB
|
||||
KEEP=5
|
||||
|
||||
[ ! -f "$LOG" ] && exit 0
|
||||
size=$(stat -c %s "$LOG" 2>/dev/null) || size=$(wc -c < "$LOG" 2>/dev/null) || exit 0
|
||||
[ "$size" -lt "$MAXSIZE" ] && exit 0
|
||||
|
||||
for i in $(seq $((KEEP - 1)) -1 1); do
|
||||
[ -f "${LOG}.$i" ] && mv "${LOG}.$i" "${LOG}.$((i+1))"
|
||||
done
|
||||
[ -f "${LOG}.1" ] && mv "${LOG}.1" "${LOG}.2"
|
||||
mv "$LOG" "${LOG}.1"
|
||||
touch "$LOG"
|
||||
chmod 644 "$LOG" 2>/dev/null || true
|
||||
14
scripts/speedtest-5g.sh
Normal file
14
scripts/speedtest-5g.sh
Normal file
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
# Optional: run speedtest and append to log (for cron)
|
||||
# Requires: apk add speedtest-cli
|
||||
# Cron example: 0 */6 * * * /usr/local/bin/speedtest-5g.sh
|
||||
# Rev: 1 (see REVISION in repo root)
|
||||
|
||||
LOG="/var/log/speedtest-5g.log"
|
||||
if command -v speedtest-cli >/dev/null 2>&1; then
|
||||
echo "=== $(date -Iseconds) ===" >> "$LOG"
|
||||
speedtest-cli --simple >> "$LOG" 2>&1
|
||||
echo "" >> "$LOG"
|
||||
else
|
||||
echo "$(date -Iseconds) speedtest-cli not installed" >> "$LOG"
|
||||
fi
|
||||
26
scripts/ssh-diag-modem.sh
Executable file
26
scripts/ssh-diag-modem.sh
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/bin/sh
|
||||
# Alpine 5G Router – run modem diagnostics on device via SSH
|
||||
# Usage: ./scripts/ssh-diag-modem.sh [user@host]
|
||||
# Or: TARGET=root@192.168.1.1 ./scripts/ssh-diag-modem.sh
|
||||
|
||||
TARGET="${1:-${TARGET:-root@10.130.60.121}}"
|
||||
SSH_OPTS="${SSH_OPTS:--o ConnectTimeout=10}"
|
||||
|
||||
echo "Running modem diagnostics on $TARGET"
|
||||
echo ""
|
||||
|
||||
ssh $SSH_OPTS "$TARGET" "
|
||||
echo '========== diag-modem-up.sh =========='
|
||||
if [ -x /usr/local/bin/diag-modem-up.sh ]; then
|
||||
/usr/local/bin/diag-modem-up.sh
|
||||
else
|
||||
echo 'Not installed. Deploy first: ./scripts/deploy.sh $TARGET'
|
||||
echo 'Then re-run this script.'
|
||||
exit 1
|
||||
fi
|
||||
echo ''
|
||||
echo '========== diag-at-port.sh =========='
|
||||
if [ -x /usr/local/bin/diag-at-port.sh ]; then
|
||||
/usr/local/bin/diag-at-port.sh
|
||||
fi
|
||||
"
|
||||
44
scripts/status-5g.sh
Normal file
44
scripts/status-5g.sh
Normal file
@@ -0,0 +1,44 @@
|
||||
#!/bin/sh
|
||||
# Alpine 5G Router – status (modem, interface, default route, last speedtest)
|
||||
# Usage: status-5g.sh [--json] (optional machine-readable output)
|
||||
# Rev: 1 (see REVISION in repo root)
|
||||
|
||||
CONFIG="/etc/5g-router.conf"
|
||||
WAN_IF="${WAN_IF:-eth1}"
|
||||
LAN_IF="${LAN_IF:-eth0.100}"
|
||||
AT_PORT="${AT_PORT:-/dev/ttyUSB1}"
|
||||
[ -f "$CONFIG" ] && . "$CONFIG"
|
||||
|
||||
SPEEDTEST_LOG="/var/log/speedtest-5g.log"
|
||||
MODEM_USB=$(lsusb 2>/dev/null | grep -i fibocom | head -1)
|
||||
DEFAULT_ROUTE=$(ip route show default 2>/dev/null | head -1)
|
||||
WAN_IP=$(ip -4 addr show "$WAN_IF" 2>/dev/null | grep -oE 'inet [0-9.]+' | awk '{print $2}')
|
||||
WAN_STATE=$(ip link show "$WAN_IF" 2>/dev/null | grep -oE 'state [A-Z]+' | awk '{print $2}')
|
||||
LAST_SPEEDTEST=""
|
||||
[ -f "$SPEEDTEST_LOG" ] && LAST_SPEEDTEST=$(tail -5 "$SPEEDTEST_LOG" 2>/dev/null)
|
||||
|
||||
if [ "$1" = "--json" ]; then
|
||||
echo "{"
|
||||
echo " \"modem_usb\": \"${MODEM_USB:-none}\","
|
||||
echo " \"wan_interface\": \"$WAN_IF\","
|
||||
echo " \"wan_state\": \"${WAN_STATE:-unknown}\","
|
||||
echo " \"wan_ip\": \"${WAN_IP:-}\","
|
||||
echo " \"default_route\": \"${DEFAULT_ROUTE:-none}\","
|
||||
echo " \"at_port\": \"$AT_PORT\","
|
||||
echo " \"at_available\": \"$([ -c \"$AT_PORT\" ] && echo yes || echo no)\""
|
||||
echo "}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "=== 5G Router Status ==="
|
||||
echo "Modem: ${MODEM_USB:-not detected}"
|
||||
echo "AT port: $AT_PORT ($([ -c "$AT_PORT" ] && echo "available" || echo "not available"))"
|
||||
echo "WAN: $WAN_IF state=$WAN_STATE ip=$WAN_IP"
|
||||
echo "Default: $DEFAULT_ROUTE"
|
||||
echo ""
|
||||
echo "--- Last speedtest ---"
|
||||
if [ -n "$LAST_SPEEDTEST" ]; then
|
||||
echo "$LAST_SPEEDTEST"
|
||||
else
|
||||
echo "(none – run speedtest-cli --simple and redirect to $SPEEDTEST_LOG)"
|
||||
fi
|
||||
145
scripts/troubleshoot-5g.sh
Normal file
145
scripts/troubleshoot-5g.sh
Normal file
@@ -0,0 +1,145 @@
|
||||
#!/bin/sh
|
||||
# Alpine 5G Router – full troubleshoot: collect all logs and run diagnostics
|
||||
# Run on device: /usr/local/bin/troubleshoot-5g.sh
|
||||
# Or via SSH: ssh root@device /usr/local/bin/troubleshoot-5g.sh
|
||||
# Rev: 1 (see REVISION in repo root)
|
||||
|
||||
CONFIG="/etc/5g-router.conf"
|
||||
AT_PORT="${AT_PORT:-/dev/ttyUSB1}"
|
||||
WAN_IF="${WAN_IF:-eth1}"
|
||||
LOG_FILE="/var/log/5g-router.log"
|
||||
|
||||
[ -f "$CONFIG" ] && . "$CONFIG"
|
||||
|
||||
echo "=============================================="
|
||||
echo " Alpine 5G Router – Full Troubleshoot"
|
||||
echo " $(date -Iseconds)"
|
||||
echo "=============================================="
|
||||
echo ""
|
||||
|
||||
# --- 1) Kernel / USB / tty (recent) ---
|
||||
echo "--- 1) Kernel messages (dmesg, last 40 lines) ---"
|
||||
dmesg 2>/dev/null | tail -40 || echo "(dmesg not available)"
|
||||
echo ""
|
||||
|
||||
# --- 2) USB devices ---
|
||||
echo "--- 2) USB devices (lsusb) ---"
|
||||
lsusb 2>/dev/null || echo "(lsusb not available)"
|
||||
if lsusb 2>/dev/null | grep -q "0e8d:7127"; then
|
||||
echo " -> WARN: Modem in Mode 41 (7127). AT port may not work. Need Mode 40 (7126)."
|
||||
elif lsusb 2>/dev/null | grep -q "0e8d:7126"; then
|
||||
echo " -> Modem in Mode 40 (RNDIS) – OK for AT on ttyUSB1"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# --- 3) Serial / AT port nodes ---
|
||||
echo "--- 3) Serial devices (/dev/ttyUSB[0-9]*, /dev/ttyACM[0-9]*) ---"
|
||||
if [ -e /dev/ttyUSB ] && [ -f /dev/ttyUSB ] && [ ! -c /dev/ttyUSB ]; then
|
||||
echo " Stray file /dev/ttyUSB (no number) – remove with: rm /dev/ttyUSB"
|
||||
fi
|
||||
for d in /dev/ttyUSB0 /dev/ttyUSB1 /dev/ttyUSB2 /dev/ttyUSB3 /dev/ttyUSB4 /dev/ttyUSB5 /dev/ttyACM0 /dev/ttyACM1; do
|
||||
[ -e "$d" ] || continue
|
||||
ls -la "$d" 2>/dev/null
|
||||
if [ -f "$d" ] && [ ! -c "$d" ]; then
|
||||
_n="${d#/dev/ttyUSB}"; _n="${_n#/dev/ttyACM}"
|
||||
echo " -> BAD: $d is a regular file. Fix: rm $d && mknod $d c 188 $_n && chmod 660 $d && chown root:dialout $d"
|
||||
fi
|
||||
done
|
||||
if ! ls /dev/ttyUSB[0-9]* /dev/ttyACM[0-9]* 2>/dev/null | grep -q .; then
|
||||
echo " No ttyUSB/ttyACM devices. Modem may not be bound or not in Mode 40."
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# --- 4) Config ---
|
||||
echo "--- 4) Config ($CONFIG) ---"
|
||||
if [ -f "$CONFIG" ]; then
|
||||
grep -E '^[A-Za-z_]+=' "$CONFIG" 2>/dev/null | sed 's/^/ /' || true
|
||||
else
|
||||
echo " File not found (using defaults: AT_PORT=$AT_PORT, WAN_IF=$WAN_IF)"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# --- 5) AT port test (with longer wait like connect-5g.sh) ---
|
||||
echo "--- 5) AT command test on $AT_PORT (wait 3s) ---"
|
||||
if [ -c "$AT_PORT" ]; then
|
||||
out=$(timeout 8 sh -c "
|
||||
cat $AT_PORT 2>/dev/null &
|
||||
_p=\$!
|
||||
sleep 0.5
|
||||
echo -e 'AT\r' > $AT_PORT 2>/dev/null
|
||||
sleep 3
|
||||
kill \$_p 2>/dev/null
|
||||
" 2>&1)
|
||||
if echo "$out" | grep -q 'OK'; then
|
||||
echo " AT response: OK (modem responding)"
|
||||
else
|
||||
echo " AT response: no OK (modem not responding or wrong port)"
|
||||
echo " Raw output:"
|
||||
echo "$out" | head -10 | sed 's/^/ /'
|
||||
fi
|
||||
else
|
||||
echo " $AT_PORT not available (missing or not a character device)"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# --- 6) AT probe on all ttyUSB (which port responds) ---
|
||||
echo "--- 6) AT probe on each ttyUSB port ---"
|
||||
for port in /dev/ttyUSB0 /dev/ttyUSB1 /dev/ttyUSB2 /dev/ttyUSB3; do
|
||||
[ -c "$port" ] || continue
|
||||
out=$(timeout 5 sh -c "cat $port 2>/dev/null & _p=\$!; sleep 0.3; echo -e 'AT\r' > $port; sleep 2; kill \$_p 2>/dev/null" 2>/dev/null)
|
||||
if echo "$out" | grep -q 'OK'; then
|
||||
echo " $port: OK (use this as AT_PORT if different from config)"
|
||||
else
|
||||
echo " $port: no OK"
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
|
||||
# --- 7) 5g-router service ---
|
||||
echo "--- 7) 5g-router service ---"
|
||||
if command -v rc-service >/dev/null 2>&1; then
|
||||
rc-service 5g-router status 2>&1 | sed 's/^/ /'
|
||||
else
|
||||
echo " OpenRC not found"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# --- 8) WAN interface and routing ---
|
||||
echo "--- 8) WAN interface ($WAN_IF) and default route ---"
|
||||
if ip link show "$WAN_IF" >/dev/null 2>&1; then
|
||||
ip link show "$WAN_IF" 2>/dev/null | sed 's/^/ /'
|
||||
ip -4 addr show "$WAN_IF" 2>/dev/null | sed 's/^/ /'
|
||||
else
|
||||
echo " Interface $WAN_IF does not exist"
|
||||
fi
|
||||
ip route show default 2>/dev/null | sed 's/^/ /'
|
||||
echo ""
|
||||
|
||||
# --- 9) Full 5g-router log ---
|
||||
echo "--- 9) Full 5g-router log (last 60 lines of $LOG_FILE) ---"
|
||||
if [ -f "$LOG_FILE" ]; then
|
||||
tail -60 "$LOG_FILE" 2>/dev/null | sed 's/^/ /'
|
||||
else
|
||||
echo " Log file not found"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# --- 10) Optional: modem status script ---
|
||||
if [ -x "/usr/local/bin/modem-status-at.sh" ]; then
|
||||
echo "--- 10) modem-status-at.sh (registration, signal) ---"
|
||||
/usr/local/bin/modem-status-at.sh 2>&1 | head -30 | sed 's/^/ /'
|
||||
else
|
||||
echo "--- 10) modem-status-at.sh ---"
|
||||
echo " Not installed"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "=============================================="
|
||||
echo " End troubleshoot – copy this output to share"
|
||||
echo "=============================================="
|
||||
echo ""
|
||||
echo "Quick fixes to try:"
|
||||
echo " - ttyUSB is regular file: rm $AT_PORT && mknod $AT_PORT c 188 1 && chmod 660 $AT_PORT && chown root:dialout $AT_PORT"
|
||||
echo " - Modem in Mode 41 (7127): power-cycle modem or reboot; need Mode 40 (7126) for AT"
|
||||
echo " - AT not OK: set AT_PORT in $CONFIG to the port that showed OK above (e.g. /dev/ttyUSB0)"
|
||||
echo " - Restart connection: service 5g-router restart or /usr/local/bin/connect-5g.sh"
|
||||
Reference in New Issue
Block a user