Files
appRobotDriver/doc/ToDo_6b_FileHandling.md
2026-06-09 12:05:18 +02:00

114 lines
5.3 KiB
Markdown

# ToDo 6b — File-Handling
## Ist-Zustand
`GCode.receiveFC()` implementiert nur einen Bruchteil der erkannten Befehle:
| Befehl | Erkannt | Implementiert | Anmerkung |
|---|---|---|---|
| `FPoint` | ✅ | ✅ | Speichert aktuelle Position |
| `FPlus` | ✅ | ✅ | Cursor vorwärts |
| `FMinus` | ✅ | ✅ | Cursor rückwärts |
| `FShow` | ✅ | ✅ | Gibt Dateiinhalt zurück |
| `FFirst` | ✅ | ❌ | Cursor auf erste Zeile |
| `FLast` | ✅ | ❌ | Cursor auf letzte Zeile |
| `FList` | ✅ | ❌ | Listet verfügbare G-Code-Dateien |
| `FLoad <file>` | ✅ | ❌ | Lädt eine andere Datei als aktive |
| `FSave <file>` | ✅ | ❌ | Speichert aktive Datei unter neuem Namen |
| `FClear` | ✅ | ❌ | Leert die aktive Log-Datei |
| `M20` | ✅ | ❌ | List SD/Files |
| `M23` | ✅ | ❌ | Select file |
| `M28` | ✅ | ❌ | Start write |
| `M29` | ✅ | ❌ | Stop write |
Zusätzliche strukturelle Probleme:
- **Cursor lebt in der Datei** (`';!'`-Marker): jedes `FPlus`/`FMinus` liest und schreibt die ganze Datei neu
- **Synchrones File-IO** (`readFileSync`/`writeFileSync`) blockiert den Node.js-Event-Loop
- **Kein Fehler-Feedback** an den WebSocket-Client — Fehler gehen nur auf `console.error`
- **Aktive Datei ist statisch**: `static fileName = "GCodeFiles/log.gcode"``FLoad` kann das nicht ändern, weil es nicht implementiert ist
- **`toPiMultiple()`** ist eine String-Manipulation aus der Vor-Parser-Ära, inkonsistent mit `GCodeParser`
- **`FPoint` hardcodiert `f1000`** — sollte `robot.feedrate` verwenden (auch in ToDo_6a)
- **Kein Directory-Listing für `FList`** — welche Dateien sind gültig?
---
## Konzept
Die gesamte Datei-Logik wird in eine eigene Klasse `GCodeFileManager` ausgelagert
(gemäß ToDo_4). Diese ToDo beschreibt die **inhaltliche Umsetzung** — unabhängig davon,
ob sie noch in `GCode.js` oder schon in `GCodeFileManager` landet.
Der **Cursor** wird aus der Datei in den Speicher verlagert: `currentLineIndex` als
Instanzvariable, die nur beim Laden einer Datei initialisiert wird. Das spart permanentes
Neu-Schreiben der Datei.
---
## Pakete
### Paket 1: Fehlende Befehle implementieren
- [ ] **`FFirst`** — `currentLineIndex` auf 0 setzen, erste Zeile anfahren
- [ ] **`FLast`** — `currentLineIndex` auf letzte Zeile setzen, anfahren
- [ ] **`FClear`** — aktive Log-Datei leeren, `currentLineIndex` auf 0
- [ ] **`FList`** — Inhalte von `GCodeFiles/` auflesen, Liste zurückgeben
```
XYZ__FList__XYZ
log.gcode
log_2025_10_04.gcode
...
```
- [ ] **`FLoad <dateiname>`** — benannte Datei aus `GCodeFiles/` laden, `currentLineIndex`
auf den `;!`-Marker setzen (Rückwärtskompatibilität), oder auf 0 falls kein Marker
- [ ] **`FSave <dateiname>`** — aktiven Puffer unter `GCodeFiles/<dateiname>` speichern
- [ ] `M20`/`M23`/`M28`/`M29` — Marlin-kompatible Aliases für `FList`/`FLoad`/`FSave`/Stop,
oder explizit als „nicht unterstützt" mit Fehlermeldung antworten
### Paket 2: Cursor in den Speicher verlagern
Aktuell wird der Cursor als `';!'` direkt in die Datei geschrieben. Das zwingt bei
jedem `FPlus`/`FMinus` die gesamte Datei neu zu schreiben.
- [ ] `currentLineIndex` als Instanzvariable einführen (startet bei 0 oder am `';!'`-Marker beim Laden)
- [ ] `FPlus`/`FMinus` nur noch `currentLineIndex` ändern, Datei bleibt unverändert
- [ ] `';!'`-Marker beim **Speichern** (`FSave`) optional mitschreiben (für externe Kompatibilität)
- [ ] Beim Laden einer bestehenden Datei: Zeile mit `';!'` suchen → `currentLineIndex` setzen,
dann `';!'`-Marker aus der Datei entfernen (einmalige Migration)
### Paket 3: `toPiMultiple` durch Parser-Integration ersetzen
Gespeicherte Dateien enthalten Winkel in Grad (`a45.00`), der Parser erwartet
Zahlenwerte ohne Umrechnungspflicht. Die Konversion muss explizit und testbar sein.
- [ ] Beim Lesen einer Zeile aus der Datei: erkennen, ob Winkel in Grad oder Rad vorliegen
- Marker-Ansatz: `FPoint` könnte einen Einheiten-Kommentar schreiben (`;unit=deg`)
- Oder: Konvention festlegen und dokumentieren (Dateien immer in Grad, Anzeige in Grad)
- [ ] `toPiMultiple()` durch eine klar benannte Funktion `degreesToRadians(gCodeString)` ersetzen,
die intern `GCodeParser.parse()` nutzt statt raw-String-Manipulation
- [ ] `FPoint` sollte die Einheit konsistent speichern — Grad ist sinnvoller für Lesbarkeit
### Paket 4: Fehler-Feedback und Validierung
- [ ] Bei Dateifehlern (nicht gefunden, Leserechte) → strukturierte Fehlermeldung an den
WebSocket-Client zurückgeben (gemäß Fehler-Envelope aus ToDo_5)
- [ ] `FLoad` validiert, dass die Zieldatei existiert und mindestens eine gültige G-Code-Zeile enthält
- [ ] Dateinamen in `FLoad`/`FSave` sanitizen: keine `../`-Pfade, nur `GCodeFiles/`-Verzeichnis
### Paket 5: Asynchrones File-IO (optional, später)
Alle aktuellen `readFileSync`/`writeFileSync`-Aufrufe blockieren den Event-Loop.
Bei kleinen Dateien (< 1 MB) ist das tolerierbar. Bei größeren Programmen oder
häufigem `FPoint`-Schreiben wird es spürbar.
- [ ] `FPoint`-Schreiben auf `fs.appendFile` (async) umstellen — Cursor ist im Speicher,
kein Lesen nötig
- [ ] `FShow`/`FList` auf `fs.readFile` (async) umstellen
- [ ] `FLoad`/`FSave` async
## Betroffene Dateien
- `robot/GCode.js` (oder künftig `robot/GCodeFileManager.js` nach ToDo_4)
- `server/InputWS.js` — Fehler-Routing für File-Befehle
- `test/GCode.FileOperation.test.js` — stark erweitern