new di8do8 switch
This commit is contained in:
315
main.cpp
315
main.cpp
@ -30,6 +30,7 @@
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
@ -118,6 +119,9 @@ struct Config {
|
||||
bool do1_raw_tty_marked = false;
|
||||
bool do1_pair_subtract_avg = false;
|
||||
std::optional<uint32_t> noise_avg_steps;
|
||||
bool do8_freq_ref = false;
|
||||
uint32_t do8_cycle_period_ticks = 10;
|
||||
std::optional<double> do8_amplitude_threshold;
|
||||
};
|
||||
|
||||
[[noreturn]] void fail(const std::string& message) {
|
||||
@ -476,6 +480,7 @@ void print_help(const char* exe_name) {
|
||||
<< " [duration_ms:100] [packet_limit:0] [csv:capture.csv] [svg:capture.svg]\n"
|
||||
<< " [live_html:live_plot.html] [live_json:live_plot.json] [tty:/tmp/ttyADC_data] [di1_group_avg]\n"
|
||||
<< " [do1_toggle_per_frame] [do1_noise_subtract] [do1_raw_tty_marked] [do1_pair_subtract_avg] [noise_avg_steps:N]\n"
|
||||
<< " [do8_freq_ref] [do8_cycle_period:10] [do8_threshold:X]\n"
|
||||
<< " [recv_block:32768] [stats_period_ms:1000] [live_update_period_ms:1000] [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"
|
||||
@ -526,6 +531,11 @@ void print_help(const char* exe_name) {
|
||||
<< " average within each constant DI1 run, and emit legacy 4-word tty frames (word0=0x000A)\n"
|
||||
<< " noise_avg_steps:N -> kept for compatibility in do1_noise_subtract mode (current baseline is previous HIGH step)\n"
|
||||
<< " (still required when do1_noise_subtract is enabled)\n"
|
||||
<< " do8_freq_ref -> enable DO8/DI8 frequency reference overlay (DO8 and DI8 must be physically looped back);\n"
|
||||
<< " DO8 toggles HIGH for 2 ticks within each do8_cycle_period cycle;\n"
|
||||
<< " DI8=HIGH samples are accumulated separately and emitted as 0x00A8 frames\n"
|
||||
<< " do8_cycle_period:10 -> DO8 cycle period in ADC ticks (default 10, minimum 4)\n"
|
||||
<< " do8_threshold:X -> only emit DI8 reference frame when channel amplitude exceeds X (raw ADC code units)\n"
|
||||
<< " tty fast stream-only modes -> di1_group_avg, do1_noise_subtract, do1_raw_tty_marked, do1_pair_subtract_avg;\n"
|
||||
<< " skip CSV/SVG/live outputs\n"
|
||||
<< " If sample_clock_hz is omitted together with clock:internal, the maximum ADC speed is used\n"
|
||||
@ -692,6 +702,18 @@ Config parse_args(int argc, char** argv) {
|
||||
cfg.noise_avg_steps = parse_u32(arg.substr(16), "noise_avg_steps");
|
||||
continue;
|
||||
}
|
||||
if (arg == "do8_freq_ref") {
|
||||
cfg.do8_freq_ref = true;
|
||||
continue;
|
||||
}
|
||||
if (starts_with(arg, "do8_cycle_period:")) {
|
||||
cfg.do8_cycle_period_ticks = parse_u32(arg.substr(17), "do8_cycle_period");
|
||||
continue;
|
||||
}
|
||||
if (starts_with(arg, "do8_threshold:")) {
|
||||
cfg.do8_amplitude_threshold = parse_double(arg.substr(14), "do8_threshold");
|
||||
continue;
|
||||
}
|
||||
if (starts_with(arg, "sample_clock_hz:")) {
|
||||
const std::string value = trim_copy(arg.substr(16));
|
||||
cfg.sample_clock_specified = true;
|
||||
@ -894,6 +916,25 @@ Config parse_args(int argc, char** argv) {
|
||||
fail("do1_pair_subtract_avg requires phase configuration: mode:diff channels:2 ch1:2 ch2:3");
|
||||
}
|
||||
}
|
||||
if (cfg.do8_freq_ref) {
|
||||
if (!cfg.tty_path.has_value()) {
|
||||
fail("do8_freq_ref requires tty:<path>");
|
||||
}
|
||||
if (!cfg.do1_toggle_per_frame) {
|
||||
fail("do8_freq_ref requires do1_toggle_per_frame (cyclic output must be active)");
|
||||
}
|
||||
if (cfg.do8_cycle_period_ticks < 4U) {
|
||||
fail("do8_cycle_period must be >= 4 (at least 2 LOW ticks + 2 HIGH ticks)");
|
||||
}
|
||||
if (cfg.do8_amplitude_threshold.has_value() && *cfg.do8_amplitude_threshold < 0.0) {
|
||||
fail("do8_threshold must be >= 0");
|
||||
}
|
||||
if (std::gcd(4U, cfg.do8_cycle_period_ticks) > 2U) {
|
||||
std::cerr << "Warning: gcd(DO1 period=4"
|
||||
<< ", DO8 period=" << cfg.do8_cycle_period_ticks
|
||||
<< ") > 2; DI8=HIGH may systematically align with the same DO1 phase\n";
|
||||
}
|
||||
}
|
||||
if (sync_uses_di_syn1(cfg.sync_mode) && sync_uses_di_syn1(cfg.sync_start_mode)) {
|
||||
fail("clock and start cannot both use DI_SYN1; use start_in or immediate start");
|
||||
}
|
||||
@ -1154,8 +1195,12 @@ constexpr uint32_t kE502Digital1Mask = (static_cast<uint32_t>(1U) << 0U);
|
||||
constexpr uint32_t kE502Digital2Mask = (static_cast<uint32_t>(1U) << 1U);
|
||||
constexpr uint32_t kE502Do1Mask = (static_cast<uint32_t>(1U) << 0U);
|
||||
constexpr uint32_t kE502Do2Mask = (static_cast<uint32_t>(1U) << 1U);
|
||||
constexpr uint32_t kE502Digital8Mask = (static_cast<uint32_t>(1U) << 7U);
|
||||
constexpr uint32_t kE502Do8Mask = (static_cast<uint32_t>(1U) << 7U);
|
||||
constexpr uint32_t kDo1TogglePeriodTicks = 2U;
|
||||
constexpr uint32_t kDo1CyclePatternWords = kDo1TogglePeriodTicks * 2U;
|
||||
constexpr uint32_t kDo8HighTicks = 2U;
|
||||
constexpr uint16_t kTtyMarkerDi8High = 0x00A8U;
|
||||
constexpr uint32_t kStreamInputAdcFlag = 0x80000000U;
|
||||
constexpr uint32_t kStreamInputCalibratedAdcFlag = 0x40000000U;
|
||||
|
||||
@ -1466,6 +1511,8 @@ struct Do1PairSubtractAverageState {
|
||||
double pending_ch1_raw = 0.0;
|
||||
bool pending_ch1_di1_high = false;
|
||||
bool pending_ch1_di2_high = false;
|
||||
bool pending_ch1_di8_settled_high = false;
|
||||
bool pending_ch1_di8_in_guard = false;
|
||||
|
||||
uint16_t next_index = 1;
|
||||
|
||||
@ -1482,6 +1529,8 @@ struct Do1PairSubtractAverageState {
|
||||
pending_ch1_raw = 0.0;
|
||||
pending_ch1_di1_high = false;
|
||||
pending_ch1_di2_high = false;
|
||||
pending_ch1_di8_settled_high = false;
|
||||
pending_ch1_di8_in_guard = false;
|
||||
}
|
||||
|
||||
void reset_packet() {
|
||||
@ -1503,11 +1552,14 @@ struct Do1PairSubtractAverageState {
|
||||
run_initialized = false;
|
||||
}
|
||||
|
||||
void add_pending_ch1(double raw_code, bool di1_high, bool di2_high) {
|
||||
void add_pending_ch1(double raw_code, bool di1_high, bool di2_high,
|
||||
bool di8_settled_high = false, bool di8_in_guard = false) {
|
||||
pending_ch1_valid = true;
|
||||
pending_ch1_raw = raw_code;
|
||||
pending_ch1_di1_high = di1_high;
|
||||
pending_ch1_di2_high = di2_high;
|
||||
pending_ch1_di8_settled_high = di8_settled_high;
|
||||
pending_ch1_di8_in_guard = di8_in_guard;
|
||||
}
|
||||
|
||||
void add_pair_sample(bool di2_high, double ch1_value, double ch2_value) {
|
||||
@ -1547,6 +1599,85 @@ struct Do1PairSubtractAverageState {
|
||||
}
|
||||
};
|
||||
|
||||
struct Di8FreqRefState {
|
||||
std::array<double, 2> high_sum {};
|
||||
std::array<uint32_t, 2> high_count {};
|
||||
|
||||
static constexpr uint32_t kGuardSamples = 2U;
|
||||
bool di8_prev_level = false;
|
||||
bool di8_initialized = false;
|
||||
uint32_t samples_since_transition = 0;
|
||||
bool in_guard = false;
|
||||
|
||||
uint16_t last_standard_index = 0;
|
||||
bool last_standard_valid = false;
|
||||
|
||||
void clear_step() {
|
||||
high_sum = {};
|
||||
high_count = {};
|
||||
}
|
||||
|
||||
void reset_packet() {
|
||||
clear_step();
|
||||
di8_prev_level = false;
|
||||
di8_initialized = false;
|
||||
samples_since_transition = 0;
|
||||
in_guard = false;
|
||||
last_standard_index = 0;
|
||||
last_standard_valid = false;
|
||||
}
|
||||
|
||||
// Returns true if the sample is in the settled DI8=HIGH region.
|
||||
// Returns false for guard samples and DI8=LOW.
|
||||
// Sets in_guard for samples within the guard window after any transition.
|
||||
bool update_di8(bool di8_level) {
|
||||
if (!di8_initialized) {
|
||||
di8_prev_level = di8_level;
|
||||
di8_initialized = true;
|
||||
in_guard = true;
|
||||
samples_since_transition = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (di8_level != di8_prev_level) {
|
||||
di8_prev_level = di8_level;
|
||||
samples_since_transition = 0;
|
||||
in_guard = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (in_guard) {
|
||||
++samples_since_transition;
|
||||
if (samples_since_transition >= kGuardSamples) {
|
||||
in_guard = false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return di8_level;
|
||||
}
|
||||
|
||||
void add_sample(uint32_t lch, double raw_code) {
|
||||
if (lch >= high_sum.size()) {
|
||||
return;
|
||||
}
|
||||
high_sum[lch] += raw_code;
|
||||
++high_count[lch];
|
||||
}
|
||||
|
||||
bool has_complete_step(uint32_t channel_count) const {
|
||||
return (high_count[0] != 0U) && ((channel_count <= 1U) || (high_count[1] != 0U));
|
||||
}
|
||||
|
||||
double step_average(uint32_t lch) const {
|
||||
if ((lch >= high_sum.size()) || (high_count[lch] == 0U)) {
|
||||
return 0.0;
|
||||
}
|
||||
return high_sum[lch] / static_cast<double>(high_count[lch]);
|
||||
}
|
||||
};
|
||||
|
||||
int16_t pack_raw_code_to_int16(double avg_raw_code) {
|
||||
const double scaled =
|
||||
avg_raw_code * 32767.0 / static_cast<double>(X502_ADC_SCALE_CODE_MAX);
|
||||
@ -1821,6 +1952,15 @@ int run(const Config& cfg) {
|
||||
<< " DO2 state: forced HIGH\n"
|
||||
<< " DOUT rate: "
|
||||
<< (cfg.do1_toggle_per_frame ? std::to_string(actual_dout_freq_hz) + " Hz" : std::string("disabled")) << "\n"
|
||||
<< " DO8 freq ref: "
|
||||
<< (cfg.do8_freq_ref
|
||||
? ("enabled (period=" + std::to_string(cfg.do8_cycle_period_ticks)
|
||||
+ " ticks, high=" + std::to_string(kDo8HighTicks) + " ticks"
|
||||
+ (cfg.do8_amplitude_threshold.has_value()
|
||||
? ", threshold=" + std::to_string(*cfg.do8_amplitude_threshold) : "")
|
||||
+ ")")
|
||||
: std::string("disabled"))
|
||||
<< "\n"
|
||||
<< " ADC range: +/-" << range_to_volts(cfg.range) << " V\n"
|
||||
<< " max frames per packet per channel: " << target_frames << "\n";
|
||||
|
||||
@ -1921,15 +2061,37 @@ int run(const Config& cfg) {
|
||||
std::cerr << "Warning: Ctrl+C handler could not be installed; continuous mode may stop abruptly.\n";
|
||||
}
|
||||
|
||||
std::array<uint32_t, kDo1CyclePatternWords> do1_cycle_pattern {};
|
||||
std::array<uint32_t, kDo1CyclePatternWords> do1_cycle_encoded {};
|
||||
const uint32_t cycle_pattern_len = cfg.do8_freq_ref
|
||||
? static_cast<uint32_t>(std::lcm(static_cast<uint32_t>(kDo1CyclePatternWords),
|
||||
cfg.do8_cycle_period_ticks))
|
||||
: kDo1CyclePatternWords;
|
||||
std::vector<uint32_t> do1_cycle_pattern(cycle_pattern_len, 0U);
|
||||
std::vector<uint32_t> do1_cycle_encoded(cycle_pattern_len, 0U);
|
||||
if (cfg.do1_toggle_per_frame) {
|
||||
if ((api.OutCycleLoadStart == nullptr) || (api.OutCycleSetup == nullptr) || (api.OutCycleStop == nullptr)) {
|
||||
fail("do1_toggle_per_frame requires X502_OutCycle* API support (cyclic output mode)");
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < do1_cycle_pattern.size(); ++i) {
|
||||
do1_cycle_pattern[i] = ((i < kDo1TogglePeriodTicks) ? 0U : kE502Do1Mask) | kE502Do2Mask;
|
||||
uint32_t word = kE502Do2Mask;
|
||||
|
||||
const uint32_t do1_phase = static_cast<uint32_t>(i) % kDo1CyclePatternWords;
|
||||
if (do1_phase >= kDo1TogglePeriodTicks) {
|
||||
word |= kE502Do1Mask;
|
||||
}
|
||||
|
||||
if (cfg.do8_freq_ref) {
|
||||
const uint32_t do8_phase = static_cast<uint32_t>(i) % cfg.do8_cycle_period_ticks;
|
||||
if (do8_phase >= (cfg.do8_cycle_period_ticks - kDo8HighTicks)) {
|
||||
word |= kE502Do8Mask;
|
||||
}
|
||||
}
|
||||
|
||||
do1_cycle_pattern[i] = word;
|
||||
}
|
||||
|
||||
if (cycle_pattern_len > 262144U) {
|
||||
fail("Combined DO1+DO8 cyclic pattern too large: " + std::to_string(cycle_pattern_len));
|
||||
}
|
||||
|
||||
expect_ok(api,
|
||||
@ -1980,6 +2142,7 @@ int run(const Config& cfg) {
|
||||
Do1RawTaggedState tty_do1_raw_state;
|
||||
Do1NoiseSubtractState tty_do1_noise_state;
|
||||
Do1PairSubtractAverageState tty_do1_pair_state;
|
||||
Di8FreqRefState tty_di8_state;
|
||||
std::vector<uint16_t> tty_frame_words;
|
||||
tty_frame_words.reserve(static_cast<std::size_t>(read_capacity_words) * 2U + 16U);
|
||||
if (tty_do1_noise_subtract) {
|
||||
@ -2104,12 +2267,17 @@ int run(const Config& cfg) {
|
||||
(cfg.channel_count <= 1U)
|
||||
? 0.0
|
||||
: (tty_group_state.sum_ch2 / static_cast<double>(tty_group_state.count_ch2));
|
||||
const uint16_t step_idx = static_cast<uint16_t>(tty_group_state.next_index);
|
||||
append_tty_frame( (cfg.profile == CaptureProfile::Amplitude) ? 0x001AU : 0x000AU,
|
||||
static_cast<uint16_t>(tty_group_state.next_index),
|
||||
step_idx,
|
||||
static_cast<uint16_t>(pack_raw_code_to_int16(ch1_avg)),
|
||||
static_cast<uint16_t>(pack_raw_code_to_int16(ch2_avg)));
|
||||
++tty_group_state.next_index;
|
||||
++packet_avg_steps;
|
||||
if (cfg.do8_freq_ref) {
|
||||
tty_di8_state.last_standard_index = step_idx;
|
||||
tty_di8_state.last_standard_valid = true;
|
||||
}
|
||||
};
|
||||
|
||||
auto append_tty_do1_raw_marked_step = [&]() {
|
||||
@ -2130,13 +2298,18 @@ int run(const Config& cfg) {
|
||||
const double ch1_avg = tty_do1_raw_state.step_average(0U);
|
||||
const double ch2_avg = (cfg.channel_count <= 1U) ? 0.0 : tty_do1_raw_state.step_average(1U);
|
||||
const uint16_t marker = tty_do1_raw_state.step_di1_high ? 0x00A4U : 0x00A3U;
|
||||
const uint16_t step_idx = tty_do1_raw_state.next_index;
|
||||
append_tty_frame(marker,
|
||||
tty_do1_raw_state.next_index,
|
||||
step_idx,
|
||||
static_cast<uint16_t>(pack_raw_code_to_int16(ch1_avg)),
|
||||
static_cast<uint16_t>(pack_raw_code_to_int16(ch2_avg)));
|
||||
++tty_do1_raw_state.next_index;
|
||||
++packet_avg_steps;
|
||||
tty_do1_raw_state.clear_step();
|
||||
if (cfg.do8_freq_ref) {
|
||||
tty_di8_state.last_standard_index = step_idx;
|
||||
tty_di8_state.last_standard_valid = true;
|
||||
}
|
||||
};
|
||||
|
||||
auto append_tty_do1_subtracted_step = [&]() {
|
||||
@ -2185,14 +2358,19 @@ int run(const Config& cfg) {
|
||||
const double ch2_corrected =
|
||||
(cfg.channel_count <= 1U) ? 0.0 : (ch2_avg - tty_do1_noise_state.last_high(1U));
|
||||
|
||||
const uint16_t step_idx = tty_do1_noise_state.next_index;
|
||||
append_tty_frame((cfg.profile == CaptureProfile::Amplitude) ? 0x001AU : 0x000AU,
|
||||
tty_do1_noise_state.next_index,
|
||||
step_idx,
|
||||
static_cast<uint16_t>(pack_raw_code_to_int16(ch1_corrected)),
|
||||
static_cast<uint16_t>(pack_raw_code_to_int16(ch2_corrected)));
|
||||
++tty_do1_noise_state.next_index;
|
||||
++packet_avg_steps;
|
||||
tty_do1_noise_state.consume_pending_high();
|
||||
tty_do1_noise_state.finish_step();
|
||||
if (cfg.do8_freq_ref) {
|
||||
tty_di8_state.last_standard_index = step_idx;
|
||||
tty_di8_state.last_standard_valid = true;
|
||||
}
|
||||
};
|
||||
|
||||
auto append_tty_do1_pair_subtracted_avg_run = [&]() {
|
||||
@ -2212,13 +2390,54 @@ int run(const Config& cfg) {
|
||||
fail("TTY protocol step index overflow within packet");
|
||||
}
|
||||
|
||||
const uint16_t step_idx = tty_do1_pair_state.next_index;
|
||||
append_tty_frame(0x000AU,
|
||||
tty_do1_pair_state.next_index,
|
||||
step_idx,
|
||||
static_cast<uint16_t>(pack_raw_code_to_int16(tty_do1_pair_state.avg_diff_ch1())),
|
||||
static_cast<uint16_t>(pack_raw_code_to_int16(tty_do1_pair_state.avg_diff_ch2())));
|
||||
++tty_do1_pair_state.next_index;
|
||||
++packet_avg_steps;
|
||||
tty_do1_pair_state.clear_run();
|
||||
if (cfg.do8_freq_ref) {
|
||||
tty_di8_state.last_standard_index = step_idx;
|
||||
tty_di8_state.last_standard_valid = true;
|
||||
}
|
||||
};
|
||||
|
||||
auto append_tty_di8_ref_step = [&]() {
|
||||
if (!cfg.do8_freq_ref) {
|
||||
return;
|
||||
}
|
||||
if (!tty_di8_state.has_complete_step(cfg.channel_count)) {
|
||||
tty_di8_state.clear_step();
|
||||
return;
|
||||
}
|
||||
|
||||
const double ch1_avg = tty_di8_state.step_average(0U);
|
||||
const double ch2_avg = (cfg.channel_count <= 1U) ? 0.0 : tty_di8_state.step_average(1U);
|
||||
|
||||
bool exceeds = true;
|
||||
if (cfg.do8_amplitude_threshold.has_value()) {
|
||||
const double t = *cfg.do8_amplitude_threshold;
|
||||
exceeds = (std::abs(ch1_avg) > t) ||
|
||||
((cfg.channel_count > 1U) && (std::abs(ch2_avg) > t));
|
||||
}
|
||||
|
||||
if (!exceeds) {
|
||||
tty_di8_state.clear_step();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tty_di8_state.last_standard_valid) {
|
||||
tty_di8_state.clear_step();
|
||||
return;
|
||||
}
|
||||
|
||||
append_tty_frame(kTtyMarkerDi8High,
|
||||
tty_di8_state.last_standard_index,
|
||||
static_cast<uint16_t>(pack_raw_code_to_int16(ch1_avg)),
|
||||
static_cast<uint16_t>(pack_raw_code_to_int16(ch2_avg)));
|
||||
tty_di8_state.clear_step();
|
||||
};
|
||||
|
||||
auto flush_tty_frames = [&]() {
|
||||
@ -2261,6 +2480,9 @@ int run(const Config& cfg) {
|
||||
tty_do1_pair_state.reset_packet();
|
||||
append_tty_packet_start();
|
||||
}
|
||||
if (cfg.do8_freq_ref) {
|
||||
tty_di8_state.reset_packet();
|
||||
}
|
||||
packet_active = true;
|
||||
};
|
||||
|
||||
@ -2275,18 +2497,25 @@ int run(const Config& cfg) {
|
||||
|
||||
if (tty_di1_group_average) {
|
||||
append_tty_group_step();
|
||||
if (cfg.do8_freq_ref) { append_tty_di8_ref_step(); }
|
||||
tty_group_state.clear_step();
|
||||
} else if (tty_do1_raw_tty_marked) {
|
||||
append_tty_do1_raw_marked_step();
|
||||
if (cfg.do8_freq_ref) { append_tty_di8_ref_step(); }
|
||||
tty_do1_raw_state.clear_step();
|
||||
} else if (tty_do1_noise_subtract) {
|
||||
// Finalize the last DI1 run in packet, drop only incomplete channel tuples.
|
||||
append_tty_do1_subtracted_step();
|
||||
if (cfg.do8_freq_ref) { append_tty_di8_ref_step(); }
|
||||
tty_do1_noise_state.clear_step();
|
||||
} else if (tty_do1_pair_subtract_avg) {
|
||||
append_tty_do1_pair_subtracted_avg_run();
|
||||
if (cfg.do8_freq_ref) { append_tty_di8_ref_step(); }
|
||||
tty_do1_pair_state.reset_packet();
|
||||
}
|
||||
if (cfg.do8_freq_ref) {
|
||||
tty_di8_state.clear_step();
|
||||
}
|
||||
|
||||
const std::size_t frames = fast_tty_avg_stream_mode
|
||||
? fast_packet_frames
|
||||
@ -2669,14 +2898,24 @@ int run(const Config& cfg) {
|
||||
}
|
||||
++packet_clock_count;
|
||||
|
||||
const bool di8_level = cfg.do8_freq_ref
|
||||
? ((din_value & kE502Digital8Mask) != 0U)
|
||||
: false;
|
||||
const bool di8_settled_high = cfg.do8_freq_ref
|
||||
? tty_di8_state.update_di8(di8_level)
|
||||
: false;
|
||||
const bool di8_in_guard = cfg.do8_freq_ref && tty_di8_state.in_guard;
|
||||
|
||||
if (tty_di1_group_average && di1_changed) {
|
||||
append_tty_group_step();
|
||||
if (cfg.do8_freq_ref) { append_tty_di8_ref_step(); tty_di8_state.clear_step(); }
|
||||
tty_group_state.clear_step();
|
||||
} else if (tty_do1_raw_tty_marked) {
|
||||
if (!tty_do1_raw_state.step_level_initialized) {
|
||||
tty_do1_raw_state.start_new_step(di1_level);
|
||||
} else if (di1_changed) {
|
||||
append_tty_do1_raw_marked_step();
|
||||
if (cfg.do8_freq_ref) { append_tty_di8_ref_step(); tty_di8_state.clear_step(); }
|
||||
tty_do1_raw_state.start_new_step(di1_level);
|
||||
}
|
||||
} else if (tty_do1_noise_subtract) {
|
||||
@ -2684,6 +2923,7 @@ int run(const Config& cfg) {
|
||||
tty_do1_noise_state.start_new_step(di1_level);
|
||||
} else if (di1_changed) {
|
||||
append_tty_do1_subtracted_step();
|
||||
if (cfg.do8_freq_ref) { append_tty_di8_ref_step(); tty_di8_state.clear_step(); }
|
||||
tty_do1_noise_state.start_new_step(di1_level);
|
||||
}
|
||||
}
|
||||
@ -2699,37 +2939,57 @@ int run(const Config& cfg) {
|
||||
if (fast_packet_frames < target_frames) {
|
||||
if (tty_do1_pair_subtract_avg) {
|
||||
if (lch == 0U) {
|
||||
tty_do1_pair_state.add_pending_ch1(adc_raw_value, di1_level, di2_level);
|
||||
tty_do1_pair_state.add_pending_ch1(adc_raw_value, di1_level, di2_level,
|
||||
di8_settled_high, di8_in_guard);
|
||||
} else if (lch == 1U) {
|
||||
if (tty_do1_pair_state.pending_ch1_valid) {
|
||||
const bool pair_di1_matches =
|
||||
(tty_do1_pair_state.pending_ch1_di1_high == di1_level);
|
||||
const bool pair_di2_matches =
|
||||
(tty_do1_pair_state.pending_ch1_di2_high == di2_level);
|
||||
const bool either_di8_guard =
|
||||
tty_do1_pair_state.pending_ch1_di8_in_guard || di8_in_guard;
|
||||
const bool both_di8_high =
|
||||
tty_do1_pair_state.pending_ch1_di8_settled_high && di8_settled_high;
|
||||
const bool both_di8_normal =
|
||||
!tty_do1_pair_state.pending_ch1_di8_settled_high &&
|
||||
!tty_do1_pair_state.pending_ch1_di8_in_guard &&
|
||||
!di8_settled_high && !di8_in_guard;
|
||||
|
||||
if (pair_di1_matches && pair_di2_matches) {
|
||||
if (!tty_do1_pair_state.run_initialized) {
|
||||
tty_do1_pair_state.start_run(di1_level);
|
||||
} else if (tty_do1_pair_state.run_di1_high != di1_level) {
|
||||
append_tty_do1_pair_subtracted_avg_run();
|
||||
tty_do1_pair_state.start_run(di1_level);
|
||||
if (pair_di1_matches && pair_di2_matches && !either_di8_guard) {
|
||||
if (both_di8_high) {
|
||||
tty_di8_state.add_sample(0U, tty_do1_pair_state.pending_ch1_raw);
|
||||
tty_di8_state.add_sample(1U, adc_raw_value);
|
||||
} else if (both_di8_normal) {
|
||||
if (!tty_do1_pair_state.run_initialized) {
|
||||
tty_do1_pair_state.start_run(di1_level);
|
||||
} else if (tty_do1_pair_state.run_di1_high != di1_level) {
|
||||
append_tty_do1_pair_subtracted_avg_run();
|
||||
if (cfg.do8_freq_ref) { append_tty_di8_ref_step(); tty_di8_state.clear_step(); }
|
||||
tty_do1_pair_state.start_run(di1_level);
|
||||
}
|
||||
|
||||
tty_do1_pair_state.add_pair_sample(di2_level,
|
||||
tty_do1_pair_state.pending_ch1_raw,
|
||||
adc_raw_value);
|
||||
}
|
||||
|
||||
tty_do1_pair_state.add_pair_sample(di2_level,
|
||||
tty_do1_pair_state.pending_ch1_raw,
|
||||
adc_raw_value);
|
||||
// else: mixed DI8 state pair -- discard
|
||||
}
|
||||
}
|
||||
tty_do1_pair_state.clear_pending_ch1();
|
||||
} else {
|
||||
tty_do1_pair_state.clear_pending_ch1();
|
||||
}
|
||||
} else if (tty_do1_noise_subtract) {
|
||||
tty_do1_noise_state.add_sample(lch, adc_raw_value);
|
||||
} else if (tty_do1_raw_tty_marked) {
|
||||
tty_do1_raw_state.add_sample(lch, adc_raw_value);
|
||||
} else {
|
||||
tty_group_state.add_sample(lch, adc_raw_value);
|
||||
} else if (di8_settled_high) {
|
||||
tty_di8_state.add_sample(lch, adc_raw_value);
|
||||
} else if (!di8_in_guard) {
|
||||
if (tty_do1_noise_subtract) {
|
||||
tty_do1_noise_state.add_sample(lch, adc_raw_value);
|
||||
} else if (tty_do1_raw_tty_marked) {
|
||||
tty_do1_raw_state.add_sample(lch, adc_raw_value);
|
||||
} else {
|
||||
tty_group_state.add_sample(lch, adc_raw_value);
|
||||
}
|
||||
}
|
||||
if (lch == (cfg.channel_count - 1U)) {
|
||||
++fast_packet_frames;
|
||||
@ -2797,9 +3057,10 @@ int run(const Config& cfg) {
|
||||
expect_ok(api, api.StreamsStop(device.hnd), "Stop streams");
|
||||
device.streams_started = false;
|
||||
if (cfg.do1_toggle_per_frame) {
|
||||
const uint32_t clear_mask = kE502Do1Mask | kE502Do2Mask | (cfg.do8_freq_ref ? kE502Do8Mask : 0U);
|
||||
expect_ok(api,
|
||||
api.AsyncOutDig(device.hnd, kE502Do2Mask, ~(kE502Do1Mask | kE502Do2Mask)),
|
||||
"Force DO1 LOW and keep DO2 HIGH after cyclic DOUT stop");
|
||||
api.AsyncOutDig(device.hnd, kE502Do2Mask, ~clear_mask),
|
||||
"Force DO1/DO8 LOW and keep DO2 HIGH after cyclic DOUT stop");
|
||||
} else {
|
||||
expect_ok(api, api.AsyncOutDig(device.hnd, kE502Do2Mask, ~kE502Do2Mask), "Keep DO2 HIGH after streams stop");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user