diff --git a/main.cpp b/main.cpp index f68d42b..f1ab8d5 100644 --- a/main.cpp +++ b/main.cpp @@ -406,15 +406,18 @@ void print_help(const char* exe_name) { << " di1:ignore -> ignore DI1 for both zeroing and plotting\n" << " 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" - << " svg_history_packets:50 -> keep last 50 packets in RAM for final SVG (0 keeps all, risky)\n" + << " live_update_period_ms:1000 -> refresh live HTML/JSON no more than once per second" + << " (ignored in tty+di1_group_avg fast mode)\n" + << " svg_history_packets:50 -> keep last 50 packets in RAM for final SVG (0 keeps all, risky)" + << " (ignored in tty+di1_group_avg fast mode)\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" << " buffer_words:8388608 -> input stream buffer size in 32-bit words\n" << " step_words:32768 -> input stream transfer step in 32-bit words\n" - << " live_html/live_json -> live graph files updated as packets arrive\n" + << " live_html/live_json -> live graph files updated as packets arrive outside tty+di1_group_avg fast mode\n" << " tty:/tmp/ttyADC_data -> write a continuous legacy 4-word CH1/CH2 stream to a Linux/POSIX tty or PTY link path\n" << " di1_group_avg -> with tty + di1:trace, emit one averaged CH1/CH2 step per constant DI1 run\n" + << " tty+di1_group_avg -> fast stream-only mode: skip CSV/SVG/live outputs and send only averaged tty data\n" << " If sample_clock_hz is omitted together with clock:internal, the maximum ADC speed is used\n" << "\n" << "Differential physical channel mapping:\n" @@ -432,7 +435,7 @@ void print_help(const char* exe_name) { << "This build enables synchronous DIN together with ADC. DI_SYN2 stop edges are detected\n" << "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" + << "Outside tty+di1_group_avg fast mode, 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" << "For tty output, use di1_group_avg together with di1:trace to emit one averaged 4-word step\n" << "per constant DI1 run while keeping the current ring-buffered binary frame format.\n" @@ -1319,6 +1322,7 @@ int run(const Config& cfg) { std::size_t tty_ring_capacity_bytes = 0; std::unique_ptr tty_writer; const bool tty_di1_group_average = cfg.tty_path.has_value() && cfg.di1_group_average; + const bool fast_tty_avg_stream_mode = tty_di1_group_average; if (cfg.tty_path) { const uint64_t typical_tty_batch_frames = (static_cast(read_capacity_words) + 1U) / 2U; const uint64_t typical_tty_batch_bytes = typical_tty_batch_frames * sizeof(uint16_t) * 4U; @@ -1333,25 +1337,39 @@ int run(const Config& cfg) { tty_writer->emit_packet_start(); } } - CaptureFileWriter writer(cfg.csv_path, cfg.svg_path, cfg.live_html_path, cfg.live_json_path); - 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" - << " live plot data: " << writer.live_json_path() << "\n" - << " tty stream output: " << (cfg.tty_path ? *cfg.tty_path : std::string("disabled")) << "\n" - << " tty ring buffer bytes: " - << (cfg.tty_path ? std::to_string(tty_ring_capacity_bytes) : std::string("disabled")) << "\n" - << " recv block words: " << cfg.recv_block_words << "\n" - << " input step words: " << cfg.input_step_words << "\n" - << " input buffer words: " << cfg.input_buffer_words << "\n" - << " tty di1_group_avg: " - << (tty_di1_group_average ? std::string("enabled") - : (cfg.di1_group_average ? std::string("requested, tty disabled") - : std::string("disabled"))) - << "\n" - << " SVG history packets kept in RAM: " - << ((cfg.svg_history_packets == 0U) ? std::string("all (unbounded)") : std::to_string(cfg.svg_history_packets)) - << "\n"; + std::unique_ptr writer; + if (!fast_tty_avg_stream_mode) { + writer = std::make_unique(cfg.csv_path, cfg.svg_path, cfg.live_html_path, cfg.live_json_path); + writer->initialize_live_plot(); + writer->initialize_csv(cfg.channel_count, cfg.di1_mode == Di1Mode::Trace); + } + if (fast_tty_avg_stream_mode) { + std::cout << " tty avg stream-only mode: enabled\n" + << " tty stream output: " << *cfg.tty_path << "\n" + << " tty ring buffer bytes: " << tty_ring_capacity_bytes << "\n" + << " recv block words: " << cfg.recv_block_words << "\n" + << " input step words: " << cfg.input_step_words << "\n" + << " input buffer words: " << cfg.input_buffer_words << "\n" + << " tty di1_group_avg: enabled\n" + << " stream-only note: ignoring csv/svg/live_html/live_json/live_update_period_ms/svg_history_packets\n"; + } else { + std::cout << " live plot html: " << writer->live_html_path() << "\n" + << " live plot data: " << writer->live_json_path() << "\n" + << " tty stream output: " << (cfg.tty_path ? *cfg.tty_path : std::string("disabled")) << "\n" + << " tty ring buffer bytes: " + << (cfg.tty_path ? std::to_string(tty_ring_capacity_bytes) : std::string("disabled")) << "\n" + << " recv block words: " << cfg.recv_block_words << "\n" + << " input step words: " << cfg.input_step_words << "\n" + << " input buffer words: " << cfg.input_buffer_words << "\n" + << " tty di1_group_avg: " + << (tty_di1_group_average ? std::string("enabled") + : (cfg.di1_group_average ? std::string("requested, tty disabled") + : std::string("disabled"))) + << "\n" + << " SVG history packets kept in RAM: " + << ((cfg.svg_history_packets == 0U) ? std::string("all (unbounded)") : std::to_string(cfg.svg_history_packets)) + << "\n"; + } ConsoleCtrlGuard console_guard; if (!console_guard.installed) { @@ -1362,7 +1380,7 @@ int run(const Config& cfg) { device.streams_started = true; std::vector raw(read_capacity_words); - std::vector adc_buffer(read_capacity_words); + std::vector adc_buffer(fast_tty_avg_stream_mode ? 0U : read_capacity_words); std::vector adc_raw_buffer(read_capacity_words); std::vector din_buffer(read_capacity_words); std::deque pending_adc; @@ -1374,8 +1392,12 @@ int run(const Config& cfg) { TtyGroupAverageState tty_group_state; std::vector tty_frame_words; tty_frame_words.reserve(static_cast(read_capacity_words) * 2U + 16U); - current_packet.reset(target_frames, cfg.channel_count); + if (!fast_tty_avg_stream_mode) { + current_packet.reset(target_frames, cfg.channel_count); + } std::size_t csv_global_frame_index = 0; + std::size_t packet_avg_steps = 0; + std::size_t fast_packet_frames = 0; bool capture_started = false; bool stop_loop_requested = false; @@ -1486,6 +1508,7 @@ int run(const Config& cfg) { static_cast(pack_raw_code_to_int16(ch1_avg)), static_cast(pack_raw_code_to_int16(ch2_avg))); ++tty_group_state.next_index; + ++packet_avg_steps; }; auto flush_tty_frames = [&]() { @@ -1507,7 +1530,11 @@ int run(const Config& cfg) { if (packet_active) { return; } - current_packet.reset(target_frames, cfg.channel_count); + packet_avg_steps = 0; + fast_packet_frames = 0; + if (!fast_tty_avg_stream_mode) { + current_packet.reset(target_frames, cfg.channel_count); + } if (tty_di1_group_average) { tty_group_state.reset_packet(); append_tty_packet_start(); @@ -1521,77 +1548,97 @@ int run(const Config& cfg) { tty_group_state.clear_step(); } - const std::size_t frames = current_packet.frame_count(cfg.channel_count); + const std::size_t frames = fast_tty_avg_stream_mode + ? fast_packet_frames + : current_packet.frame_count(cfg.channel_count); if (frames != 0U) { - current_packet.channels[0].resize(frames); - if (cfg.channel_count >= 2U) { - current_packet.channels[1].resize(frames); - } else { - current_packet.channels[1].clear(); - } - if (cfg.di1_mode == Di1Mode::Trace) { - current_packet.di1.resize(frames); - } else { - current_packet.di1.clear(); - } - - CapturePacket packet; - packet.packet_index = static_cast(total_completed_packets + 1U); - packet.channel_count = cfg.channel_count; - packet.has_di1_trace = (cfg.di1_mode == Di1Mode::Trace); - packet.ch1 = std::move(current_packet.channels[0]); - packet.ch2 = std::move(current_packet.channels[1]); - packet.di1 = std::move(current_packet.di1); - const double packet_duration_ms = (1000.0 * static_cast(frames)) / actual_frame_freq_hz; - const double zeroed_fraction = (current_packet.stored_samples == 0U) - ? 0.0 - : (100.0 * static_cast(current_packet.zeroed_samples) / - static_cast(current_packet.stored_samples)); + if (fast_tty_avg_stream_mode) { + const std::size_t packet_index = static_cast(total_completed_packets + 1U); + std::cout << std::fixed << std::setprecision(3) + << "Packet " << packet_index + << ": frames/ch=" << frames + << ", duration_ms=" << packet_duration_ms + << ", close_reason=" << packet_close_reason_to_string(reason) + << ", avg_steps=" << packet_avg_steps + << "\n"; + } else { + current_packet.channels[0].resize(frames); + if (cfg.channel_count >= 2U) { + current_packet.channels[1].resize(frames); + } else { + current_packet.channels[1].clear(); + } + if (cfg.di1_mode == Di1Mode::Trace) { + current_packet.di1.resize(frames); + } else { + current_packet.di1.clear(); + } - std::cout << std::fixed << std::setprecision(3) - << "Packet " << packet.packet_index - << ": frames/ch=" << frames - << ", duration_ms=" << packet_duration_ms - << ", close_reason=" << packet_close_reason_to_string(reason); - if (cfg.di1_mode == Di1Mode::ZeroOnChange) { - std::cout << ", zeroed_on_DI1_change=" << zeroed_fraction << "% (" - << current_packet.zeroed_samples << "/" << current_packet.stored_samples << ")"; - } else if (cfg.di1_mode == Di1Mode::Trace) { - std::cout << ", di1_trace_frames=" << packet.di1.size(); + CapturePacket packet; + packet.packet_index = static_cast(total_completed_packets + 1U); + packet.channel_count = cfg.channel_count; + packet.has_di1_trace = (cfg.di1_mode == Di1Mode::Trace); + packet.ch1 = std::move(current_packet.channels[0]); + packet.ch2 = std::move(current_packet.channels[1]); + packet.di1 = std::move(current_packet.di1); + + const double zeroed_fraction = (current_packet.stored_samples == 0U) + ? 0.0 + : (100.0 * static_cast(current_packet.zeroed_samples) / + static_cast(current_packet.stored_samples)); + + std::cout << std::fixed << std::setprecision(3) + << "Packet " << packet.packet_index + << ": frames/ch=" << frames + << ", duration_ms=" << packet_duration_ms + << ", close_reason=" << packet_close_reason_to_string(reason); + if (cfg.di1_mode == Di1Mode::ZeroOnChange) { + std::cout << ", zeroed_on_DI1_change=" << zeroed_fraction << "% (" + << current_packet.zeroed_samples << "/" << current_packet.stored_samples << ")"; + } else if (cfg.di1_mode == Di1Mode::Trace) { + std::cout << ", di1_trace_frames=" << packet.di1.size(); + } + std::cout << "\n"; + + writer->append_csv_packet(packet, actual_frame_freq_hz, csv_global_frame_index); + packets.push_back(std::move(packet)); + if ((cfg.svg_history_packets != 0U) && (packets.size() > cfg.svg_history_packets)) { + packets.pop_front(); + } + + const double elapsed_capture_s = + std::max(1e-9, static_cast(tick_count_ms() - capture_loop_start) / 1000.0); + const double packets_per_second = + (elapsed_capture_s >= 0.1) + ? (static_cast(total_completed_packets + 1U) / elapsed_capture_s) + : 0.0; + const TickMs now = tick_count_ms(); + const bool should_update_live = + (cfg.live_update_period_ms == 0U) || + (last_live_update == 0U) || + ((now - last_live_update) >= cfg.live_update_period_ms); + if (should_update_live) { + writer->update_live_plot(packets.back(), + static_cast(total_completed_packets + 1U), + packets_per_second, + actual_frame_freq_hz, + packet_close_reason_to_string(reason), + current_packet.zeroed_samples, + current_packet.stored_samples); + last_live_update = now; + } } - std::cout << "\n"; - writer.append_csv_packet(packet, actual_frame_freq_hz, csv_global_frame_index); ++total_completed_packets; ++stats_completed_packets; - packets.push_back(std::move(packet)); - if ((cfg.svg_history_packets != 0U) && (packets.size() > cfg.svg_history_packets)) { - packets.pop_front(); - } - const double elapsed_capture_s = std::max(1e-9, static_cast(tick_count_ms() - capture_loop_start) / 1000.0); const double packets_per_second = (elapsed_capture_s >= 0.1) ? (static_cast(total_completed_packets) / elapsed_capture_s) : 0.0; - const TickMs now = tick_count_ms(); - const bool should_update_live = - (cfg.live_update_period_ms == 0U) || - (last_live_update == 0U) || - ((now - last_live_update) >= cfg.live_update_period_ms); - if (should_update_live) { - writer.update_live_plot(packets.back(), - static_cast(total_completed_packets), - packets_per_second, - actual_frame_freq_hz, - packet_close_reason_to_string(reason), - current_packet.zeroed_samples, - current_packet.stored_samples); - last_live_update = now; - } std::cout << std::fixed << std::setprecision(3) << " packets/s(avg)=" << packets_per_second; if (elapsed_capture_s < 0.1) { @@ -1601,7 +1648,11 @@ int run(const Config& cfg) { } packet_active = false; - current_packet.reset(target_frames, cfg.channel_count); + packet_avg_steps = 0; + fast_packet_frames = 0; + if (!fast_tty_avg_stream_mode) { + current_packet.reset(target_frames, cfg.channel_count); + } if (tty_di1_group_average) { tty_group_state.clear_step(); } @@ -1666,13 +1717,16 @@ int run(const Config& cfg) { continue; } - uint32_t adc_count = static_cast(adc_buffer.size()); + uint32_t adc_count = fast_tty_avg_stream_mode ? static_cast(adc_raw_buffer.size()) + : static_cast(adc_buffer.size()); uint32_t din_count = static_cast(din_buffer.size()); + const uint32_t process_flags = + fast_tty_avg_stream_mode ? 0U : static_cast(X502_PROC_FLAGS_VOLT); const int32_t process_err = api.ProcessData(device.hnd, raw.data(), static_cast(recvd), - X502_PROC_FLAGS_VOLT, - adc_buffer.data(), + process_flags, + fast_tty_avg_stream_mode ? adc_raw_buffer.data() : adc_buffer.data(), &adc_count, din_buffer.data(), &din_count); @@ -1688,8 +1742,8 @@ int run(const Config& cfg) { } expect_ok(api, process_err, "Process ADC+DIN data"); - uint32_t raw_adc_count = 0; - if (tty_writer) { + uint32_t raw_adc_count = fast_tty_avg_stream_mode ? adc_count : 0U; + if (tty_writer && !fast_tty_avg_stream_mode) { for (std::size_t i = 0; i < static_cast(recvd); ++i) { double raw_code = 0.0; if (!try_extract_raw_adc_code(raw[i], raw_code)) { @@ -1740,32 +1794,34 @@ int run(const Config& cfg) { total_din_samples += din_count; stats_adc_samples += adc_count; stats_din_samples += din_count; - for (uint32_t i = 0; i < adc_count; ++i) { - pending_adc.push_back(adc_buffer[i]); - } - if (tty_di1_group_average) { + if (fast_tty_avg_stream_mode) { for (uint32_t i = 0; i < raw_adc_count; ++i) { pending_adc_raw.push_back(adc_raw_buffer[i]); } + } else { + for (uint32_t i = 0; i < adc_count; ++i) { + pending_adc.push_back(adc_buffer[i]); + } } for (uint32_t i = 0; i < din_count; ++i) { pending_din.push_back(din_buffer[i]); } - if ((pending_adc.size() > 1000000U) || + if (((!fast_tty_avg_stream_mode) && (pending_adc.size() > 1000000U)) || (pending_din.size() > 1000000U) || - (tty_di1_group_average && (pending_adc_raw.size() > 1000000U))) { + (fast_tty_avg_stream_mode && (pending_adc_raw.size() > 1000000U))) { fail("Internal backlog grew too large while aligning ADC and DIN samples"); } - while (!pending_adc.empty() && + while ((fast_tty_avg_stream_mode ? !pending_adc_raw.empty() : !pending_adc.empty()) && !pending_din.empty() && - (!tty_di1_group_average || !pending_adc_raw.empty()) && !stop_loop_requested) { - const double adc_value = pending_adc.front(); - pending_adc.pop_front(); - const double adc_raw_value = tty_di1_group_average ? pending_adc_raw.front() : 0.0; - if (tty_di1_group_average) { + const double adc_value = fast_tty_avg_stream_mode ? 0.0 : pending_adc.front(); + if (!fast_tty_avg_stream_mode) { + pending_adc.pop_front(); + } + const double adc_raw_value = fast_tty_avg_stream_mode ? pending_adc_raw.front() : 0.0; + if (fast_tty_avg_stream_mode) { pending_adc_raw.pop_front(); } @@ -1840,40 +1896,53 @@ int run(const Config& cfg) { const uint32_t lch = next_lch; next_lch = (next_lch + 1U) % cfg.channel_count; - if ((cfg.di1_mode == Di1Mode::Trace) && ((cfg.channel_count <= 1U) || (lch == 0U))) { + if (!fast_tty_avg_stream_mode && + (cfg.di1_mode == Di1Mode::Trace) && + ((cfg.channel_count <= 1U) || (lch == 0U))) { current_packet.pending_frame_di1 = static_cast(di1_level ? 1U : 0U); current_packet.pending_frame_di1_valid = true; } - double stored_value = adc_value; - if ((cfg.di1_mode == Di1Mode::ZeroOnChange) && di1_changed) { - stored_value = 0.0; - ++total_zeroed_samples; - ++stats_zeroed_samples; - ++current_packet.zeroed_samples; - } - - if (current_packet.channels[lch].size() < target_frames) { - current_packet.channels[lch].push_back(stored_value); - if (tty_di1_group_average) { + if (fast_tty_avg_stream_mode) { + if (fast_packet_frames < target_frames) { tty_group_state.add_sample(lch, adc_raw_value); - } - ++current_packet.stored_samples; - ++total_stored_adc_samples; - ++stats_stored_adc_samples; - if (lch == (cfg.channel_count - 1U)) { - if ((cfg.di1_mode == Di1Mode::Trace) && - current_packet.pending_frame_di1_valid && - (current_packet.di1.size() < target_frames)) { - current_packet.di1.push_back(current_packet.pending_frame_di1); - current_packet.pending_frame_di1_valid = false; + if (lch == (cfg.channel_count - 1U)) { + ++fast_packet_frames; + ++total_completed_frames; + ++stats_completed_frames; + } + } + } else { + double stored_value = adc_value; + if ((cfg.di1_mode == Di1Mode::ZeroOnChange) && di1_changed) { + stored_value = 0.0; + ++total_zeroed_samples; + ++stats_zeroed_samples; + ++current_packet.zeroed_samples; + } + + if (current_packet.channels[lch].size() < target_frames) { + current_packet.channels[lch].push_back(stored_value); + ++current_packet.stored_samples; + ++total_stored_adc_samples; + ++stats_stored_adc_samples; + if (lch == (cfg.channel_count - 1U)) { + if ((cfg.di1_mode == Di1Mode::Trace) && + current_packet.pending_frame_di1_valid && + (current_packet.di1.size() < target_frames)) { + current_packet.di1.push_back(current_packet.pending_frame_di1); + current_packet.pending_frame_di1_valid = false; + } + ++total_completed_frames; + ++stats_completed_frames; } - ++total_completed_frames; - ++stats_completed_frames; } } - if (current_packet.frame_count(cfg.channel_count) >= target_frames) { + const std::size_t completed_frames = fast_tty_avg_stream_mode + ? fast_packet_frames + : current_packet.frame_count(cfg.channel_count); + if (completed_frames >= target_frames) { finish_packet(PacketCloseReason::DurationLimit); if ((cfg.packet_limit != 0U) && (total_completed_packets >= cfg.packet_limit)) { stop_loop_requested = true; @@ -1912,22 +1981,27 @@ int run(const Config& cfg) { tty_final_stats = tty_writer->stats(); } - const std::vector svg_packets(packets.begin(), packets.end()); - writer.write(svg_packets, actual_frame_freq_hz, range_to_volts(cfg.range)); + if (!fast_tty_avg_stream_mode) { + const std::vector svg_packets(packets.begin(), packets.end()); + writer->write(svg_packets, actual_frame_freq_hz, range_to_volts(cfg.range)); - std::size_t total_packet_frames = 0; - for (const auto& packet : svg_packets) { - total_packet_frames += (packet.channel_count <= 1U) - ? packet.ch1.size() - : std::min(packet.ch1.size(), packet.ch2.size()); - } + std::size_t total_packet_frames = 0; + for (const auto& packet : svg_packets) { + total_packet_frames += (packet.channel_count <= 1U) + ? packet.ch1.size() + : std::min(packet.ch1.size(), packet.ch2.size()); + } - std::cout << "Captured " << total_completed_packets << " packet(s), " - << total_packet_frames << " total frames per channel kept for final SVG\n"; - if (cfg.di1_mode == Di1Mode::ZeroOnChange) { - std::cout << "ADC samples forced to 0 on DI1 change: " << total_zeroed_samples << "\n"; - } else if (cfg.di1_mode == Di1Mode::Trace) { - std::cout << "DI1 synchronous trace exported to CSV/live plot/SVG\n"; + std::cout << "Captured " << total_completed_packets << " packet(s), " + << total_packet_frames << " total frames per channel kept for final SVG\n"; + if (cfg.di1_mode == Di1Mode::ZeroOnChange) { + std::cout << "ADC samples forced to 0 on DI1 change: " << total_zeroed_samples << "\n"; + } else if (cfg.di1_mode == Di1Mode::Trace) { + std::cout << "DI1 synchronous trace exported to CSV/live plot/SVG\n"; + } + } else { + std::cout << "Captured " << total_completed_packets + << " packet(s) in tty avg stream-only mode\n"; } std::cout << "Average stats: " << "MB/s=" << std::fixed << std::setprecision(3) @@ -1961,10 +2035,15 @@ int run(const Config& cfg) { << ", tty_frames_dropped=" << tty_final_stats.frames_dropped << ", tty_ring_overflows=" << tty_final_stats.ring_overflows; } - std::cout << "\n" - << "Final SVG packets retained in memory: " << svg_packets.size() << "\n" - << "CSV: " << cfg.csv_path << "\n" - << "SVG: " << cfg.svg_path << "\n"; + if (fast_tty_avg_stream_mode) { + std::cout << ", tty avg stream-only mode=enabled"; + } + std::cout << "\n"; + if (!fast_tty_avg_stream_mode) { + std::cout << "Final SVG packets retained in memory: " << packets.size() << "\n" + << "CSV: " << cfg.csv_path << "\n" + << "SVG: " << cfg.svg_path << "\n"; + } return 0; } diff --git a/run_di1_group_avg.sh b/run_di1_group_avg.sh index e900b5e..e965e3d 100755 --- a/run_di1_group_avg.sh +++ b/run_di1_group_avg.sh @@ -6,8 +6,6 @@ cd "$SCRIPT_DIR" BIN="${BIN:-./main.exe}" TTY_PATH="${TTY_PATH:-/tmp/ttyADC_data}" -CSV_PATH="${CSV_PATH:-capture.csv}" -SVG_PATH="${SVG_PATH:-capture.svg}" LIB_DIR="${LIB_DIR:-$HOME/.local/lib}" if [[ ! -x "$BIN" ]]; then @@ -31,6 +29,4 @@ exec "$BIN" \ duration_ms:100 \ packet_limit:0 \ "tty:${TTY_PATH}" \ - "csv:${CSV_PATH}" \ - "svg:${SVG_PATH}" \ "$@"