110 lines
2.7 KiB
Go
110 lines
2.7 KiB
Go
//
|
|
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
//
|
|
|
|
package enumerator
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"go.bug.st/serial"
|
|
)
|
|
|
|
func nativeGetDetailedPortsList() ([]*PortDetails, error) {
|
|
// Retrieve the port list
|
|
ports, err := serial.GetPortsList()
|
|
if err != nil {
|
|
return nil, &PortEnumerationError{causedBy: err}
|
|
}
|
|
|
|
var res []*PortDetails
|
|
for _, port := range ports {
|
|
details, err := nativeGetPortDetails(port)
|
|
if err != nil {
|
|
return nil, &PortEnumerationError{causedBy: err}
|
|
}
|
|
res = append(res, details)
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
func nativeGetPortDetails(portPath string) (*PortDetails, error) {
|
|
portName := filepath.Base(portPath)
|
|
devicePath := fmt.Sprintf("/sys/class/tty/%s/device", portName)
|
|
if _, err := os.Stat(devicePath); err != nil {
|
|
return &PortDetails{}, nil
|
|
}
|
|
realDevicePath, err := filepath.EvalSymlinks(devicePath)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Can't determine real path of %s: %s", devicePath, err.Error())
|
|
}
|
|
subSystemPath, err := filepath.EvalSymlinks(filepath.Join(realDevicePath, "subsystem"))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Can't determine real path of %s: %s", filepath.Join(realDevicePath, "subsystem"), err.Error())
|
|
}
|
|
subSystem := filepath.Base(subSystemPath)
|
|
|
|
result := &PortDetails{Name: portPath}
|
|
switch subSystem {
|
|
case "usb-serial":
|
|
err := parseUSBSysFS(filepath.Dir(filepath.Dir(realDevicePath)), result)
|
|
return result, err
|
|
case "usb":
|
|
err := parseUSBSysFS(filepath.Dir(realDevicePath), result)
|
|
return result, err
|
|
// TODO: other cases?
|
|
default:
|
|
return result, nil
|
|
}
|
|
}
|
|
|
|
func parseUSBSysFS(usbDevicePath string, details *PortDetails) error {
|
|
vid, err := readLine(filepath.Join(usbDevicePath, "idVendor"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
pid, err := readLine(filepath.Join(usbDevicePath, "idProduct"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
serial, err := readLine(filepath.Join(usbDevicePath, "serial"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
//manufacturer, err := readLine(filepath.Join(usbDevicePath, "manufacturer"))
|
|
//if err != nil {
|
|
// return err
|
|
//}
|
|
//product, err := readLine(filepath.Join(usbDevicePath, "product"))
|
|
//if err != nil {
|
|
// return err
|
|
//}
|
|
|
|
details.IsUSB = true
|
|
details.VID = vid
|
|
details.PID = pid
|
|
details.SerialNumber = serial
|
|
//details.Manufacturer = manufacturer
|
|
//details.Product = product
|
|
return nil
|
|
}
|
|
|
|
func readLine(filename string) (string, error) {
|
|
file, err := os.Open(filename)
|
|
if os.IsNotExist(err) {
|
|
return "", nil
|
|
}
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer file.Close()
|
|
reader := bufio.NewReader(file)
|
|
line, _, err := reader.ReadLine()
|
|
return string(line), err
|
|
}
|