Files
appRobotFileservice/README.md
2026-06-14 13:40:38 +02:00

134 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# appRobotFileservice
Programm-/File-Handling-Service für den AppRobot. Speichert **G-Code-Programme**
(`.gcode` + `.json`-Sidecar), hält das **aktive Programm + Cursor** und unterstützt
**Teaching** (Pose aufnehmen) und **Playback** (Programm abspielen).
Dieses Projekt wurde aus dem `appRobotDriver` ausgelagert (vormals `GCode.receiveFC`,
ToDo_4 / ToDo_6b). Konzept und Schnittstelle:
[`doc/draft_filehandeling.md`](doc/draft_filehandeling.md) ·
[`doc/draft_filehandeling_API.md`](doc/draft_filehandeling_API.md).
## Rolle in der Architektur
```
Steuerungen → appRobotDriver → appRobotFileservice
(Joystick, …) (Gateway) (dieses Projekt, passiv)
```
- Steuerungen kennen **nur den Driver**. Datei-Befehle (**FCodes** wie `FList`,
`FPoint`, `FPlus`) schickt die Steuerung an den Driver, der sie als REST-Aufrufe
hierher weiterreicht.
- Dieser Service ist **passiv und driver-agnostisch**: er ruft den Driver nie an,
kennt weder dessen URL noch dessen Pose. Beim `FPoint` schickt der **Driver die
Pose mit**.
- **Playback:** dieser Service liefert die nächste Zeile **driver-nativ (Radian)**
zurück; **ausgeführt** wird sie vom Driver.
## Einheiten (wichtig)
- **Gespeichert** wird in **Grad** (standardnahe `.gcode`, lesbar): `a/b/c/e` in Grad,
`x/y/z` in mm.
- **Am Wire / zum Driver** ist alles **driver-nativ**: `a/b/c/e` in **Radian**.
- Die Umrechnung passiert **ausschließlich hier** (`src/gcode/units.js`) — der Driver
rechnet nie um.
## Dateiformat
`.gcode` ist die **einzige verbindliche Positions-Abfolge** — reiner Standard-G-Code,
nur der Aufnahme-Zeitstempel steht im **Kommentarfeld** (`;…`, standardkonform):
```
G90 G1 x0 y300 z0 a90.00 b-90.00 c0.00 e0.00 f1000 ;1759566014
G90 G1 x310 y444 z0.5 a90.00 b-90.00 c0.00 e6.88 f1000 ;1759566112
```
- `;<epoch>` = Aufnahme-Zeitstempel. Sonst nichts Service-Internes in der `.gcode`.
- `<id>.json` ist ein Sidecar mit **Zusatz-Infos**: Name, Zeiten, `lineCount`,
`angleUnit` und der **`cursor`** (Index der zuletzt angefahrenen Zeile).
- Der Cursor lebt zur Laufzeit als In-Memory-Index (schnelles Stepping ohne
Neuschreiben) und wird beim Speichern/Entladen ins `.json` geschrieben — die
`.gcode` bleibt sauber.
- Migration: alte `.gcode`-Dateien mit `!`-Cursor-Marker werden beim ersten Lesen
automatisch übernommen (Marker raus, Cursor ins `.json`).
## Start
```
npm install
npm start # http://localhost:2100
npm test # jest
```
HTTP (kein TLS) — der Service ist intern (Driver → Service). TLS kann später analog
zum Driver-`InfoServer` ergänzt werden.
## API (Kurzüberblick)
Vollständig in [`doc/draft_filehandeling_API.md`](doc/draft_filehandeling_API.md).
| FCode (am Driver) | Endpoint |
|---|---|
| `FList` | `GET /api/programs` |
| `FShow [id]` | `GET /api/programs/:id` |
| `FSave <name>` | `POST /api/programs` |
| `FLoad <id>` | `PUT /api/active` |
| `FClear` | `POST /api/active/clear` |
| `FPoint` | `POST /api/active/points` |
| `FPlus` / `FMinus` | `POST /api/active/next` / `/prev` |
| `FFirst` / `FLast` | `POST /api/active/first` / `/last` |
| `FGoto <n>` | `POST /api/active/goto` |
| `FPlay` / `FStop` | `POST /api/active/play` / `/stop` |
Beispiel:
```bash
# Teaching: leeres Programm aktiv, Pose aufnehmen, speichern
curl -X PUT localhost:2100/api/active -H 'content-type: application/json' -d '{"id":"demo_c"}'
curl -X POST localhost:2100/api/active/points -H 'content-type: application/json' \
-d '{"pose":{"x":0,"y":300,"z":0,"a":1.5708,"b":-1.5708,"c":0,"e":0},"feedrate":1000}'
curl -X POST localhost:2100/api/programs -H 'content-type: application/json' -d '{"name":"Demo C","fromActive":true}'
# Playback: laden, erste Zeile (Radian) holen → der Driver führt sie aus
curl -X PUT localhost:2100/api/active -H 'content-type: application/json' -d '{"id":"demo_c"}'
curl -X POST localhost:2100/api/active/first
```
> Hinweis: `PUT /api/active` legt ein nicht existierendes Programm **leer an** (für
> Teaching). `EMPTY_PROGRAM`/`CURSOR_OUT_OF_RANGE` betreffen nur das Stepping/Playback.
## Konfiguration (Env)
| Variable | Default | Zweck |
|---|---|---|
| `FILE_SERVICE_PORT` | `2100` | Port |
| `STORAGE_DIR` | `./GCodeFiles` | Verzeichnis für `.gcode` + `.json` |
| `FILE_EXT` | `gcode` | `gcode` oder `ngc` |
| `STORE_ANGLE_UNIT` | `deg` | Speichereinheit der Winkel |
| `FILE_API_KEY` | | Bearer-Token für Schreibzugriffe (fehlt → offen, Dev) |
## Projektstruktur
```
index.js Einstiegspunkt (startet den Server)
src/
config.js Env-Konfiguration
server.js Express-App (createApp)
errors.js Fehler-Envelope + Middleware
auth.js Bearer-Auth (für Schreibzugriffe)
gcode/units.js Grad↔Radian, Zeilenformat, Cursor-/Kommentar-Helfer
store/fileStore.js .gcode + .json Persistenz (id-basiert, kein Pfad-Zugriff)
active/activeState.js aktives Programm + Cursor (Single Source of Truth)
routes/programs.js /api/programs*
routes/active.js /api/active*
test/ jest (units, fileStore, activeState)
doc/ Konzept + API (Drafts)
GCodeFiles/ Programm-Storage (zur Laufzeit)
```
## Status
Erste lauffähige Umsetzung. Offen u. a.: WebSocket-Event-Kanal (Live-Cursor),
Playlists („nächste File"), benannte Labels im Sidecar, TLS. Siehe „Offene Fragen"
in [`doc/draft_filehandeling.md`](doc/draft_filehandeling.md).