137 lines
3.2 KiB
Go
137 lines
3.2 KiB
Go
//go:build linux
|
|
|
|
/*
|
|
* ============================================================================
|
|
* Projekt.....: rs2322tcp
|
|
* Datei.......: internal/client/virtual_port_manager_linux.go
|
|
* Copyright (C) 2026 Dieter Lang
|
|
*
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*
|
|
* Beschreibung:
|
|
* Linux-spezifische Erzeugung und Verwaltung virtueller rs2322tcp-Ports.
|
|
*
|
|
* Der öffentliche /dev/ttyUSBxxx-Eintrag wird bei der Installation
|
|
* bereitgestellt. Der Client verwaltet ausschließlich den internen Link
|
|
* unter ~/.rs2322tcp/virtual/.
|
|
* ============================================================================
|
|
*/
|
|
package client
|
|
|
|
import "fmt"
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Managed virtual port
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ManagedVirtualPort verbindet einen reservierten Port mit einer
|
|
// VirtualSerial-Instanz und verwaltet deren Lebenszyklus.
|
|
type ManagedVirtualPort struct {
|
|
port *VirtualPort
|
|
manager *VirtualPortManager
|
|
number int
|
|
}
|
|
|
|
// Path returns the device path visible to the external application.
|
|
func (p *ManagedVirtualPort) Path() string {
|
|
if p == nil || p.port == nil {
|
|
return ""
|
|
}
|
|
|
|
return p.port.Path()
|
|
}
|
|
|
|
// Read reads data from the underlying virtual serial device.
|
|
func (p *ManagedVirtualPort) Read(b []byte) (int, error) {
|
|
if p == nil || p.port == nil {
|
|
return 0, fmt.Errorf("managed virtual port is nil")
|
|
}
|
|
|
|
return p.port.Read(b)
|
|
}
|
|
|
|
// Write writes data to the underlying virtual serial device.
|
|
func (p *ManagedVirtualPort) Write(b []byte) (int, error) {
|
|
if p == nil || p.port == nil {
|
|
return 0, fmt.Errorf("managed virtual port is nil")
|
|
}
|
|
|
|
return p.port.Write(b)
|
|
}
|
|
|
|
// Close removes the internal link, closes the PTY and releases the
|
|
// reservation.
|
|
func (p *ManagedVirtualPort) Close() error {
|
|
if p == nil || p.port == nil {
|
|
return nil
|
|
}
|
|
|
|
var firstErr error
|
|
|
|
if err := removeVirtualPortLink(p.port.Path()); err != nil {
|
|
firstErr = err
|
|
}
|
|
|
|
if err := p.port.Close(); err != nil && firstErr == nil {
|
|
firstErr = err
|
|
}
|
|
|
|
if p.manager != nil {
|
|
p.manager.Release(p.number)
|
|
}
|
|
|
|
p.port = nil
|
|
|
|
return firstErr
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Open
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Open creates a new virtual serial port using the next free port number.
|
|
//
|
|
// The internal PTY is created by newVirtualSerial(). The internal
|
|
// ~/.rs2322tcp/virtual/ttyUSBxxx link is then pointed at the PTY.
|
|
func (m *VirtualPortManager) Open() (*ManagedVirtualPort, error) {
|
|
if m == nil {
|
|
return nil, fmt.Errorf("virtual port manager is nil")
|
|
}
|
|
|
|
number, err := m.Reserve()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
portPath := m.PortPath(number)
|
|
|
|
serial, err := newVirtualSerial()
|
|
if err != nil {
|
|
m.Release(number)
|
|
return nil, fmt.Errorf(
|
|
"create virtual serial for %s: %w",
|
|
portPath,
|
|
err,
|
|
)
|
|
}
|
|
|
|
if err := setVirtualPortLink(portPath, serial.Path()); err != nil {
|
|
_ = serial.Close()
|
|
m.Release(number)
|
|
|
|
return nil, fmt.Errorf(
|
|
"bind %s to %s: %w",
|
|
portPath,
|
|
serial.Path(),
|
|
err,
|
|
)
|
|
}
|
|
|
|
port := NewVirtualPort(portPath, serial)
|
|
|
|
return &ManagedVirtualPort{
|
|
port: port,
|
|
manager: m,
|
|
number: number,
|
|
}, nil
|
|
}
|