From e4b88249608e2e0ae75cfafc258b56d5da5ff9b4 Mon Sep 17 00:00:00 2001 From: awe Date: Thu, 9 Apr 2026 13:52:10 +0300 Subject: [PATCH] fix --- main.cpp | 202 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 170 insertions(+), 32 deletions(-) diff --git a/main.cpp b/main.cpp index 2d3ddb6..6aeb63a 100644 --- a/main.cpp +++ b/main.cpp @@ -19,6 +19,8 @@ #include #include +#include +#include #include #include #include @@ -34,6 +36,11 @@ #include #include +#ifndef _WIN32 + #include + #include +#endif + namespace { enum class StopMode { @@ -662,18 +669,87 @@ Config parse_args(int argc, char** argv) { return cfg; } +#ifdef _WIN32 +using ModuleHandle = HMODULE; +#else +using ModuleHandle = void*; +#endif + +std::string dynamic_loader_error() { +#ifdef _WIN32 + return "unknown error"; +#else + const char* error = dlerror(); + return ((error != nullptr) && (*error != '\0')) ? std::string(error) : std::string("unknown error"); +#endif +} + +ModuleHandle open_library(const char* path) { +#ifdef _WIN32 + return LoadLibraryA(path); +#else + dlerror(); + return dlopen(path, RTLD_LAZY | RTLD_LOCAL); +#endif +} + +void close_library(ModuleHandle module) { +#ifdef _WIN32 + if (module != nullptr) { + FreeLibrary(module); + } +#else + if (module != nullptr) { + dlclose(module); + } +#endif +} + +ModuleHandle load_library_or_fail(const std::vector& candidates, + const std::string& description) { + std::string last_error = "no candidates provided"; + for (const auto& candidate : candidates) { + ModuleHandle module = open_library(candidate.c_str()); + if (module != nullptr) { + return module; + } + last_error = dynamic_loader_error(); + } + + std::ostringstream out; + out << "Cannot load " << description << ". Tried:"; + for (const auto& candidate : candidates) { + out << " " << candidate; + } + out << ". Last error: " << last_error; + fail(out.str()); +} + template -Fn load_symbol(HMODULE module, const char* name) { +Fn load_symbol(ModuleHandle module, const char* name) { +#ifdef _WIN32 const auto addr = GetProcAddress(module, name); if (addr == nullptr) { fail(std::string("GetProcAddress failed for symbol: ") + name); } return reinterpret_cast(addr); +#else + dlerror(); + void* addr = dlsym(module, name); + const char* error = dlerror(); + if ((addr == nullptr) || (error != nullptr)) { + std::ostringstream out; + out << "dlsym failed for symbol " << name << ": " + << ((error != nullptr) ? error : "unknown error"); + fail(out.str()); + } + return reinterpret_cast(addr); +#endif } struct Api { - HMODULE x502_module = nullptr; - HMODULE e502_module = nullptr; + ModuleHandle x502_module = nullptr; + ModuleHandle e502_module = nullptr; decltype(&X502_Create) Create = nullptr; decltype(&X502_Free) Free = nullptr; @@ -709,14 +785,20 @@ struct Api { decltype(&E502_OpenByIpAddr) OpenByIpAddr = nullptr; Api() { - x502_module = LoadLibraryA("x502api.dll"); - if (x502_module == nullptr) { - fail("Cannot load x502api.dll"); - } - e502_module = LoadLibraryA("e502api.dll"); - if (e502_module == nullptr) { - fail("Cannot load e502api.dll"); - } + x502_module = load_library_or_fail( +#ifdef _WIN32 + {"x502api.dll"}, +#else + {"libx502api.so", "x502api.so", "./libx502api.so", "./x502api.so"}, +#endif + "x502 API library"); + e502_module = load_library_or_fail( +#ifdef _WIN32 + {"e502api.dll"}, +#else + {"libe502api.so", "e502api.so", "./libe502api.so", "./e502api.so"}, +#endif + "e502 API library"); Create = load_symbol(x502_module, "X502_Create"); Free = load_symbol(x502_module, "X502_Free"); @@ -753,12 +835,8 @@ struct Api { } ~Api() { - if (e502_module != nullptr) { - FreeLibrary(e502_module); - } - if (x502_module != nullptr) { - FreeLibrary(x502_module); - } + close_library(e502_module); + close_library(x502_module); } }; @@ -782,6 +860,19 @@ constexpr uint32_t kE502DiSyn2Mask = (static_cast(1U) << 13U) | (static_cast(1U) << 17U); constexpr uint32_t kE502Digital1Mask = (static_cast(1U) << 0U); +using TickMs = uint64_t; + +TickMs tick_count_ms() { +#ifdef _WIN32 + return static_cast(GetTickCount64()); +#else + using namespace std::chrono; + return static_cast( + duration_cast(steady_clock::now().time_since_epoch()).count()); +#endif +} + +#ifdef _WIN32 volatile LONG g_console_stop_requested = 0; BOOL WINAPI console_ctrl_handler(DWORD ctrl_type) { @@ -795,6 +886,17 @@ BOOL WINAPI console_ctrl_handler(DWORD ctrl_type) { bool console_stop_requested() { return InterlockedCompareExchange(&g_console_stop_requested, 0, 0) != 0; } +#else +volatile std::sig_atomic_t g_console_stop_requested = 0; + +void console_ctrl_handler(int) { + g_console_stop_requested = 1; +} + +bool console_stop_requested() { + return g_console_stop_requested != 0; +} +#endif enum class PacketCloseReason { ExternalStopEdge, @@ -913,16 +1015,52 @@ int16_t pack_raw_code_to_int16(double avg_raw_code) { struct ConsoleCtrlGuard { bool installed = false; +#ifndef _WIN32 + bool sigint_installed = false; + bool sigterm_installed = false; + bool sigabrt_installed = false; + struct sigaction old_sigint {}; + struct sigaction old_sigterm {}; + struct sigaction old_sigabrt {}; +#endif + ConsoleCtrlGuard() { +#ifdef _WIN32 InterlockedExchange(&g_console_stop_requested, 0); installed = SetConsoleCtrlHandler(console_ctrl_handler, TRUE) != 0; +#else + g_console_stop_requested = 0; + + struct sigaction action {}; + action.sa_handler = console_ctrl_handler; + sigemptyset(&action.sa_mask); + action.sa_flags = 0; + + sigint_installed = sigaction(SIGINT, &action, &old_sigint) == 0; + sigterm_installed = sigaction(SIGTERM, &action, &old_sigterm) == 0; + sigabrt_installed = sigaction(SIGABRT, &action, &old_sigabrt) == 0; + installed = sigint_installed && sigterm_installed && sigabrt_installed; +#endif } ~ConsoleCtrlGuard() { +#ifdef _WIN32 if (installed) { SetConsoleCtrlHandler(console_ctrl_handler, FALSE); } InterlockedExchange(&g_console_stop_requested, 0); +#else + if (sigint_installed) { + sigaction(SIGINT, &old_sigint, nullptr); + } + if (sigterm_installed) { + sigaction(SIGTERM, &old_sigterm, nullptr); + } + if (sigabrt_installed) { + sigaction(SIGABRT, &old_sigabrt, nullptr); + } + g_console_stop_requested = 0; +#endif } }; @@ -1140,11 +1278,11 @@ int run(const Config& cfg) { uint32_t next_lch = 0; bool di1_initialized = false; bool di1_prev_level = false; - const ULONGLONG start_wait_deadline = GetTickCount64() + cfg.start_wait_ms; - const ULONGLONG capture_loop_start = GetTickCount64(); - ULONGLONG stats_window_start = capture_loop_start; - ULONGLONG last_stats_print = capture_loop_start; - ULONGLONG last_live_update = 0; + const TickMs start_wait_deadline = tick_count_ms() + cfg.start_wait_ms; + const TickMs capture_loop_start = tick_count_ms(); + TickMs stats_window_start = capture_loop_start; + TickMs last_stats_print = capture_loop_start; + TickMs last_live_update = 0; uint64_t total_raw_words = 0; uint64_t total_adc_samples = 0; @@ -1162,7 +1300,7 @@ int run(const Config& cfg) { uint64_t stats_completed_packets = 0; auto print_stats = [&](bool final_report) { - const ULONGLONG now = GetTickCount64(); + const TickMs now = tick_count_ms(); const double elapsed_s = std::max(1e-9, static_cast(now - stats_window_start) / 1000.0); const double mb_per_s = (static_cast(stats_raw_words) * sizeof(uint32_t)) / elapsed_s / 1000.0 / 1000.0; const double adc_samples_per_s = static_cast(stats_adc_samples) / elapsed_s; @@ -1281,12 +1419,12 @@ int run(const Config& cfg) { } const double elapsed_capture_s = - std::max(1e-9, static_cast(GetTickCount64() - capture_loop_start) / 1000.0); + 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 ULONGLONG now = GetTickCount64(); + const TickMs now = tick_count_ms(); const bool should_update_live = (cfg.live_update_period_ms == 0U) || (last_live_update == 0U) || @@ -1345,7 +1483,7 @@ int run(const Config& cfg) { stats_raw_words += static_cast(recvd); } if (recvd == 0) { - if (!capture_started && (GetTickCount64() >= start_wait_deadline)) { + if (!capture_started && (tick_count_ms() >= start_wait_deadline)) { std::ostringstream message; message << "Timeout before first ADC data. start=" << sync_mode_to_string(cfg.sync_start_mode, true) @@ -1558,7 +1696,7 @@ int run(const Config& cfg) { stop_loop_requested = true; } - if ((cfg.stats_period_ms != 0U) && ((GetTickCount64() - last_stats_print) >= cfg.stats_period_ms)) { + if ((cfg.stats_period_ms != 0U) && ((tick_count_ms() - last_stats_print) >= cfg.stats_period_ms)) { print_stats(false); } } @@ -1592,20 +1730,20 @@ int run(const Config& cfg) { std::cout << "Average stats: " << "MB/s=" << std::fixed << std::setprecision(3) << ((static_cast(total_raw_words) * sizeof(uint32_t)) / - std::max(1e-9, static_cast(GetTickCount64() - capture_loop_start) / 1000.0) / + std::max(1e-9, static_cast(tick_count_ms() - capture_loop_start) / 1000.0) / 1000.0 / 1000.0) << ", ADC samples/s=" << (static_cast(total_adc_samples) / - std::max(1e-9, static_cast(GetTickCount64() - capture_loop_start) / 1000.0)) + std::max(1e-9, static_cast(tick_count_ms() - capture_loop_start) / 1000.0)) << ", DIN samples/s=" << (static_cast(total_din_samples) / - std::max(1e-9, static_cast(GetTickCount64() - capture_loop_start) / 1000.0)) + std::max(1e-9, static_cast(tick_count_ms() - capture_loop_start) / 1000.0)) << ", frames/s per channel=" << (static_cast(total_completed_frames) / - std::max(1e-9, static_cast(GetTickCount64() - capture_loop_start) / 1000.0)) + std::max(1e-9, static_cast(tick_count_ms() - capture_loop_start) / 1000.0)) << ", packets/s=" << (static_cast(total_completed_packets) / - std::max(1e-9, static_cast(GetTickCount64() - capture_loop_start) / 1000.0)) + std::max(1e-9, static_cast(tick_count_ms() - capture_loop_start) / 1000.0)) << ", packets captured=" << total_completed_packets; if (cfg.di1_mode == Di1Mode::ZeroOnChange) { std::cout << ", zeroed on DI1 change="