Extend device simulator with interactive TX

This commit is contained in:
Dieter Lang 2026-08-10 13:51:26 +02:00
parent 2a61b5a79c
commit ea4499b93f
4 changed files with 536 additions and 178 deletions

View file

@ -2,58 +2,102 @@
Alle wesentlichen Änderungen am Projekt werden in dieser Datei dokumentiert.
## [Unreleased]
## [0.0.4] - 2026-08-10
### Added
- Linux-PTY-Unterstützung für die clientseitige virtuelle serielle Schnittstelle
- Interaktiver Geräte-Simulator `rs2322tcp-device-sim`
- Senden beliebiger Bytefolgen über eine interaktive Hex-Eingabe
- Ausgabe empfangener Daten als Hex-Dump
- Unterstützung von Hex-Eingaben mit und ohne Leerzeichen
- Fehlerbehandlung für ungültige Hex-Eingaben
- Automatisierte Tests für die Hex-Konvertierung
- Erweiterte Dokumentation des Geräte-Simulators und des PTY-Testaufbaus
- Möglichkeit, den Simulator als virtuelle serielle Gegenstelle für
externe Software zu verwenden
### Tests
- Byte-orientierte Übertragung mit beliebigen Binärdaten getestet
- Übertragung aller Bytewerte `00` bis `FF` getestet
- Übertragung vom PTY-Slave zum PTY-Master getestet
- Übertragung vom PTY-Master zum PTY-Slave getestet
- `go test ./...` erfolgreich
- `go test -race ./...` erfolgreich
---
## [0.0.3] - 2026-08-10
### Added
- Linux-PTY-Unterstützung für die clientseitige virtuelle serielle
Schnittstelle
- Abstraktion der virtuellen seriellen Schnittstelle über `VirtualSerial`
- Automatisierter bidirektionaler PTY-Test mit allen 256 möglichen Bytewerten
- Eigenständiges Programm `rs2322tcp-device-sim` als Simulator für ein angeschlossenes serielles Gerät
- Eigenständiges Programm `rs2322tcp-device-sim` als Simulator für ein
angeschlossenes serielles Gerät
- Hexadezimale Darstellung der vom Geräte-Simulator empfangenen Rohdaten
### Tests
- PTY-Slave und PTY-Master erfolgreich miteinander getestet
- Bidirektionale Übertragung von Binärdaten getestet
- Bytefolgen mit Werten von `00` bis `FF` erfolgreich übertragen
- Empfang beliebiger Datenblöcke über den PTY-Master getestet
---
## [0.0.2] - 2026-08-09
### Added
- Implementierung der seriellen Schnittstellenschicht unter `internal/serial`
- Verwendung von `go.bug.st/serial v1.7.1` für die Ansteuerung der seriellen Schnittstellen
- Konfigurationsunterstützung für Baudrate, Datenbits, Parität und Stopbits
- Öffnen und Schließen serieller Schnittstellen über die interne Serial-Abstraktion
- Lesen und Schreiben von RS232-Daten über die Serial-Abstraktion
- Dynamische TCP-Data-Listener für konfigurierte Geräte
- Session-Verwaltung für dynamische Data-Listener
- Session-Verwaltung für aktive DataConnections
- Bidirektionale Datenübertragung zwischen TCP und RS232
- Öffnen der seriellen Schnittstelle erst beim Aufbau einer tatsächlichen Data-Verbindung
- Begrenzung auf eine aktive Data-Verbindung pro konfiguriertem Gerät
- Integrationstest mit virtuellen seriellen Schnittstellen über `socat`
- Tests für TCP → RS232 und RS232 → TCP
- Tests für Session-Reconnect und Ressourcenverwaltung
- Serielle Geräte können über Konfiguration definiert werden
- Server-Control-Verbindung
- Session-Verwaltung
- Dynamische Data-Ports pro Gerät
- Serverseitiger Aufbau der TCP-Data-Verbindung
- `DataConnection` für die bidirektionale Datenübertragung
- `DataListener` zur Annahme von Data-Verbindungen
- TCP → RS232 Datenübertragung
- RS232 → TCP Datenübertragung
- Client-Control-Verbindung unter `internal/client`
- Clientseitige Verarbeitung von `HELLO`
- Clientseitige Abfrage der konfigurierten Geräte über `GET_DEVICES`
- Clientseitige Verarbeitung der vom Server gelieferten Geräteinformationen einschließlich dynamischem Data-Port
- Clientseitige Verarbeitung der vom Server gelieferten Geräteinformationen
einschließlich dynamischem Data-Port
- Clientseitiger Aufbau der TCP-Data-Verbindung
- Integrationstest für die vollständige Client-/Server-Kommunikation
- End-to-End-Test der TCP-/RS232-Datenübertragung in beide Richtungen
### Changed
- Go-Version des Projektes auf Go `1.25.0` aktualisiert
- `go.bug.st/serial` wird in Version `v1.7.1` verwendet
- `golang.org/x/sys v0.43.0` wird als indirekte Abhängigkeit verwendet
- Die Serial-Bibliothek `go.bug.st/serial` wurde zusätzlich auf dem privaten Git-Server des Projektes als Ausfallsicherung gespiegelt:
`git.lang-dieter.de/third-party/go-serial`
- Der `DataListener` wurde nebenläufigkeitssicher implementiert
- Das Schließen eines `DataListener` kann gleichzeitig mit einem laufenden `Accept()` erfolgen
- Serial-Kommunikation vollständig über `go.bug.st/serial`
- Server öffnet serielle Schnittstellen erst bei aktiver Data-Verbindung
- Pro Gerät wird nur eine aktive Data-Verbindung zugelassen
- Session- und Ressourcenverwaltung überarbeitet
- Race Condition im `DataListener` behoben
### Tests
- `go test ./...` erfolgreich
- `go test -race ./...` erfolgreich
- Race Condition im `DataListener` erkannt und behoben
- Unit-Tests für Serial
- Unit-Tests für Session
- Unit-Tests für DataConnection
- Unit-Tests für DataListener
- Integrationstest mit virtuellen seriellen Schnittstellen über `socat`
- Tests für TCP → RS232 und RS232 → TCP
- Tests für Session-Reconnect und Ressourcenverwaltung
- Client-/Server-Integrationstest erfolgreich
- Race-Test des Client-/Server-Integrationstests erfolgreich
- Automatisierter bidirektionaler PTY-Test mit einem vollständigen Bytebereich von `0x00` bis `0xFF`
- Race-Detection für die neue Linux-PTY-Komponente erfolgreich
### Status
Die grundlegende TCP-/RS232-Datenübertragung ist serverseitig implementiert und der Client kann inzwischen die Control-Verbindung sowie die zugehörige Data-Verbindung aufbauen.
Die grundlegende TCP-/RS232-Datenübertragung ist serverseitig implementiert
und der Client kann die Control-Verbindung sowie die zugehörige
Data-Verbindung aufbauen.
Der aktuelle Datenpfad ist:
@ -103,49 +147,19 @@ Der Geräte-Simulator ist als eigenständiges Testprogramm vorhanden und kann
eine serielle Schnittstelle öffnen und empfangene Rohdaten hexadezimal
anzeigen.
Die TX-Funktion des Geräte-Simulators sowie die vollständige Integration der
virtuellen seriellen Schnittstelle in den Client-Datenpfad sind noch nicht
implementiert.
Die interaktive TX-Funktion des Geräte-Simulators sowie die vollständige
Integration der virtuellen seriellen Schnittstelle in den produktiven
Client-Datenpfad sind noch nicht abgeschlossen.
---
## [0.0.1] - 2026-08-09
### Added
- Grundstruktur des Projektes `rs2322tcp`
- Go-Modul `git.lang-dieter.de/rs2322tcp`
- separates Programmgerüst für `rs2322tcp-client`
- separates Programmgerüst für `rs2322tcp-server`
- gemeinsame Versionierungsinformationen
- Git-basierte Build-Informationen
- zentrales Build-Skript `scripts/build.sh`
- automatische Quellcode-Formatierung beim Build
- automatische Tests beim Build
- SHA256-Prüfsummen der erzeugten Binärdateien
- `.gitignore` für Build- und Entwicklungsdateien
- erste Projekt- und Architekturdokumentation
### Build-Ziele
Der erste Build unterstützt:
- Linux amd64 Client und Server
- Linux arm64 Server
- Windows amd64 Client
### Architekturentscheidungen
- TCP wird für die Übertragung der RS232-Daten verwendet.
- Windows und Linux werden als gleichberechtigte Client-Plattformen betrachtet.
- Der Server ist zunächst für den Raspberry Pi 5 vorgesehen.
- Tailscale wird als vertrauenswürdiges Netzwerk verwendet.
- Eine zusätzliche TLS-Schicht ist zunächst nicht vorgesehen.
- Für eine spätere Audioübertragung ist ein separates UDP-basiertes Transportkonzept vorgesehen.
- `socat` kann für Entwicklung und Diagnose eingesetzt werden.
- Eine Sniffer-/Logging-Funktion für den übertragenen Datenverkehr ist vorgesehen.
### Status
Version `0.0.1` enthält ausschließlich die Projektgrundlage.
Die eigentliche TCP-/RS232-Kommunikation und die virtuelle serielle Schnittstelle sind noch nicht implementiert.
- Initiale Projektstruktur
- Go-Modul und Build-Grundlagen
- Basis für Server und Client
- Konfigurationsgrundlagen
- Versionsverwaltung und Build-Metadaten
- Erste Dokumentation

