feat(client)+feat(daemon): eq.names, @eq.command, E90/E157 RPCs
Python client:
- eq.names.event.* / .alarm.* / .command.* / .var.* / .constant.* —
autocomplete-able, typo-safe name lookup backed by the Describe RPC
(lazy, cached; AttributeError on bad name with close-match hints)
- @eq.command decorator — binds a handler by function name, validated
against the equipment's real command set at decoration time
- eq.report_substrate() — E90 wafer milestone reporting
- eq.report_module() — E157 module state reporting (auto-create)
Daemon (C++ service):
- ReportSubstrate RPC — drives E90 location + processing FSMs
- ReportModule RPC — drives E157 module FSM (auto-create on first report)
- ack_from_outcome() helper — consistent Ack mapping for read_sync results
Proto: SubstrateReport, ModuleReport, EquipmentDescription,
SpoolFlushRequest, TerminalMessage; Describe, FlushSpool,
SendTerminalMessage RPCs
Tests: C++ FSM test (journey + ghost rejection + E157 illegal jump);
interop coverage for names API and E90/E157 round-trip
Docs: ch42 RPC table + Python example updated; ch16 daemon-path section added
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -39,16 +39,22 @@ Three ways in, same engine underneath:
|
||||
from secsgem_client import Equipment
|
||||
|
||||
eq = Equipment("localhost:50051")
|
||||
eq.set(ChamberPressure=2.5) # host sees it on its next poll
|
||||
eq.fire("ProcessStarted") # S6F11, report auto-assembled
|
||||
eq.set(ChamberPressure=2.5) # variables: kwargs, not strings
|
||||
|
||||
@eq.on("START") # host remote commands -> your function
|
||||
def start(cmd):
|
||||
run_recipe(cmd.params.get("PPID"))
|
||||
@eq.command # the function name IS the command,
|
||||
def START(cmd): # validated against the real equipment
|
||||
run_recipe(cmd.params.get("PPID")) # — so a typo fails at startup
|
||||
eq.fire(eq.names.event.ProcessStarted) # autocomplete + typo-safe
|
||||
|
||||
eq.listen()
|
||||
```
|
||||
|
||||
Names come from *your* `equipment.yaml`. `@eq.command` binds a handler by
|
||||
its function name; `eq.names.event.*` / `.alarm.*` / `.command.*` are
|
||||
autocomplete-able, typo-checked views fetched from the live daemon — so
|
||||
you rarely type a bare string. (The plain forms — `@eq.on("START")`,
|
||||
`eq.fire("ProcessStarted")` — still work.)
|
||||
|
||||
A complete tool is ~25 lines: [clients/python/examples/mini_tool.py](clients/python/examples/mini_tool.py).
|
||||
|
||||
2. **Any language over gRPC** — `secs_gemd` exposes the name-based API in
|
||||
|
||||
Reference in New Issue
Block a user