# Monitor whether DPTF/INT3404 sends fan control: ETW trace + high-frequency _FST poll.
# Run as Administrator. Needs ectest (ec-test-app) for _FST polling.
# -Mode watch: poll _FST, print only when FAND *changes* (INT3404 sends _FSL => FAND changes).

param(
    [ValidateSet("check", "poll", "watch", "etw", "all")]
    [string]$Mode = "check",
    [string]$EctestPath = "C:\Users\Jack\ec-test-app\exe\x64\Release\ectest.exe",
    [int]$PollSeconds = 60,
    [double]$PollIntervalMs = 200,
    [string]$LogDir = $PSScriptRoot
)

$ErrorActionPreference = "Stop"

# ---- 1) Check DPTF presence ----
function Get-DptfPresence {
    Write-Host "=== DPTF / thermal stack check ===" -ForegroundColor Cyan
    $svc = Get-Service -ErrorAction SilentlyContinue | Where-Object { $_.Name -match "dptf|esif|intel.*thermal|dynamic.*thermal" }
    if ($svc) {
        $svc | Format-Table Name, Status, DisplayName -AutoSize
    } else {
        Write-Host "No DPTF/ESIF/thermal service found by name." -ForegroundColor Yellow
    }
    $drv = Get-WmiObject Win32_PnPSignedDriver -ErrorAction SilentlyContinue | Where-Object { $_.DeviceName -match "DPTF|Dynamic Platform|Intel.*Thermal|ESIF" }
    if ($drv) {
        $drv | Select-Object DeviceName, DriverVersion | Format-Table -AutoSize
    } else {
        Write-Host "No DPTF/thermal driver found by name." -ForegroundColor Yellow
    }
    $acpiByClass = Get-PnpDevice -Class ACPI -ErrorAction SilentlyContinue | Where-Object { $_.FriendlyName -match "INT3404|INT3400|DPTF|Thermal|Dynamic Tuning|Fan Participant" }
    $acpiById   = Get-PnpDevice -ErrorAction SilentlyContinue | Where-Object { $_.InstanceId -match "ACPI\\INT340[04]" }
    $acpi = @($acpiByClass) + @($acpiById) | Sort-Object -Property InstanceId -Unique
    if ($acpi) {
        Write-Host "ACPI devices (DPTF/thermal/fan, INT3404/INT3400):" -ForegroundColor Green
        $acpi | Select-Object Class, Status, FriendlyName, InstanceId | Format-Table -AutoSize
    } else {
        Write-Host "No DPTF-related ACPI device (INT3404/INT3400) found." -ForegroundColor Yellow
        Write-Host "  -> INT3404 = DPTF fan device (_FSL); INT3400 = thermal. Without these, Windows/DPTF cannot send fan control." -ForegroundColor DarkGray
    }
    $any = Get-PnpDevice -ErrorAction SilentlyContinue | Where-Object { $_.FriendlyName -match "Dynamic Tuning|Fan Participant" }
    if ($any -and -not $acpi) {
        Write-Host "Dynamic Tuning devices (any class):" -ForegroundColor Cyan
        $any | Select-Object Class, Status, FriendlyName | Format-Table -AutoSize
        Write-Host "  -> Check device Details for 'Device instance path'; if ACPI\INT3404\0, the fan device is present but was missed by class filter." -ForegroundColor DarkGray
    }
    Write-Host ""

    # Power / thermal (DPTF may be gated by power plan or OEM settings)
    Write-Host "=== Power / thermal (for DPTF fan control) ===" -ForegroundColor Cyan
    try {
        $active = powercfg /getactivescheme
        if ($active) {
            Write-Host "Active power scheme:" -ForegroundColor Green
            $active
        }
    } catch {}
    Write-Host "Manual check:" -ForegroundColor Yellow
    Write-Host "  1. Settings -> System -> Power -> Power mode / Additional power settings" -ForegroundColor DarkGray
    Write-Host "  2. Control Panel -> Power Options -> Change plan settings -> Change advanced power settings" -ForegroundColor DarkGray
    Write-Host "     Look for: Processor power, Intel, Thermal, or OEM (e.g. Acer) thermal/fan." -ForegroundColor DarkGray
    Write-Host "  3. Device Manager -> Intel Dynamic Tuning Fan Participant -> Properties -> Driver: ensure enabled, no errors." -ForegroundColor DarkGray
    Write-Host "  4. OEM app (e.g. Acer Care, Lenovo Vantage): turn OFF any 'quiet/silent fan' or 'disable DPTF'." -ForegroundColor DarkGray
    Write-Host ""
}

