diff --git a/host/hackrf-tools/src/hackrf_transfer.c b/host/hackrf-tools/src/hackrf_transfer.c index 654e4af2..5d1adbc9 100644 --- a/host/hackrf-tools/src/hackrf_transfer.c +++ b/host/hackrf-tools/src/hackrf_transfer.c @@ -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", diff --git a/host/libhackrf/src/hackrf.c b/host/libhackrf/src/hackrf.c index 65554e1f..1a14ee75 100644 --- a/host/libhackrf/src/hackrf.c +++ b/host/libhackrf/src/hackrf.c @@ -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); } }