#!/usr/bin/env bash

[[ "$1" != "nocolor" ]] && source colors

if [[ "$1" == -h || "$1" == --help ]]; then
	echo "Usage: amd-info [index] [busid:00] ..."
	exit 0
fi

HIGH_TEMP=100
MID_TEMP=70

TIMEOUT_T1=5
TIMEOUT_T2=10
TIMEOUT_T3=15

LEGACY=0

date


if [[ ! -f $GPU_DETECT_JSON ]]; then
	gpu_detect_json=`gpu-detect listjson`
else
	gpu_detect_json=$(< $GPU_DETECT_JSON)
fi


idx=0
while IFS=";" read busid brand name mem vbios memtype uuid; do
	BUSID[$idx]="$busid"
	BRAND[$idx]="$brand"
	NAME[$idx]="$name"
	RAM[$idx]="$mem"
	VBIOS[$idx]="$vbios"
	MEMTYPE[$idx]="$memtype"
	UUID[$idx]="$uuid"
	((idx++))
done < <( echo "$gpu_detect_json" | jq -r -c '.[] | select(.brand == "amd" or .vendor == "AMD") | (.busid+";"+.brand+";"+.name+";"+.mem+";"+.vbios+";"+.mem_type+";"+.uuid)' 2>/dev/null )

