|
| 1 | +function ctx = simple_live_dashboard() |
| 2 | +%SIMPLE_LIVE_DASHBOARD Minimal one-FastSensePlot dashboard with live mode + events. |
| 3 | +% |
| 4 | +% Shows the smallest possible DashboardEngine setup that exercises both |
| 5 | +% live refresh and threshold-driven event markers: |
| 6 | +% - one SensorTag fed by a writer timer (1 sample / second) |
| 7 | +% - one MonitorTag tripping when y > 5 (drives the EventStore) |
| 8 | +% - one FastSenseWidget on the dashboard with ShowEventMarkers=true |
| 9 | +% - engine.startLive() refreshes the plot every LiveInterval |
| 10 | +% |
| 11 | +% Returns: |
| 12 | +% ctx — struct with fields: |
| 13 | +% engine — DashboardEngine handle (rendered, live) |
| 14 | +% writerTimer — MATLAB timer pushing synthetic samples |
| 15 | +% tag — SensorTag streaming the signal |
| 16 | +% monitor — MonitorTag tripping on y > 5 |
| 17 | +% store — EventStore receiving events |
| 18 | +% |
| 19 | +% Teardown is wired to the figure's CloseRequestFcn — closing the |
| 20 | +% window stops the writer + live timer cleanly. Calling |
| 21 | +% simple_live_dashboard_teardown(ctx) does the same explicitly. |
| 22 | +% |
| 23 | +% Example: |
| 24 | +% ctx = simple_live_dashboard(); |
| 25 | +% pause(60); % watch a few cycles |
| 26 | +% evts = ctx.store.getEventsForTag('demo.signal.high'); |
| 27 | +% |
| 28 | +% See also DashboardEngine, FastSenseWidget, MonitorTag, EventStore, |
| 29 | +% example_event_markers. |
| 30 | + |
| 31 | + install(); |
| 32 | + |
| 33 | + % --- Domain objects -------------------------------------------------- |
| 34 | + es = EventStore(); |
| 35 | + tag = SensorTag('demo.signal', 'Name', 'Demo Signal', 'Units', 'units'); |
| 36 | + mon = MonitorTag('demo.signal.high', tag, @(x, y) y > 5, ... |
| 37 | + 'EventStore', es, 'MinDuration', 0); |
| 38 | + |
| 39 | + % --- Dashboard with a single FastSenseWidget ------------------------- |
| 40 | + engine = DashboardEngine('Simple Live Dashboard', ... |
| 41 | + 'Theme', 'light', 'LiveInterval', 1.0); |
| 42 | + engine.addWidget('fastsense', ... |
| 43 | + 'Title', 'Demo Signal (threshold y > 5)', ... |
| 44 | + 'Tag', tag, ... |
| 45 | + 'ShowEventMarkers', true, ... |
| 46 | + 'EventStore', es, ... |
| 47 | + 'Position', [1 1 24 8]); |
| 48 | + engine.render(); |
| 49 | + engine.startLive(); |
| 50 | + |
| 51 | + % --- Writer timer: one synthetic sample per second ------------------- |
| 52 | + % Slow sine swinging 1..7, crossing the y=5 threshold roughly every |
| 53 | + % 15 s — gives the user a steady cadence of events to watch. |
| 54 | + t0 = posixtime(datetime('now')); |
| 55 | + writer = timer( ... |
| 56 | + 'ExecutionMode', 'fixedRate', ... |
| 57 | + 'Period', 1.0, ... |
| 58 | + 'BusyMode', 'drop', ... |
| 59 | + 'TimerFcn', @(~,~) writeOne_(), ... |
| 60 | + 'ErrorFcn', @(~,~) []); |
| 61 | + start(writer); |
| 62 | + |
| 63 | + ctx = struct( ... |
| 64 | + 'engine', engine, ... |
| 65 | + 'writerTimer', writer, ... |
| 66 | + 'tag', tag, ... |
| 67 | + 'monitor', mon, ... |
| 68 | + 'store', es); |
| 69 | + |
| 70 | + % --- Wire CloseRequestFcn so X-button cleans up ---------------------- |
| 71 | + if ~isempty(engine.hFigure) && ishandle(engine.hFigure) |
| 72 | + set(engine.hFigure, 'CloseRequestFcn', @(s, ~) closeAll_(s)); |
| 73 | + end |
| 74 | + |
| 75 | + % ===== nested helpers ============================================== |
| 76 | + |
| 77 | + function writeOne_() |
| 78 | + try |
| 79 | + elapsed = posixtime(datetime('now')) - t0; |
| 80 | + y = 4 + 3 * sin(elapsed * 2 * pi / 30); |
| 81 | + tag.updateData([tag.X, elapsed], [tag.Y, y]); |
| 82 | + mon.appendData(elapsed, y); |
| 83 | + catch |
| 84 | + % Writer ticks must never crash the timer. |
| 85 | + end |
| 86 | + end |
| 87 | + |
| 88 | + function closeAll_(fig) |
| 89 | + try |
| 90 | + if ~isempty(writer) && isvalid(writer) |
| 91 | + if strcmp(writer.Running, 'on'); stop(writer); end |
| 92 | + delete(writer); |
| 93 | + end |
| 94 | + catch |
| 95 | + end |
| 96 | + try |
| 97 | + if ~isempty(engine) && isvalid(engine) ... |
| 98 | + && ismethod(engine, 'stopLive') |
| 99 | + engine.stopLive(); |
| 100 | + end |
| 101 | + catch |
| 102 | + end |
| 103 | + try; delete(fig); catch; end |
| 104 | + end |
| 105 | +end |
0 commit comments