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:
@ -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",
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user