diff --git a/host/hackrf-tools/src/hackrf_transfer.c b/host/hackrf-tools/src/hackrf_transfer.c index 89ee4832..41061ff0 100644 --- a/host/hackrf-tools/src/hackrf_transfer.c +++ b/host/hackrf-tools/src/hackrf_transfer.c @@ -322,6 +322,7 @@ char* u64toa(uint64_t val, t_u64toa* str) } static volatile bool do_exit = false; +static volatile bool interrupted = false; #ifdef _WIN32 static HANDLE interrupt_handle; #endif @@ -642,6 +643,7 @@ static hackrf_device* device = NULL; BOOL WINAPI sighandler(int signum) { if (CTRL_C_EVENT == signum) { + interrupted = true; fprintf(stderr, "Caught signal %d\n", signum); stop_main_loop(); return TRUE; @@ -651,6 +653,7 @@ BOOL WINAPI sighandler(int signum) #else void sigint_callback_handler(int signum) { + interrupted = true; fprintf(stderr, "Caught signal %d\n", signum); do_exit = true; } @@ -1176,6 +1179,7 @@ int main(int argc, char** argv) result |= hackrf_start_rx(device, rx_callback, NULL); } else { result = hackrf_set_txvga_gain(device, txvga_gain); + result |= hackrf_enable_tx_flush(device, 1); result |= hackrf_start_tx(device, tx_callback, NULL); } if (result != HACKRF_SUCCESS) { @@ -1403,6 +1407,10 @@ int main(int argc, char** argv) interval_timer.it_value.tv_sec = 0; setitimer(ITIMER_REAL, &interval_timer, NULL); #endif + if ((transmit || signalsource) && !interrupted) { + // Wait for TX to finish. + hackrf_await_tx_flush(device); + } result = hackrf_is_streaming(device); if (do_exit) { diff --git a/host/libhackrf/src/hackrf.c b/host/libhackrf/src/hackrf.c index 49f3a49d..eaf3a935 100644 --- a/host/libhackrf/src/hackrf.c +++ b/host/libhackrf/src/hackrf.c @@ -123,6 +123,7 @@ typedef enum { #define TRANSFER_COUNT 4 #define TRANSFER_BUFFER_SIZE 262144 +#define DEVICE_BUFFER_SIZE 32768 #define USB_MAX_SERIAL_LENGTH 32 struct hackrf_device { @@ -142,6 +143,8 @@ struct hackrf_device { volatile int active_transfers; /* number of active transfers */ pthread_cond_t all_finished_cv; /* signalled when all transfers have finished */ pthread_mutex_t all_finished_lock; /* used to protect all_finished */ + bool flush; + struct libusb_transfer* flush_transfer; }; typedef struct { @@ -272,6 +275,9 @@ static int free_transfers(hackrf_device* device) free(device->transfers); device->transfers = NULL; } + + libusb_free_transfer(device->flush_transfer); + return HACKRF_SUCCESS; } @@ -695,6 +701,8 @@ static int hackrf_open_setup(libusb_device_handle* usb_device, hackrf_device** d lib_device->streaming = false; lib_device->do_exit = false; lib_device->active_transfers = 0; + lib_device->flush = false; + lib_device->flush_transfer = NULL; result = pthread_mutex_init(&lib_device->transfer_lock, NULL); if (result != 0) { @@ -1734,20 +1742,44 @@ static void transfer_finished( struct hackrf_device* device, struct libusb_transfer* finished_transfer) { + int result; + // If a transfer finished for any reason, we're shutting down. device->streaming = false; // If this is the last transfer, signal that all are now finished. pthread_mutex_lock(&device->all_finished_lock); if (device->active_transfers == 1) { - device->active_transfers = 0; - pthread_cond_signal(&device->all_finished_cv); + if (device->flush) { + // Don't finish yet - flush the TX buffer first. + result = libusb_submit_transfer(device->flush_transfer); + // If that fails, just shut down. + if (result != LIBUSB_SUCCESS) { + device->flush = false; + device->active_transfers = 0; + pthread_cond_broadcast(&device->all_finished_cv); + } + } else { + device->active_transfers = 0; + pthread_cond_broadcast(&device->all_finished_cv); + } } else { device->active_transfers--; } pthread_mutex_unlock(&device->all_finished_lock); } +static void LIBUSB_CALL hackrf_libusb_flush_callback(struct libusb_transfer* usb_transfer) +{ + // TX buffer is now flushed, so proceed with signalling completion. + hackrf_device* device = (hackrf_device*) usb_transfer->user_data; + pthread_mutex_lock(&device->all_finished_lock); + device->flush = false; + device->active_transfers = 0; + pthread_cond_broadcast(&device->all_finished_cv); + pthread_mutex_unlock(&device->all_finished_lock); +} + static void LIBUSB_CALL hackrf_libusb_transfer_callback(struct libusb_transfer* usb_transfer) { @@ -1935,6 +1967,9 @@ int ADDCALL hackrf_start_tx( { int result; const uint8_t endpoint_address = TX_ENDPOINT_ADDRESS; + if (device->flush_transfer != NULL) { + device->flush = true; + } result = hackrf_set_transceiver_mode(device, HACKRF_TRANSCEIVER_MODE_TRANSMIT); if (result == HACKRF_SUCCESS) { device->tx_ctx = tx_ctx; @@ -1943,6 +1978,49 @@ int ADDCALL hackrf_start_tx( return result; } +int ADDCALL hackrf_enable_tx_flush(hackrf_device* device, int enable) +{ + if (enable) { + if (device->flush_transfer) { + return HACKRF_SUCCESS; + } + + if ((device->flush_transfer = libusb_alloc_transfer(0)) == NULL) { + return HACKRF_ERROR_LIBUSB; + } + + libusb_fill_bulk_transfer( + device->flush_transfer, + device->usb_device, + TX_ENDPOINT_ADDRESS, + calloc(1, DEVICE_BUFFER_SIZE), + DEVICE_BUFFER_SIZE, + hackrf_libusb_flush_callback, + device, + 0); + + device->flush_transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER; + } else { + libusb_free_transfer(device->flush_transfer); + device->flush_transfer = NULL; + } + + return HACKRF_SUCCESS; +} + +int ADDCALL hackrf_await_tx_flush(hackrf_device* device) +{ + // Wait for the transfer thread to signal that all transfers + // have finished. + pthread_mutex_lock(&device->all_finished_lock); + while (device->active_transfers > 0) { + pthread_cond_wait(&device->all_finished_cv, &device->all_finished_lock); + } + pthread_mutex_unlock(&device->all_finished_lock); + + return HACKRF_SUCCESS; +} + /* * Stop any pending transmit. * diff --git a/host/libhackrf/src/hackrf.h b/host/libhackrf/src/hackrf.h index 4f9ddbc8..87a52ac5 100644 --- a/host/libhackrf/src/hackrf.h +++ b/host/libhackrf/src/hackrf.h @@ -238,6 +238,9 @@ extern ADDAPI int ADDCALL hackrf_start_tx( hackrf_sample_block_cb_fn callback, void* tx_ctx); +extern ADDAPI int ADDCALL hackrf_enable_tx_flush(hackrf_device* device, int enable); +extern ADDAPI int ADDCALL hackrf_await_tx_flush(hackrf_device* device); + extern ADDAPI int ADDCALL hackrf_stop_tx(hackrf_device* device); extern ADDAPI int ADDCALL hackrf_get_m0_state(