122 lines
5.9 KiB
Markdown
122 lines
5.9 KiB
Markdown
# ToDo 6b — File-Handling
|
|
|
|
> **✅ Erledigt / abgelöst:** Das File-Handling wird in das eigenständige Projekt
|
|
> **`appRobotFileservice`** ausgelagert (Driver als Gateway, FCodes als Pass-through).
|
|
> Die hier beschriebenen Detailprobleme werden **dort** gelöst: Cursor als In-Memory-
|
|
> Index (Paket 2), explizite Grad↔Radian-Umrechnung im Fileservice (Paket 3),
|
|
> Fehler-Envelope (Paket 4), asynchrones IO (Paket 5). Konzept & Schnittstelle:
|
|
> [`fileserviceAPI.md`](fileserviceAPI.md).
|
|
> Die folgende Analyse bleibt als Umsetzungs-Vorlage für *jenes* Projekt erhalten.
|
|
|
|
## 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
|