Extend device simulator with interactive TX
This commit is contained in:
parent
2a61b5a79c
commit
ea4499b93f
4 changed files with 536 additions and 178 deletions
150
CHANGELOG.md
150
CHANGELOG.md
|
|
@ -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
215
README.md
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
)
|
||||
|
||||
|
|
|
|||
92
cmd/rs2322tcp-device-sim/main_test.go
Normal file
92
cmd/rs2322tcp-device-sim/main_test.go
Normal 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue