rs2322tcp/internal/client/virtual_port_manager.go
2026-08-10 16:20:28 +02:00

85 lines
2 KiB
Go

/*
* ============================================================================
* Projekt.....: rs2322tcp
* Datei.......: internal/client/virtual_port_manager.go
* Copyright (C) 2026 Dieter Lang
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Beschreibung:
* Verwaltung und Auswahl der für rs2322tcp reservierten virtuellen
* seriellen Ports.
* ============================================================================
*/
package client
import (
"fmt"
"git.lang-dieter.de/rs2322tcp/internal/config"
)
///////////////////////////////////////////////////////////////////////////////
// VirtualPortManager
///////////////////////////////////////////////////////////////////////////////
// VirtualPortManager verwaltet den reservierten Bereich virtueller
// /dev/ttyUSBxxx-Schnittstellen.
type VirtualPortManager struct {
first int
last int
used map[int]bool
}
// NewVirtualPortManager erzeugt einen VirtualPortManager aus der
// konfigurierten Portbereich.
func NewVirtualPortManager(cfg config.VirtualPortRangeConfig) *VirtualPortManager {
return &VirtualPortManager{
first: cfg.First,
last: cfg.Last,
used: make(map[int]bool),
}
}
// PortPath erzeugt den für die externe Software sichtbaren Gerätenamen
// für eine Portnummer.
func (m *VirtualPortManager) PortPath(number int) string {
if m == nil {
return ""
}
return fmt.Sprintf("/dev/ttyUSB%d", number)
}
// Reserve reserviert den nächsten freien virtuellen Port.
// Es wird immer mit dem kleinsten freien Port im konfigurierten Bereich
// begonnen.
func (m *VirtualPortManager) Reserve() (int, error) {
if m == nil {
return 0, fmt.Errorf("virtual port manager is nil")
}
for number := m.first; number <= m.last; number++ {
if m.used[number] {
continue
}
m.used[number] = true
return number, nil
}
return 0, fmt.Errorf(
"no free virtual port in range %d-%d",
m.first,
m.last,
)
}
// Release gibt einen zuvor reservierten Port wieder frei.
func (m *VirtualPortManager) Release(number int) {
if m == nil {
return
}
delete(m.used, number)
}