#!/bin/sh

# led 9.3.0 (Raspberry Pi)
# Copyright (c)2017-2026 John Lawson & Sons
# All Rights Reserved

# Color  State     Meaning
# -----  -----     -------
#
# Green  ON        Ethernet
#        FLASHING  WiFi
# Red    OFF       ONLINE
#        ON        NOT ONLINE

PWR_BRIGHTNESS="/sys/class/leds/PWR/brightness"
PWR_TRIGGER="/sys/class/leds/PWR/trigger"
ACT_BRIGHTNESS="/sys/class/leds/ACT/brightness"
ACT_TRIGGER="/sys/class/leds/ACT/trigger"

contains() {
    case "$1" in
        *"$2"*) return 0 ;;
        *) return 1 ;;
    esac
}

write_if_exists() {
    local file="$1"
    local value="$2"

    [ -e "$file" ] || return 0
    printf '%s\n' "$value" > "$file" 2>/dev/null || true
}

read_file() {
    local file="$1"

    [ -r "$file" ] || return 1
    IFS= read -r value < "$file"
    printf '%s\n' "$value"
}

# Defaults
actON="default-on"
actOFF="none"
actLIGHT=1
actDARK=0

cpuinfo="$(cat /proc/cpuinfo 2>/dev/null || true)"

# Raspberry Pi 3 Model B has inverted ACT behaviour.
if contains "$cpuinfo" "Raspberry Pi 3 Model B" && ! contains "$cpuinfo" "Raspberry Pi 3 Model B Plus"; then
    actON="none"
    actOFF="default-on"
fi

# Raspberry Pi 5 has inverted ACT trigger and brightness behaviour.
if contains "$cpuinfo" "Raspberry Pi 5 Model B"; then
    actON="none"
    actOFF="default-on"
    actLIGHT=0
    actDARK=1
fi

set_ethernet_led() {
    write_if_exists "$ACT_TRIGGER" "$actON"
    write_if_exists "$ACT_BRIGHTNESS" "$actLIGHT"

    write_if_exists "$PWR_TRIGGER" "none"
    write_if_exists "$PWR_BRIGHTNESS" "0"
}

set_offline_led() {
    write_if_exists "$ACT_TRIGGER" "$actOFF"
    write_if_exists "$ACT_BRIGHTNESS" "$actDARK"

    write_if_exists "$PWR_TRIGGER" "default-on"
    write_if_exists "$PWR_BRIGHTNESS" "1"
}

set_wifi_led_on() {
    write_if_exists "$ACT_TRIGGER" "none"
    write_if_exists "$ACT_BRIGHTNESS" "$actLIGHT"

    write_if_exists "$PWR_TRIGGER" "none"
    write_if_exists "$PWR_BRIGHTNESS" "0"
}

set_wifi_led_off() {
    write_if_exists "$ACT_TRIGGER" "none"
    write_if_exists "$ACT_BRIGHTNESS" "$actDARK"

    write_if_exists "$PWR_TRIGGER" "none"
    write_if_exists "$PWR_BRIGHTNESS" "0"
}

interface_is_up() {
    local path="$1"
    local carrier
    local operstate

    if [ -r "$path/carrier" ]; then
        carrier="$(read_file "$path/carrier" 2>/dev/null || true)"
        [ "$carrier" = "1" ] && return 0
        return 1
    fi

    operstate="$(read_file "$path/operstate" 2>/dev/null || true)"
    [ "$operstate" = "up" ]
}

get_network_state() {
    local path
    local name
    local wifi_up=0

    for path in /sys/class/net/*; do
        [ -e "$path" ] || continue

        name="${path##*/}"
        [ "$name" = "lo" ] && continue

        case "$name" in
            eth*|en*)
                if interface_is_up "$path"; then
                    printf '%s\n' "ethernet"
                    return 0
                fi
                ;;

            wlan*|wl*)
                if interface_is_up "$path"; then
                    wifi_up=1
                fi
                ;;
        esac
    done

    if [ "$wifi_up" -eq 1 ]; then
        printf '%s\n' "wifi"
    else
        printf '%s\n' "offline"
    fi
}

# Disable firmware control once at startup.
write_if_exists "$PWR_TRIGGER" "none"
write_if_exists "$ACT_TRIGGER" "none"

last_state=""
wifi_flash=0

while true; do
    state="$(get_network_state)"

    case "$state" in
        wifi)
            if [ "$wifi_flash" -eq 0 ]; then
                set_wifi_led_on
                wifi_flash=1
            else
                set_wifi_led_off
                wifi_flash=0
            fi

            last_state="wifi"
            sleep 0.5
            ;;

        ethernet)
            if [ "$state" != "$last_state" ]; then
                set_ethernet_led
                last_state="$state"
            fi

            wifi_flash=0
            sleep 1
            ;;

        *)
            if [ "$state" != "$last_state" ]; then
                set_offline_led
                last_state="$state"
            fi

            wifi_flash=0
            sleep 1
            ;;
    esac
done