diff --git a/host/hackrf-tools/src/hackrf_transfer.c b/host/hackrf-tools/src/hackrf_transfer.c index 4978316d..89ee4832 100644 --- a/host/hackrf-tools/src/hackrf_transfer.c +++ b/host/hackrf-tools/src/hackrf_transfer.c @@ -343,17 +343,8 @@ uint32_t stream_tail = 0; uint32_t stream_drop = 0; uint8_t* stream_buf = NULL; -/* - * To report amplitude, best would be dB(fullscale) and the variance, - * but that would require more math per sample (dB(amplitude) = log(sqrt(i^2 + q^2) and sum of squares). - * For now, just sum iabs(i)+iabs(q) and divide by the number of samples*2. - * That allows us to give a measure of dB(fullscale). - * I don't know whether overload causes wrapping or clamping the 8-bit values. - * Clamping would produce a sigmoid curve, so with a signal of variable intensity you're - * probably getting substantial overload anytime this reports more than about -6dBfs. - */ -uint64_t stream_amplitude = - 0; /* sum of magnitudes of all I&Q samples, reset on the periodic report */ +/* sum of power of all samples, reset on the periodic report */ +volatile uint64_t stream_power = 0; bool transmit = false; struct timeval time_start; @@ -419,8 +410,18 @@ int rx_callback(hackrf_transfer* transfer) return -1; } - byte_count += transfer->valid_length; + /* Accumulate power (magnitude squared). */ bytes_to_write = transfer->valid_length; + uint64_t sum = 0; + for (i = 0; i < bytes_to_write; i++) { + int8_t value = transfer->buffer[i]; + sum += value * value; + } + + /* Update both running totals at approximately the same time. */ + byte_count += transfer->valid_length; + stream_power += sum; + if (limit_num_samples) { if (bytes_to_write >= bytes_to_xfer) { bytes_to_write = bytes_to_xfer; @@ -428,11 +429,6 @@ int rx_callback(hackrf_transfer* transfer) bytes_to_xfer -= bytes_to_write; } - // accumulate stream_amplitude: - for (i = 0; i < bytes_to_write; i++) { - stream_amplitude += abs((signed char) transfer->buffer[i]); - } - if (receive_wav) { /* convert .wav contents from signed to unsigned */ for (i = 0; i < bytes_to_write; i++) { @@ -487,12 +483,19 @@ int tx_callback(hackrf_transfer* transfer) stop_main_loop(); return -1; } - byte_count += transfer->valid_length; + + /* Accumulate power (magnitude squared). */ bytes_to_read = transfer->valid_length; + uint64_t sum = 0; for (i = 0; i < bytes_to_read; i++) { - stream_amplitude += abs((signed char) transfer->buffer[i]); + int8_t value = transfer->buffer[i]; + sum += value * value; } + /* Update both running totals at approximately the same time. */ + 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) { @@ -503,7 +506,7 @@ int tx_callback(hackrf_transfer* transfer) } for (i = 0; i < bytes_to_read; i++) - transfer->buffer[i] = amplitude; + transfer->buffer[i] = -(uint8_t) amplitude; if (limit_num_samples && (bytes_to_xfer == 0)) { stop_main_loop(); @@ -625,7 +628,7 @@ static void usage() printf("\t[-S buf_size] # Enable receive streaming with buffer size buf_size.\n"); #endif printf("\t[-B] # Print buffer statistics during transfer\n"); - printf("\t[-c amplitude] # CW signal source mode, amplitude 0-127 (DC value to DAC).\n"); + printf("\t[-c amplitude] # CW signal source mode, amplitude 0-128 (DC value to DAC).\n"); printf("\t[-R] # Repeat TX mode (default is off) \n"); printf("\t[-b baseband_filter_bw_hz] # Set baseband filter bandwidth in Hz.\n"); printf("\tPossible values: 1.75/2.5/3.5/5/5.5/6/7/8/9/10/12/14/15/20/24/28MHz, default <= 0.75 * sample_rate_hz.\n"); @@ -680,6 +683,7 @@ int main(int argc, char** argv) unsigned int lna_gain = 8, vga_gain = 20, txvga_gain = 0; hackrf_m0_state state; stats_t stats = {0, 0}; + static int32_t preload_bytes = 0; while ((opt = getopt(argc, @@ -1012,9 +1016,9 @@ int main(int argc, char** argv) if (signalsource) { transceiver_mode = TRANSCEIVER_MODE_SS; - if (amplitude > 127) { + if (amplitude > 128) { fprintf(stderr, - "argument error: amplitude shall be in between 0 and 127.\n"); + "argument error: amplitude must be between 0 and 128.\n"); usage(); return EXIT_FAILURE; } @@ -1269,9 +1273,11 @@ int main(int argc, char** argv) .it_value = {.tv_sec = 1, .tv_usec = 0}}; setitimer(ITIMER_REAL, &interval_timer, NULL); #endif + preload_bytes = hackrf_get_transfer_queue_depth(device) * + hackrf_get_transfer_buffer_size(device); while ((hackrf_is_streaming(device) == HACKRF_TRUE) && (do_exit == false)) { - uint32_t byte_count_now; + uint64_t byte_count_now; struct timeval time_now; float time_difference, rate; if (stream_size > 0) { @@ -1304,7 +1310,7 @@ int main(int argc, char** argv) } #endif } else { - uint64_t stream_amplitude_now; + uint64_t stream_power_now; #ifdef _WIN32 // Wait for interval timer event, or interrupt event. HANDLE handles[] = {timer_handle, interrupt_handle}; @@ -1315,13 +1321,28 @@ int main(int argc, char** argv) #endif gettimeofday(&time_now, NULL); + /* Read and reset both totals at approximately the same time. */ byte_count_now = byte_count; + stream_power_now = stream_power; byte_count = 0; - stream_amplitude_now = stream_amplitude; - stream_amplitude = 0; - if (byte_count_now < - sample_rate_hz / 20) // Don't report on very short frames - stream_amplitude_now = 0; + stream_power = 0; + + /* + * The TX callback is called to preload the USB + * transfer buffers at the start of TX. This results in + * invalid statistics collected about the empty buffers + * before any USB transfer is completed. We skip these + * statistics and do not report them to the user. + */ + if (preload_bytes > 0) { + if (preload_bytes > byte_count_now) { + preload_bytes -= byte_count_now; + byte_count_now = 0; + } else { + byte_count_now -= preload_bytes; + preload_bytes = 0; + } + } time_difference = TimevalDiff(&time_now, &time_start); rate = (float) byte_count_now / time_difference; @@ -1329,21 +1350,15 @@ int main(int argc, char** argv) hw_sync_enable != 0) { fprintf(stderr, "Waiting for sync...\n"); } else { - // This is only an approximate measure, to assist getting receive levels right: - double full_scale_ratio = - ((double) stream_amplitude_now / - (byte_count_now ? byte_count_now : 1)) / - 128; - double dB_full_scale_ratio = 10 * log10(full_scale_ratio); - // Guard against ridiculous reports - if (dB_full_scale_ratio > 1) - dB_full_scale_ratio = -0.0; + double full_scale_ratio = (double) stream_power_now / + (byte_count_now * 128 * 128); + double dB_full_scale = 10 * log10(full_scale_ratio); fprintf(stderr, - "%4.1f MiB / %5.3f sec = %4.1f MiB/second, amplitude %3.1f dBfs", + "%4.1f MiB / %5.3f sec = %4.1f MiB/second, average power %3.1f dBfs", (byte_count_now / 1e6f), time_difference, (rate / 1e6f), - dB_full_scale_ratio); + dB_full_scale); if (display_stats) { bool tx = transmit || signalsource; result = update_stats(device, &state, &stats); diff --git a/host/libhackrf/src/hackrf.c b/host/libhackrf/src/hackrf.c index ab49a920..49f3a49d 100644 --- a/host/libhackrf/src/hackrf.c +++ b/host/libhackrf/src/hackrf.c @@ -2685,6 +2685,26 @@ int ADDCALL hackrf_start_rx_sweep( return result; } +/** + * Get USB transfer buffer size. + * @return size in bytes + */ +size_t ADDCALL hackrf_get_transfer_buffer_size(hackrf_device* device) +{ + (void) device; + return TRANSFER_BUFFER_SIZE; +} + +/** + * Get the total number of USB transfer buffers. + * @return number of buffers + */ +uint32_t ADDCALL hackrf_get_transfer_queue_depth(hackrf_device* device) +{ + (void) device; + return TRANSFER_COUNT; +} + #ifdef __cplusplus } // __cplusplus defined. #endif diff --git a/host/libhackrf/src/hackrf.h b/host/libhackrf/src/hackrf.h index 0d3efc8f..4f9ddbc8 100644 --- a/host/libhackrf/src/hackrf.h +++ b/host/libhackrf/src/hackrf.h @@ -25,6 +25,7 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSI #define __HACKRF_H__ #include +#include #ifdef _WIN32 #define ADD_EXPORTS @@ -458,6 +459,10 @@ extern ADDAPI int ADDCALL hackrf_start_rx_sweep( hackrf_sample_block_cb_fn callback, void* rx_ctx); +extern ADDAPI size_t ADDCALL hackrf_get_transfer_buffer_size(hackrf_device* device); + +extern ADDAPI uint32_t ADDCALL hackrf_get_transfer_queue_depth(hackrf_device* device); + #ifdef __cplusplus } // __cplusplus defined. #endif