#!/bin/bash
# SkillFishOS sensor value helper. Single key: `skillfish-hud-val <key>`.
# Batch: `skillfish-hud-val all` prints "key value" lines for every metric in ONE
# process (used by the Monitor app and the telemetry web dashboard to avoid a
# subprocess fan-out per sample). CPU load% is stateful (delta) → computed by callers.
#
# ⚠️ On hardware that is not a BC-250 every key used to come back EMPTY: the
# paths were the board's own (k10temp, amdgpu card0, nct6686). Conky cannot
# measure the size of empty text, shrinks its window to a few pixels and
# vanishes — which is why the HUD was gated to the BC-250 instead of being
# fixed. Each key now falls back to whatever the machine actually exposes, and
# returns nothing only when the machine genuinely has no such sensor. The
# BC-250 paths are still tried FIRST, so nothing changes on the board.
GHW=$(echo /sys/class/drm/card0/device/hwmon/hwmon*)
hw(){ for h in /sys/class/hwmon/hwmon*; do [ "$(cat "$h/name" 2>/dev/null)" = "$1" ] && { echo "$h"; return; }; done; }
# The NCT6686 is claimed by two drivers (mainline nct6683 + out-of-tree nct6687) and
# both register an "nct6686" hwmon, in an order that changes between boots. Only one
# carries the fan tacho, so pick by the node we actually need, not by first match.
hw_with(){ for h in /sys/class/hwmon/hwmon*; do [ "$(cat "$h/name" 2>/dev/null)" = "$1" ] && [ -e "$h/$2" ] && { echo "$h"; return; }; done; }

# --- ripieghi generici -------------------------------------------------------
# Il primo hwmon che espone il nodo chiesto, qualunque sia il chip. Serve alle
# macchine che non hanno i chip della BC-250: un portatile Intel ha coretemp, un
# server ha una PCH, una scheda NVIDIA con nouveau espone temperatura e PWM.
hw_any(){ for h in /sys/class/hwmon/hwmon*; do [ -e "$h/$1" ] && { echo "$h/$1"; return; }; done; }
# La prima scheda video che espone il nodo chiesto: card0 puo' essere una scheda
# che non ha quel dato mentre card1 ce l'ha.
drm_any(){ for d in /sys/class/drm/card[0-9]/device; do
             for f in "$d"/$1 "$d"/hwmon/hwmon*/$1; do [ -e "$f" ] && { echo "$f"; return; }; done
           done; }
# Temperatura CPU su una macchina qualsiasi: si preferisce l'etichetta del
# package, se non c'e' si prende il primo sensore di un chip noto per la CPU.
cpu_temp_generico(){
  for h in /sys/class/hwmon/hwmon*; do
    n=$(cat "$h/name" 2>/dev/null)
    case "$n" in coretemp|k10temp|zenpower|cpu_thermal)
      for l in "$h"/temp*_label; do
        [ -e "$l" ] || continue
        case "$(cat "$l" 2>/dev/null)" in Package*|Tctl*|Tdie*)
          v="${l%_label}_input"; [ -e "$v" ] && { cat "$v"; return; } ;;
        esac
      done
      [ -e "$h/temp1_input" ] && { cat "$h/temp1_input"; return; } ;;
    esac
  done
  # ultimo ripiego: la zona termica del sistema
  cat /sys/class/thermal/thermal_zone0/temp 2>/dev/null
}
primo(){ [ -n "${1:-}" ] && [ -e "$1" ] && cat "$1" 2>/dev/null; }

