Пример #1
0
/* Require a 10% margin on the sample rate to ensure we can keep up, and
 * warn if this margin is violated
 */
static void check_samplerate(struct cli_state *s, struct rxtx_data *rxtx)
{
    int status;
    uint64_t samplerate_min;        /* Min required sample rate */
    unsigned int samplerate_dev;    /* Device's current sample rate */
    unsigned int n_xfers, samp_per_buf;

    pthread_mutex_lock(&rxtx->data_mgmt.lock);
    n_xfers = (unsigned int)rxtx->data_mgmt.num_transfers;
    samp_per_buf = (unsigned int)rxtx->data_mgmt.samples_per_buffer;
    pthread_mutex_unlock(&rxtx->data_mgmt.lock);

    samplerate_min = (uint64_t)n_xfers * samp_per_buf;
    samplerate_min += (samplerate_min + 9) / 10;

    status = bladerf_get_sample_rate(s->dev, rxtx->module, &samplerate_dev);
    if (status < 0) {
        cli_err(s, "Error", "Failed read device's current sample rate. "
                            "Unable to perform sanity check.");
    } else if (samplerate_dev < samplerate_min) {
        if (samplerate_min <= 40000000) {
            printf("\n  Warning: The current sample rate may be too low. "
                   "For %u transfers and\n"
                   "           %u samples per buffer, a sample rate >= %"
                   PRIu64" Hz is\n           recommended to avoid timeouts.\n\n",
                   n_xfers, samp_per_buf, samplerate_min);
        } else {
            printf("\n  Warning: The current configuraion with %u transfers and"
                   "%u samples per buffer requires a sample rate above 40MHz.\n"
                   "Timeouts will likely occur with these settings.\n",
                   n_xfers, samp_per_buf);
        }
    }
}
Пример #2
0
static int set_and_check(struct bladerf *dev, bladerf_module m,
                         unsigned int rate)
{
    int status;
    unsigned int actual, readback;

    status = bladerf_set_sample_rate(dev, m, rate, &actual);
    if (status != 0) {
        PR_ERROR("Failed to set sample rate: %s\n",
                 bladerf_strerror(status));
        return status;
    }

    status = bladerf_get_sample_rate(dev, m, &readback);
    if (status != 0) {
        PR_ERROR("Failed to read back sample rate: %s\n",
                 bladerf_strerror(status));
        return status;
    }

    return 0;
}
Пример #3
0
/* Require a 10% margin on the sample rate to ensure we can keep up, and
 * warn if this margin is violated.
 *
 * We effectively ensuring:
 *
 * Min sample rate > (xfers / timeout period) * samples / buffer
 *                    ^
 *  1 xfer = buffer --'
 */