# ---- 2) High-frequency _FST poll and log ----
function Start-FstPollLog {
    if (-not (Test-Path $EctestPath)) {
        Write-Host "ectest not found: $EctestPath" -ForegroundColor Red
        return
    }
    $ts = Get-Date -Format "yyyyMMdd_HHmmss"
    $csvPath = Join-Path $LogDir "FST_poll_$ts.csv"
    $end = [DateTime]::UtcNow.AddSeconds($PollSeconds)
    Write-Host "Polling _FST every $PollIntervalMs ms for $PollSeconds s. Log: $csvPath" -ForegroundColor Cyan
    Write-Host "Apply CPU load (e.g. stress) to see if FAND changes. Ctrl+C to stop early." -ForegroundColor Yellow
    $headers = "TimeUtc,ElapsedMs,FAND"
    $headers | Set-Content $csvPath -Encoding UTF8
    $t0 = [DateTime]::UtcNow
    $lastFand = $null
    $changeCount = 0
    while ([DateTime]::UtcNow -lt $end) {
        $out = & $EctestPath -acpi "\_SB.ECT0._FST" 2>$null
        $fand = $null
        $capture = $false
        foreach ($line in ($out -split "`n")) {
            if ($line -match 'Argument\[1\]:') { $capture = $true; continue }
            if ($capture -and $line -match 'Integer Value:\s*(0x[0-9A-Fa-f]+|\d+)') {
                $fand = $Matches[1]
                break
            }
        }
        $elapsed = ([DateTime]::UtcNow - $t0).TotalMilliseconds
        $val = if ($fand) { $fand } else { "N/A" }
        $line = "{0:O},{1:F0},{2}" -f [DateTime]::UtcNow, $elapsed, $val
        Add-Content $csvPath $line -Encoding UTF8
        if ($null -ne $lastFand -and $fand -ne $lastFand) { $changeCount++ }
        $lastFand = $fand
        [System.Threading.Thread]::Sleep([int]$PollIntervalMs)
    }
    Write-Host "Done. FAND changed $changeCount times. Log: $csvPath" -ForegroundColor Green
}

# ---- 2b) Watch FAND: print only when value changes (see if INT3404 sends _FSL) ----
function Start-FstWatch {
    if (-not (Test-Path $EctestPath)) {
        Write-Host "ectest not found: $EctestPath" -ForegroundColor Red
        return
    }
    $ts = Get-Date -Format "yyyyMMdd_HHmmss"
    $csvPath = Join-Path $LogDir "FST_watch_$ts.csv"
    $end = [DateTime]::UtcNow.AddSeconds($PollSeconds)
    Write-Host "=== INT3404 / FAND watch (FAND change = something wrote _FSL) ===" -ForegroundColor Cyan
    Write-Host "Polling _FST every $PollIntervalMs ms for $PollSeconds s. Log: $csvPath" -ForegroundColor Cyan
    Write-Host "Apply CPU load; if you see 'FAND changed' below, INT3404 or host wrote _FSL." -ForegroundColor Yellow
    Write-Host ""
    "TimeUtc,ElapsedMs,FAND,Changed" | Set-Content $csvPath -Encoding UTF8
    $t0 = [DateTime]::UtcNow
    $lastFand = $null
    $changeCount = 0
    while ([DateTime]::UtcNow -lt $end) {
        $out = & $EctestPath -acpi "\_SB.ECT0._FST" 2>$null
        $fand = $null
        $capture = $false
        foreach ($line in ($out -split "`n")) {
            if ($line -match 'Argument\[1\]:') { $capture = $true; continue }
            if ($capture -and $line -match 'Integer Value:\s*(0x[0-9A-Fa-f]+|\d+)') {
                $fand = $Matches[1]
                break
            }
        }
        $val = if ($fand) { $fand } else { "N/A" }
        $elapsed = ([DateTime]::UtcNow - $t0).TotalMilliseconds
        $changed = $false
        if ($null -ne $lastFand -and $fand -ne $lastFand) {
            $changeCount++
            $changed = $true
            Write-Host ("  {0}  FAND changed: {1} -> {2}" -f (Get-Date -Format "HH:mm:ss"), $lastFand, $val) -ForegroundColor Green
        }
        $flag = if ($changed) { "1" } else { "0" }
        $line = "{0:O},{1:F0},{2},{3}" -f [DateTime]::UtcNow, $elapsed, $val, $flag
        Add-Content $csvPath $line -Encoding UTF8
        $lastFand = $fand
        [System.Threading.Thread]::Sleep([int]$PollIntervalMs)
    }
    Write-Host ""
    if ($changeCount -eq 0) {
        Write-Host "FAND never changed => INT3404 did not send _FSL (or EC overwrote)." -ForegroundColor Yellow
    } else {
        Write-Host "FAND changed $changeCount times => fan control was written (e.g. by INT3404)." -ForegroundColor Green
    }
    Write-Host "Log: $csvPath" -ForegroundColor Cyan
}

