clock:internal internal_ref_hz:2000000 start:di_syn2_rise stop:di_syn2_fall sample_clock_hz:max range:0.2 di1:trace di1_group_avg full_res_live live_history_packets:8 duration_ms:100 packet_limit:0 csv:capture.csv svg:capture.svgC

This commit is contained in:
kamil
2026-04-09 16:58:47 +03:00
parent f916aa25c3
commit 5fa0b9ac39
16 changed files with 623 additions and 171 deletions

View File

@ -75,7 +75,10 @@ struct Config {
uint32_t input_buffer_words = 8 * 1024 * 1024;
uint32_t input_step_words = 32768;
uint32_t live_update_period_ms = 1000;
uint32_t live_history_packets = 8;
uint32_t svg_history_packets = 50;
bool full_res_live = false;
bool di1_group_average = false;
bool recv_block_specified = false;
bool input_buffer_specified = false;
@ -371,8 +374,8 @@ void print_help(const char* exe_name) {
<< " [internal_ref_hz:2000000]\n"
<< " [di1:zero|trace|ignore]\n"
<< " [duration_ms:100] [packet_limit:0] [csv:capture.csv] [svg:capture.svg]\n"
<< " [live_html:live_plot.html] [live_json:live_plot.json]\n"
<< " [recv_block:32768] [stats_period_ms:1000] [live_update_period_ms:1000] [svg_history_packets:50] [start_wait_ms:10000]\n"
<< " [live_html:live_plot.html] [live_json:live_plot.json] [full_res_live] [di1_group_avg]\n"
<< " [recv_block:32768] [stats_period_ms:1000] [live_update_period_ms:1000] [live_history_packets:8] [svg_history_packets:50] [start_wait_ms:10000]\n"
<< " [buffer_words:8388608] [step_words:32768]\n"
<< " [pullup_syn1] [pullup_syn2] [pulldown_conv_in] [pulldown_start_in]\n"
<< "\n"
@ -396,6 +399,9 @@ void print_help(const char* exe_name) {
<< " stats_period_ms:1000 -> print online transfer/capture statistics every 1000 ms (0 disables)\n"
<< " recv_block:32768 -> request up to 32768 raw 32-bit words per X502_Recv() call\n"
<< " live_update_period_ms:1000 -> refresh live HTML/JSON no more than once per second\n"
<< " live_history_packets:8 -> live graph shows the last 8 packets as one continuous time window (0 = all kept in RAM)\n"
<< " full_res_live -> add denser live traces and increase graph resolution when zooming\n"
<< " di1_group_avg -> for di1:trace, average ADC points inside each constant-DI1 run before plotting\n"
<< " svg_history_packets:50 -> keep last 50 packets in RAM for final SVG (0 keeps all, risky)\n"
<< " duration_ms:100 -> max packet length if stop edge does not arrive\n"
<< " packet_limit:0 -> 0 means continuous until Ctrl+C, N means stop after N packets\n"
@ -420,7 +426,10 @@ void print_help(const char* exe_name) {
<< "inside the same input stream, packets are split continuously by DI_SYN2 edges, and DI1\n"
<< "can either zero ADC samples on change, be exported as a separate synchronous trace, or be ignored.\n"
<< "Open live_plot.html in a browser to see the live graph update over time.\n"
<< "The live HTML supports X/Y zoom buttons, mouse-wheel zoom, and reset.\n"
<< "The live HTML supports X/Y zoom, Left/Right pan, mouse-wheel zoom, and reset.\n"
<< "CSV keeps all ADC points; the live graph and SVG use min/max compression for speed.\n"
<< "Use full_res_live to write denser live traces and sharpen the graph when zooming.\n"
<< "Use di1_group_avg together with di1:trace to plot one averaged point per constant-DI1 subgroup.\n"
<< "\n"
<< "Recommended working example:\n"
<< " " << exe_name
@ -502,6 +511,14 @@ Config parse_args(int argc, char** argv) {
cfg.di1_mode = parse_di1_mode(arg.substr(4));
continue;
}
if (arg == "full_res_live") {
cfg.full_res_live = true;
continue;
}
if ((arg == "di1_group_avg") || (arg == "di1_avg")) {
cfg.di1_group_average = true;
continue;
}
if (starts_with(arg, "sample_clock_hz:")) {
const std::string value = trim_copy(arg.substr(16));
cfg.sample_clock_specified = true;
@ -543,6 +560,10 @@ Config parse_args(int argc, char** argv) {
cfg.live_update_specified = true;
continue;
}
if (starts_with(arg, "live_history_packets:")) {
cfg.live_history_packets = parse_u32(arg.substr(21), "live_history_packets");
continue;
}
if (starts_with(arg, "svg_history_packets:")) {
cfg.svg_history_packets = parse_u32(arg.substr(20), "svg_history_packets");
continue;
@ -1039,7 +1060,13 @@ int run(const Config& cfg) {
<< " ADC range: +/-" << range_to_volts(cfg.range) << " V\n"
<< " max frames per packet per channel: " << target_frames << "\n";
CaptureFileWriter writer(cfg.csv_path, cfg.svg_path, cfg.live_html_path, cfg.live_json_path);
CaptureFileWriter writer(cfg.csv_path,
cfg.svg_path,
cfg.live_html_path,
cfg.live_json_path,
cfg.full_res_live,
cfg.live_history_packets,
cfg.di1_group_average);
writer.initialize_live_plot();
writer.initialize_csv(cfg.channel_count, cfg.di1_mode == Di1Mode::Trace);
std::cout << " live plot html: " << writer.live_html_path() << "\n"
@ -1047,9 +1074,14 @@ int run(const Config& cfg) {
<< " recv block words: " << cfg.recv_block_words << "\n"
<< " input step words: " << cfg.input_step_words << "\n"
<< " input buffer words: " << cfg.input_buffer_words << "\n"
<< " live history packets: "
<< ((cfg.live_history_packets == 0U) ? std::string("all kept in RAM") : std::to_string(cfg.live_history_packets))
<< "\n"
<< " SVG history packets kept in RAM: "
<< ((cfg.svg_history_packets == 0U) ? std::string("all (unbounded)") : std::to_string(cfg.svg_history_packets))
<< "\n";
<< "\n"
<< " full_res_live: " << (cfg.full_res_live ? "enabled" : "disabled") << "\n"
<< " di1_group_avg: " << (cfg.di1_group_average ? "enabled" : "disabled") << "\n";
ConsoleCtrlGuard console_guard;
if (!console_guard.installed) {
@ -1211,7 +1243,7 @@ int run(const Config& cfg) {
(last_live_update == 0U) ||
((now - last_live_update) >= cfg.live_update_period_ms);
if (should_update_live) {
writer.update_live_plot(packets.back(),
writer.update_live_plot(packets,
static_cast<std::size_t>(total_completed_packets),
packets_per_second,
actual_frame_freq_hz,