215
README.md
View file

@ -28,7 +28,7 @@ Typische Anwendungen sind beispielsweise:
## Architektur
``` text
```text
Client-PC Raspberry Pi 5
───────────────── ─────────────────
@ -52,7 +52,7 @@ rs2322tcp-client │
Die serverseitige TCP-/RS232-Verbindung ist implementiert:
``` text
```text
TCP-Control
@ -80,7 +80,7 @@ Pro konfiguriertem Gerät ist nur eine aktive Data-Verbindung vorgesehen.
Die Datenübertragung erfolgt bidirektional:
``` text
```text
TCP ───────────────► RS232
TCP ◄────────────── RS232
```
@ -126,7 +126,7 @@ Die serverseitige Serial-Kommunikation verwendet `go.bug.st/serial`.
Für die Ansteuerung der seriellen Schnittstellen wird derzeit verwendet:
``` text
```text
go.bug.st/serial v1.7.1
```
@ -134,7 +134,7 @@ Die Bibliothek wurde zusätzlich auf dem privaten Git-Server des
Projektes gespiegelt, um bei einem Ausfall des ursprünglichen Anbieters
weiterhin auf den verwendeten Quellstand zugreifen zu können:
``` text
```text
git.lang-dieter.de/third-party/go-serial
```
@ -191,7 +191,7 @@ Für den Linux-Client wird die virtuelle serielle Schnittstelle direkt
Dabei entsteht ein PTY-Paar:
``` text
```text
/dev/ptmx
@ -223,89 +223,194 @@ Der Simulator ist bewusst als eigenständiges Programm ausgeführt. Der
`rs2322tcp-server` muss nicht wissen, ob am seriellen Port ein echtes
Gerät oder der Simulator angeschlossen ist.
Der aktuelle Simulator kann eine serielle Schnittstelle öffnen und
empfangene Rohdaten als Hexdump anzeigen.
Der Simulator kann:
- Daten von einer seriellen Schnittstelle oder einem Linux-PTY empfangen
- empfangene Rohdaten als Hexdump anzeigen
- beliebige Bytefolgen über eine interaktive Hex-Eingabe senden
- ungültige Hex-Eingaben erkennen
- als virtuelle serielle Gegenstelle für externe Software dienen
Beispiel:
``` bash
rs2322tcp-device-sim -port /dev/pts/7
```bash
go run ./cmd/rs2322tcp-device-sim -port /dev/pts/7
```
Beispielausgabe:
Zum Senden wird eine Hex-Folge eingegeben:
``` text
rs2322tcp-device-sim
Port: /dev/pts/7
Warte auf Daten ...
```text
TX> 46 41 00 10 0D
```
12:34:01.123 RX 5 Bytes
Der Simulator überträgt diese fünf Bytes.
Empfangene Daten werden beispielsweise so angezeigt:
```text
RX 5 Bytes
46 41 00 10 0D
```
Die Daten werden zunächst nicht interpretiert. Dadurch kann der
Simulator auch zum Beobachten unbekannter serieller Protokolle verwendet
werden.
Die Hex-Eingabe kann mit oder ohne Leerzeichen erfolgen:
```text
46 41 00 10 0D
```
und:
```text
464100100D
```
sind gleichwertig.
Auch Groß- und Kleinschreibung kann gemischt werden:
```text
0a FF 01 b7
```
Ungültige Eingaben wie
```text
GG
```
oder
```text
4
```
werden erkannt und führen nicht zum Beenden des Simulators.
Der Simulator soll insbesondere auch als Sniffer dienen können, wenn
externe Hersteller-Software untersucht werden soll. Dadurch lassen sich
die von einer Software gesendeten seriellen Kommandos zunächst als
Rohdaten beobachten.
Geplante Erweiterungen sind:
Geplante bzw. mögliche Erweiterungen sind:
- manuelles Senden von Rohbytes
- Anzeige von RX und TX
- automatische Geräteantworten
- Protokollsimulation
- Aufzeichnung und Wiedergabe von Datenströmen
## PTY-Testprogramm
Für die Entwicklung existiert zusätzlich das separate Testprogramm:
```text
~/rs2322tcp-pty-test
```
Es erzeugt unter Linux ein PTY, setzt den Slave in den Raw Mode und zeigt
den Namen des Slave-Gerätes an.
Beispiel:
```bash
cd ~/rs2322tcp-pty-test
go run .
```
Ausgabe:
```text
PTY Slave: /dev/pts/2
PTY ist im Raw Mode.
Warte auf Daten vom PTY-Slave ...
Mit Ctrl+C beenden.
```
Das Programm zeigt anschließend beliebige empfangene Bytes unmittelbar
als Hexdump an.
Der Testaufbau ermöglicht damit Tests in beiden Richtungen:
```text
Master → Slave
Slave → Master
```
und eignet sich auch als einfacher Beobachtungspunkt für den Datenstrom.
## Sniffer-Funktion
Der Empfänger des Testaufbaus kann gleichzeitig als einfacher Sniffer
verwendet werden.
Dadurch kann später auch externe Software angeschlossen werden, um zu
beobachten, welche Kommandos diese Software tatsächlich über die serielle
Schnittstelle versendet.
Besonders für die Entwicklung von Protokollen für Funkgeräte oder andere
Hardware ist das hilfreich.
Der Sniffer verändert die empfangenen Daten nicht, sondern zeigt die
empfangenen Bytes lediglich an.
## Externe USB-to-Seriell-Adapter
Für den späteren praktischen Einsatz sind USB-to-Seriell-Adapter
vorgesehen.
Unter Linux werden solche Adapter normalerweise als serielle Gerätedateien
bereitgestellt, beispielsweise:
```text
/dev/ttyUSB0
```
Die Kommunikation erfolgt über die normale serielle Schnittstelle des
Betriebssystems und die vorhandene Serial-Abstraktion.
Das Projekt benötigt für die serielle Kommunikation keine direkte
`libusb`-Anbindung. Bei üblichen USB-to-Seriell-Adaptern, beispielsweise
mit FTDI-Chips, wird die serielle Schnittstelle über den Linux-Kernel-
Treiber bereitgestellt.
Eine spezielle Hardware-Anbindung über `libusb` ist für `rs2322tcp`
daher nicht vorgesehen.
## Tests
Die wichtigsten Komponenten verfügen über automatisierte Tests.
Der aktuelle Stand wird unter anderem mit folgenden Befehlen geprüft:
``` bash
```bash
go test ./...
```
und:
``` bash
```bash
go test -race ./...
```
Der Race Detector wird eingesetzt, um Probleme bei der nebenläufigen
Verarbeitung von Sessions, Data-Listenern und DataConnections zu
erkennen.
Verarbeitung von Sessions, Data-Listenern, DataConnections und Client-
Komponenten zu erkennen.
Die Linux-PTY-Komponente verfügt über einen automatisierten
bidirektionalen Byte-Test.
Die Linux-PTY-Komponente wurde mit einem vollständigen Bytebereich von
`0x00` bis `0xFF` geprüft.
Dabei werden alle 256 möglichen Bytewerte übertragen:
Der Geräte-Simulator verfügt zusätzlich über automatisierte Tests für
die Hex-Konvertierung und die Behandlung ungültiger Eingaben.
``` text
00 01 02 03 ... FD FE FF
Für die Prüfung des Arbeitsbaums:
```bash
git diff --check
git status
```
Geprüft werden beide Richtungen:
``` text
PTY-Slave → Client
Client → PTY-Slave
```
Für den Integrationstest des Client-/Server-Datenpfades werden virtuelle
serielle Schnittstellen verwendet. Während der Entwicklung kann hierfür
`socat` eingesetzt werden.
Damit kann der Datenpfad ohne angeschlossene RS232-Hardware getestet
werden.
## Projektstruktur
``` text
```text
rs2322tcp/
├── cmd/
│ ├── rs2322tcp-client/
@ -332,7 +437,7 @@ rs2322tcp/
Der Build erfolgt über das zentrale Build-Skript:
``` bash
```bash
./scripts/build.sh
```
@ -363,15 +468,18 @@ Build-Datum erfasst.
Release-Versionen werden über Git-Tags gekennzeichnet.
Aktueller Stand:
- `v0.0.1` erste Projektversion
- `v0.0.2` Client-Control- und Data-Verbindungen
- `v0.0.3` Linux-PTY-Unterstützung und Geräte-Simulator
- `v0.0.4` in Vorbereitung: interaktive TX-Funktion und automatisierte
Tests des Geräte-Simulators
## Entwicklungsstand
Das Projekt befindet sich weiterhin in der frühen Entwicklungsphase.
Die ursprüngliche Projektgrundlage aus Version `0.0.1` wurde inzwischen
um eine funktionierende serverseitige TCP-/RS232-Datenübertragung und
die clientseitige Grundlage für virtuelle serielle Schnittstellen
erweitert.
Implementiert und getestet sind derzeit:
- Server-Control-Verbindung
@ -390,13 +498,14 @@ Implementiert und getestet sind derzeit:
- nebenläufigkeitssichere Data-Listener
- Race-Detection
- eigenständiger Geräte-Simulator mit RX-Hexdump
- interaktive TX-Hex-Eingabe des Geräte-Simulators
- automatisierte Tests der Hex-Konvertierung
Noch nicht vollständig implementiert sind insbesondere:
- die vollständige Anbindung der virtuellen seriellen Schnittstelle an
den produktiven Client-Anwendungsdatenpfad
- die Windows-Implementierung der virtuellen seriellen Schnittstelle
- TX-Funktion des Geräte-Simulators
- automatische Geräteantworten und Protokollsimulation
## Lizenz

View file

@ -7,24 +7,37 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Beschreibung:
* Einfacher Simulator für ein serielles Endgerät.
* Interaktiver Simulator für ein serielles Endgerät.
*
* Der Simulator öffnet eine angegebene serielle Schnittstelle und protokolliert
* alle vom angeschlossenen System empfangenen Bytes als Hexdump.
*
* Zusätzlich können über die Standardeingabe hexadezimal angegebene Bytefolgen
* an das serielle Gerät gesendet werden. Dadurch kann der Simulator sowohl als
* passiver Sniffer als auch als einfaches interaktives Testgerät verwendet
* werden.
*
* Der Simulator stellt bewusst keine eigene PTY-Erzeugung bereit. Für
* Entwicklung und Integrationstests kann ihm beispielsweise ein unter Linux
* erzeugter PTY-Slave (/dev/pts/N) übergeben werden. Im späteren Testaufbau
* kann derselbe Simulator jedoch auch direkt mit einer echten seriellen
* Schnittstelle verbunden werden.
*
* Der Simulator dient zunächst als passives Gegenstück zum
* rs2322tcp-server. Er soll insbesondere ermöglichen, die vom Server an ein
* simuliertes Gerät übertragenen Bytes sichtbar zu machen.
* Der Simulator dient zunächst als externes Gegenstück zum
* rs2322tcp-server. Er ermöglicht insbesondere, die vom Server an ein
* simuliertes Gerät übertragenen Bytes sichtbar zu machen und umgekehrt
* definierte Bytefolgen an den Server zurückzusenden.
*
* Zukünftige Erweiterungen können unter anderem das manuelle Senden von
* Bytes, automatische Geräteantworten, Protokollsimulation und das Aufzeichnen
* bzw. Wiedergeben von Datenströmen umfassen.
* Eingabeformat:
*
* TX> 46 41 00 10 0D
*
* Die Leerzeichen zwischen den Bytes sind optional. Groß- und Kleinschreibung
* der Hex-Ziffern spielt keine Rolle.
*
* Zukünftige Erweiterungen können unter anderem automatische Geräteantworten,
* Protokollsimulation und das Aufzeichnen bzw. Wiedergeben von Datenströmen
* umfassen.
*
* Aufruf:
*
@ -36,12 +49,16 @@
* Port: /dev/pts/7
* Warte auf Daten ...
*
* Empfangene Daten werden mit Zeitstempel, Richtung und Byteanzahl ausgegeben:
* Empfangene und gesendete Daten werden mit Zeitstempel, Richtung und
* Byteanzahl ausgegeben:
*
* 12:34:01.123 RX 5 Bytes
* 46 41 00 10 0D
*
* Der Simulator interpretiert die empfangenen Daten nicht. Die Darstellung
* 12:34:05.456 TX 5 Bytes
* 46 41 01 10 0D
*
* Der Simulator interpretiert die seriellen Daten nicht. Die Darstellung
* erfolgt ausschließlich als Rohdaten in hexadezimaler Form.
*
* ============================================================================
@ -50,10 +67,14 @@
package main
import (
"bufio"
"encoding/hex"
"flag"
"fmt"
"io"
"log"
"os"
"strings"
"time"
"golang.org/x/sys/unix"
@ -92,6 +113,13 @@ func main() {
fmt.Printf("Port: %s\n", *port)
fmt.Println("Warte auf Daten ...")
fmt.Println()
fmt.Println("Hex-Bytes senden mit:")
fmt.Println("TX> 46 41 00 10 0D")
fmt.Println()
// Die Standardeingabe wird parallel zur seriellen Schnittstelle gelesen.
// Dadurch kann der Simulator gleichzeitig Daten empfangen und senden.
go readTX(fd)
// Der Simulator arbeitet byteorientiert. Die Größe des Puffers ist
// bewusst ausreichend groß gewählt, damit auch größere Datenblöcke
@ -135,15 +163,130 @@ func main() {
}
}
// readTX liest Zeilen von stdin und interpretiert sie als Folge von
// hexadezimal angegebenen Bytes.
//
// Die Eingabe wird bewusst zeilenorientiert verarbeitet. Dadurch kann eine
// komplette Bytefolge zuerst geprüft werden, bevor sie an die serielle
// Schnittstelle gesendet wird.
func readTX(fd int) {
scanner := bufio.NewScanner(os.Stdin)
fmt.Print("TX> ")
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if line == "" {
fmt.Print("TX> ")
continue
}
data, err := parseHexBytes(line)
if err != nil {
fmt.Printf("Ungültige Hex-Eingabe: %v\n", err)
fmt.Print("TX> ")
continue
}
if len(data) == 0 {
fmt.Print("TX> ")
continue
}
if err := writeAll(fd, data); err != nil {
fmt.Fprintf(os.Stderr, "Senden: %v\n", err)
return
}
printTX(data)
fmt.Print("TX> ")
}
if err := scanner.Err(); err != nil {
fmt.Fprintf(os.Stderr, "Lesen von stdin: %v\n", err)
}
// Bei EOF (Ctrl+D) wird der Dateideskriptor geschlossen. Dadurch wird
// der blockierende Lesevorgang im Haupt-Goroutine beendet und der
// Simulator kann sauber verlassen werden.
_ = unix.Close(fd)
}
// parseHexBytes wandelt eine zeilenorientierte Hex-Eingabe in einen
// Byte-Block um.
//
// Leerzeichen zwischen den Bytes sind erlaubt und werden entfernt. Dadurch
// werden beispielsweise sowohl
//
// 46 41 00 10 0D
//
// als auch
//
// 464100100D
//
// akzeptiert. Die Funktion selbst enthält keine Ausgabe und ist deshalb
// unabhängig vom interaktiven Terminalbetrieb testbar.
func parseHexBytes(line string) ([]byte, error) {
fields := strings.Fields(line)
hexText := strings.Join(fields, "")
if hexText == "" {
return nil, nil
}
data, err := hex.DecodeString(hexText)
if err != nil {
return nil, err
}
return data, nil
}
// writeAll schreibt alle Bytes des angegebenen Datenblocks auf den seriellen
// Dateideskriptor. unix.Write() darf weniger Bytes als angefordert schreiben.
func writeAll(fd int, data []byte) error {
for len(data) > 0 {
n, err := unix.Write(fd, data)
if err != nil {
if err == unix.EINTR {
continue
}
return err
}
if n == 0 {
return io.ErrShortWrite
}
data = data[n:]
}
return nil
}
// printRX gibt einen empfangenen Datenblock als Hexdump aus.
//
// Die Daten werden absichtlich nicht als Text interpretiert. Dadurch bleiben
// auch nicht druckbare Bytes und Bytes oberhalb von 0x7F sichtbar und können
// bei der Analyse serieller Protokolle eindeutig nachvollzogen werden.
func printRX(data []byte) {
printHexDump("RX", data)
}
// printTX gibt einen gesendeten Datenblock als Hexdump aus.
func printTX(data []byte) {
printHexDump("TX", data)
}
// printHexDump gibt einen Datenblock mit Zeitstempel, Richtung und Byteanzahl
// als Hexdump aus.
func printHexDump(direction string, data []byte) {
fmt.Printf(
"%s RX %d Bytes\n",
"%s %s %d Bytes\n",
time.Now().Format("15:04:05.000"),
direction,
len(data),
)

View file

@ -0,0 +1,92 @@
/*
* ============================================================================
* Projekt.....: rs2322tcp
* Datei.......: main_test.go
* Copyright (C) 2026 Dieter Lang
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Beschreibung:
* Unit-Tests für die Hex-Eingabe des Geräte-Simulators.
*
* Getestet werden gültige Bytefolgen, optionale Leerzeichen, Groß- und
* Kleinschreibung sowie typische ungültige Eingaben.
*
* ============================================================================
*/
package main
import (
"bytes"
"testing"
)
func TestParseHexBytes(t *testing.T) {
tests := []struct {
name string
input string
want []byte
wantErr bool
}{
{
name: "mehrere Bytes mit Leerzeichen",
input: "46 41 00 10 0D",
want: []byte{0x46, 0x41, 0x00, 0x10, 0x0D},
},
{
name: "mehrere Bytes ohne Leerzeichen",
input: "464100100D",
want: []byte{0x46, 0x41, 0x00, 0x10, 0x0D},
},
{
name: "gemischte Groß- und Kleinschreibung",
input: "0a FF 01 b7",
want: []byte{0x0A, 0xFF, 0x01, 0xB7},
},
{
name: "ein Byte",
input: "00",
want: []byte{0x00},
},
{
name: "leere Eingabe",
input: "",
want: nil,
},
{
name: "nur Leerzeichen",
input: " ",
want: nil,
},
{
name: "ungültiges Hex-Zeichen",
input: "GG",
wantErr: true,
},
{
name: "ungerade Hex-Länge",
input: "4",
wantErr: true,
},
{
name: "dreistellige Eingabe",
input: "100",
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parseHexBytes(tt.input)
if (err != nil) != tt.wantErr {
t.Fatalf("Fehlerstatus: got %v, wantErr %v", err, tt.wantErr)
}
if !bytes.Equal(got, tt.want) {
t.Fatalf("Ergebnis: got % X, want % X", got, tt.want)
}
})
}
}