static void check_samplerate(struct cli_state *s, struct rxtx_data *rxtx)
{
    int status;
    uint64_t samplerate_min;        /* Min required sample rate */
    unsigned int samplerate_dev;    /* Device's current sample rate */
    unsigned int n_xfers, samp_per_buf, timeout_ms;

    MUTEX_LOCK(&rxtx->data_mgmt.lock);
    n_xfers = (unsigned int)rxtx->data_mgmt.num_transfers;
    samp_per_buf = (unsigned int)rxtx->data_mgmt.samples_per_buffer;
    timeout_ms = rxtx->data_mgmt.timeout_ms;
    MUTEX_UNLOCK(&rxtx->data_mgmt.lock);

    samplerate_min = (uint64_t)n_xfers * samp_per_buf * 1000 / timeout_ms;
    samplerate_min += (samplerate_min + 9) / 10;

    status = bladerf_get_sample_rate(s->dev, rxtx->module, &samplerate_dev);
    if (status < 0) {
        cli_err(s, "Error", "Failed read device's current sample rate. "
                            "Unable to perform sanity check.\n");
    } else if (samplerate_dev < samplerate_min) {
        if (samplerate_min <= 40000000) {
            printf("\n");
            printf("    Warning: The current sample rate may be too low. For %u transfers,\n"
                   "    %u samples per buffer, and a %u ms timeout, a sample rate\n"
                   "    over %"PRIu64" Hz may be required. Alternatively, the 'timeout'\n"
                   "    parameter could be increased, but may yield underruns.\n\n",
                   n_xfers, samp_per_buf, timeout_ms, samplerate_min);
        } else {
            printf("\n");
            printf("    Warning: The current configuraion with %u transfers,\n"
                   "    %u samples per buffer, and a %u ms timeout requires a\n"
                   "    sample rate above 40MHz. Timeouts may occur with these settings.\n\n",
                   n_xfers, samp_per_buf, timeout_ms);
        }
    }
}
Пример #4
0
static int tx_task_exec_running(struct rxtx_data *tx, struct cli_state *s)
{
    int status = 0;
    unsigned int samples_per_buffer;
    int16_t *tx_buffer;
    struct tx_params *tx_params = tx->params;
    unsigned int repeats_remaining;
    unsigned int delay_us;
    unsigned int delay_samples;
    unsigned int delay_samples_remaining;
    bool repeat_infinite;
    unsigned int timeout_ms;
    unsigned int sample_rate;

    enum state { INIT, READ_FILE, DELAY, PAD_TRAILING, DONE };
    enum state state = INIT;

    /* Fetch the parameters required for the TX operation */
    MUTEX_LOCK(&tx->param_lock);
    repeats_remaining = tx_params->repeat;
    delay_us = tx_params->repeat_delay;
    MUTEX_UNLOCK(&tx->param_lock);

    repeat_infinite = (repeats_remaining == 0);

    MUTEX_LOCK(&tx->data_mgmt.lock);
    samples_per_buffer = (unsigned int)tx->data_mgmt.samples_per_buffer;
    timeout_ms = tx->data_mgmt.timeout_ms;
    MUTEX_UNLOCK(&tx->data_mgmt.lock);

    status = bladerf_get_sample_rate(s->dev, tx->module, &sample_rate);
    if (status != 0) {
        set_last_error(&tx->last_error, ETYPE_BLADERF, status);
        return CLI_RET_LIBBLADERF;
    }

    /* Compute delay time as a sample count */
    delay_samples = (unsigned int)((uint64_t)sample_rate * delay_us / 1000000);
    delay_samples_remaining = delay_samples;

    /* Allocate a buffer to hold each block of samples to transmit */
    tx_buffer = (int16_t*) malloc(samples_per_buffer * 2 * sizeof(int16_t));
    if (tx_buffer == NULL) {
        status = CLI_RET_MEM;
        set_last_error(&tx->last_error, ETYPE_ERRNO,
                       errno == 0 ? ENOMEM : errno);
    }

    /* Keep writing samples while there is more data to send and no failures
     * have occurred */
    while (state != DONE && status == 0) {

        unsigned char requests;
        unsigned int buffer_samples_remaining = samples_per_buffer;
        int16_t *tx_buffer_current = tx_buffer;

        /* Stop stream on STOP or SHUTDOWN, but only clear STOP. This will keep
         * the SHUTDOWN request around so we can read it when determining
         * our state transition */
        requests = rxtx_get_requests(tx, RXTX_TASK_REQ_STOP);
        if (requests & (RXTX_TASK_REQ_STOP | RXTX_TASK_REQ_SHUTDOWN)) {
            break;
        }

        /* Keep adding to the buffer until it is full or a failure occurs */
        while (buffer_samples_remaining > 0 && status == 0 && state != DONE) {
            size_t samples_populated = 0;

            switch (state) {
                case INIT:
                case READ_FILE:

                    MUTEX_LOCK(&tx->file_mgmt.file_lock);

                    /* Read from the input file */
                    samples_populated = fread(tx_buffer_current,
                                              2 * sizeof(int16_t),
                                              buffer_samples_remaining,
                                              tx->file_mgmt.file);

                    assert(samples_populated <= UINT_MAX);

                    /* If the end of the file was reached, determine whether
                     * to delay, re-read from the file, or pad the rest of the
                     * buffer and finish */
                    if (feof(tx->file_mgmt.file)) {
                        repeats_remaining--;

                        if ((repeats_remaining > 0) || repeat_infinite) {
                            if (delay_samples != 0) {
                                delay_samples_remaining = delay_samples;
                                state = DELAY;
                            }
                        }
                        else {
                            state = PAD_TRAILING;
                        }

                        /* Clear the EOF condition and rewind the file */
                        clearerr(tx->file_mgmt.file);
                        rewind(tx->file_mgmt.file);
                    }

                    /* Check for errors */
                    else if (ferror(tx->file_mgmt.file)) {
                        status = errno;
                        set_last_error(&tx->last_error, ETYPE_ERRNO, status);
                    }

                    MUTEX_UNLOCK(&tx->file_mgmt.file_lock);
                    break;

                case DELAY:
                    /* Insert as many zeros as are necessary to realize the
                     * specified repeat delay */
                    samples_populated = uint_min(buffer_samples_remaining,
                                                 delay_samples_remaining);

                    memset(tx_buffer_current, 0,
                           samples_populated * 2 * sizeof(uint16_t));

                    delay_samples_remaining -= (unsigned int)samples_populated;

                    if (delay_samples_remaining == 0) {
                        state = READ_FILE;
                    }
                    break;

                case PAD_TRAILING:
                    /* Populate the remainder of the buffer with zeros */
                    memset(tx_buffer_current, 0,
                            buffer_samples_remaining * 2 * sizeof(uint16_t));

                    state = DONE;
                    break;

                case DONE:
                default:
                    break;
            }

            /* Advance the buffer pointer.
             * Remember, two int16_t's make up 1 sample in the SC16Q11 format */
            buffer_samples_remaining -= (unsigned int)samples_populated;
            tx_buffer_current += (2 * samples_populated);
        }

        /* If there were no errors, transmit the data buffer */
        if (status == 0) {
            bladerf_sync_tx(s->dev, tx_buffer, samples_per_buffer, NULL,
                            timeout_ms);
        }
    }

    free(tx_buffer);
    return status;
}