/* * ============================================================================ * Projekt.....: rs2322tcp * Datei.......: serial.go * Copyright (C) 2026 Dieter Lang * * SPDX-License-Identifier: GPL-3.0-or-later * * Beschreibung: * Öffnet und verwaltet eine serielle Schnittstelle auf Basis der * konfigurierten Geräteparameter. * ============================================================================ */ package serial import ( "fmt" "io" bugserial "go.bug.st/serial" "git.lang-dieter.de/rs2322tcp/internal/config" ) /////////////////////////////////////////////////////////////////////////////// // Connection /////////////////////////////////////////////////////////////////////////////// // Connection represents an opened serial connection. type Connection struct { port bugserial.Port } /////////////////////////////////////////////////////////////////////////////// // Open /////////////////////////////////////////////////////////////////////////////// // Open opens the serial device described by the configuration. func Open(device config.DeviceConfig) (*Connection, error) { mode, err := createMode(device) if err != nil { return nil, err } port, err := bugserial.Open(device.SerialPort, mode) if err != nil { return nil, fmt.Errorf( "open serial port %q: %w", device.SerialPort, err, ) } return &Connection{ port: port, }, nil } /////////////////////////////////////////////////////////////////////////////// // Mode /////////////////////////////////////////////////////////////////////////////// func createMode(device config.DeviceConfig) (*bugserial.Mode, error) { mode := &bugserial.Mode{ BaudRate: device.BaudRate, DataBits: device.DataBits, Parity: bugserial.NoParity, StopBits: bugserial.OneStopBit, } if device.BaudRate <= 0 { return nil, fmt.Errorf( "invalid baud rate: %d", device.BaudRate, ) } switch device.DataBits { case 5, 6, 7, 8: // Supported by go.bug.st/serial. default: return nil, fmt.Errorf( "unsupported data bits: %d", device.DataBits, ) } switch device.Parity { case "none": mode.Parity = bugserial.NoParity case "odd": mode.Parity = bugserial.OddParity case "even": mode.Parity = bugserial.EvenParity default: return nil, fmt.Errorf( "unsupported parity: %q", device.Parity, ) } switch device.StopBits { case 1: mode.StopBits = bugserial.OneStopBit case 2: mode.StopBits = bugserial.TwoStopBits default: return nil, fmt.Errorf( "unsupported stop bits: %d", device.StopBits, ) } return mode, nil } /////////////////////////////////////////////////////////////////////////////// // Read / Write /////////////////////////////////////////////////////////////////////////////// // Read reads data from the serial connection. func (c *Connection) Read(p []byte) (int, error) { if c == nil || c.port == nil { return 0, io.ErrClosedPipe } return c.port.Read(p) } // Write writes data to the serial connection. func (c *Connection) Write(p []byte) (int, error) { if c == nil || c.port == nil { return 0, io.ErrClosedPipe } return c.port.Write(p) } /////////////////////////////////////////////////////////////////////////////// // Close /////////////////////////////////////////////////////////////////////////////// // Close closes the serial connection. func (c *Connection) Close() error { if c == nil || c.port == nil { return nil } err := c.port.Close() c.port = nil return err }