Skip to content

Instantly share code, notes, and snippets.

@larsgk
Created September 23, 2016 12:10
Show Gist options
  • Save larsgk/932232c83d6d21d9040bc6694d6c7b1d to your computer and use it in GitHub Desktop.
Save larsgk/932232c83d6d21d9040bc6694d6c7b1d to your computer and use it in GitHub Desktop.
Get PnP data (VID, PID, deviceName) from serial ports where available
package main
import (
"bufio"
serial "github.com/facchinm/go-serial"
"log"
"os/exec"
"strconv"
"strings"
)
func getPnPDetailsByUdevadm(path string) (*SerialPort, error) {
out, err := exec.Command("udevadm", "info", "-q", "path", "-n", path).Output()
if err != nil {
log.Printf("Error creating exec.Command: %v\n", err)
return nil, err
}
syspath := strings.TrimSpace(string(out))
cmd := exec.Command("udevadm", "info", "--query=property", "-p", syspath)
cmdReader, err := cmd.StdoutPipe()
if err != nil {
log.Printf("Error creating StdoutPipe: %v\n", err)
return nil, err
}
var VID, PID uint16 = 0, 0
var displayName string = ""
scanner := bufio.NewScanner(cmdReader)
stop := make(chan bool)
go func() {
for scanner.Scan() {
// log.Printf("READ> %s\n", scanner.Text())
keyValue := strings.Split(scanner.Text(), "=")
if len(keyValue) > 1 {
switch keyValue[0] {
case "ID_MODEL", "ID_MODEL_FROM_DATABASE":
if len(displayName) == 0 {
displayName = keyValue[1]
}
case "ID_VENDOR_ID":
val, _ := strconv.ParseUint(strings.Replace(keyValue[1], "0x", "", 1), 16, 16)
VID = uint16(val)
case "ID_MODEL_ID":
val, _ := strconv.ParseUint(strings.Replace(keyValue[1], "0x", "", 1), 16, 16)
PID = uint16(val)
}
}
}
stop <- true
}()
err = cmd.Start()
if err != nil {
log.Printf("Error starting cmd: %v\n", err)
return nil, err
}
<-stop
err = cmd.Wait()
if err != nil {
log.Printf("Error waiting for cmd: %v\n", err)
return nil, err
}
return &SerialPort{Path: path, VendorId: VID, ProductId: PID, DisplayName: displayName}, err
}
func GetSerialPortList() ([]SerialPort, error) {
serialPorts := []SerialPort{}
paths, err := serial.GetPortsList()
if err == nil {
for _, path := range paths {
serialPort, err := getPnPDetailsByUdevadm(path)
if err == nil {
serialPorts = append(serialPorts, *serialPort)
}
}
}
return serialPorts, err
}
package main
import (
"github.com/go-ole/go-ole"
"github.com/go-ole/go-ole/oleutil"
"log"
"regexp"
"strconv"
)
func init() {
err := ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED)
if err != nil {
log.Fatal("Init error: ", err)
}
}
func GetSerialPortList() ([]SerialPort, error) {
unknown, _ := oleutil.CreateObject("WbemScripting.SWbemLocator")
defer unknown.Release()
wmi, _ := unknown.QueryInterface(ole.IID_IDispatch)
defer wmi.Release()
serviceRaw, _ := oleutil.CallMethod(wmi, "ConnectServer")
service := serviceRaw.ToIDispatch()
defer service.Release()
query := "SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0 and Name like '%(COM%'"
queryResult, err := oleutil.CallMethod(service, "ExecQuery", query)
serialPorts := []SerialPort{}
if err != nil {
log.Printf("Error from oleutil.CallMethod: ", err)
return nil, err
}
result := queryResult.ToIDispatch()
defer result.Release()
countVar, _ := oleutil.GetProperty(result, "Count")
count := int(countVar.Val)
// Should we filter on VID/PID here or later?
for i := 0; i < count; i++ {
itemRaw, _ := oleutil.CallMethod(result, "ItemIndex", i)
item := itemRaw.ToIDispatch()
defer item.Release()
displayName, _ := oleutil.GetProperty(item, "Name")
re := regexp.MustCompile("\\((COM[0-9]+)\\)").FindAllStringSubmatch(displayName.ToString(), 1)
var path string = ""
if re != nil && len(re[0]) > 1 {
path = re[0][1]
}
deviceId, _ := oleutil.GetProperty(item, "DeviceID")
re = regexp.MustCompile("ID_(....)").FindAllStringSubmatch(deviceId.ToString(), 2)
var VID, PID uint16 = 0, 0
if re != nil && len(re) == 2 {
if len(re[0]) > 1 {
val, _ := strconv.ParseUint(re[0][1], 16, 16)
VID = uint16(val)
}
if len(re[1]) > 1 {
val, _ := strconv.ParseUint(re[1][1], 16, 16)
PID = uint16(val)
}
}
serialPorts = append(serialPorts, SerialPort{Path: path, VendorId: VID, ProductId: PID, DisplayName: displayName.ToString()})
}
return serialPorts, err
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment