Files
linuxcncWebWASM/web/react/src/protocol.ts

169 lines
6.1 KiB
TypeScript

export const PROTOCOL_SCHEMA = 1 as const;
export const CONTEXT_ID = "linuxcnc-2.10.0-pre0-wasm-m1-py-c1" as const;
export type MessageKind =
| "HELLO" | "CAPABILITIES" | "SESSION_ATTACH" | "SESSION_READY"
| "LOAD_WORKSPACE" | "COMMAND_RESULT" | "STATE_SNAPSHOT" | "EVENT"
| "ALARM" | "RECOVERY_STATUS" | "ERROR";
export type MessageEnvelope<TPayload = unknown> = {
schema_version: typeof PROTOCOL_SCHEMA;
kind: MessageKind | string;
context_id: string;
session_id: string;
seq: number;
operation_id?: string;
simulation_tick?: number;
payload: TPayload;
};
export type MotionSnapshot = {
axes?: number[];
joints?: number[];
velocity?: number[];
homed?: boolean | boolean[];
homed_axes?: boolean[];
limits?: number | Record<string, boolean>;
on_any_limit?: boolean;
fault?: string | null;
velocity_limit?: number;
velocity_scale?: number;
jog_scale?: number;
jog_velocity_linear?: number;
jog_velocity_angular?: number;
spindle_override?: number;
};
export type TrajectorySnapshot = {
queue?: Array<{ id?: number; source_line?: number | null; start?: Record<string, number>; end?: Record<string, number> }>;
active?: { id?: number; source_line?: number | null; start?: Record<string, number>; end?: Record<string, number> } | null;
queue_depth?: number;
};
export type SimSnapshotV1 = {
schema?: string;
snapshot_id?: string;
base_snapshot_id?: string;
full?: boolean;
simulation_tick: number;
state_hash: string;
task?: { state: string; mode: string; interp_state?: string; current_line?: number | null };
program?: Record<string, unknown> | null;
motion?: MotionSnapshot;
wasm_motion?: Record<string, unknown>;
authoritative?: { state_hash?: string; planner?: TrajectorySnapshot; kinematics?: Record<string, unknown> };
coordinates?: { machine?: number[]; relative?: number[]; g5x?: number; g92?: number[]; tool_offset?: number[] };
spindle?: Array<{ enabled?: boolean; direction?: number; commanded?: number; actual?: number; at_speed?: boolean }>;
io?: { coolant?: number; lube?: boolean; digital?: number[]; analog?: number[]; probe?: boolean };
tool?: { current?: number; prepared?: number; pocket?: number; change_state?: string };
overrides?: { feed?: number; rapid?: number; spindle?: number[]; adaptive?: number; feed_hold?: boolean };
hal?: { graph_revision?: number; changed_values?: ArrayBuffer };
alarms?: Array<{ id?: string; severity?: string; code?: string; acknowledged?: boolean }>;
recovery?: { status?: string; last_verified_seq?: number; checkpoint_tick?: number };
panel_snapshot?: PanelSnapshotV1;
configuration?: Record<string, unknown> | null;
visual?: PanelSnapshotV1["visual"];
motion_sample?: { tick?: number; pose?: Record<string, number>; joints?: number[]; active_segment_id?: number; active_progress?: number };
snapshot_mode?: "full" | "motion_delta";
kinematics?: XyzacKinematicsSnapshot;
xyzac?: XyzacCapabilitySnapshot;
gates?: Record<string, { action: string; enabled: boolean; reason: string }>;
motion_authority?: string;
task_authority?: string;
};
export type XyzacKinematicsSnapshot = {
schema: "wasm-xyzac-kinematics.v1";
status: "verified" | "error" | "blocked";
active_type: 0 | 1 | 2;
native_type: string;
coordinates: "XYZAC";
joint_count: 5;
linear_units: "mm";
angular_units: "deg";
pose: Record<"x" | "y" | "z" | "a" | "b" | "c" | "u" | "v" | "w", number>;
joints: [number, number, number, number, number];
offsets: { x_rot_point: number; y_offset: number; z_offset: number; tool_offset: number };
generation: number;
switch_count: number;
state_hash: string;
wasm_state_hash: string;
};
export type XyzacCapabilitySnapshot = {
coordinates: "XYZAC";
joint_count: 5;
active_type: 0 | 1 | 2;
hal_pin_vars: boolean;
switchkins_net: boolean;
finite_offsets: boolean;
userk_capability: boolean;
};
export type PanelSnapshotV1 = {
schema: "axis-panel-snapshot.v1";
context_id: string;
session_id: string;
simulation_tick: number;
state_hash: string;
task: Record<string, unknown>;
program: Record<string, unknown> | null;
motion: Record<string, unknown>;
coordinates?: { machine?: number[]; relative?: number[]; commanded?: number[] };
overrides?: { feed?: number; spindle?: number[] };
wasm_motion: Record<string, unknown>;
home_limit: Record<string, unknown>;
hal: Record<string, unknown>;
devices: Record<string, unknown>;
device_io: Record<string, unknown>;
configuration: Record<string, unknown> | null;
axis_state: AxisStateView;
gates: Record<string, { action: string; enabled: boolean; reason: string }>;
visual: {
schema: "axis-visual.v1";
pose: Record<string, number>;
joints: number[];
toolpath?: Array<Record<string, unknown>>;
active_segment_id?: number | null;
active_progress?: number;
motion_trace?: Array<{ tick: number; pose: Record<string, number>; joints: number[]; active_segment_id: number; active_progress: number }>;
source: "wasm_canonical_motion";
};
authoritative: Record<string, unknown>;
motion_authority: string;
task_authority: string;
kinematics?: XyzacKinematicsSnapshot;
xyzac?: XyzacCapabilitySnapshot;
io?: Record<string, unknown>;
};
export type Capabilities = {
context_id?: string;
abi?: Record<string, unknown>;
snapshot?: Record<string, unknown>;
commands?: string[];
streams?: string[];
limits?: Record<string, number>;
exclusions?: string[];
};
export type AxisStateView = {
state: "ESTOP" | "ESTOP_RESET" | "OFF" | "ON" | "HOME" | "IDLE" | "RUNNING" | "PAUSED";
machine_state: "ESTOP" | "ESTOP_RESET" | "OFF" | "ON";
operation_state: "HOME" | "IDLE" | "RUNNING" | "PAUSED";
source_task_state: string;
source_interp_state: string;
source_mode: "MANUAL" | "MDI" | "AUTO";
};
export function isEnvelope(value: unknown): value is MessageEnvelope {
if (!value || typeof value !== "object") return false;
const candidate = value as Partial<MessageEnvelope>;
return candidate.schema_version === PROTOCOL_SCHEMA
&& typeof candidate.kind === "string"
&& typeof candidate.context_id === "string"
&& typeof candidate.session_id === "string"
&& Number.isSafeInteger(candidate.seq)
&& "payload" in candidate;
}