# FOCAS simulator (focas-mock) plan Notes on the focas-mock simulator that the FOCAS driver's integration tests will eventually talk to. Today there is no FOCAS integration-test project; this doc is the contract the future fixture will be built against. Keeping the contract tracked in repo means the wire-protocol command ids (and their request/response payloads) don't drift between the .NET wire client and a future Python implementation. ## Ground rules - Append-only command ids. Mirror [`focas-wire-protocol.md`](./focas-wire-protocol.md) verbatim. - Per-profile state. The simulator hosts N CNC profiles concurrently (`Series0i`, `Series30i`, `PowerMotion`, ...). Each profile has its own alarm-history ring buffer + its own override map. - Admin endpoints under `POST /admin/...` mutate state without going through the wire protocol; integration tests use these to seed canned inputs. ## Protocol surface (current scope) | Cmd | API | State impact | | --- | --- | --- | | `0x0001` | `cnc_rdcncstat` | reads cached ODBST per profile | | `0x0002` | `cnc_rdparam` | reads parameter map per profile | | `0x0003` | `cnc_rdmacro` | reads macro variables per profile | | `0x0004` | `cnc_rddiag` | reads diagnostic map per profile | | `0x0010` | `pmc_rdpmcrng` | reads PMC byte ranges | | `0x0020` | `cnc_modal` | reads cached modal MSTB per profile | | ... | ... | ... | | **`0x0F1A`** | **`cnc_rdalmhistry`** | **dumps the per-profile alarm-history ring buffer (issue #267, plan PR F3-a)** | ## `cnc_rdalmhistry` mock behaviour The simulator keeps a per-profile ring buffer of alarm-history entries. Default fixture seeds 5 profiles with 10 canned entries each (per the F3-a plan). ### Request decode ``` [int16 LE depth] ``` ### Response encode Use `FocasAlarmHistoryDecoder.Encode` semantics in reverse: emit the count followed by `ALMHIS_data` blocks padded to 4-byte boundaries. The .NET-side decoder consumes the same format verbatim, so a Python encoder written against the table in [`focas-wire-protocol.md`](./focas-wire-protocol.md) interoperates without extra glue. ### Admin endpoint — `POST /admin/mock_patch_alarmhistory` Replaces the alarm-history ring buffer for a profile. ``` POST /admin/mock_patch_alarmhistory { "profile": "Series30i", "entries": [ { "occurrenceTime": "2025-04-01T09:30:00Z", "axisNo": 1, "alarmType": 2, "alarmNumber": 100, "message": "Spindle overload" }, ... ] } ``` `entries` order is interpreted as ring-buffer order (most-recent first to match FANUC's natural surface). ### `FocasSimFixture.SeedAlarmHistoryAsync` The future test-support helper wraps the admin endpoint: ```csharp await fixture.SeedAlarmHistoryAsync( profile: "Series30i", entries: new [] { new FocasAlarmHistoryEntry( new DateTimeOffset(2025, 4, 1, 9, 30, 0, TimeSpan.Zero), AxisNo: 1, AlarmType: 2, AlarmNumber: 100, Message: "Spindle overload"), }); ``` Integration test `Series/AlarmHistoryProjectionTests.cs` will assert: - historic events fire once with the seeded timestamps - second poll yields zero new events (dedup honoured end-to-end) - active-alarm raise/clear still works alongside the history poll These tests are blocked on the focas-mock + integration-test project landing; the unit-test coverage in `FocasAlarmProjectionTests` already exercises every same-process invariant.