feat: enhance waveform viewer with record type handling and improved empty state messaging
This commit is contained in:
@@ -838,7 +838,9 @@ def _extract_record_type(data: bytes) -> Optional[str]:
|
|||||||
code = data[1]
|
code = data[1]
|
||||||
if code == 0x10:
|
if code == 0x10:
|
||||||
return "Waveform"
|
return "Waveform"
|
||||||
# TODO: add histogram sub_code once a histogram event is captured with debug=true
|
# Unknown code — log it so we can identify histogram/noise sub_codes from real captures
|
||||||
|
log.warning("_extract_record_type: unknown sub_code=0x%02X — returning raw string", code)
|
||||||
|
return f"Unknown(0x{code:02X})"
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -183,21 +183,23 @@ def _build_client(
|
|||||||
baud: int,
|
baud: int,
|
||||||
host: Optional[str],
|
host: Optional[str],
|
||||||
tcp_port: int,
|
tcp_port: int,
|
||||||
|
timeout: float = 30.0,
|
||||||
) -> MiniMateClient:
|
) -> MiniMateClient:
|
||||||
"""
|
"""
|
||||||
Return a MiniMateClient configured for either serial or TCP transport.
|
Return a MiniMateClient configured for either serial or TCP transport.
|
||||||
|
|
||||||
TCP takes priority if *host* is supplied; otherwise *port* (serial) is used.
|
TCP takes priority if *host* is supplied; otherwise *port* (serial) is used.
|
||||||
Raises HTTPException(422) if neither is provided.
|
Raises HTTPException(422) if neither is provided.
|
||||||
|
|
||||||
|
Use timeout=120.0 (or higher) for endpoints that perform a full 5A waveform
|
||||||
|
download — a 70-second event at 1024 sps takes 2-3 minutes to transfer over
|
||||||
|
cellular and each individual recv must complete within the timeout window.
|
||||||
"""
|
"""
|
||||||
if host:
|
if host:
|
||||||
# TCP / modem / ACH path — use a longer timeout to survive cold boots
|
|
||||||
# (unit takes 5-15s to wake from RS-232 line assertion over cellular)
|
|
||||||
transport = TcpTransport(host, port=tcp_port)
|
transport = TcpTransport(host, port=tcp_port)
|
||||||
log.debug("TCP transport: %s:%d", host, tcp_port)
|
log.debug("TCP transport: %s:%d timeout=%.0fs", host, tcp_port, timeout)
|
||||||
return MiniMateClient(transport=transport, timeout=30.0)
|
return MiniMateClient(transport=transport, timeout=timeout)
|
||||||
elif port:
|
elif port:
|
||||||
# Direct serial path
|
|
||||||
log.debug("Serial transport: %s baud=%d", port, baud)
|
log.debug("Serial transport: %s baud=%d", port, baud)
|
||||||
return MiniMateClient(port, baud)
|
return MiniMateClient(port, baud)
|
||||||
else:
|
else:
|
||||||
@@ -425,7 +427,7 @@ def device_event_waveform(
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
def _do():
|
def _do():
|
||||||
with _build_client(port, baud, host, tcp_port) as client:
|
with _build_client(port, baud, host, tcp_port, timeout=120.0) as client:
|
||||||
info = client.connect()
|
info = client.connect()
|
||||||
# full_waveform=True fetches the complete 5A stream inside the
|
# full_waveform=True fetches the complete 5A stream inside the
|
||||||
# 1E→0A→0C→5A→1F loop. Issuing a second 5A after 1F times out.
|
# 1E→0A→0C→5A→1F loop. Issuing a second 5A after 1F times out.
|
||||||
@@ -458,12 +460,14 @@ def device_event_waveform(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
"index": ev.index,
|
"index": ev.index,
|
||||||
|
"record_type": ev.record_type,
|
||||||
"timestamp": _serialise_timestamp(ev.timestamp),
|
"timestamp": _serialise_timestamp(ev.timestamp),
|
||||||
"total_samples": ev.total_samples,
|
"total_samples": ev.total_samples,
|
||||||
"pretrig_samples": ev.pretrig_samples,
|
"pretrig_samples": ev.pretrig_samples,
|
||||||
"rectime_seconds": ev.rectime_seconds,
|
"rectime_seconds": ev.rectime_seconds,
|
||||||
"samples_decoded": samples_decoded,
|
"samples_decoded": samples_decoded,
|
||||||
"sample_rate": sample_rate,
|
"sample_rate": sample_rate,
|
||||||
|
"peak_values": _serialise_peak_values(ev.peak_values),
|
||||||
"channels": raw,
|
"channels": raw,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -374,13 +374,7 @@
|
|||||||
const decoded = data.samples_decoded || 0;
|
const decoded = data.samples_decoded || 0;
|
||||||
const total = data.total_samples || decoded;
|
const total = data.total_samples || decoded;
|
||||||
const channels = data.channels || {};
|
const channels = data.channels || {};
|
||||||
|
const recType = data.record_type || 'Unknown';
|
||||||
// Build time axis (ms)
|
|
||||||
const times = Array.from({ length: decoded }, (_, i) =>
|
|
||||||
((i - pretrig) / sr * 1000).toFixed(2)
|
|
||||||
);
|
|
||||||
|
|
||||||
const triggerMs = 0; // t=0 is trigger by construction
|
|
||||||
|
|
||||||
// Status bar
|
// Status bar
|
||||||
const bar = document.getElementById('status-bar');
|
const bar = document.getElementById('status-bar');
|
||||||
@@ -392,11 +386,30 @@
|
|||||||
} else {
|
} else {
|
||||||
bar.textContent = `Event #${data.index} `;
|
bar.textContent = `Event #${data.index} `;
|
||||||
}
|
}
|
||||||
|
appendMeta('type', recType);
|
||||||
appendMeta('sr', `${sr} sps`);
|
appendMeta('sr', `${sr} sps`);
|
||||||
appendMeta('samples', `${decoded.toLocaleString()} / ${total.toLocaleString()}`);
|
appendMeta('samples', `${decoded.toLocaleString()} / ${total.toLocaleString()}`);
|
||||||
appendMeta('pretrig', pretrig);
|
appendMeta('pretrig', pretrig);
|
||||||
appendMeta('rectime', `${data.rectime_seconds ?? '?'}s`);
|
appendMeta('rectime', `${data.rectime_seconds ?? '?'}s`);
|
||||||
|
|
||||||
|
// No waveform data — show a clear reason instead of empty charts
|
||||||
|
if (decoded === 0) {
|
||||||
|
document.getElementById('empty-state').style.display = 'flex';
|
||||||
|
document.getElementById('empty-state').querySelector('p').textContent =
|
||||||
|
recType === 'Waveform'
|
||||||
|
? 'Waveform decode returned no samples — check server logs'
|
||||||
|
: `Record type "${recType}" — waveform decode not yet supported for this mode`;
|
||||||
|
document.getElementById('charts').style.display = 'none';
|
||||||
|
Object.values(charts).forEach(c => c.destroy());
|
||||||
|
charts = {};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build time axis (ms)
|
||||||
|
const times = Array.from({ length: decoded }, (_, i) =>
|
||||||
|
((i - pretrig) / sr * 1000).toFixed(2)
|
||||||
|
);
|
||||||
|
|
||||||
// Show charts area
|
// Show charts area
|
||||||
document.getElementById('empty-state').style.display = 'none';
|
document.getElementById('empty-state').style.display = 'none';
|
||||||
const chartsDiv = document.getElementById('charts');
|
const chartsDiv = document.getElementById('charts');
|
||||||
|
|||||||
Reference in New Issue
Block a user