x buffer overflow
This commit is contained in:
367
main.cpp
367
main.cpp
@ -406,15 +406,18 @@ void print_help(const char* exe_name) {
|
|||||||
<< " di1:ignore -> ignore DI1 for both zeroing and plotting\n"
|
<< " 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"
|
<< " 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"
|
<< " 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_update_period_ms:1000 -> refresh live HTML/JSON no more than once per second"
|
||||||
<< " svg_history_packets:50 -> keep last 50 packets in RAM for final SVG (0 keeps all, risky)\n"
|
<< " (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"
|
<< " 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"
|
<< " 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"
|
<< " buffer_words:8388608 -> input stream buffer size in 32-bit words\n"
|
||||||
<< " step_words:32768 -> input stream transfer step 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"
|
<< " 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"
|
<< " 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"
|
<< " If sample_clock_hz is omitted together with clock:internal, the maximum ADC speed is used\n"
|
||||||
<< "\n"
|
<< "\n"
|
||||||
<< "Differential physical channel mapping:\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"
|
<< "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"
|
<< "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"
|
<< "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"
|
<< "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"
|
<< "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"
|
<< "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::size_t tty_ring_capacity_bytes = 0;
|
||||||
std::unique_ptr<TtyProtocolWriter> tty_writer;
|
std::unique_ptr<TtyProtocolWriter> tty_writer;
|
||||||
const bool tty_di1_group_average = cfg.tty_path.has_value() && cfg.di1_group_average;
|
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) {
|
if (cfg.tty_path) {
|
||||||
const uint64_t typical_tty_batch_frames = (static_cast<uint64_t>(read_capacity_words) + 1U) / 2U;
|
const uint64_t typical_tty_batch_frames = (static_cast<uint64_t>(read_capacity_words) + 1U) / 2U;
|
||||||
const uint64_t typical_tty_batch_bytes = typical_tty_batch_frames * sizeof(uint16_t) * 4U;
|
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();
|
tty_writer->emit_packet_start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CaptureFileWriter writer(cfg.csv_path, cfg.svg_path, cfg.live_html_path, cfg.live_json_path);
|
std::unique_ptr<CaptureFileWriter> writer;
|
||||||
writer.initialize_live_plot();
|
if (!fast_tty_avg_stream_mode) {
|
||||||
writer.initialize_csv(cfg.channel_count, cfg.di1_mode == Di1Mode::Trace);
|
writer = std::make_unique<CaptureFileWriter>(cfg.csv_path, cfg.svg_path, cfg.live_html_path, cfg.live_json_path);
|
||||||
std::cout << " live plot html: " << writer.live_html_path() << "\n"
|
writer->initialize_live_plot();
|
||||||
<< " live plot data: " << writer.live_json_path() << "\n"
|
writer->initialize_csv(cfg.channel_count, cfg.di1_mode == Di1Mode::Trace);
|
||||||
<< " tty stream output: " << (cfg.tty_path ? *cfg.tty_path : std::string("disabled")) << "\n"
|
}
|
||||||
<< " tty ring buffer bytes: "
|
if (fast_tty_avg_stream_mode) {
|
||||||
<< (cfg.tty_path ? std::to_string(tty_ring_capacity_bytes) : std::string("disabled")) << "\n"
|
std::cout << " tty avg stream-only mode: enabled\n"
|
||||||
<< " recv block words: " << cfg.recv_block_words << "\n"
|
<< " tty stream output: " << *cfg.tty_path << "\n"
|
||||||
<< " input step words: " << cfg.input_step_words << "\n"
|
<< " tty ring buffer bytes: " << tty_ring_capacity_bytes << "\n"
|
||||||
<< " input buffer words: " << cfg.input_buffer_words << "\n"
|
<< " recv block words: " << cfg.recv_block_words << "\n"
|
||||||
<< " tty di1_group_avg: "
|
<< " input step words: " << cfg.input_step_words << "\n"
|
||||||
<< (tty_di1_group_average ? std::string("enabled")
|
<< " input buffer words: " << cfg.input_buffer_words << "\n"
|
||||||
: (cfg.di1_group_average ? std::string("requested, tty disabled")
|
<< " tty di1_group_avg: enabled\n"
|
||||||
: std::string("disabled")))
|
<< " stream-only note: ignoring csv/svg/live_html/live_json/live_update_period_ms/svg_history_packets\n";
|
||||||
<< "\n"
|
} else {
|
||||||
<< " SVG history packets kept in RAM: "
|
std::cout << " live plot html: " << writer->live_html_path() << "\n"
|
||||||
<< ((cfg.svg_history_packets == 0U) ? std::string("all (unbounded)") : std::to_string(cfg.svg_history_packets))
|
<< " live plot data: " << writer->live_json_path() << "\n"
|
||||||
<< "\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;
|
ConsoleCtrlGuard console_guard;
|
||||||
if (!console_guard.installed) {
|
if (!console_guard.installed) {
|
||||||
@ -1362,7 +1380,7 @@ int run(const Config& cfg) {
|
|||||||
device.streams_started = true;
|
device.streams_started = true;
|
||||||
|
|
||||||
std::vector<uint32_t> raw(read_capacity_words);
|
std::vector<uint32_t> raw(read_capacity_words);
|
||||||
std::vector<double> adc_buffer(read_capacity_words);
|
std::vector<double> adc_buffer(fast_tty_avg_stream_mode ? 0U : read_capacity_words);
|
||||||
std::vector<double> adc_raw_buffer(read_capacity_words);
|
std::vector<double> adc_raw_buffer(read_capacity_words);
|
||||||
std::vector<uint32_t> din_buffer(read_capacity_words);
|
std::vector<uint32_t> din_buffer(read_capacity_words);
|
||||||
std::deque<double> pending_adc;
|
std::deque<double> pending_adc;
|
||||||
@ -1374,8 +1392,12 @@ int run(const Config& cfg) {
|
|||||||
TtyGroupAverageState tty_group_state;
|
TtyGroupAverageState tty_group_state;
|
||||||
std::vector<uint16_t> tty_frame_words;
|
std::vector<uint16_t> tty_frame_words;
|
||||||
tty_frame_words.reserve(static_cast<std::size_t>(read_capacity_words) * 2U + 16U);
|
tty_frame_words.reserve(static_cast<std::size_t>(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 csv_global_frame_index = 0;
|
||||||
|
std::size_t packet_avg_steps = 0;
|
||||||
|
std::size_t fast_packet_frames = 0;
|
||||||
|
|
||||||
bool capture_started = false;
|
bool capture_started = false;
|
||||||
bool stop_loop_requested = false;
|
bool stop_loop_requested = false;
|
||||||
@ -1486,6 +1508,7 @@ int run(const Config& cfg) {
|
|||||||
static_cast<uint16_t>(pack_raw_code_to_int16(ch1_avg)),
|
static_cast<uint16_t>(pack_raw_code_to_int16(ch1_avg)),
|
||||||
static_cast<uint16_t>(pack_raw_code_to_int16(ch2_avg)));
|
static_cast<uint16_t>(pack_raw_code_to_int16(ch2_avg)));
|
||||||
++tty_group_state.next_index;
|
++tty_group_state.next_index;
|
||||||
|
++packet_avg_steps;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto flush_tty_frames = [&]() {
|
auto flush_tty_frames = [&]() {
|
||||||
@ -1507,7 +1530,11 @@ int run(const Config& cfg) {
|
|||||||
if (packet_active) {
|
if (packet_active) {
|
||||||
return;
|
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) {
|
if (tty_di1_group_average) {
|
||||||
tty_group_state.reset_packet();
|
tty_group_state.reset_packet();
|
||||||
append_tty_packet_start();
|
append_tty_packet_start();
|
||||||
@ -1521,77 +1548,97 @@ int run(const Config& cfg) {
|
|||||||
tty_group_state.clear_step();
|
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) {
|
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<std::size_t>(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<double>(frames)) / actual_frame_freq_hz;
|
const double packet_duration_ms = (1000.0 * static_cast<double>(frames)) / actual_frame_freq_hz;
|
||||||
const double zeroed_fraction = (current_packet.stored_samples == 0U)
|
if (fast_tty_avg_stream_mode) {
|
||||||
? 0.0
|
const std::size_t packet_index = static_cast<std::size_t>(total_completed_packets + 1U);
|
||||||
: (100.0 * static_cast<double>(current_packet.zeroed_samples) /
|
std::cout << std::fixed << std::setprecision(3)
|
||||||
static_cast<double>(current_packet.stored_samples));
|
<< "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)
|
CapturePacket packet;
|
||||||
<< "Packet " << packet.packet_index
|
packet.packet_index = static_cast<std::size_t>(total_completed_packets + 1U);
|
||||||
<< ": frames/ch=" << frames
|
packet.channel_count = cfg.channel_count;
|
||||||
<< ", duration_ms=" << packet_duration_ms
|
packet.has_di1_trace = (cfg.di1_mode == Di1Mode::Trace);
|
||||||
<< ", close_reason=" << packet_close_reason_to_string(reason);
|
packet.ch1 = std::move(current_packet.channels[0]);
|
||||||
if (cfg.di1_mode == Di1Mode::ZeroOnChange) {
|
packet.ch2 = std::move(current_packet.channels[1]);
|
||||||
std::cout << ", zeroed_on_DI1_change=" << zeroed_fraction << "% ("
|
packet.di1 = std::move(current_packet.di1);
|
||||||
<< current_packet.zeroed_samples << "/" << current_packet.stored_samples << ")";
|
|
||||||
} else if (cfg.di1_mode == Di1Mode::Trace) {
|
const double zeroed_fraction = (current_packet.stored_samples == 0U)
|
||||||
std::cout << ", di1_trace_frames=" << packet.di1.size();
|
? 0.0
|
||||||
|
: (100.0 * static_cast<double>(current_packet.zeroed_samples) /
|
||||||
|
static_cast<double>(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<double>(tick_count_ms() - capture_loop_start) / 1000.0);
|
||||||
|
const double packets_per_second =
|
||||||
|
(elapsed_capture_s >= 0.1)
|
||||||
|
? (static_cast<double>(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<std::size_t>(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;
|
++total_completed_packets;
|
||||||
++stats_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 =
|
const double elapsed_capture_s =
|
||||||
std::max(1e-9, static_cast<double>(tick_count_ms() - capture_loop_start) / 1000.0);
|
std::max(1e-9, static_cast<double>(tick_count_ms() - capture_loop_start) / 1000.0);
|
||||||
const double packets_per_second =
|
const double packets_per_second =
|
||||||
(elapsed_capture_s >= 0.1)
|
(elapsed_capture_s >= 0.1)
|
||||||
? (static_cast<double>(total_completed_packets) / elapsed_capture_s)
|
? (static_cast<double>(total_completed_packets) / elapsed_capture_s)
|
||||||
: 0.0;
|
: 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<std::size_t>(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)
|
std::cout << std::fixed << std::setprecision(3)
|
||||||
<< " packets/s(avg)=" << packets_per_second;
|
<< " packets/s(avg)=" << packets_per_second;
|
||||||
if (elapsed_capture_s < 0.1) {
|
if (elapsed_capture_s < 0.1) {
|
||||||
@ -1601,7 +1648,11 @@ int run(const Config& cfg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
packet_active = false;
|
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) {
|
if (tty_di1_group_average) {
|
||||||
tty_group_state.clear_step();
|
tty_group_state.clear_step();
|
||||||
}
|
}
|
||||||
@ -1666,13 +1717,16 @@ int run(const Config& cfg) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t adc_count = static_cast<uint32_t>(adc_buffer.size());
|
uint32_t adc_count = fast_tty_avg_stream_mode ? static_cast<uint32_t>(adc_raw_buffer.size())
|
||||||
|
: static_cast<uint32_t>(adc_buffer.size());
|
||||||
uint32_t din_count = static_cast<uint32_t>(din_buffer.size());
|
uint32_t din_count = static_cast<uint32_t>(din_buffer.size());
|
||||||
|
const uint32_t process_flags =
|
||||||
|
fast_tty_avg_stream_mode ? 0U : static_cast<uint32_t>(X502_PROC_FLAGS_VOLT);
|
||||||
const int32_t process_err = api.ProcessData(device.hnd,
|
const int32_t process_err = api.ProcessData(device.hnd,
|
||||||
raw.data(),
|
raw.data(),
|
||||||
static_cast<uint32_t>(recvd),
|
static_cast<uint32_t>(recvd),
|
||||||
X502_PROC_FLAGS_VOLT,
|
process_flags,
|
||||||
adc_buffer.data(),
|
fast_tty_avg_stream_mode ? adc_raw_buffer.data() : adc_buffer.data(),
|
||||||
&adc_count,
|
&adc_count,
|
||||||
din_buffer.data(),
|
din_buffer.data(),
|
||||||
&din_count);
|
&din_count);
|
||||||
@ -1688,8 +1742,8 @@ int run(const Config& cfg) {
|
|||||||
}
|
}
|
||||||
expect_ok(api, process_err, "Process ADC+DIN data");
|
expect_ok(api, process_err, "Process ADC+DIN data");
|
||||||
|
|
||||||
uint32_t raw_adc_count = 0;
|
uint32_t raw_adc_count = fast_tty_avg_stream_mode ? adc_count : 0U;
|
||||||
if (tty_writer) {
|
if (tty_writer && !fast_tty_avg_stream_mode) {
|
||||||
for (std::size_t i = 0; i < static_cast<std::size_t>(recvd); ++i) {
|
for (std::size_t i = 0; i < static_cast<std::size_t>(recvd); ++i) {
|
||||||
double raw_code = 0.0;
|
double raw_code = 0.0;
|
||||||
if (!try_extract_raw_adc_code(raw[i], raw_code)) {
|
if (!try_extract_raw_adc_code(raw[i], raw_code)) {
|
||||||
@ -1740,32 +1794,34 @@ int run(const Config& cfg) {
|
|||||||
total_din_samples += din_count;
|
total_din_samples += din_count;
|
||||||
stats_adc_samples += adc_count;
|
stats_adc_samples += adc_count;
|
||||||
stats_din_samples += din_count;
|
stats_din_samples += din_count;
|
||||||
for (uint32_t i = 0; i < adc_count; ++i) {
|
if (fast_tty_avg_stream_mode) {
|
||||||
pending_adc.push_back(adc_buffer[i]);
|
|
||||||
}
|
|
||||||
if (tty_di1_group_average) {
|
|
||||||
for (uint32_t i = 0; i < raw_adc_count; ++i) {
|
for (uint32_t i = 0; i < raw_adc_count; ++i) {
|
||||||
pending_adc_raw.push_back(adc_raw_buffer[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) {
|
for (uint32_t i = 0; i < din_count; ++i) {
|
||||||
pending_din.push_back(din_buffer[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) ||
|
(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");
|
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() &&
|
!pending_din.empty() &&
|
||||||
(!tty_di1_group_average || !pending_adc_raw.empty()) &&
|
|
||||||
!stop_loop_requested) {
|
!stop_loop_requested) {
|
||||||
const double adc_value = pending_adc.front();
|
const double adc_value = fast_tty_avg_stream_mode ? 0.0 : pending_adc.front();
|
||||||
pending_adc.pop_front();
|
if (!fast_tty_avg_stream_mode) {
|
||||||
const double adc_raw_value = tty_di1_group_average ? pending_adc_raw.front() : 0.0;
|
pending_adc.pop_front();
|
||||||
if (tty_di1_group_average) {
|
}
|
||||||
|
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();
|
pending_adc_raw.pop_front();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1840,40 +1896,53 @@ int run(const Config& cfg) {
|
|||||||
const uint32_t lch = next_lch;
|
const uint32_t lch = next_lch;
|
||||||
next_lch = (next_lch + 1U) % cfg.channel_count;
|
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<uint8_t>(di1_level ? 1U : 0U);
|
current_packet.pending_frame_di1 = static_cast<uint8_t>(di1_level ? 1U : 0U);
|
||||||
current_packet.pending_frame_di1_valid = true;
|
current_packet.pending_frame_di1_valid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
double stored_value = adc_value;
|
if (fast_tty_avg_stream_mode) {
|
||||||
if ((cfg.di1_mode == Di1Mode::ZeroOnChange) && di1_changed) {
|
if (fast_packet_frames < target_frames) {
|
||||||
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) {
|
|
||||||
tty_group_state.add_sample(lch, adc_raw_value);
|
tty_group_state.add_sample(lch, adc_raw_value);
|
||||||
}
|
if (lch == (cfg.channel_count - 1U)) {
|
||||||
++current_packet.stored_samples;
|
++fast_packet_frames;
|
||||||
++total_stored_adc_samples;
|
++total_completed_frames;
|
||||||
++stats_stored_adc_samples;
|
++stats_completed_frames;
|
||||||
if (lch == (cfg.channel_count - 1U)) {
|
}
|
||||||
if ((cfg.di1_mode == Di1Mode::Trace) &&
|
}
|
||||||
current_packet.pending_frame_di1_valid &&
|
} else {
|
||||||
(current_packet.di1.size() < target_frames)) {
|
double stored_value = adc_value;
|
||||||
current_packet.di1.push_back(current_packet.pending_frame_di1);
|
if ((cfg.di1_mode == Di1Mode::ZeroOnChange) && di1_changed) {
|
||||||
current_packet.pending_frame_di1_valid = false;
|
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);
|
finish_packet(PacketCloseReason::DurationLimit);
|
||||||
if ((cfg.packet_limit != 0U) && (total_completed_packets >= cfg.packet_limit)) {
|
if ((cfg.packet_limit != 0U) && (total_completed_packets >= cfg.packet_limit)) {
|
||||||
stop_loop_requested = true;
|
stop_loop_requested = true;
|
||||||
@ -1912,22 +1981,27 @@ int run(const Config& cfg) {
|
|||||||
tty_final_stats = tty_writer->stats();
|
tty_final_stats = tty_writer->stats();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<CapturePacket> svg_packets(packets.begin(), packets.end());
|
if (!fast_tty_avg_stream_mode) {
|
||||||
writer.write(svg_packets, actual_frame_freq_hz, range_to_volts(cfg.range));
|
const std::vector<CapturePacket> 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;
|
std::size_t total_packet_frames = 0;
|
||||||
for (const auto& packet : svg_packets) {
|
for (const auto& packet : svg_packets) {
|
||||||
total_packet_frames += (packet.channel_count <= 1U)
|
total_packet_frames += (packet.channel_count <= 1U)
|
||||||
? packet.ch1.size()
|
? packet.ch1.size()
|
||||||
: std::min(packet.ch1.size(), packet.ch2.size());
|
: std::min(packet.ch1.size(), packet.ch2.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "Captured " << total_completed_packets << " packet(s), "
|
std::cout << "Captured " << total_completed_packets << " packet(s), "
|
||||||
<< total_packet_frames << " total frames per channel kept for final SVG\n";
|
<< total_packet_frames << " total frames per channel kept for final SVG\n";
|
||||||
if (cfg.di1_mode == Di1Mode::ZeroOnChange) {
|
if (cfg.di1_mode == Di1Mode::ZeroOnChange) {
|
||||||
std::cout << "ADC samples forced to 0 on DI1 change: " << total_zeroed_samples << "\n";
|
std::cout << "ADC samples forced to 0 on DI1 change: " << total_zeroed_samples << "\n";
|
||||||
} else if (cfg.di1_mode == Di1Mode::Trace) {
|
} else if (cfg.di1_mode == Di1Mode::Trace) {
|
||||||
std::cout << "DI1 synchronous trace exported to CSV/live plot/SVG\n";
|
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: "
|
std::cout << "Average stats: "
|
||||||
<< "MB/s=" << std::fixed << std::setprecision(3)
|
<< "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_frames_dropped=" << tty_final_stats.frames_dropped
|
||||||
<< ", tty_ring_overflows=" << tty_final_stats.ring_overflows;
|
<< ", tty_ring_overflows=" << tty_final_stats.ring_overflows;
|
||||||
}
|
}
|
||||||
std::cout << "\n"
|
if (fast_tty_avg_stream_mode) {
|
||||||
<< "Final SVG packets retained in memory: " << svg_packets.size() << "\n"
|
std::cout << ", tty avg stream-only mode=enabled";
|
||||||
<< "CSV: " << cfg.csv_path << "\n"
|
}
|
||||||
<< "SVG: " << cfg.svg_path << "\n";
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,8 +6,6 @@ cd "$SCRIPT_DIR"
|
|||||||
|
|
||||||
BIN="${BIN:-./main.exe}"
|
BIN="${BIN:-./main.exe}"
|
||||||
TTY_PATH="${TTY_PATH:-/tmp/ttyADC_data}"
|
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}"
|
LIB_DIR="${LIB_DIR:-$HOME/.local/lib}"
|
||||||
|
|
||||||
if [[ ! -x "$BIN" ]]; then
|
if [[ ! -x "$BIN" ]]; then
|
||||||
@ -31,6 +29,4 @@ exec "$BIN" \
|
|||||||
duration_ms:100 \
|
duration_ms:100 \
|
||||||
packet_limit:0 \
|
packet_limit:0 \
|
||||||
"tty:${TTY_PATH}" \
|
"tty:${TTY_PATH}" \
|
||||||
"csv:${CSV_PATH}" \
|
|
||||||
"svg:${SVG_PATH}" \
|
|
||||||
"$@"
|
"$@"
|
||||||
|
|||||||
Reference in New Issue
Block a user