Skip to main content

autocore_std/
tis.rs

1// Copyright (C) 2026 Automated Design Corp. All Rights Reserved.
2//
3//! Test Information System (TIS) producer helpers.
4//!
5//! Thin, hand-written conveniences over the `tis.*` IPC commands. The
6//! per-method `TestManager` codegen targets the same commands for the
7//! common writes (`add_cycle`, `add_raw_data`, `update_results`, …); the
8//! helpers here cover writes that aren't bound to a single method's
9//! generated shape. Today that's attaching **chart region bands** to a
10//! recorded cycle's raw trace.
11
12use serde::Serialize;
13
14use crate::CommandClient;
15
16/// A shaded X-range band drawn over a chart view in the HMI, used to
17/// indicate a processed / region-of-interest span of a cycle's trace.
18///
19/// Serializes to the JSON shape the autocore-react `ChartRegion` consumes
20/// (`xMin` / `xMax` / `label` / `color` / `borderColor`) — the band spans
21/// the full Y height between `x_min` and `x_max` on the view's x scale.
22#[derive(Debug, Clone, Serialize)]
23#[serde(rename_all = "camelCase")]
24pub struct ChartRegion {
25    /// Band start on the X axis, in the view's x-data units.
26    pub x_min: f64,
27    /// Band end on the X axis.
28    pub x_max: f64,
29    /// Optional caption drawn at the top-center of the band.
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub label: Option<String>,
32    /// Optional fill color (any CSS color). HMI applies a default when unset.
33    #[serde(skip_serializing_if = "Option::is_none")]
34    pub color: Option<String>,
35    /// Optional band-edge border color (no border when unset).
36    #[serde(skip_serializing_if = "Option::is_none")]
37    pub border_color: Option<String>,
38}
39
40impl ChartRegion {
41    /// A bare band between `x_min` and `x_max` with HMI-default styling.
42    pub fn new(x_min: f64, x_max: f64) -> Self {
43        Self { x_min, x_max, label: None, color: None, border_color: None }
44    }
45
46    /// Builder: set the band caption.
47    pub fn with_label(mut self, label: impl Into<String>) -> Self {
48        self.label = Some(label.into());
49        self
50    }
51
52    /// Builder: set the fill color (any CSS color string).
53    pub fn with_color(mut self, color: impl Into<String>) -> Self {
54        self.color = Some(color.into());
55        self
56    }
57
58    /// Builder: set the band-edge border color.
59    pub fn with_border_color(mut self, color: impl Into<String>) -> Self {
60        self.border_color = Some(color.into());
61        self
62    }
63}
64
65/// Set (replacing any prior set) the chart region bands on one recorded
66/// cycle's raw trace. The bands are patched into that cycle's raw-data
67/// envelope, so the HMI renders them whenever the cycle is viewed — and
68/// live-updates if that cycle is on screen when this write lands.
69///
70/// Decoupled from the trace write: call it any time *after* the cycle's
71/// `add_raw_data` / `record_raw_trace` has produced the on-disk file — the
72/// same tick, a later tick, or a separate post-processing pass. The trace
73/// file must already exist (you can't annotate a trace that hasn't been
74/// recorded). Passing an empty slice clears the bands for that cycle.
75///
76/// `run_id` is optional:
77/// - `None` — target the project/method's currently-active test. The server
78///   resolves the run from its active-test registry, exactly as
79///   `add_raw_data` does. Use this from a live control program.
80/// - `Some(run_id)` — target a specific run explicitly, e.g. a
81///   post-processing step annotating a run that has already finished.
82///
83/// Returns the transaction id of the sent command; poll `client` for its
84/// response as with any other `tis.*` write.
85pub fn set_chart_regions(
86    client: &mut CommandClient,
87    project_id: &str,
88    method_id: &str,
89    run_id: Option<&str>,
90    name: &str,
91    cycle_index: u32,
92    regions: &[ChartRegion],
93) -> u32 {
94    let mut payload = serde_json::json!({
95        "project_id":  project_id,
96        "method_id":   method_id,
97        "name":        name,
98        "cycle_index": cycle_index,
99        "regions":     regions,
100    });
101    if let (Some(rid), Some(obj)) = (run_id, payload.as_object_mut()) {
102        obj.insert("run_id".to_string(), serde_json::json!(rid));
103    }
104    client.send("tis.set_chart_regions", payload)
105}