E40 Process Jobs + E94 Control Jobs + E30 communication state
GEM300 layer: SEMI E40-0705 Process Job and E94-0705 Control Job state machines, plus the E30 §6.1 communication-state machine that sits between HSMS SELECT and full GEM communication. Data-driven via data/process_job_state.yaml and data/control_job_state.yaml, mirroring the existing control_state.yaml pattern. Wire coverage: S14F9/F10 CreateObject (CJ) host -> equipment S14F11/F12 DeleteObject (CJ) host -> equipment S16F5/F6 PRJobCommand host -> equipment S16F9 PRJobAlert equipment -> host S16F11/F12 PRJobCreate (simplified body) host -> equipment S16F13/F14 PRJobDequeue host -> equipment S16F27/F28 CJobCommand host -> equipment Process Job FSM exposes 8 states matching PRJOBSTATE bytes (E40 §10.3.2); HOQ is reorder-aware (move-to-head against an insertion-order vector); Stop/Abort on a Queued PJ routes through ABORTING so the host observes PRJOBSTATE=7 on the wire (§6.3); alert_enabled is settable per-PJ for PRALERT control; FSM dispatches through ProcessJobStore::on_change_ dynamically so a late set_state_change_handler() reaches existing PJs. Hardening: loader rejects NoState (sentinel) as initial/from/to and rejects `on: created` rows; static_asserts pin enum values to wire bytes; ProcessJobStore is non-movable to keep the per-PJ this-capture safe. Server simulator cascades the full CJ -> PJ lifecycle on CJSTART so the wire trace exercises every legal state. CEIDs 400/401 fire on CJ state changes via the existing event-report pipeline. Tests: 60+ new assertions across test_process_jobs, test_control_jobs, test_communication_state, test_hsms_connection, plus loader and messages round-trip coverage. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
# E94 §6 Control Job state model — encoded as a transition table.
|
||||
#
|
||||
# CJ governs the batch — it owns an ordered list of PRJOBIDs and
|
||||
# proceeds Queued -> Selected -> WaitingForStart -> Executing ->
|
||||
# Completed; from any of those a Stop or Abort diverts to Stopping or
|
||||
# Aborting (then Completed).
|
||||
#
|
||||
# State values are this project's encoding (see control_job_state.hpp).
|
||||
# Host-initiated events (start / pause / resume / stop / abort) arrive
|
||||
# via S16F27; internal events (select / setup_complete /
|
||||
# all_jobs_complete / abort_complete) fire from the equipment's
|
||||
# application logic as the contained PJs progress.
|
||||
|
||||
initial: Queued
|
||||
|
||||
transitions:
|
||||
# --- QUEUED ----------------------------------------------------------
|
||||
- {from: Queued, on: select, to: Selected}
|
||||
- {from: Queued, on: stop, to: Completed}
|
||||
- {from: Queued, on: abort, to: Completed}
|
||||
|
||||
# --- SELECTED --------------------------------------------------------
|
||||
- {from: Selected, on: setup_complete, to: WaitingForStart}
|
||||
- {from: Selected, on: stop, to: Stopping}
|
||||
- {from: Selected, on: abort, to: Aborting}
|
||||
|
||||
# --- WAITING-FOR-START -----------------------------------------------
|
||||
- {from: WaitingForStart, on: start, to: Executing}
|
||||
- {from: WaitingForStart, on: stop, to: Stopping}
|
||||
- {from: WaitingForStart, on: abort, to: Aborting}
|
||||
|
||||
# --- EXECUTING -------------------------------------------------------
|
||||
- {from: Executing, on: pause, to: Paused}
|
||||
- {from: Executing, on: stop, to: Stopping}
|
||||
- {from: Executing, on: abort, to: Aborting}
|
||||
- {from: Executing, on: all_jobs_complete, to: Completed}
|
||||
|
||||
# --- PAUSED ----------------------------------------------------------
|
||||
- {from: Paused, on: resume, to: Executing}
|
||||
- {from: Paused, on: stop, to: Stopping}
|
||||
- {from: Paused, on: abort, to: Aborting}
|
||||
|
||||
# --- STOPPING --------------------------------------------------------
|
||||
- {from: Stopping, on: all_jobs_complete, to: Completed}
|
||||
- {from: Stopping, on: abort, to: Aborting}
|
||||
|
||||
# --- ABORTING --------------------------------------------------------
|
||||
- {from: Aborting, on: abort_complete, to: Completed}
|
||||
@@ -26,6 +26,9 @@ capabilities:
|
||||
- {code: 12, name: "Clock"}
|
||||
- {code: 14, name: "Spooling (partial; S2F43/F44 + S6F23/F24)"}
|
||||
- {code: 15, name: "Control (operator initiated)"}
|
||||
# GEM300 extensions (declared so the host can probe with S1F19).
|
||||
- {code: 40, name: "E40 Process Job Management"}
|
||||
- {code: 94, name: "E94 Control Job Management"}
|
||||
|
||||
# Reported on S1F3 (values) and S1F11 (namelist). `value` is the initial.
|
||||
# `type` controls the SECS-II Item format.
|
||||
@@ -50,6 +53,8 @@ ceids:
|
||||
- {id: 100, name: ControlStateChanged}
|
||||
- {id: 200, name: AlarmSetEvent}
|
||||
- {id: 300, name: ProcessStarted}
|
||||
- {id: 400, name: ControlJobExecuting} # E94 CJ entered Executing
|
||||
- {id: 401, name: ControlJobCompleted} # E94 CJ entered Completed
|
||||
|
||||
# Reported on S5F5 / S5F1. `category` is the lower-7 of ALCD.
|
||||
alarms:
|
||||
|
||||
@@ -251,6 +251,24 @@ messages:
|
||||
parser: parse_s2f18
|
||||
body: {kind: scalar, item_type: ASCII, param: time_str}
|
||||
|
||||
# S2F25 / S2F26 — Loopback Diagnostic. Host sends an arbitrary byte
|
||||
# blob; equipment echoes it back unchanged in S2F26. Useful for round-
|
||||
# trip diagnostics and as a "keep-alive at the application layer."
|
||||
- id: S2F25
|
||||
stream: 2
|
||||
function: 25
|
||||
w: true
|
||||
builder: s2f25_loopback_diagnostic_request
|
||||
parser: parse_s2f25
|
||||
body: {kind: scalar, item_type: BINARY, param: payload}
|
||||
|
||||
- id: S2F26
|
||||
stream: 2
|
||||
function: 26
|
||||
builder: s2f26_loopback_diagnostic_data
|
||||
parser: parse_s2f26
|
||||
body: {kind: scalar, item_type: BINARY, param: payload}
|
||||
|
||||
- id: S2F29
|
||||
stream: 2
|
||||
function: 29
|
||||
@@ -660,6 +678,53 @@ messages:
|
||||
- {name: alid, shape: {kind: scalar, item_type: U4}}
|
||||
- {name: altx, shape: {kind: scalar, item_type: ASCII}}
|
||||
|
||||
# S5F9 / S5F10 — Exception Post Notify / Confirm (E5).
|
||||
# Equipment posts a recoverable exception; the body lists the allowed
|
||||
# recovery actions that S5F13 may then send. Host acks via S5F10.
|
||||
- id: S5F9
|
||||
stream: 5
|
||||
function: 9
|
||||
w: true
|
||||
builder: s5f9_exception_post_notify
|
||||
parser: parse_s5f9
|
||||
body:
|
||||
kind: list
|
||||
struct_name: ExceptionPost
|
||||
fields:
|
||||
- {name: exid, shape: {kind: scalar, item_type: U4}}
|
||||
- {name: extype, shape: {kind: scalar, item_type: ASCII}}
|
||||
- {name: exmessage, shape: {kind: scalar, item_type: ASCII}}
|
||||
- name: exrecvra
|
||||
shape: {kind: list_of, element: {kind: scalar, item_type: ASCII}}
|
||||
|
||||
- id: S5F10
|
||||
stream: 5
|
||||
function: 10
|
||||
builder: s5f10_exception_post_confirm
|
||||
body: {kind: scalar, item_type: BINARY_BYTE, enum: AlarmAck, param: ack}
|
||||
|
||||
# S5F11 / S5F12 — Exception Clear Notify / Confirm. Equipment signals
|
||||
# that a previously-posted exception has cleared.
|
||||
- id: S5F11
|
||||
stream: 5
|
||||
function: 11
|
||||
w: true
|
||||
builder: s5f11_exception_clear_notify
|
||||
parser: parse_s5f11
|
||||
body:
|
||||
kind: list
|
||||
struct_name: ExceptionClear
|
||||
fields:
|
||||
- {name: exid, shape: {kind: scalar, item_type: U4}}
|
||||
- {name: extype, shape: {kind: scalar, item_type: ASCII}}
|
||||
- {name: exmessage, shape: {kind: scalar, item_type: ASCII}}
|
||||
|
||||
- id: S5F12
|
||||
stream: 5
|
||||
function: 12
|
||||
builder: s5f12_exception_clear_confirm
|
||||
body: {kind: scalar, item_type: BINARY_BYTE, enum: AlarmAck, param: ack}
|
||||
|
||||
# =====================================================================
|
||||
# S6 — Data collection
|
||||
# =====================================================================
|
||||
@@ -909,3 +974,168 @@ messages:
|
||||
function: 6
|
||||
builder: s10f6_terminal_display_multi_ack
|
||||
body: {kind: scalar, item_type: BINARY_BYTE, enum: TerminalAck, param: ack}
|
||||
|
||||
# =====================================================================
|
||||
# S14 — Object services (E94 ControlJob create/delete).
|
||||
#
|
||||
# Real E14 ObjectService is a fully generic generic-attribute carrier;
|
||||
# for the E94 demo we use a simplified shape that names the object
|
||||
# type ("ControlJob") and carries the CTLJOBID + contained PRJOBIDs
|
||||
# directly. The wire shape is a defensible subset of E14F9 with the
|
||||
# generic ATTRIBUTES list specialized.
|
||||
# =====================================================================
|
||||
|
||||
# S14F9 / F10 — CreateObject (CJ). Host asks the equipment to bring
|
||||
# a new ControlJob into existence and registers the list of PJs it
|
||||
# contains; the CJ starts in CJ-QUEUED.
|
||||
- id: S14F9
|
||||
stream: 14
|
||||
function: 9
|
||||
w: true
|
||||
builder: s14f9_create_control_job
|
||||
parser: parse_s14f9
|
||||
body:
|
||||
kind: list
|
||||
struct_name: CreateControlJobRequest
|
||||
fields:
|
||||
- {name: ctljobid, shape: {kind: scalar, item_type: ASCII}}
|
||||
- name: prjobids
|
||||
shape: {kind: list_of, element: {kind: scalar, item_type: ASCII}}
|
||||
|
||||
- id: S14F10
|
||||
stream: 14
|
||||
function: 10
|
||||
builder: s14f10_create_control_job_ack
|
||||
parser: parse_s14f10
|
||||
body:
|
||||
kind: list
|
||||
struct_name: CreateControlJobAck
|
||||
fields:
|
||||
- {name: ctljobid, shape: {kind: scalar, item_type: ASCII}}
|
||||
- {name: ack, shape: {kind: scalar, item_type: BINARY_BYTE, enum: ObjectAck}}
|
||||
|
||||
# S14F11 / F12 — DeleteObject (CJ).
|
||||
- id: S14F11
|
||||
stream: 14
|
||||
function: 11
|
||||
w: true
|
||||
builder: s14f11_delete_control_job
|
||||
parser: parse_s14f11
|
||||
body: {kind: scalar, item_type: ASCII, param: ctljobid}
|
||||
|
||||
- id: S14F12
|
||||
stream: 14
|
||||
function: 12
|
||||
builder: s14f12_delete_control_job_ack
|
||||
body: {kind: scalar, item_type: BINARY_BYTE, enum: ObjectAck, param: ack}
|
||||
|
||||
# =====================================================================
|
||||
# S16 — Process Management (E40 Process Jobs, E94 Control Jobs).
|
||||
#
|
||||
# Wire shapes are E40-0705 / E94-0705 with a couple of deliberate
|
||||
# simplifications documented inline. The PJ/CJ state set and the legal
|
||||
# transitions live in data/process_job_state.yaml and
|
||||
# data/control_job_state.yaml respectively (data-driven, same pattern
|
||||
# as data/control_state.yaml).
|
||||
# =====================================================================
|
||||
|
||||
# S16F5 / F6 — PRJobCommand. Host issues Start / Pause / Resume /
|
||||
# Stop / Abort / HOQ against an existing process job.
|
||||
- id: S16F5
|
||||
stream: 16
|
||||
function: 5
|
||||
w: true
|
||||
builder: s16f5_pr_job_command
|
||||
parser: parse_s16f5
|
||||
body:
|
||||
kind: list
|
||||
struct_name: PRJobCommandRequest
|
||||
fields:
|
||||
- {name: prjobid, shape: {kind: scalar, item_type: ASCII}}
|
||||
- {name: prcmd, shape: {kind: scalar, item_type: ASCII}}
|
||||
|
||||
- id: S16F6
|
||||
stream: 16
|
||||
function: 6
|
||||
builder: s16f6_pr_job_command_ack
|
||||
body: {kind: scalar, item_type: BINARY_BYTE, enum: HostCmdAck, param: ack}
|
||||
|
||||
# S16F9 — PRJobAlert. E->H one-way alert that a PJ entered a new
|
||||
# state. PRJOBSTATE is the E40 PJ state code (0..7). Equipment
|
||||
# emits one per PJ state transition when alerts are enabled.
|
||||
- id: S16F9
|
||||
stream: 16
|
||||
function: 9
|
||||
builder: s16f9_pr_job_alert
|
||||
parser: parse_s16f9
|
||||
body:
|
||||
kind: list
|
||||
struct_name: PRJobAlert
|
||||
fields:
|
||||
- {name: prjobid, shape: {kind: scalar, item_type: ASCII}}
|
||||
- {name: prjobstate, shape: {kind: scalar, item_type: BINARY_BYTE, enum: ProcessJobState}}
|
||||
|
||||
# S16F11 / F12 — PRJobCreate.
|
||||
#
|
||||
# Real E40-0705 S16F11 body is <L,5 PRJOBID MF PRRECIPEMETHOD
|
||||
# RCPSPEC L MTRLOUTSPEC L PRPROCESSPARAMS>. We simplify to the
|
||||
# three pieces that actually drive the demo state machine:
|
||||
# PRJOBID, recipe (PPID), and the list of material identifiers. MF
|
||||
# / PRRECIPEMETHOD / PRPROCESSPARAMS are tool-specific; layering
|
||||
# them in is a YAML edit + builder overload, not surgery.
|
||||
- id: S16F11
|
||||
stream: 16
|
||||
function: 11
|
||||
w: true
|
||||
builder: s16f11_pr_job_create
|
||||
parser: parse_s16f11
|
||||
body:
|
||||
kind: list
|
||||
struct_name: PRJobCreateRequest
|
||||
fields:
|
||||
- {name: prjobid, shape: {kind: scalar, item_type: ASCII}}
|
||||
- {name: ppid, shape: {kind: scalar, item_type: ASCII}}
|
||||
- name: mtrloutspec
|
||||
shape: {kind: list_of, element: {kind: scalar, item_type: ASCII}}
|
||||
|
||||
- id: S16F12
|
||||
stream: 16
|
||||
function: 12
|
||||
builder: s16f12_pr_job_create_ack
|
||||
body: {kind: scalar, item_type: BINARY_BYTE, enum: HostCmdAck, param: ack}
|
||||
|
||||
# S16F13 / F14 — PRJobDequeue. Host removes a queued PJ.
|
||||
- id: S16F13
|
||||
stream: 16
|
||||
function: 13
|
||||
w: true
|
||||
builder: s16f13_pr_job_dequeue
|
||||
parser: parse_s16f13
|
||||
body: {kind: scalar, item_type: ASCII, param: prjobid}
|
||||
|
||||
- id: S16F14
|
||||
stream: 16
|
||||
function: 14
|
||||
builder: s16f14_pr_job_dequeue_ack
|
||||
body: {kind: scalar, item_type: BINARY_BYTE, enum: HostCmdAck, param: ack}
|
||||
|
||||
# S16F27 / F28 — CJobCommand (E94). Host issues Start / Pause /
|
||||
# Resume / Stop / Abort against an existing CJ.
|
||||
- id: S16F27
|
||||
stream: 16
|
||||
function: 27
|
||||
w: true
|
||||
builder: s16f27_cj_command
|
||||
parser: parse_s16f27
|
||||
body:
|
||||
kind: list
|
||||
struct_name: CJobCommandRequest
|
||||
fields:
|
||||
- {name: ctljobid, shape: {kind: scalar, item_type: ASCII}}
|
||||
- {name: ctljobcmd, shape: {kind: scalar, item_type: ASCII}}
|
||||
|
||||
- id: S16F28
|
||||
stream: 16
|
||||
function: 28
|
||||
builder: s16f28_cj_command_ack
|
||||
body: {kind: scalar, item_type: BINARY_BYTE, enum: HostCmdAck, param: ack}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
# E40 §6 Process Job state model — encoded as a transition table.
|
||||
#
|
||||
# Each row is a (from, on) -> (to [, ack]) tuple, mirroring the encoding
|
||||
# in data/control_state.yaml. Events are the lower-snake-case verbs the
|
||||
# loader maps to ProcessJobEvent: start / pause / resume / stop / abort /
|
||||
# hoq / select / setup_complete / process_complete / abort_complete /
|
||||
# created. Host-initiated events (start, pause, resume, stop, abort,
|
||||
# hoq) carry an `ack` when the row should override the default
|
||||
# HostCmdAck::Accept (e.g. a row that only validates an event without
|
||||
# changing state).
|
||||
#
|
||||
# Wire reference: S16F9 PRJOBSTATE byte (E40-0705 §10.3.2):
|
||||
# 0 Queued, 1 SettingUp, 2 WaitingForStart, 3 Processing,
|
||||
# 4 ProcessComplete, 5 Paused, 6 Stopping, 7 Aborting.
|
||||
#
|
||||
# Process-Complete is terminal — deletion happens out-of-band via the
|
||||
# ProcessJobStore (CJ cleanup or explicit S16F13 while still QUEUED).
|
||||
|
||||
initial: Queued
|
||||
|
||||
transitions:
|
||||
# --- QUEUED ----------------------------------------------------------
|
||||
# PJSTOP/PJABORT on a Queued PJ routes through Aborting so the host
|
||||
# observes PRJOBSTATE=7 on the wire (E40-0705 §6.3). PJDELETE / S16F13
|
||||
# is the dequeue-without-state-change path.
|
||||
- {from: Queued, on: select, to: SettingUp}
|
||||
- {from: Queued, on: hoq} # reorder only, no state change
|
||||
- {from: Queued, on: stop, to: Aborting}
|
||||
- {from: Queued, on: abort, to: Aborting}
|
||||
|
||||
# --- SETTING-UP -------------------------------------------------------
|
||||
- {from: SettingUp, on: setup_complete, to: WaitingForStart}
|
||||
- {from: SettingUp, on: stop, to: Stopping}
|
||||
- {from: SettingUp, on: abort, to: Aborting}
|
||||
|
||||
# --- WAITING-FOR-START -----------------------------------------------
|
||||
- {from: WaitingForStart, on: start, to: Processing}
|
||||
- {from: WaitingForStart, on: stop, to: Stopping}
|
||||
- {from: WaitingForStart, on: abort, to: Aborting}
|
||||
|
||||
# --- PROCESSING -------------------------------------------------------
|
||||
- {from: Processing, on: pause, to: Paused}
|
||||
- {from: Processing, on: stop, to: Stopping}
|
||||
- {from: Processing, on: abort, to: Aborting}
|
||||
- {from: Processing, on: process_complete, to: ProcessComplete}
|
||||
|
||||
# --- PAUSED ----------------------------------------------------------
|
||||
- {from: Paused, on: resume, to: Processing}
|
||||
- {from: Paused, on: stop, to: Stopping}
|
||||
- {from: Paused, on: abort, to: Aborting}
|
||||
|
||||
# --- STOPPING --------------------------------------------------------
|
||||
- {from: Stopping, on: process_complete, to: ProcessComplete}
|
||||
- {from: Stopping, on: abort, to: Aborting}
|
||||
|
||||
# --- ABORTING --------------------------------------------------------
|
||||
- {from: Aborting, on: abort_complete, to: ProcessComplete}
|
||||
Reference in New Issue
Block a user