-
Notifications
You must be signed in to change notification settings - Fork 44
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Powershell script shows which serial ports are for which function on …
…Windows (#133)
- Loading branch information
Showing
1 changed file
with
218 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,218 @@ | ||
Set-StrictMode -Version Latest | ||
|
||
# execute as follows: | ||
# First, load the script from a Windows Powershell prompt: | ||
# . .\show_port_info.ps1 | ||
# If necessary, permit the loading of the script (only after reviewing what the script does below): | ||
# Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process | ||
# Then, run the function that was defined by the script: | ||
# Get-BusPirateDetails | ||
# | ||
# If something goes awry, you can execute the script with more verbose output: | ||
# Get-BusPirateDetails -Verbose -Debug | ||
|
||
# Example output with a single BusPirate5 device connected: | ||
# | ||
# PS C:\Users\ian> Get-BusPirateDetails | ||
# InstanceId : USB\VID_1209&PID_7331\FEDCBA9876543210 | ||
# Serial : FEDCBA9876543210 | ||
# Location : Port_#0003.Hub_#0007 | ||
# InstanceID_Terminal : USB\VID_1209&PID_7331&MI_00\8&32E00187&0&0000 | ||
# Port_Terminal : COM55 | ||
# InstanceID_Binary : USB\VID_1209&PID_7331&MI_02\8&32E00187&0&0002 | ||
# Port_Binary : COM56 | ||
# InstanceId_Storage : USB\VID_1209&PID_7331&MI_04\8&32E00187&0&0004 | ||
# | ||
# Which shows that, to connect to the terminal of this BP5, one should use COM55. | ||
# similarly, the binary serial port is using COM56. | ||
|
||
|
||
function Has-Property { | ||
param ( | ||
[object]$Object, | ||
[string]$PropertyName | ||
) | ||
|
||
# Not all objects have the 'PSObject' property nor the 'Properties' property | ||
# So the following commented-out code is not great with strict mode enabled. | ||
# if ($Object.PSObject.Properties.Match($PropertyName) -eq $null) { | ||
# return $true; | ||
# } else { | ||
# return $false; | ||
# } | ||
|
||
# Instead, brute force it (not great performance-wise, but it works) | ||
if ($Object -eq $null) { | ||
return $false; | ||
} | ||
$properties = $Object | Get-Member -MemberType Properties | ||
if ($properties.Name -contains $PropertyName) { | ||
return $true; | ||
} else { | ||
return $false; | ||
} | ||
|
||
} | ||
function Get-BusPirate { | ||
# USB VID and PID for the Bus Pirate devices seems to fluctuate slightly? | ||
# 0x1209 / 0x7331 - Bus Pirate 5 | ||
# 0x1209 / 0x7332 - Bus Pirate 5 | ||
# | ||
# The composite device instance ID is of the form: | ||
# USB\VID_1209&PID_7331\{serial} | ||
# | ||
# The interface instance IDs are of the form: | ||
# USB\VID_1209&PID_7331&MI{interface}\{USB_Specific_Path} | ||
# | ||
# Get only the composite (root) device (no `MI{interface}`) | ||
# | ||
Get-PnpDevice -PresentOnly | | ||
Where-Object { | ||
$_.InstanceId -match '^USB\\VID_1209&PID_733[\dA-Fa-f]\\' | ||
} | ||
} | ||
|
||
function Get-BusPirateDetails { | ||
[CmdletBinding()] | ||
param ( | ||
[Parameter(Mandatory=$false)] | ||
[object]$InstanceId, | ||
[switch]$IncludeResultsWithErrors | ||
) | ||
|
||
Write-Verbose "Function Entry - Get-BusPirateDetails" | ||
|
||
[System.Collections.Generic.List[String]]$errors = [System.Collections.Generic.List[String]]::new(); | ||
|
||
[CimInstance]$rootDevice = $null; | ||
|
||
# get all instances, if no instance ID was provided | ||
if (-not $PSCmdlet.MyInvocation.BoundParameters.ContainsKey('InstanceId')) { | ||
Get-BusPirate |% { | ||
Get-BusPirateDetails -InstanceId $_; | ||
} | ||
return; | ||
} elseif ($InstanceId -is [CimInstance]) { | ||
$rootDevice = $InstanceId; | ||
} elseif ($InstanceId -is [String]) { | ||
$rootDevice = Get-PnpDevice -PresentOnly -InstanceId $InstanceId; | ||
} else { | ||
Out-Error "Unsupported input type: $($InstanceId.GetType().FullName) -- Only support [String] and [CimInstance]"; | ||
return; | ||
} | ||
|
||
Write-Verbose "Processing root device $($rootDevice.InstanceId)" | ||
|
||
$resultObj = New-Object PSObject -Property @{ InstanceId = $device.InstanceId }; | ||
|
||
# Hack ... the serial number is the tail end of the instance ID | ||
$serialNumber = ($rootDevice.InstanceId -split '\\')[-1]; | ||
Write-Verbose "Serial number: $($serialNumber)" | ||
$resultObj | Add-Member -MemberType NoteProperty -Name Serial -Value $serialNumber; | ||
|
||
# The USB hub and port data is sometimes useful | ||
$location = (Get-PnpDeviceProperty -InstanceId $rootDevice.InstanceId -KeyName DEVPKEY_Device_LocationInfo).Data; | ||
Write-Verbose "Location: $($location)" | ||
$resultObj | Add-Member -MemberType NoteProperty -Name Location -Value $location | ||
|
||
|
||
# Each composite device has a list of child devices, one for each interface. | ||
[String[]]$interfaces = (Get-PnpDeviceProperty -InstanceId $rootDevice.InstanceId -KeyName DEVPKEY_Device_BusRelations).Data | ||
Write-Verbose "Found $($interfaces.Count) interfaces" | ||
$interfaces |% { Write-Verbose "Interface: $_" } | ||
|
||
# Loop through those interfaces to add additional information to the result object | ||
$interfaces |% { | ||
|
||
Write-Verbose "Processing interface $_" | ||
|
||
[CimInstance] $interface = Get-PnpDevice -PresentOnly -InstanceId $_; | ||
|
||
Write-Verbose " FriendlyName: $interface.FriendlyName" | ||
|
||
|
||
# Mass storage devices (MSC) have a friendly name of the form "USB Mass Storage Device" | ||
# Serial ports (CDC) have a friendly name of the form "USB Serial Device (COM<n>)" (where <n> is a decimal number) | ||
if ($interface.FriendlyName -match 'USB Mass Storage Device') { | ||
|
||
# add the mass storage instanceID to the result object | ||
if (Has-Property -PSObject $resultObj -PropertyName 'InstanceId_Storage') { | ||
$errors.Add("Multiple storage interfaces detected: $($interface.InstanceId) friendlyName $($interface.FriendlyName)"); | ||
} else { | ||
$resultObj | Add-Member -MemberType NoteProperty -Name InstanceId_Storage -Value $interface.InstanceId; | ||
} | ||
|
||
} elseif ($interface.FriendlyName -match 'USB Serial Device \(COM(\d+)\)') { | ||
|
||
$port = "COM$($Matches[1])"; | ||
|
||
# The actual type of the CDC interface is defined by the bus-reported device description | ||
# Currently, two CDC interfaces are supported, reporting the name as either: | ||
# Bus Pirate BIN | ||
# Bus Pirate CDC | ||
$interfaceName = (Get-PnpDeviceProperty -InstanceId $interface.InstanceId -KeyName DEVPKEY_Device_BusReportedDeviceDesc).Data; | ||
|
||
if ($interfaceName -match 'CDC$') { | ||
|
||
if ( Has-Property -PSObject $resultObj -PropertyName 'InstanceId_Terminal') { | ||
$errors.Add("Multiple CDC interfaces (a) detected: $($interface.InstanceId) / $($interface.FriendlyName) / $($interfaceName)"); | ||
} elseif (Has-Property -PSObject $resultObj -PropertyName 'Port_Terminal') { | ||
$errors.Add("Multiple CDC interfaces (b) detected: $($interface.InstanceId) / $($interface.FriendlyName) / $($interfaceName)"); | ||
} else { | ||
$resultObj | Add-Member -MemberType NoteProperty -Name InstanceID_Terminal -Value $interface.InstanceId; | ||
$resultObj | Add-Member -MemberType NoteProperty -Name Port_Terminal -Value $port; | ||
} | ||
|
||
} elseif ($interfaceName -match 'BIN') { | ||
|
||
if ( Has-Property -PSObject $resultObj -PropertyName 'InstanceId_Binary') { | ||
$errors.Add("Multiple BIN interfaces (a) detected: $($interface.InstanceId) / $($interface.FriendlyName) / $($interfaceName)"); | ||
} elseif (Has-Property -PSObject $resultObj -PropertyName 'Port_Binary') { | ||
$errors.Add("Multiple BIN interfaces (b) detected: $($interface.InstanceId) / $($interface.FriendlyName) / $($interfaceName)"); | ||
} else { | ||
$resultObj | Add-Member -MemberType NoteProperty -Name InstanceID_Binary -Value $interface.InstanceId; | ||
$resultObj | Add-Member -MemberType NoteProperty -Name Port_Binary -Value $port; | ||
} | ||
|
||
} else { | ||
|
||
$errors.Add("Unknown CDC interface: $($interface.InstanceId) / $($interface.FriendlyName) / $($interfaceName)"); | ||
|
||
} | ||
|
||
} else { | ||
|
||
$errors.Add("Unknown interface type: $($interface.InstanceId) / $($interface.FriendlyName)"); | ||
|
||
} | ||
|
||
} | ||
|
||
# Verify all the expected information was added. | ||
[String[]]$MandatoryProperties = @('InstanceId', 'Serial', 'Location', 'InstanceId_Terminal', 'Port_Terminal', 'InstanceId_Binary', 'Port_Binary', 'InstanceId_Storage'); | ||
$MandatoryProperties |% { | ||
Write-Verbose "Checking for property: $_" | ||
[String]$propertyToCheck = $_; | ||
if (-not (Has-Property -Object $resultObj -PropertyName $propertyToCheck)) { | ||
Write-Verbose "Did not find property: $_" | ||
$errors.Add("Missing property: $($propertyToCheck)"); | ||
} | ||
} | ||
|
||
# $errors.Add("Test error"); | ||
|
||
# Were there any errors detected? | ||
if ($errors.Count -eq 0) { | ||
return $resultObj; | ||
} elseif ($IncludeResultsWithErrors) { | ||
$resultObj | Add-Member -MemberType NoteProperty -Name Errors -Value $errors; | ||
return $resultObj; | ||
} | ||
# else had errors, but flag to return objects with errors was not provided. | ||
Write-Error "Detected $($errors.Count) errors for device $($rootDevice.InstanceId)"; | ||
$errors |% { | ||
Write-Debug " Error: $($_)"; | ||
} | ||
return; | ||
} | ||
|