# Le ventole della SCHEDA MADRE, in ordine di hwmon. Si escludono quelle che
# stanno sotto una scheda video (quelle le riporta fan_gpu) e quelle ferme: un
# connettore senza ventola attaccata legge 0, e stampare "0 rpm" fa credere a un
# guasto invece che a un connettore libero.
#
# ⚠️ Niente etichette da inventare. Sul Fujitsu di sviluppo il driver nct6792
# non fornisce fanN_label, quindi non c'e' modo ONESTO di sapere quale sia la
# ventola del processore e quale quella del case: si mostrano i valori nell'
# ordine in cui il chip li espone, che almeno resta stabile fra un avvio e l'altro.
fan_scheda(){
  for f in /sys/class/hwmon/hwmon*/fan[0-9]_input; do
    [ -e "$f" ] || continue
    case "$(readlink -f "$f")" in *devices/pci*/drm/*) continue ;; esac
    v=$(cat "$f" 2>/dev/null)
    [ -n "$v" ] && [ "$v" -gt 0 ] 2>/dev/null && echo "$v"
  done
}

# locale: it* -> Italian labels, anything else -> English
_loc="${LC_ALL:-${LC_MESSAGES:-${LANG:-$LANGUAGE}}}"; case "$_loc" in it*) IT=1;; *) IT=0;; esac

get(){
  case "$1" in
    lbl_use)  [ "$IT" = 1 ] && echo "uso"   || echo "use"  ;;
    lbl_disk) [ "$IT" = 1 ] && echo "DISCO" || echo "DISK" ;;
    cpu_temp) v=$(cat "$(hw k10temp)/temp1_input" 2>/dev/null)
              [ -z "$v" ] && v=$(cpu_temp_generico)
              [ -n "$v" ] && echo "$v" | awk '{printf "%.0f",$1/1000}' ;;
    gpu_freq) f=$(cat /run/skillfish-gpu-freq 2>/dev/null)   # SMU sample (correct after 8-core unlock)
              if [ -n "$f" ]; then echo "${f}Mhz"
              else
                # AMD: il livello attivo e' quello segnato con l'asterisco
                v=$(awk '/\*/{print $2}' /sys/class/drm/card0/device/pp_dpm_sclk 2>/dev/null)
                # Intel: i915 e xe pubblicano la frequenza reale in MHz, in due
                # posti diversi a seconda della generazione.
                if [ -z "$v" ]; then
                  for g in /sys/class/drm/card[0-9]/gt_act_freq_mhz                            /sys/class/drm/card[0-9]/gt/gt0/rps_act_freq_mhz; do
                    [ -r "$g" ] && { v="$(cat "$g" 2>/dev/null)Mhz"; break; }
                  done
                fi
                # Un hwmon di scheda video che espone freq1_input, in Hz
                [ -z "$v" ] && { g=$(drm_any freq1_input); [ -n "$g" ] && v=$(awk '{printf "%dMhz",$1/1000000}' "$g"); }
                # nouveau: la frequenza sta in debugfs, non in sysfs, e serve root.
                # ⚠️ Sulle schede dalla Maxwell in poi (qui una GP107) il file c'e'
                # ma risponde ENODEV: nouveau non implementa il controllo dei
                # clock su quelle GPU. Non e' un nostro difetto e non si aggira:
                # dove non risponde, la voce resta vuota e la riga non compare.
                if [ -z "$v" ]; then
                  p=$(cat /sys/kernel/debug/dri/0/pstate 2>/dev/null | sed -n 's/.*AC: core \([0-9]\{1,\}\).*//p' | head -1)
                  [ -n "$p" ] && v="${p}Mhz"
                fi
                [ -n "$v" ] && echo "$v"
              fi ;;
    gpu_util) u=$(cat /run/skillfish-gpu-util 2>/dev/null)
              [ -z "$u" ] && u=$(primo "$(drm_any gpu_busy_percent)")
              echo "${u:-0}" ;;
    gpu_temp) v=$(cat "$GHW/temp1_input" 2>/dev/null)
              [ -z "$v" ] && v=$(primo "$(drm_any temp1_input)")
              [ -n "$v" ] && echo "$v" | awk '{printf "%.0f",$1/1000}' ;;
    gpu_power) v=$(cat "$GHW/power1_average" 2>/dev/null)
               [ -z "$v" ] && v=$(primo "$(drm_any power1_average)")
               [ -n "$v" ] && echo "$v" | awk '{printf "%.0f",$1/1000000}' ;;
    gpu_mv) v=$(cat "$GHW/in0_input" 2>/dev/null)
            [ -z "$v" ] && v=$(primo "$(drm_any in0_input)")
            [ -n "$v" ] && echo "$v" ;;
    cpu_mv) cat "$GHW/in1_input" 2>/dev/null ;;   # vddnb = APU SoC/uncore (CPU-side) rail; nct6686 Vcore reads 0 on the BC-250
    vram) v=$(cat /sys/class/drm/card0/device/mem_info_vram_used 2>/dev/null)
          [ -z "$v" ] && v=$(primo "$(drm_any mem_info_vram_used)")
          [ -n "$v" ] && echo "$v" | awk '{printf "%.0f",$1/1048576}' ;;
    fan) v=$(cat "$(hw_with nct6686 fan2_input)/fan2_input" 2>/dev/null)
         [ -z "$v" ] && v=$(primo "$(hw_any fan1_input)")
         [ -n "$v" ] && echo "$v" ;;
    # Sulla BC-250 il conto lo tiene skillfish-cu; altrove lo dichiara Vulkan
    # (unita' di calcolo su AMD, CUDA core su NVIDIA) e lo deposita
    # skillfish-sensori all'avvio. Dove nessuno dei due sa rispondere si tace.
    cu) v=$(cat /run/skillfish/cu_active 2>/dev/null)
        [ -z "$v" ] && v=$(primo /run/skillfish/gpu_cores)
        [ -n "$v" ] && echo "$v" ;;
    cpu_mhz) awk -F: '/cpu MHz/{printf "%d",$2; exit}' /proc/cpuinfo 2>/dev/null ;;
    kernel) uname -r ;;
    ram_mhz) primo /run/skillfish/ram_mhz ;;
    vram_tot) v=$(cat /sys/class/drm/card0/device/mem_info_vram_total 2>/dev/null)
              [ -z "$v" ] && v=$(primo "$(drm_any mem_info_vram_total)")
              if [ -n "$v" ]; then echo "$v" | awk '{printf "%.0f",$1/1048576}'
              else primo /run/skillfish/vram_total; fi ;;   # ripiego: dichiarata da Vulkan
    # ⚠️ Si mostra SOLO se il driver espone piu' di uno stato. Sulla BC-250
    # pp_dpm_mclk contiene una riga sola, "0: 450Mhz *", identica a pp_dpm_fclk:
    # e' un valore fisso che non cambia mai, non la velocita' della memoria. La
    # scheda e' una APU e la sua GDDR6 gira a 1750 MT/s, che e' il numero gia'
    # mostrato sulla riga RAM. Scrivere "@450" accanto a VRAM faceva sembrare
    # quella memoria piu' lenta di una DDR vecchia: il contrario del vero.
    # Dove il driver espone una vera tabella di stati il valore serve, e resta.
    vram_mhz) f=/sys/class/drm/card0/device/pp_dpm_mclk
              [ -r "$f" ] || f=$(drm_any pp_dpm_mclk)
              if [ -n "${f:-}" ] && [ -r "$f" ] && [ "$(grep -c . "$f")" -gt 1 ]; then
                awk '/\*/{gsub(/[Mm]hz/,"",$2); print $2; exit}' "$f" 2>/dev/null
              fi ;;
    # I giri delle ventole della scheda madre, separati da un punto centrale.
    fan_all) fan_scheda | awk '{s = s (s ? " · " : "") $1} END{if (s) print s}' ;;
    # La ventola della scheda video. Molte schede non hanno un contagiri e
    # dichiarano solo il PWM: in quel caso si mostra la percentuale, che e' un
    # dato vero, invece di tacere o di spacciare il PWM per giri al minuto.
    fan_gpu) v=$(primo "$(drm_any fan1_input)")
             if [ -n "$v" ] && [ "$v" -gt 0 ] 2>/dev/null; then echo "${v} rpm"
             else p=$(primo "$(drm_any pwm1)")
                  [ -n "$p" ] && echo "$p" | awk '{printf "%d%%",$1*100/255}'
             fi ;;
  esac
}

if [ "$1" = "all" ]; then
  for k in cpu_temp gpu_temp cpu_mhz gpu_freq gpu_mv cpu_mv gpu_power fan fan_all fan_gpu vram vram_tot vram_mhz ram_mhz gpu_util cu kernel; do
    printf '%s %s\n' "$k" "$(get "$k")"
  done
  exit 0
fi
get "$1"
