Merge pull request #1156 from martinling/tx-transfer-sizing

Fix handling of the final <256KiB of data transmitted with `hackrf_transfer`
This commit is contained in:
Michael Ossmann
2022-09-18 04:31:47 -04:00
committed by GitHub
2 changed files with 84 additions and 63 deletions

View File

@ -323,6 +323,7 @@ char* u64toa(uint64_t val, t_u64toa* str)
static volatile bool do_exit = false;
static volatile bool interrupted = false;
static volatile bool tx_complete = false;
#ifdef _WIN32
static HANDLE interrupt_handle;
#endif
@ -480,15 +481,15 @@ int tx_callback(hackrf_transfer* transfer)
size_t bytes_read;
unsigned int i;
/* Check we have a valid source of samples. */
if (file == NULL && transceiver_mode != TRANSCEIVER_MODE_SS) {
stop_main_loop();
return -1;
}
/* Accumulate power (magnitude squared). */
bytes_to_read = transfer->valid_length;
uint64_t sum = 0;
for (i = 0; i < bytes_to_read; i++) {
for (i = 0; i < transfer->valid_length; i++) {
int8_t value = transfer->buffer[i];
sum += value * value;
}
@ -497,53 +498,53 @@ int tx_callback(hackrf_transfer* transfer)
byte_count += transfer->valid_length;
stream_power += sum;
if (file == NULL) { // transceiver_mode == TRANSCEIVER_MODE_SS
/* Transmit continuous wave with specific amplitude */
if (limit_num_samples) {
if (bytes_to_read >= bytes_to_xfer) {
bytes_to_read = bytes_to_xfer;
}
bytes_to_xfer -= bytes_to_read;
}
for (i = 0; i < bytes_to_read; i += 2) {
transfer->buffer[i] = amplitude;
transfer->buffer[i + 1] = 0;
}
if (limit_num_samples && (bytes_to_xfer == 0)) {
stop_main_loop();
return -1;
} else {
return 0;
}
}
if (limit_num_samples) {
if (bytes_to_read >= bytes_to_xfer) {
/*
* In this condition, we probably tx some of the previous
* buffer contents at the end. :-(
*/
bytes_to_read = bytes_to_xfer;
}
bytes_to_xfer -= bytes_to_read;
}
bytes_read = fread(transfer->buffer, 1, bytes_to_read, file);
if (limit_num_samples && (bytes_to_xfer == 0)) {
/* If the last data was already buffered, stop. */
if (tx_complete) {
stop_main_loop();
return -1;
}
/* Determine how many bytes we need to put in the buffer. */
bytes_to_read = transfer->buffer_length;
if (limit_num_samples) {
if (bytes_to_read >= bytes_to_xfer) {
bytes_to_read = bytes_to_xfer;
}
bytes_to_xfer -= bytes_to_read;
}
/* Fill the buffer. */
if (file == NULL) {
/* Transmit continuous wave with specific amplitude */
for (i = 0; i < bytes_to_read; i += 2) {
transfer->buffer[i] = amplitude;
transfer->buffer[i + 1] = 0;
}
bytes_read = bytes_to_read;
} else {
/* Read samples from file. */
bytes_read = fread(transfer->buffer, 1, bytes_to_read, file);
}
transfer->valid_length = bytes_read;
/* If the sample limit has been reached, this is the last data. */
if (limit_num_samples && (bytes_to_xfer == 0)) {
tx_complete = true;
return 0;
}
/* If we filled the number of bytes needed, return normally. */
if (bytes_read == bytes_to_read) {
return 0;
}
/* Otherwise, the file ran short. If not repeating, this is the last data. */
if (!repeat) {
stop_main_loop();
return -1; /* not repeat mode, end of file */
tx_complete = true;
return 0;
}
/* If we get to here, we need to repeat the file until we fill the buffer. */
while (bytes_read < bytes_to_read) {
rewind(file);
bytes_read +=
@ -551,8 +552,10 @@ int tx_callback(hackrf_transfer* transfer)
1,
bytes_to_read - bytes_read,
file);
transfer->valid_length = bytes_read;
}
/* Then return normally. */
return 0;
}
@ -1175,15 +1178,6 @@ int main(int argc, char** argv)
return EXIT_FAILURE;
}
if (transceiver_mode == TRANSCEIVER_MODE_RX) {
result = hackrf_set_vga_gain(device, vga_gain);
result |= hackrf_set_lna_gain(device, lna_gain);
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) {
fprintf(stderr,
"hackrf_start_?x() failed: %s (%d)\n",
@ -1254,6 +1248,16 @@ int main(int argc, char** argv)
}
}
if (transceiver_mode == TRANSCEIVER_MODE_RX) {
result = hackrf_set_vga_gain(device, vga_gain);
result |= hackrf_set_lna_gain(device, lna_gain);
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 (limit_num_samples) {
fprintf(stderr,
"samples_to_xfer %s/%sMio\n",

View File

@ -237,6 +237,7 @@ static int cancel_transfers(hackrf_device* device)
}
device->transfers_setup = false;
device->flush = false;
// Now release the lock. It's possible that some transfers were
// already complete when we called libusb_cancel_transfer() on
@ -361,6 +362,8 @@ static int prepare_transfers(
.tx_ctx = device->tx_ctx,
};
if (device->callback(&transfer) == 0) {
device->transfers[transfer_index]->length =
transfer.valid_length;
ready_transfers++;
} else {
break;
@ -374,10 +377,17 @@ static int prepare_transfers(
// Now everything is ready, go ahead and submit the ready transfers.
for (transfer_index = 0; transfer_index < ready_transfers; transfer_index++) {
device->transfers[transfer_index]->endpoint = endpoint_address;
device->transfers[transfer_index]->callback = callback;
struct libusb_transfer* transfer = device->transfers[transfer_index];
transfer->endpoint = endpoint_address;
transfer->callback = callback;
error = libusb_submit_transfer(device->transfers[transfer_index]);
// Pad the size of a short transfer to the next 512-byte boundary.
if (endpoint_address == TX_ENDPOINT_ADDRESS) {
while (transfer->length % 512 != 0)
transfer->buffer[transfer->length++] = 0;
}
error = libusb_submit_transfer(transfer);
if (error != 0) {
last_libusb_error = error;
return HACKRF_ERROR_LIBUSB;
@ -391,6 +401,15 @@ static int prepare_transfers(
device->streaming = (ready_transfers == TRANSFER_COUNT);
device->transfers_setup = true;
// If we're not continuing streaming, follow up with a flush if needed.
if (!device->streaming && device->flush) {
error = libusb_submit_transfer(device->flush_transfer);
if (error != 0) {
last_libusb_error = error;
return HACKRF_ERROR_LIBUSB;
}
}
return HACKRF_SUCCESS;
}
@ -1744,24 +1763,13 @@ 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_broadcast(&device->all_finished_cv);
}
} else {
if (!device->flush) {
device->active_transfers = 0;
pthread_cond_broadcast(&device->all_finished_cv);
}
@ -1793,7 +1801,7 @@ hackrf_libusb_transfer_callback(struct libusb_transfer* usb_transfer)
hackrf_transfer transfer = {
.device = device,
.buffer = usb_transfer->buffer,
.buffer_length = usb_transfer->length,
.buffer_length = TRANSFER_BUFFER_SIZE,
.valid_length = usb_transfer->actual_length,
.rx_ctx = device->rx_ctx,
.tx_ctx = device->tx_ctx};
@ -1805,6 +1813,13 @@ hackrf_libusb_transfer_callback(struct libusb_transfer* usb_transfer)
pthread_mutex_lock(&device->transfer_lock);
if ((resubmit = device->transfers_setup)) {
if (usb_transfer->endpoint == TX_ENDPOINT_ADDRESS) {
usb_transfer->length = transfer.valid_length;
// Pad to the next 512-byte boundary.
uint8_t* buffer = usb_transfer->buffer;
while (usb_transfer->length % 512 != 0)
buffer[usb_transfer->length++] = 0;
}
result = libusb_submit_transfer(usb_transfer);
}
@ -1814,6 +1829,8 @@ hackrf_libusb_transfer_callback(struct libusb_transfer* usb_transfer)
if (resubmit && result == LIBUSB_SUCCESS)
return;
} else if (device->flush) {
libusb_submit_transfer(device->flush_transfer);
}
}