diff --git a/scripts/install/server.sh b/scripts/install/server.sh index 7436ab1..f85341e 100755 --- a/scripts/install/server.sh +++ b/scripts/install/server.sh @@ -30,24 +30,51 @@ is_attached_state() { return 1 } +normalize_hdmi_connector() { + local name="$1" + if [[ $name =~ (HDMI-A-[0-9]+)$ ]]; then + printf '%s\n' "${BASH_REMATCH[1]}" + else + printf '%s\n' "$name" + fi +} + +read_existing_hdmi_connector() { + local line value + line=$(grep -E '^LESAVKA_HDMI_CONNECTOR=' /etc/lesavka/server.env 2>/dev/null | tail -n1 || true) + [[ -n $line ]] || return 0 + value=${line#*=} + value=${value%\"} + value=${value#\"} + value=${value%\'} + value=${value#\'} + normalize_hdmi_connector "$value" +} + +describe_hdmi_connectors() { + local dev name status id + for dev in /sys/class/drm/card*-HDMI-A-*; do + [[ -e $dev/status ]] || continue + name=$(basename "$dev") + status=$(cat "$dev/status" 2>/dev/null || true) + id=$(cat "$dev/connector_id" 2>/dev/null || true) + printf ' %s (%s): %s\n' "$(normalize_hdmi_connector "$name")" "${id:-no-id}" "${status:-unknown}" >&2 + done +} + detect_connected_hdmi_connector() { - local dev name stable_name status score suffix - local best="" best_score=0 best_suffix=0 + local dev name stable_name status score + local best="" best_score=0 best_count=0 declare -A scores=() - # HDMI status can briefly flap during gadget/display bring-up. Sample a few - # times and prefer the connector that stays connected; ties prefer HDMI-A-2, - # which is the dedicated downstream capture leg on the current Pi layout. - # Store the logical connector suffix, not the DRM card prefix, so this stays - # valid if Linux renumbers cardN across boots. + # HDMI status can briefly flap during gadget/display bring-up, so sample a + # few times. Store the logical connector suffix, not the DRM card prefix, so + # this stays valid if Linux renumbers cardN across boots. for _ in 1 2 3 4 5; do for dev in /sys/class/drm/card*-HDMI-A-*; do [[ -e $dev/status ]] || continue name=$(basename "$dev") - stable_name=$name - if [[ $name =~ (HDMI-A-[0-9]+)$ ]]; then - stable_name=${BASH_REMATCH[1]} - fi + stable_name=$(normalize_hdmi_connector "$name") status=$(cat "$dev/status" 2>/dev/null || true) if [[ $status == connected ]]; then scores[$stable_name]=$(( ${scores[$stable_name]:-0} + 1 )) @@ -58,15 +85,51 @@ detect_connected_hdmi_connector() { for name in "${!scores[@]}"; do score=${scores[$name]} - suffix=${name##*-} - if (( score > best_score || (score == best_score && suffix > best_suffix) )); then + if (( score > best_score )); then best=$name best_score=$score - best_suffix=$suffix fi done - printf '%s\n' "$best" + (( best_score > 0 )) || return 0 + + for name in "${!scores[@]}"; do + if (( scores[$name] == best_score )); then + best_count=$((best_count + 1)) + fi + done + + if (( best_count == 1 )); then + printf '%s\n' "$best" + return 0 + fi + + echo "❌ multiple HDMI connectors are equally connected; refusing to guess." >&2 + describe_hdmi_connectors + echo " Disconnect the non-target HDMI output or run once with LESAVKA_HDMI_CONNECTOR=HDMI-A-N." >&2 + return 1 +} + +resolve_hdmi_connector() { + local detected existing + if [[ -n ${LESAVKA_HDMI_CONNECTOR:-} ]]; then + normalize_hdmi_connector "$LESAVKA_HDMI_CONNECTOR" + return 0 + fi + + if ! detected=$(detect_connected_hdmi_connector); then + return 1 + fi + if [[ -n $detected ]]; then + printf '%s\n' "$detected" + return 0 + fi + + existing=$(read_existing_hdmi_connector) + if [[ -n $existing ]]; then + echo "⚠️ no connected HDMI connector detected; preserving existing LESAVKA_HDMI_CONNECTOR=$existing." >&2 + printf '%s\n' "$existing" + fi } run_as_user() { @@ -232,7 +295,7 @@ sudo install -Dm755 "$SRC_DIR/scripts/daemon/lesavka-uvc.sh" /usr/local/b echo "==> 5b. Runtime environment defaults" sudo install -d -m 0755 /etc/lesavka -HDMI_CONNECTOR=${LESAVKA_HDMI_CONNECTOR:-$(detect_connected_hdmi_connector)} +HDMI_CONNECTOR=$(resolve_hdmi_connector) if [[ -n $HDMI_CONNECTOR ]]; then echo " ↪ HDMI connector: $HDMI_CONNECTOR" else