GUI
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
package localuart
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.bug.st/serial"
|
||||
)
|
||||
|
||||
const (
|
||||
bufferSize = 4096
|
||||
readTimeout = 50 * time.Millisecond
|
||||
idle = 200 * time.Millisecond
|
||||
silenceTimeout = 2 * time.Second // если вообще нет ответа — не виснуть
|
||||
)
|
||||
|
||||
// Port — открытый напрямую USB-UART порт (без демона).
|
||||
type Port struct {
|
||||
name string
|
||||
port serial.Port
|
||||
}
|
||||
|
||||
// Open открывает порт по имени на заданной скорости.
|
||||
func Open(name string, baud int) (*Port, error) {
|
||||
mode := &serial.Mode{BaudRate: baud}
|
||||
p, err := serial.Open(name, mode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := p.SetReadTimeout(readTimeout); err != nil {
|
||||
_ = p.Close()
|
||||
return nil, err
|
||||
}
|
||||
return &Port{name: name, port: p}, nil
|
||||
}
|
||||
|
||||
// Name возвращает имя порта (например /dev/ttyUSB0 или COM3).
|
||||
func (p *Port) Name() string { return p.name }
|
||||
|
||||
// Write отправляет команду устройству (как в internal/uart.UART).
|
||||
func (p *Port) Write(cmd string) error {
|
||||
_, err := p.port.Write([]byte(strings.TrimSpace(cmd) + "\r"))
|
||||
return err
|
||||
}
|
||||
|
||||
// ReadResponse читает ответ до паузы в потоке данных (idle), либо
|
||||
// возвращает ошибку, если устройство вообще не ответило за silenceTimeout —
|
||||
// это важно для standalone-режима: кнопка проверки не должна виснуть
|
||||
// навсегда, если выбранный порт "не тот".
|
||||
func (p *Port) ReadResponse() (string, error) {
|
||||
buf := make([]byte, bufferSize)
|
||||
var out bytes.Buffer
|
||||
|
||||
received := false
|
||||
lastData := time.Now()
|
||||
started := time.Now()
|
||||
for {
|
||||
n, err := p.port.Read(buf)
|
||||
if err != nil && err != io.EOF {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if n > 0 {
|
||||
received = true
|
||||
lastData = time.Now()
|
||||
out.Write(buf[:n])
|
||||
}
|
||||
|
||||
if received && time.Since(lastData) >= idle {
|
||||
return strings.TrimSpace(out.String()), nil
|
||||
}
|
||||
if !received && time.Since(started) >= silenceTimeout {
|
||||
return "", io.ErrNoProgress
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Exec отправляет команду и возвращает ответ устройства.
|
||||
func (p *Port) Exec(cmd string) (string, error) {
|
||||
if err := p.Write(cmd); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return p.ReadResponse()
|
||||
}
|
||||
|
||||
// Close закрывает порт.
|
||||
func (p *Port) Close() error {
|
||||
return p.port.Close()
|
||||
}
|
||||
Reference in New Issue
Block a user