71 lines
2.0 KiB
Go
71 lines
2.0 KiB
Go
// Package localuart находит и открывает USB-UART адаптер напрямую, без
|
|
// демона — для standalone-версии приложения (internal/localctl).
|
|
package localuart
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
|
|
"go.bug.st/serial/enumerator"
|
|
)
|
|
|
|
// knownVID — VID распространённых чипов USB-UART мостов. Порты с таким VID
|
|
// считаются вероятным переходником "UART to USB" и предлагаются первыми.
|
|
var knownVID = map[string]bool{
|
|
"0403": true, // FTDI
|
|
"1A86": true, // WCH CH340 / CH341
|
|
"10C4": true, // Silicon Labs CP210x
|
|
"067B": true, // Prolific PL2303
|
|
}
|
|
|
|
// Candidate — один найденный USB-serial порт.
|
|
type Candidate struct {
|
|
Name string
|
|
VID string
|
|
PID string
|
|
}
|
|
|
|
// ListCandidates возвращает USB-serial порты, обнаруженные в системе;
|
|
// порты с известным VID переходника идут первыми.
|
|
func ListCandidates() ([]Candidate, error) {
|
|
ports, err := enumerator.GetDetailedPortsList()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var known, other []Candidate
|
|
for _, p := range ports {
|
|
if !p.IsUSB {
|
|
continue
|
|
}
|
|
c := Candidate{
|
|
Name: p.Name,
|
|
VID: strings.ToUpper(p.VID),
|
|
PID: strings.ToUpper(p.PID),
|
|
}
|
|
if knownVID[c.VID] {
|
|
known = append(known, c)
|
|
} else {
|
|
other = append(other, c)
|
|
}
|
|
}
|
|
|
|
sort.Slice(known, func(i, j int) bool { return known[i].Name < known[j].Name })
|
|
sort.Slice(other, func(i, j int) bool { return other[i].Name < other[j].Name })
|
|
|
|
return append(known, other...), nil
|
|
}
|
|
|
|
// PickPort возвращает наиболее вероятный порт UART-to-USB переходника.
|
|
func PickPort() (string, error) {
|
|
candidates, err := ListCandidates()
|
|
if err != nil {
|
|
return "", fmt.Errorf("не удалось получить список портов: %w", err)
|
|
}
|
|
if len(candidates) == 0 {
|
|
return "", fmt.Errorf("USB-UART адаптер не найден")
|
|
}
|
|
return candidates[0].Name, nil
|
|
}
|