# 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` sieht aus wie Standard-G-Code; Zeitstempel und Cursor stehen 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! <- Cursor (!) ``` - `;` = Aufnahme-Zeitstempel · abschließendes `!` = Cursor-Zeile. - Der Cursor lebt zur Laufzeit als In-Memory-Index (schnelles Stepping ohne Neuschreiben) und wird beim Speichern/Entladen als `!` zurückgeschrieben. - `.json` ist ein Sidecar mit Metadaten (Name, Zeiten, `lineCount`, `angleUnit`). ## 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 ` | `POST /api/programs` | | `FLoad ` | `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 ` | `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).