# ---- 3) ETW trace (DPTF / ESIF) ----
function Start-DptfEtwTrace {
    $isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
    if (-not $isAdmin) {
        Write-Host "ETW mode requires Administrator. Right-click PowerShell -> Run as administrator, then run again." -ForegroundColor Red
        return
    }
    $ts = Get-Date -Format "yyyyMMdd_HHmmss"
    $etlPath = Join-Path $LogDir "DPTF_trace_$ts.etl"
    $sessionName = "DptfMonitorSession"
    # Remove if leftover (suppress "data collector set not found" and "access denied" when not admin)
    $null = cmd /c "logman stop $sessionName 2>nul"
    $null = cmd /c "logman delete $sessionName 2>nul"
    # Prefer ESIF low-level (often present when DPTF is installed)
    $providers = @(
        @{ N = "EsifLfEtwProvider"; K = "0x200000"; L = 5 },
        @{ N = "EsifUmdf2EtwProvider"; K = "0xFFFFFFFF"; L = 5 }
    )
    $added = $false
    foreach ($p in $providers) {
        $err = & { logman create trace $sessionName -p $p.N $p.K $p.L -o $etlPath -ets 2>&1 }
        if ($LASTEXITCODE -eq 0) {
            Write-Host "Created trace with provider: $($p.N)" -ForegroundColor Green
            $added = $true
            break
        }
    }
    if (-not $added) {
        Write-Host "Could not create trace. Possible causes:" -ForegroundColor Red
        Write-Host "  - Not running as Administrator (required for ETW)." -ForegroundColor DarkGray
        Write-Host "  - DPTF ETW providers (EsifLfEtwProvider etc.) not registered on this build." -ForegroundColor DarkGray
        Write-Host "You can still use -Mode watch to see if FAND changes." -ForegroundColor Yellow
        return
    }
    logman start $sessionName -ets
    Write-Host "ETW trace started. Run CPU stress for 1-2 min, then press Enter to stop..." -ForegroundColor Yellow
    Read-Host
    logman stop $sessionName -ets
    $csvOut = $etlPath -replace '\.etl$', '.csv'
    tracerpt $etlPath -o $csvOut -of CSV 2>$null
    if (Test-Path $csvOut) {
        Write-Host "Trace summary: $csvOut" -ForegroundColor Green
    }
    Write-Host "Raw ETL: $etlPath" -ForegroundColor Cyan
    logman delete $sessionName -ets 2>$null
}

# ---- Main ----
switch ($Mode) {
    "check" {
        Get-DptfPresence
    }
    "poll" {
        Get-DptfPresence
        Start-FstPollLog
    }
    "watch" {
        Get-DptfPresence
        Start-FstWatch
    }
    "etw" {
        Get-DptfPresence
        Start-DptfEtwTrace
    }
    "all" {
        Get-DptfPresence
        Start-DptfEtwTrace
        Write-Host "Now polling _FST for $PollSeconds s..." -ForegroundColor Cyan
        Start-FstPollLog
    }
}
