diff --git a/main.cpp b/main.cpp index de578e0..74d3ced 100644 --- a/main.cpp +++ b/main.cpp @@ -506,9 +506,9 @@ void print_help(const char* exe_name) { << " 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; with channels:1, CH2 is 0\n" << " di1_group_avg -> with tty + di1:trace, emit one averaged 4-word step per constant DI1 run\n" - << " do1_toggle_per_frame -> packet-gated DO1 state machine in DI_SYN2 window:\n" - << " force LOW on packet start, then CH1->CH2->toggle DO1 per frame,\n" - << " repeat until packet end, then force LOW with full DOUT flush\n" + << " do1_toggle_per_frame -> DI_SYN2 level-gated DO1 modulation:\n" + << " DO1 is forced LOW when DI_SYN2 is LOW,\n" + << " while DI_SYN2 is HIGH DO1 toggles every 3 complete CH1+CH2 frames\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" @@ -764,10 +764,10 @@ Config parse_args(int argc, char** argv) { } if (cfg.do1_toggle_per_frame) { if (!cfg.recv_block_specified) { - cfg.recv_block_words = 256U; + cfg.recv_block_words = 32U; } if (!cfg.input_step_specified) { - cfg.input_step_words = 256U; + cfg.input_step_words = 32U; } if (!cfg.input_buffer_specified) { cfg.input_buffer_words = std::max(cfg.input_buffer_words, 256U * 1024U); @@ -1041,6 +1041,7 @@ constexpr uint32_t kE502DiSyn2Mask = constexpr uint32_t kE502Digital1Mask = (static_cast(1U) << 0U); constexpr uint32_t kE502Digital2Mask = (static_cast(1U) << 1U); constexpr uint32_t kE502Do1Mask = (static_cast(1U) << 0U); +constexpr uint32_t kDo1TogglePeriodFrames = 3U; constexpr uint32_t kStreamInputAdcFlag = 0x80000000U; constexpr uint32_t kStreamInputCalibratedAdcFlag = 0x40000000U; @@ -1461,7 +1462,7 @@ int run(const Config& cfg) { << ((cfg.channel_count >= 2U) ? phy_channel_name(cfg.mode, cfg.ch2) : std::string("disabled")) << "\n" << " DI1 handling: " << di1_mode_to_string(cfg.di1_mode) << "\n" << " DO1 toggle per frame: " - << (cfg.do1_toggle_per_frame ? std::string("enabled (DI_SYN2-gated CH1->CH2->toggle, LOW at start/end)") + << (cfg.do1_toggle_per_frame ? std::string("enabled (DI_SYN2 level-gated, toggle each 3 frames, LOW outside HIGH)") : std::string("disabled")) << "\n" << " DOUT rate: " << (cfg.do1_toggle_per_frame ? std::to_string(actual_dout_freq_hz) + " Hz" : std::string("disabled")) << "\n" @@ -1586,6 +1587,8 @@ int run(const Config& cfg) { TickMs last_stats_print = capture_loop_start; TickMs last_live_update = 0; bool do1_output_high = false; + bool do1_gate_active = false; + uint32_t do1_frames_since_toggle = 0; uint64_t do1_packet_toggle_count = 0; uint64_t do1_packet_queued_words = 0; uint64_t do1_packet_sent_words_baseline = 0; @@ -1774,20 +1777,22 @@ int run(const Config& cfg) { } }; - // Packet-scoped DO1 sequencing: LOW on packet start, toggle after each complete CH1+CH2 frame, LOW on packet end. - auto do1_queue_level = [&](bool do1_high, - uint32_t flush_timeout_ms, - bool require_full_flush, - bool count_for_packet) { + auto do1_queue_level = [&](bool do1_high, bool count_for_packet) { if (!cfg.do1_toggle_per_frame) { return; } append_dout_word(do1_high); - do1_output_high = do1_high; if (count_for_packet) { ++do1_packet_queued_words; } - flush_dout_queue(flush_timeout_ms, require_full_flush); + if (do1_output_high != do1_high) { + if (count_for_packet) { + ++do1_packet_toggle_count; + } + do1_output_high = do1_high; + } else { + do1_output_high = do1_high; + } }; auto do1_on_packet_start = [&]() { @@ -1797,29 +1802,43 @@ int run(const Config& cfg) { do1_packet_toggle_count = 0; do1_packet_queued_words = 0; do1_packet_sent_words_baseline = do1_total_sent_words; - do1_queue_level(false, 0U, false, true); }; - auto do1_on_frame_complete = [&]() { - if (!cfg.do1_toggle_per_frame || !packet_active) { + auto do1_on_frame_complete = [&](bool di_syn2_frame_high) { + if (!cfg.do1_toggle_per_frame) { return; } - const bool next_state_high = !do1_output_high; - do1_queue_level(next_state_high, 0U, false, true); - ++do1_packet_toggle_count; + bool next_state_high = false; + if (di_syn2_frame_high) { + if (!do1_gate_active) { + do1_gate_active = true; + do1_frames_since_toggle = 0U; + next_state_high = true; + } else if ((do1_frames_since_toggle + 1U) >= kDo1TogglePeriodFrames) { + do1_frames_since_toggle = 0U; + next_state_high = !do1_output_high; + } else { + ++do1_frames_since_toggle; + next_state_high = do1_output_high; + } + } else { + do1_gate_active = false; + do1_frames_since_toggle = 0U; + next_state_high = false; + } + do1_queue_level(next_state_high, packet_active); }; auto do1_on_packet_end = [&](bool print_packet_stats) { if (!cfg.do1_toggle_per_frame) { return; } - do1_queue_level(false, cfg.recv_timeout_ms, true, true); if (print_packet_stats) { const uint64_t packet_sent_words = do1_total_sent_words - do1_packet_sent_words_baseline; - std::cout << " DO1 stats: toggles=" << do1_packet_toggle_count + std::cout << " DO1 stats: transitions=" << do1_packet_toggle_count << ", queued_words=" << do1_packet_queued_words << ", sent_words=" << packet_sent_words - << ", final_state=" << (do1_output_high ? "HIGH" : "LOW") << "\n"; + << ", state=" << (do1_output_high ? "HIGH" : "LOW") << "\n"; } }; @@ -2201,6 +2220,12 @@ int run(const Config& cfg) { } trigger_prev_level = di_syn2_level; } + const bool frame_complete = (lch == (cfg.channel_count - 1U)); + if (cfg.do1_toggle_per_frame) { + if (frame_complete) { + do1_on_frame_complete(di_syn2_level); + } + } if (!packet_active && (cfg.sync_start_mode == X502_SYNC_INTERNAL)) { start_packet(); @@ -2284,10 +2309,6 @@ int run(const Config& cfg) { } } - if (cfg.do1_toggle_per_frame && (lch == (cfg.channel_count - 1U))) { - do1_on_frame_complete(); - } - const std::size_t completed_frames = fast_tty_avg_stream_mode ? fast_packet_frames : current_packet.frame_count(cfg.channel_count); @@ -2316,7 +2337,8 @@ int run(const Config& cfg) { } if (cfg.do1_toggle_per_frame) { - do1_queue_level(false, cfg.recv_timeout_ms, true, false); + do1_queue_level(false, false); + flush_dout_queue(cfg.recv_timeout_ms, true); } expect_ok(api, api.StreamsStop(device.hnd), "Stop streams");