163 lines
3.3 KiB
Go
163 lines
3.3 KiB
Go
/*
|
|
* ============================================================================
|
|
* Projekt.....: rs2322tcp
|
|
* Datei.......: internal/client/virtual_port_manager_open.go
|
|
* Copyright (C) 2026 Dieter Lang
|
|
*
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*
|
|
* Beschreibung:
|
|
* Plattformneutrale Verwaltung geöffneter virtueller Ports.
|
|
*
|
|
* Die konkrete Erzeugung eines virtuellen seriellen Ports erfolgt über
|
|
* openVirtualPort() in der jeweiligen Plattformimplementierung.
|
|
* ============================================================================
|
|
*/
|
|
|
|
package client
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Managed virtual port
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ManagedVirtualPort verbindet einen reservierten Port mit einer
|
|
// VirtualSerial-Instanz und verwaltet deren Lebenszyklus.
|
|
type ManagedVirtualPort struct {
|
|
mu sync.Mutex
|
|
|
|
port *VirtualPort
|
|
manager *VirtualPortManager
|
|
number int
|
|
}
|
|
|
|
// Path returns the device path visible to the external application.
|
|
func (p *ManagedVirtualPort) Path() string {
|
|
if p == nil {
|
|
return ""
|
|
}
|
|
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
|
|
if 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 {
|
|
return 0, fmt.Errorf("managed virtual port is nil")
|
|
}
|
|
|
|
p.mu.Lock()
|
|
port := p.port
|
|
p.mu.Unlock()
|
|
|
|
if port == nil {
|
|
return 0, fmt.Errorf("managed virtual port is closed")
|
|
}
|
|
|
|
return port.Read(b)
|
|
}
|
|
|
|
// Write writes data to the underlying virtual serial device.
|
|
func (p *ManagedVirtualPort) Write(b []byte) (int, error) {
|
|
if p == nil {
|
|
return 0, fmt.Errorf("managed virtual port is nil")
|
|
}
|
|
|
|
p.mu.Lock()
|
|
port := p.port
|
|
p.mu.Unlock()
|
|
|
|
if port == nil {
|
|
return 0, fmt.Errorf("managed virtual port is closed")
|
|
}
|
|
|
|
return port.Write(b)
|
|
}
|
|
|
|
// Close closes the managed virtual port and releases its reservation.
|
|
func (p *ManagedVirtualPort) Close() error {
|
|
if p == nil {
|
|
return nil
|
|
}
|
|
|
|
p.mu.Lock()
|
|
|
|
port := p.port
|
|
p.port = nil
|
|
|
|
manager := p.manager
|
|
number := p.number
|
|
|
|
p.mu.Unlock()
|
|
|
|
if port == nil {
|
|
return nil
|
|
}
|
|
|
|
err := port.Close()
|
|
|
|
if manager != nil {
|
|
manager.Release(number)
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Open
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Open creates a new virtual serial port using the next free port number.
|
|
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
|
|
}
|
|
|
|
port, err := openVirtualPort(m, number)
|
|
if err != nil {
|
|
m.Release(number)
|
|
|
|
return nil, err
|
|
}
|
|
|
|
return port, nil
|
|
}
|
|
|
|
// OpenSpecific creates a new virtual serial port using exactly the specified
|
|
// port number.
|
|
func (m *VirtualPortManager) OpenSpecific(
|
|
number int,
|
|
) (*ManagedVirtualPort, error) {
|
|
if m == nil {
|
|
return nil, fmt.Errorf("virtual port manager is nil")
|
|
}
|
|
|
|
if err := m.ReserveSpecific(number); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
port, err := openVirtualPort(m, number)
|
|
if err != nil {
|
|
m.Release(number)
|
|
|
|
return nil, err
|
|
}
|
|
|
|
return port, nil
|
|
}
|