test tty writer

This commit is contained in:
awe
2026-04-09 17:32:34 +03:00
parent cb95b5ff48
commit 3899e99f80
3 changed files with 197 additions and 24 deletions

View File

@ -381,7 +381,7 @@ 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] [tty:/dev/ttyADC_data]\n"
<< " [live_html:live_plot.html] [live_json:live_plot.json] [tty:/tmp/ttyADC_data]\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"
@ -412,7 +412,7 @@ void print_help(const char* exe_name) {
<< " 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"
<< " tty:/dev/ttyADC_data -> write binary step frames to a Linux/POSIX tty path\n"
<< " tty:/tmp/ttyADC_data -> write binary step frames to a Linux/POSIX tty or PTY link path\n"
<< " If sample_clock_hz is omitted together with clock:internal, the maximum ADC speed is used\n"
<< "\n"
<< "Differential physical channel mapping:\n"
@ -747,6 +747,19 @@ Fn load_symbol(ModuleHandle module, const char* name) {
#endif
}
template <typename Fn>
Fn try_load_symbol(ModuleHandle module, const char* name) {
#ifdef _WIN32
const auto addr = GetProcAddress(module, name);
return reinterpret_cast<Fn>(addr);
#else
dlerror();
void* addr = dlsym(module, name);
(void) dlerror();
return reinterpret_cast<Fn>(addr);
#endif
}
struct Api {
ModuleHandle x502_module = nullptr;
ModuleHandle e502_module = nullptr;
@ -755,6 +768,7 @@ struct Api {
decltype(&X502_Free) Free = nullptr;
decltype(&X502_Close) Close = nullptr;
decltype(&X502_GetErrorString) GetErrorString = nullptr;
decltype(&X502_GetDevInfo) GetDevInfo = nullptr;
decltype(&X502_GetDevInfo2) GetDevInfo2 = nullptr;
decltype(&X502_SetMode) SetMode = nullptr;
decltype(&X502_StreamsStop) StreamsStop = nullptr;
@ -804,7 +818,11 @@ struct Api {
Free = load_symbol<decltype(Free)>(x502_module, "X502_Free");
Close = load_symbol<decltype(Close)>(x502_module, "X502_Close");
GetErrorString = load_symbol<decltype(GetErrorString)>(x502_module, "X502_GetErrorString");
GetDevInfo2 = load_symbol<decltype(GetDevInfo2)>(x502_module, "X502_GetDevInfo2");
GetDevInfo = try_load_symbol<decltype(GetDevInfo)>(x502_module, "X502_GetDevInfo");
GetDevInfo2 = try_load_symbol<decltype(GetDevInfo2)>(x502_module, "X502_GetDevInfo2");
if ((GetDevInfo == nullptr) && (GetDevInfo2 == nullptr)) {
fail("Neither X502_GetDevInfo nor X502_GetDevInfo2 is available in x502 API library");
}
SetMode = load_symbol<decltype(SetMode)>(x502_module, "X502_SetMode");
StreamsStop = load_symbol<decltype(StreamsStop)>(x502_module, "X502_StreamsStop");
StreamsDisable = load_symbol<decltype(StreamsDisable)>(x502_module, "X502_StreamsDisable");
@ -859,6 +877,8 @@ void expect_ok(const Api& api, int32_t err, const std::string& what) {
constexpr uint32_t kE502DiSyn2Mask =
(static_cast<uint32_t>(1U) << 13U) | (static_cast<uint32_t>(1U) << 17U);
constexpr uint32_t kE502Digital1Mask = (static_cast<uint32_t>(1U) << 0U);
constexpr uint32_t kStreamInputAdcFlag = 0x80000000U;
constexpr uint32_t kStreamInputCalibratedAdcFlag = 0x40000000U;
using TickMs = uint64_t;
@ -1012,6 +1032,30 @@ int16_t pack_raw_code_to_int16(double avg_raw_code) {
return static_cast<int16_t>(clamped);
}
bool try_extract_raw_adc_code(uint32_t word, double& raw_code) {
if ((word & kStreamInputAdcFlag) == 0U) {
return false;
}
int32_t value = 0;
if ((word & kStreamInputCalibratedAdcFlag) != 0U) {
const uint32_t payload = word & 0x00FFFFFFU;
value = static_cast<int32_t>(payload);
if ((payload & 0x00800000U) != 0U) {
value |= static_cast<int32_t>(0xFF000000U);
}
} else {
const uint32_t payload = word & 0x0000FFFFU;
value = static_cast<int32_t>(payload);
if ((payload & 0x00008000U) != 0U) {
value |= static_cast<int32_t>(0xFFFF0000U);
}
}
raw_code = static_cast<double>(value);
return true;
}
struct ConsoleCtrlGuard {
bool installed = false;
@ -1113,7 +1157,11 @@ int run(const Config& cfg) {
device.opened = true;
t_x502_info info{};
err = api.GetDevInfo2(device.hnd, &info, sizeof(info));
if (api.GetDevInfo2 != nullptr) {
err = api.GetDevInfo2(device.hnd, &info, sizeof(info));
} else {
err = api.GetDevInfo(device.hnd, &info);
}
expect_ok(api, err, "Get device info");
print_device_info(info);
@ -1356,7 +1404,9 @@ int run(const Config& cfg) {
return;
}
if (tty_step.next_step_index >= 0xFFFFU) {
fail("TTY protocol step index overflow within packet");
std::cerr << "Warning: TTY protocol step index overflow, forcing tty packet restart\n";
tty_step.reset_packet();
tty_writer->emit_packet_start();
}
const double ch1_avg = tty_step.sum_ch1 / static_cast<double>(tty_step.count_ch1);
@ -1531,18 +1581,18 @@ int run(const Config& cfg) {
uint32_t raw_adc_count = 0;
if (tty_writer) {
raw_adc_count = static_cast<uint32_t>(adc_raw_buffer.size());
const int32_t raw_process_err = api.ProcessData(device.hnd,
raw.data(),
static_cast<uint32_t>(recvd),
0,
adc_raw_buffer.data(),
&raw_adc_count,
nullptr,
nullptr);
expect_ok(api, raw_process_err, "Process raw ADC data");
for (std::size_t i = 0; i < recvd; ++i) {
double raw_code = 0.0;
if (!try_extract_raw_adc_code(raw[i], raw_code)) {
continue;
}
if (raw_adc_count >= adc_raw_buffer.size()) {
fail("Raw ADC parsing overflowed the temporary buffer");
}
adc_raw_buffer[raw_adc_count++] = raw_code;
}
if (raw_adc_count != adc_count) {
fail("Raw ADC processing returned a different sample count than voltage processing");
fail("Raw ADC parsing returned a different sample count than voltage processing");
}
}
@ -1624,7 +1674,14 @@ int run(const Config& cfg) {
start_packet();
}
if (!packet_active && start_edge) {
if (packet_active && start_edge) {
finish_packet(PacketCloseReason::ExternalStopEdge);
if ((cfg.packet_limit != 0U) && (total_completed_packets >= cfg.packet_limit)) {
stop_loop_requested = true;
continue;
}
start_packet();
} else if (!packet_active && start_edge) {
start_packet();
}