Merge pull request #1139 from martinling/tx-flush

Support flushing the device TX buffer before ending transmission
This commit is contained in:
Michael Ossmann
2022-09-14 05:45:40 -04:00
committed by GitHub
3 changed files with 91 additions and 2 deletions

View File

@ -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) {

View File

@ -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) {
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_signal(&device->all_finished_cv);
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.
*

View File

@ -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(