n=${#BUSID[@]}
if [[ $n -eq 0 ]]; then
	echo  "${RED}No AMD GPU detected${NOCOLOR}"
	exit 1
fi


# get current memory params
MEMTWEAK="$(amdmemtweak --current)"

# get amdflash support
readarray -t AMDFLASH < <( amd-flash --busid )


function get_clocks() {
	local cardno="$1"
	local param="$2"
	if [[ ! -f "/sys/class/drm/card$cardno/device/$param" ]]; then
		unset ${param}_clocks ${param}_state ${param}_mhz
		return 1
	fi
	local -n pp_dpm="$param"
	pp_dpm=$(< /sys/class/drm/card$cardno/device/$param)
	readarray -t ${param}_clocks < <(echo "$pp_dpm" | grep -oP ":\s*\K[0-9]+")
	read ${param}_state ${param}_mhz < <(echo "$pp_dpm" | grep -m1 '*' | awk '{print int($1)" "int($2)}')
}


function print_clocks() {
	local param="$1"
	local name="$2"
	local color="$3"
	local -n clocks="${param}_clocks"
	local -n state="${param}_state"
	local out=
	if [[ ${#clocks[@]} -gt 0 ]]; then
		for((idx=0; idx < ${#clocks[@]}; idx++)); do
			[[ $idx == "$state" ]] && out+=" ${WHITE}${clocks[$idx]}*${NOCOLOR}" || out+=" ${clocks[$idx]}"
		done
		if [[ ! -z "$state" ]]; then
			echo "  $name state: ${color:-$WHITE}$state${NOCOLOR}, clocks:$out"
		else
			echo "  $name clocks:$out"
		fi
	fi
}


print_temp() {
	local temp=${1%%.}
	local coef=$2
	[[ -z $temp ]] && echo "${BPURPLE}n/a${NOCOLOR}" && return 1
	[[ ! "$temp" =~ ^[0-9]+$ ]] && echo "${WHITE}$1°C${NOCOLOR}" && return 1
	[[ $coef -gt 0 ]] && temp=$(( temp/coef ))
	[[ $temp -ge $HIGH_TEMP ]] && echo "${BRED}${temp}°C${NOCOLOR}" && return
	[[ $temp -ge $MID_TEMP ]] && echo "${BYELLOW}${temp}°C${NOCOLOR}" && return
	echo "${BGREEN}${temp}°C${NOCOLOR}"
}

index=-1
for (( i=0; i < $n; i++ )); do
	gpu_idx=
	if [[ "${BRAND[$i]}" == "amd" ]]; then
		((index++))
		gpu_idx=$index
	fi
	busid="${BUSID[$i]}"

	# filter output by index or busid
	[[ ! -z "$@" && ! " $@ " =~ ( ${gpu_idx:--} ) && ! " $@ " =~  ( ${busid/.0} ) ]] && continue

	echo ""

	if [[ "${BRAND[$i]}" != "amd" ]]; then
		echo "${YELLOW}===${NOCOLOR} GPU ${CYAN}-${NOCOLOR}, ${PURPLE}$busid ${RED}${NAME[$i]}${NOCOLOR} - ${BYELLOW}${VBIOS[$i]} ${YELLOW}===${NOCOLOR}"
		continue
	fi

	[[ `echo /sys/bus/pci/devices/0000:$busid/drm/card*/` =~ \/card([0-9]+)\/ ]]
	cardno=${BASH_REMATCH[1]}

	echo "${YELLOW}===${NOCOLOR} GPU ${CYAN}$index${NOCOLOR}, ${PURPLE}$busid ${RED}${NAME[$i]} ${WHITE}${RAM[$i]} ${YELLOW}===${NOCOLOR}"

	[[ -z $cardno ]] && echo "${RED}ERROR: can not match card id${NOCOLOR}" && continue

	#amdcovc -a $index

	hwmondir=`realpath /sys/class/drm/card$cardno/device/hwmon/hwmon*/`

	vbios=`cat /sys/class/drm/card$cardno/device/vbios_version 2>/dev/null | tr -d '[:cntrl:]'`
	echo -n "  Bios: ${WHITE}${vbios}${NOCOLOR}"
	#uuid=`timeout -s9 $TIMEOUT_T1 atitool -i=PCI:0000:$busid -sidslt -debug=0 2>/dev/null | grep -oP "^\s*\K[A-Z0-9]+$"`

	uuid="${UUID[$i]}"
	[[ ! -z $uuid ]] && echo -n ", UUID: ${WHITE}${uuid}${NOCOLOR}"
	[[ " ${AMDFLASH[@]} " =~ " ${busid/.0} " ]] && echo -n ", ROM flash: ${WHITE}Supported${NOCOLOR}" || echo -n ", ROM flash: ${WHITE}Not supported${NOCOLOR}"
	echo ""

	#echo "  Performance level: `cat /sys/class/drm/card$cardno/device/power_dpm_force_performance_level`"
	#echo "  Core state: `cat /sys/class/drm/card$cardno/device/pp_dpm_sclk | grep '*'`"
	#echo "  Mem state: `cat /sys/class/drm/card$cardno/device/pp_dpm_mclk | grep '*'`"

	#plevel=`cat /sys/class/drm/card$cardno/device/power_dpm_force_performance_level 2>/dev/null`
	#[[ $plevel == "manual" ]] && plevelStr="${YELLOW}$plevel${NOCOLOR}" || plevelStr="${BLUE}$plevel${NOCOLOR}"

	amdgpu_pm_info=()
	declare -A PMINFO=()
	if [[ -f /sys/kernel/debug/dri/$cardno/amdgpu_pm_info ]]; then
		readarray -t amdgpu_pm_info < /sys/kernel/debug/dri/$cardno/amdgpu_pm_info
		# convert into associative array
		for line in "${amdgpu_pm_info[@]}"; do
			if [[ "$line" =~ ([^:]+):\ ([0-9\.]+) ]]; then
				PMINFO["${BASH_REMATCH[1]// }"]="${BASH_REMATCH[2]}"
			elif [[ "$line" =~ ([0-9\.]+)[^\(]+\(([^\)]+) ]]; then
				PMINFO["${BASH_REMATCH[2]// }"]="${BASH_REMATCH[1]}"
			fi
		done
		#echo "${PMINFO[@]}" #"
	fi

	power="${PMINFO[averageGPU]}"
	if [[ -z "$power" && -f ${hwmondir}/power1_average ]]; then
		power=$(< ${hwmondir}/power1_average)
		power=$(( power/1000/1000 ))
	elif [[ -z "$power" && -f ${hwmondir}/power1_input ]]; then
		power=$(< ${hwmondir}/power1_input)
		power=$(( power/1000/1000 ))
	fi

	load="${PMINFO[GPULoad]}"
	if [[ -z "$load" && -f /sys/class/drm/card${cardno}/device/gpu_busy_percent ]]; then
		load=$(< /sys/class/drm/card${cardno}/device/gpu_busy_percent)
	fi

	mload="${PMINFO[MEMLoad]}"

	gtemp="${PMINFO[GPUTemperature]}"
	if [[ -z "$gtemp" && -f ${hwmondir}/temp1_input ]]; then
		gtemp=$(< ${hwmondir}/temp1_input)
		gtemp=$(( temp / 1000 ))
	fi
	#gtemp=`cat ${hwmondir}/temp1_input 2>/dev/null`
	jtemp=`cat ${hwmondir}/temp2_input 2>/dev/null`
	mtemp=`cat ${hwmondir}/temp3_input 2>/dev/null`
	powercap=`cat ${hwmondir}/power1_cap 2>/dev/null`
	fanrpm=`cat ${hwmondir}/fan1_input 2>/dev/null` # rpm from fan

	fanspeed=0
	if [[ -f ${hwmondir}/pwm1 ]]; then
		[[ -f ${hwmondir}/pwm1_max ]] && fanmax=$(< ${hwmondir}/pwm1_max) || fanmax=255
		[[ -f ${hwmondir}/pwm1_min ]] && fanmin=$(< ${hwmondir}/pwm1_min) || fanmin=0
		fan=$(< ${hwmondir}/pwm1)
		[[ $fan -gt $fanmin && $fanmax -gt $fanmin ]] && fanspeed=$(( (fan - fanmin) * 100 / (fanmax - fanmin) )) || fanspeed=0
	fi

	mem_mhz=${PMINFO[MCLK]}
	core_mhz=${PMINFO[SCLK]}
	vddc=${PMINFO[VDDGFX]}

	ref=`echo "$MEMTWEAK" | sed -n "/pci:0000:${busid}/,/pci/p" | grep -m1 -oP "REF: \K[0-9]+"`

	[[ -f /sys/class/drm/card${cardno}/device/power_dpm_force_performance_level ]] &&
		plevel=$(< /sys/class/drm/card${cardno}/device/power_dpm_force_performance_level) ||
		plevel="unknown"

	get_clocks $cardno pp_dpm_sclk
	get_clocks $cardno pp_dpm_mclk
	get_clocks $cardno pp_dpm_socclk
	get_clocks $cardno pp_dpm_dcefclk
	get_clocks $cardno pp_dpm_fclk

	core_dpm=$pp_dpm_sclk_state
	mem_dpm=$pp_dpm_mclk_state

	#[[ -z $core_mhz ]] && core_mhz=$pp_dpm_sclk_mhz
	#[[ -z $mem_mhz ]] && core_mhz=$pp_dpm_mclk_mhz

	ppod=`cat /sys/class/drm/card${cardno}/device/pp_od_clk_voltage | tr -d '\0' 2>/dev/null`
	if [[ ! -z "$ppod" ]]; then
		#corev=`echo "$ppod" | grep -m1 -A7 "OD_SCLK" | grep -m1 "$core_dpm:" | awk '{print $3}'`
		memv=`echo "$ppod" | grep -m1 -A4 "OD_MCLK" | grep -m1 "$mem_dpm:" | awk '{print $3}'`
	fi
	mem_info=`ohgodatool -i $cardno --show-mem`
	[[ -z $memv || $memv == 0 ]] && memv=`echo "$mem_info" | grep -m1 -A1 "Memory state $mem_dpm" | grep -oP "VDDC: \K.*"`
	vddci=`echo "$mem_info" | grep -m1 -A2 "Memory state $mem_dpm" | grep -oP "VDDCI: \K.*"`

	echo -n "  Core: ${WHITE}${core_mhz} MHz${NOCOLOR}"
	[[ ! -z $vddc ]] && echo -n " ${WHITE}${vddc}mV${NOCOLOR}"
	echo -n ", Mem: ${WHITE}${mem_mhz} MHz${NOCOLOR}"
	[[ ! -z $memv ]] && echo -n " ${WHITE}${memv}${NOCOLOR}"
	[[ ! -z $vddci ]] && echo -n ", VDDCI: ${WHITE}${vddci}${NOCOLOR}"
	[[ ! -z $ref ]] && echo -n ", REF: ${WHITE}$ref${NOCOLOR}"
	echo ""

	echo -n "  PerfCtrl: ${WHITE}$plevel${NOCOLOR}, Load: ${WHITE}${load:-n/a}%${NOCOLOR}"
	[[ ! -z $mload ]] && echo -n ", MemLoad: ${WHITE}${mload}%${NOCOLOR}"
	echo -n ", Power: ${WHITE}${power} W${NOCOLOR}"
	[[ ! -z $powercap ]] && echo -n ", Cap: ${WHITE}$(( powercap/1000/1000 )) W${NOCOLOR}"
	echo ""

	echo -n "  Core: $(print_temp $gtemp)"
	[[ ! -z $jtemp ]] && echo -n ", HotSpot: $(print_temp $jtemp 1000)"
	[[ ! -z $mtemp ]] && echo -n ", Mem: $(print_temp $mtemp 1000)"
	echo ", Fan: ${WHITE}${fanspeed}%${NOCOLOR}, RPM: ${WHITE}${fanrpm:-n/a}${NOCOLOR}"

	print_clocks pp_dpm_sclk "Core" $BPURPLE
	print_clocks pp_dpm_mclk "Mem " $BPURPLE
	print_clocks pp_dpm_socclk "SOC "
	print_clocks pp_dpm_dcefclk "DCEF"
	print_clocks pp_dpm_fclk "F   "

	if [[ -f /sys/class/drm/card${cardno}/device/current_link_speed ]]; then
		pciestatus=$(timeout -s9 $TIMEOUT_T3 atitool -i=PCI:0000:$busid -pciestatus -debug=0 2>/dev/null)
		pciespeed=$(echo "$pciestatus" | grep -oP "Link Speed.*=\s*\K.*")
		pciewidth=$(echo "$pciestatus" | grep -oP "Link Width.*=\s*\K.*")
		#pciespeed=`cat /sys/class/drm/card$cardno/device/current_link_speed`
		#pciewidth=`cat /sys/class/drm/card$cardno/device/current_link_width`
		echo  "  PCIE Link speed: ${WHITE}${pciespeed:-n/a}${NOCOLOR}, PCIE Link width: ${WHITE}${pciewidth:-n/a}${NOCOLOR}"
	fi

	meminfo=
	if [[ -f /sys/kernel/debug/dri/$cardno/amdgpu_vram_mm ]]; then
		vram=`grep -m 1 "^total:" /sys/kernel/debug/dri/$cardno/amdgpu_vram_mm`
		#total: 2097152, used 978872 free 1118280
		[[ ! -z "$vram" ]] &&
			meminfo=`echo "$WHITE $NOCOLOR $vram" | awk '{printf "%s %s%.2f MB%s, %s: %s%.2f MB%s, %s: %s%.2f MB%s, ", $3, $1, $4/256, $2, $5, $1, $6/256, $2, $7, $1, $8/256, $2}'`
		echo "  Memory ${meminfo}type: ${WHITE}${MEMTYPE[$i]}${NOCOLOR}"
	fi

	vctfstatus=()
	#[[ ! -z $uuid && ! $uuid =~ ^0+$ ]] &&
	readarray -t vctfstatus < <(timeout -s9 $TIMEOUT_T2 atitool -i=PCI:0000:$busid -vctfstatus -debug=0 2>/dev/null | grep "VDD.*V$" | grep -v "Measured")
	if [[ ${#vctfstatus[@]} -gt 0 ]]; then
		out=
		for line in "${vctfstatus[@]}"; do
			[[ ! "$line" =~ ([^:]+):\ ([0-9\.]+) ]] && continue
			volt=`echo "${BASH_REMATCH[2]}" | awk '{print int($1*1000)}'`
			out+="${out:+, }${BASH_REMATCH[1]// }: ${WHITE}${volt}mV${NOCOLOR}"
		done
		[[ ! -z $out ]] && echo "  $out"
	fi

	# old legacy line
	if [[ $LEGACY == 1 ]]; then
		echo -n "  ${PURPLE}DPM${NOCOLOR} ${core_dpm:--} ${PURPLE}CORE${NOCOLOR} ${core_mhz:--}MHz ${vddc}mV"
		echo -n " ${PURPLE}MDPM${NOCOLOR} ${mem_dpm:--} ${PURPLE}MEM${NOCOLOR} ${mem_mhz:--}MHz"
		[[ ! -z $memv ]] && echo -n " $memv"
		[[ ! -z $vddci ]] && echo -en " ${PURPLE}VDDCI${NOCOLOR} $vddci"
		[[ ! -z $ref ]] && echo -n " ${PURPLE}REF${NOCOLOR} $ref"
		echo    " ${PURPLE}PWR${NOCOLOR} ${power:-n/a} W" # ${PURPLE}RPM${NOCOLOR} ${fanrpm:-n/a}"
	fi
done
