From eeaaaf3b9bde030aeeba6ebd50f032a30c31016f Mon Sep 17 00:00:00 2001 From: Martin Ling Date: Wed, 17 Aug 2022 12:54:22 +0100 Subject: [PATCH 1/2] Make use of Win32 functions conditional on _WIN32, not _MSC_VER. Using _MSC_VER here means that the choice of signal() versus SetConsoleCtrlHandler depends on the compiler being used, rather than the OS being targeted. When built with MinGW rather than MSVC, this happens to work because MinGW's signal emulation is used, but that emulation is quite limited. Instead, be consistent and use the Win32 API when building for that platform, regardless of compiler. Note that if building for Cygwin, _WIN32 is not defined and POSIX APIs are used. --- host/hackrf-tools/src/hackrf_transfer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/host/hackrf-tools/src/hackrf_transfer.c b/host/hackrf-tools/src/hackrf_transfer.c index f39f9517..98ff6044 100644 --- a/host/hackrf-tools/src/hackrf_transfer.c +++ b/host/hackrf-tools/src/hackrf_transfer.c @@ -609,7 +609,7 @@ static void usage() static hackrf_device* device = NULL; -#ifdef _MSC_VER +#ifdef _WIN32 BOOL WINAPI sighandler(int signum) { if (CTRL_C_EVENT == signum) { @@ -1041,7 +1041,7 @@ int main(int argc, char** argv) fwrite(&wave_file_hdr, 1, sizeof(t_wav_file_hdr), file); } -#ifdef _MSC_VER +#ifdef _WIN32 SetConsoleCtrlHandler((PHANDLER_ROUTINE) sighandler, TRUE); #else signal(SIGINT, &sigint_callback_handler); From a09e9a20ed42567b1fe979ab4db12f9f2590b2a4 Mon Sep 17 00:00:00 2001 From: Martin Ling Date: Fri, 5 Aug 2022 15:43:25 +0100 Subject: [PATCH 2/2] Overhaul timing in hackrf_transfer. Rather than using sleep() for 1s at a time, set up an interval timer that will fire once per second, and wait in the main loop for either this or some other event. On POSIX, the timing is set up with setitimer(), which generates a SIGALRM signal each time the timer fires. The main loop runs pause() to wait for any signal. On Windows, the timing is set up using CreateWaitableTimer, which provides an event handle that is set each time the timer fires. The main loop runs WaitForMultipleObjects() to wait on this and an interrupt event. The TX and RX callbacks can now stop the main loop immediately when they stop streaming. This fixes #1019. --- host/hackrf-tools/src/hackrf_transfer.c | 71 ++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/host/hackrf-tools/src/hackrf_transfer.c b/host/hackrf-tools/src/hackrf_transfer.c index 98ff6044..456d9d94 100644 --- a/host/hackrf-tools/src/hackrf_transfer.c +++ b/host/hackrf-tools/src/hackrf_transfer.c @@ -106,10 +106,6 @@ int gettimeofday(struct timeval* tv, void* ignored) #define BASEBAND_FILTER_BW_MIN (1750000) /* 1.75 MHz min value */ #define BASEBAND_FILTER_BW_MAX (28000000) /* 28 MHz max value */ -#if defined _WIN32 - #define sleep(a) Sleep((a * 1000)) -#endif - typedef enum { TRANSCEIVER_MODE_OFF = 0, TRANSCEIVER_MODE_RX = 1, @@ -323,6 +319,9 @@ char* u64toa(uint64_t val, t_u64toa* str) } static volatile bool do_exit = false; +#ifdef _WIN32 +static HANDLE interrupt_handle; +#endif FILE* file = NULL; volatile uint32_t byte_count = 0; @@ -394,6 +393,16 @@ uint32_t crystal_correct_ppm; int requested_mode_count = 0; +void stop_main_loop(void) +{ + do_exit = true; +#ifdef _WIN32 + SetEvent(interrupt_handle); +#else + kill(0, SIGALRM); +#endif +} + int rx_callback(hackrf_transfer* transfer) { size_t bytes_to_write; @@ -452,12 +461,14 @@ int rx_callback(hackrf_transfer* transfer) bytes_written = fwrite(transfer->buffer, 1, bytes_to_write, file); if ((bytes_written != bytes_to_write) || (limit_num_samples && (bytes_to_xfer == 0))) { + stop_main_loop(); return -1; } else { return 0; } } } else { + stop_main_loop(); return -1; } } @@ -469,6 +480,7 @@ int tx_callback(hackrf_transfer* transfer) unsigned int i; if (file == NULL && transceiver_mode != TRANSCEIVER_MODE_SS) { + stop_main_loop(); return -1; } byte_count += transfer->valid_length; @@ -490,6 +502,7 @@ int tx_callback(hackrf_transfer* transfer) } bytes_read = fread(transfer->buffer, 1, bytes_to_read, file); if (limit_num_samples && (bytes_to_xfer == 0)) { + stop_main_loop(); return -1; } if (bytes_read != bytes_to_read) { @@ -503,6 +516,7 @@ int tx_callback(hackrf_transfer* transfer) file); return 0; } else { + stop_main_loop(); return -1; /* not repeat mode, end of file */ } @@ -522,6 +536,7 @@ int tx_callback(hackrf_transfer* transfer) transfer->buffer[i] = amplitude; if (limit_num_samples && (bytes_to_xfer == 0)) { + stop_main_loop(); return -1; } else { return 0; @@ -614,7 +629,7 @@ BOOL WINAPI sighandler(int signum) { if (CTRL_C_EVENT == signum) { fprintf(stderr, "Caught signal %d\n", signum); - do_exit = true; + stop_main_loop(); return TRUE; } return FALSE; @@ -627,6 +642,12 @@ void sigint_callback_handler(int signum) } #endif +#ifndef _WIN32 +void sigalrm_callback_handler(int signum) +{ +} +#endif + #define PATH_FILE_MAX_LEN (FILENAME_MAX) #define DATE_TIME_MAX_LEN (32) @@ -1051,6 +1072,13 @@ int main(int argc, char** argv) signal(SIGTERM, &sigint_callback_handler); signal(SIGABRT, &sigint_callback_handler); #endif + +#ifdef _WIN32 + interrupt_handle = CreateEvent(NULL, TRUE, FALSE, NULL); +#else + signal(SIGALRM, &sigalrm_callback_handler); +#endif + fprintf(stderr, "call hackrf_set_sample_rate(%u Hz/%.03f MHz)\n", sample_rate_hz, @@ -1184,6 +1212,21 @@ int main(int argc, char** argv) gettimeofday(&time_start, NULL); fprintf(stderr, "Stop with Ctrl-C\n"); + + // Set up an interval timer which will fire once per second. +#ifdef _WIN32 + HANDLE timer_handle = CreateWaitableTimer(NULL, FALSE, NULL); + LARGE_INTEGER due_time; + due_time.QuadPart = -10000000LL; + LONG period = 1000; + SetWaitableTimer(timer_handle, &due_time, period, NULL, NULL, 0); +#else + struct itimerval interval_timer = { + .it_interval = {.tv_sec = 1, .tv_usec = 0}, + .it_value = {.tv_sec = 1, .tv_usec = 0}}; + setitimer(ITIMER_REAL, &interval_timer, NULL); +#endif + while ((hackrf_is_streaming(device) == HACKRF_TRUE) && (do_exit == false)) { uint32_t byte_count_now; struct timeval time_now; @@ -1219,7 +1262,14 @@ int main(int argc, char** argv) #endif } else { uint64_t stream_amplitude_now; - sleep(1); +#ifdef _WIN32 + // Wait for interval timer event, or interrupt event. + HANDLE handles[] = {timer_handle, interrupt_handle}; + WaitForMultipleObjects(2, handles, FALSE, INFINITE); +#else + // Wait for SIGALRM from interval timer, or another signal. + pause(); +#endif gettimeofday(&time_now, NULL); byte_count_now = byte_count; @@ -1287,6 +1337,15 @@ int main(int argc, char** argv) } } + // Stop interval timer. +#ifdef _WIN32 + CancelWaitableTimer(timer_handle); + CloseHandle(timer_handle); +#else + interval_timer.it_value.tv_sec = 0; + setitimer(ITIMER_REAL, &interval_timer, NULL); +#endif + result = hackrf_is_streaming(device); if (do_exit) { fprintf(stderr, "\nExiting...\n");