From 425456c7e78f216b34190fe5c69e43d256c797fb Mon Sep 17 00:00:00 2001 From: Ivan Tustanivskyi Date: Tue, 24 Feb 2026 13:23:17 +0200 Subject: [PATCH 1/7] fix: Pass `--platform` param to set default Switch (Ounce) targets --- app-runner/Private/DeviceProviders/SwitchProvider.ps1 | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app-runner/Private/DeviceProviders/SwitchProvider.ps1 b/app-runner/Private/DeviceProviders/SwitchProvider.ps1 index 5e0c819..4a6fdbc 100644 --- a/app-runner/Private/DeviceProviders/SwitchProvider.ps1 +++ b/app-runner/Private/DeviceProviders/SwitchProvider.ps1 @@ -44,7 +44,7 @@ class SwitchProvider : DeviceProvider { 'reset' = @($this.TargetControlTool, 'reset') 'getstatus' = @($this.TargetControlTool, 'get-default --detail --json', { $input | ConvertFrom-Json }) 'get-default-target' = @($this.TargetControlTool, 'get-default --json', { $input | ConvertFrom-Json }) - 'set-default-target' = @($this.TargetControlTool, 'set-default --target "{0}"') + 'set-default-target' = @($this.TargetControlTool, 'set-default --target "{0}" --platform {1}') 'list-target' = @($this.TargetControlTool, 'list-target --json', { $input | ConvertFrom-Json }) 'detect-target' = @($this.TargetControlTool, 'detect-target --json', { $input | ConvertFrom-Json }) 'register-target' = @($this.TargetControlTool, 'register --target "{0}"') @@ -66,7 +66,12 @@ class SwitchProvider : DeviceProvider { if (-not [string]::IsNullOrEmpty($target)) { Write-Debug "$($this.Platform): Setting target device: $target" $this.Target = $target - $this.InvokeCommand('set-default-target', @($target)) + + # Target Manager 2 requires the platform to be specified explicitly. + # Platform can be inferred from the target name (HAL* targets are Ounce/Switch 2, others are NX/Switch 1). + $platform = if ($target -match '^HAL') { 'Ounce' } else { 'NX' } + + $this.InvokeCommand('set-default-target', @($target, $platform)) } return $this.Connect() } From 0bf9ee703cb2e6aea9c2e6b0d78a3137370c352c Mon Sep 17 00:00:00 2001 From: Ivan Tustanivskyi Date: Tue, 24 Feb 2026 15:30:38 +0200 Subject: [PATCH 2/7] Add platform arg for getstatus command --- .../DeviceProviders/SwitchProvider.ps1 | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/app-runner/Private/DeviceProviders/SwitchProvider.ps1 b/app-runner/Private/DeviceProviders/SwitchProvider.ps1 index 4a6fdbc..178a9b1 100644 --- a/app-runner/Private/DeviceProviders/SwitchProvider.ps1 +++ b/app-runner/Private/DeviceProviders/SwitchProvider.ps1 @@ -17,6 +17,7 @@ class SwitchProvider : DeviceProvider { [string]$TargetControlTool = 'ControlTarget.exe' [string]$ApplicationRunnerTool = 'RunOnTarget.exe' [string]$Target = $null # Stores the target device identifier for commands that need explicit --target + [string]$TargetPlatform = $null # Target Manager platform: 'NX' or 'Ounce', resolved from target serial SwitchProvider() { $this.Platform = 'Switch' @@ -42,7 +43,7 @@ class SwitchProvider : DeviceProvider { 'poweroff' = @($this.TargetControlTool, 'power-off') 'press-power-button' = @($this.TargetControlTool, 'press-power-button') 'reset' = @($this.TargetControlTool, 'reset') - 'getstatus' = @($this.TargetControlTool, 'get-default --detail --json', { $input | ConvertFrom-Json }) + 'getstatus' = @($this.TargetControlTool, 'get-default --detail --platform {0} --json', { $input | ConvertFrom-Json }) 'get-default-target' = @($this.TargetControlTool, 'get-default --json', { $input | ConvertFrom-Json }) 'set-default-target' = @($this.TargetControlTool, 'set-default --target "{0}" --platform {1}') 'list-target' = @($this.TargetControlTool, 'list-target --json', { $input | ConvertFrom-Json }) @@ -69,13 +70,38 @@ class SwitchProvider : DeviceProvider { # Target Manager 2 requires the platform to be specified explicitly. # Platform can be inferred from the target name (HAL* targets are Ounce/Switch 2, others are NX/Switch 1). - $platform = if ($target -match '^HAL') { 'Ounce' } else { 'NX' } + $this.TargetPlatform = if ($target -match '^HAL') { 'Ounce' } else { 'NX' } + Write-Debug "$($this.Platform): Using Target Manager platform: $($this.TargetPlatform)" - $this.InvokeCommand('set-default-target', @($target, $platform)) + $this.InvokeCommand('set-default-target', @($target, $this.TargetPlatform)) } return $this.Connect() } + # Override DetectAndSetDefaultTarget to skip auto-detection when target was explicitly set in Connect + [void] DetectAndSetDefaultTarget() { + if (-not [string]::IsNullOrEmpty($this.Target)) { + Write-Debug "$($this.Platform): Target explicitly set to $($this.Target), skipping auto-detection" + return + } + ([DeviceProvider] $this).DetectAndSetDefaultTarget() + } + + # Override GetDeviceStatus to include `--platform` arg when querying device status so that it works correctly when multiple platforms are registered + [hashtable] GetDeviceStatus() { + Write-Debug "$($this.Platform): Getting device status" + + $platform = if ($this.TargetPlatform) { $this.TargetPlatform } else { 'NX' } + $result = $this.InvokeCommand('getstatus', @($platform)) + + return @{ + Platform = $this.Platform + Status = 'Online' + StatusData = $result + Timestamp = Get-Date + } + } + # Override Connect to provide Switch specific wakeup [hashtable] Connect() { Write-Debug 'Connecting to Switch Devkit...' From 78524035c7d348ca748b9ea6cbc4d15d0904c4fb Mon Sep 17 00:00:00 2001 From: Ivan Tustanivskyi Date: Tue, 24 Feb 2026 15:40:51 +0200 Subject: [PATCH 3/7] Override TestConnection --- app-runner/Private/DeviceProviders/SwitchProvider.ps1 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app-runner/Private/DeviceProviders/SwitchProvider.ps1 b/app-runner/Private/DeviceProviders/SwitchProvider.ps1 index 178a9b1..2b1e4b8 100644 --- a/app-runner/Private/DeviceProviders/SwitchProvider.ps1 +++ b/app-runner/Private/DeviceProviders/SwitchProvider.ps1 @@ -102,6 +102,12 @@ class SwitchProvider : DeviceProvider { } } + [bool] TestConnection() { + Write-Debug "$($this.Platform): Testing connection to device" + $this.GetDeviceStatus() + return $true + } + # Override Connect to provide Switch specific wakeup [hashtable] Connect() { Write-Debug 'Connecting to Switch Devkit...' From 52dc67247701012b14ee493e08bb28202ef1ace8 Mon Sep 17 00:00:00 2001 From: Ivan Tustanivskyi Date: Wed, 25 Feb 2026 09:24:16 +0200 Subject: [PATCH 4/7] Fix reboot mechanism --- .../Private/DeviceProviders/SwitchProvider.ps1 | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/app-runner/Private/DeviceProviders/SwitchProvider.ps1 b/app-runner/Private/DeviceProviders/SwitchProvider.ps1 index 2b1e4b8..24193d8 100644 --- a/app-runner/Private/DeviceProviders/SwitchProvider.ps1 +++ b/app-runner/Private/DeviceProviders/SwitchProvider.ps1 @@ -147,18 +147,25 @@ class SwitchProvider : DeviceProvider { } 2 { Write-Warning 'Attempting to reboot the Devkit...' + $powerOffCmd = $this.BuildCommand('poweroff', @()).Command + $powerOnCmd = $this.BuildCommand('poweron', @()).Command $job2 = Start-Job { - ControlTarget power-off + param($offCmd, $onCmd) + Invoke-Expression $offCmd Start-Sleep -Seconds 5 - ControlTarget power-on - } + Invoke-Expression $onCmd + } -ArgumentList $powerOffCmd, $powerOnCmd Wait-Job $job2 -Timeout 20 | Out-Null } 3 { if ($info.IpAddress -ne $null) { Write-Warning 'Attempting to reboot host bridge...' - Invoke-WebRequest -Uri "http://$($info.IpAddress)/cgi-bin/config?reboot" - $nextTimeout = 300 # This takes a long time so wait longer next time + try { + Invoke-WebRequest -Uri "http://$($info.IpAddress)/cgi-bin/config?reboot" + $nextTimeout = 300 # This takes a long time so wait longer next time + } catch { + Write-Warning "Failed to reboot host bridge: $_" + } } } } From ad65f1cd077dca35906d4133a31423424c86eb59 Mon Sep 17 00:00:00 2001 From: Ivan Tustanivskyi Date: Wed, 25 Feb 2026 09:34:51 +0200 Subject: [PATCH 5/7] Add connection status check --- app-runner/Private/DeviceProviders/SwitchProvider.ps1 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app-runner/Private/DeviceProviders/SwitchProvider.ps1 b/app-runner/Private/DeviceProviders/SwitchProvider.ps1 index 24193d8..f16c26d 100644 --- a/app-runner/Private/DeviceProviders/SwitchProvider.ps1 +++ b/app-runner/Private/DeviceProviders/SwitchProvider.ps1 @@ -176,6 +176,12 @@ class SwitchProvider : DeviceProvider { throw 'Failed to connect to the Switch Devkit.' } + # Verify the device is actually connected after recovery attempts + $finalStatus = $this.GetDeviceStatus().StatusData + if ("$($finalStatus.Status)" -ne 'Connected') { + throw "Failed to connect to the Switch Devkit. Device status: $($finalStatus.Status)" + } + Write-Debug 'Successfully connected to the Switch Devkit.' return $this.CreateSessionInfo() } From 2959cf52caca1fd8207fc79bdcc6d6b56f686ca6 Mon Sep 17 00:00:00 2001 From: Ivan Tustanivskyi Date: Wed, 25 Feb 2026 09:37:01 +0200 Subject: [PATCH 6/7] Test --- app-runner/Private/DeviceProviders/SwitchProvider.ps1 | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app-runner/Private/DeviceProviders/SwitchProvider.ps1 b/app-runner/Private/DeviceProviders/SwitchProvider.ps1 index f16c26d..2f2cfff 100644 --- a/app-runner/Private/DeviceProviders/SwitchProvider.ps1 +++ b/app-runner/Private/DeviceProviders/SwitchProvider.ps1 @@ -73,6 +73,16 @@ class SwitchProvider : DeviceProvider { $this.TargetPlatform = if ($target -match '^HAL') { 'Ounce' } else { 'NX' } Write-Debug "$($this.Platform): Using Target Manager platform: $($this.TargetPlatform)" + # Update device-control commands to include --target so they operate on the correct device + # when multiple targets (NX and Ounce) are registered in Target Manager. + $targetArg = " --target `"$target`"" + $this.Commands['connect'] = @($this.TargetControlTool, "connect --force$targetArg") + $this.Commands['disconnect'] = @($this.TargetControlTool, "disconnect$targetArg") + $this.Commands['poweron'] = @($this.TargetControlTool, "power-on$targetArg") + $this.Commands['poweroff'] = @($this.TargetControlTool, "power-off$targetArg") + $this.Commands['press-power-button'] = @($this.TargetControlTool, "press-power-button$targetArg") + $this.Commands['reset'] = @($this.TargetControlTool, "reset$targetArg") + $this.InvokeCommand('set-default-target', @($target, $this.TargetPlatform)) } return $this.Connect() From f90066c41f93ddd0d8818ece781b8cd2b6da2c3c Mon Sep 17 00:00:00 2001 From: Ivan Tustanivskyi Date: Wed, 25 Feb 2026 09:58:32 +0200 Subject: [PATCH 7/7] Test --- .../DeviceProviders/SwitchProvider.ps1 | 41 ++++++++++++------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/app-runner/Private/DeviceProviders/SwitchProvider.ps1 b/app-runner/Private/DeviceProviders/SwitchProvider.ps1 index 2f2cfff..9cd07df 100644 --- a/app-runner/Private/DeviceProviders/SwitchProvider.ps1 +++ b/app-runner/Private/DeviceProviders/SwitchProvider.ps1 @@ -146,26 +146,39 @@ class SwitchProvider : DeviceProvider { } } + # Recovery steps are best-effort: if one fails, continue to the next switch ($i) { 0 { - Write-Warning 'Attempting to wake up the Devkit from sleep...' - $this.InvokeCommand('press-power-button', @()) + try { + Write-Warning 'Attempting to wake up the Devkit from sleep...' + $this.InvokeCommand('press-power-button', @()) + } catch { + Write-Warning "Failed to wake up Devkit: $_" + } } 1 { - Write-Warning 'Attempting to start the Devkit...' - $this.StartDevice() + try { + Write-Warning 'Attempting to start the Devkit...' + $this.StartDevice() + } catch { + Write-Warning "Failed to start Devkit: $_" + } } 2 { - Write-Warning 'Attempting to reboot the Devkit...' - $powerOffCmd = $this.BuildCommand('poweroff', @()).Command - $powerOnCmd = $this.BuildCommand('poweron', @()).Command - $job2 = Start-Job { - param($offCmd, $onCmd) - Invoke-Expression $offCmd - Start-Sleep -Seconds 5 - Invoke-Expression $onCmd - } -ArgumentList $powerOffCmd, $powerOnCmd - Wait-Job $job2 -Timeout 20 | Out-Null + try { + Write-Warning 'Attempting to reboot the Devkit...' + $powerOffCmd = $this.BuildCommand('poweroff', @()).Command + $powerOnCmd = $this.BuildCommand('poweron', @()).Command + $job2 = Start-Job { + param($offCmd, $onCmd) + Invoke-Expression $offCmd + Start-Sleep -Seconds 5 + Invoke-Expression $onCmd + } -ArgumentList $powerOffCmd, $powerOnCmd + Wait-Job $job2 -Timeout 20 | Out-Null + } catch { + Write-Warning "Failed to reboot Devkit: $_" + } } 3 { if ($info.IpAddress -ne $null) {