Exemplo n.º 1
0
static void *rx_callback(struct bladerf *dev,
                         struct bladerf_stream *stream,
                         struct bladerf_metadata *meta,
                         void *samples,
                         size_t num_samples,
                         void *user_data)
{
    unsigned int requests;      /* Pending requests */
    unsigned int next_idx;
    unsigned int samples_idx;
    void *next_buf = NULL;      /* Next buffer to submit for reception */

    struct bladerf_sync *s = (struct bladerf_sync *)user_data;
    struct sync_worker  *w = s->worker;
    struct buffer_mgmt  *b = &s->buf_mgmt;

    /* Check if the caller has requested us to shut down. We'll keep the
     * SHUTDOWN bit set through our transition into the IDLE state so we
     * can act on it there. */
    pthread_mutex_lock(&w->request_lock);
    requests = w->requests;
    pthread_mutex_unlock(&w->request_lock);

    if (requests & SYNC_WORKER_STOP) {
        log_verbose("%s worker: Got STOP request upon entering callback. "
                    "Ending stream.\n", MODULE_STR(s));
        return NULL;
    }

    pthread_mutex_lock(&b->lock);

    /* Get the index of the buffer we've been notified about having been
     * completed */
    samples_idx = sync_buf2idx(b, samples);

    if (b->status[b->prod_i] == SYNC_BUFFER_EMPTY) {
        next_idx = b->prod_i;
        b->prod_i = (next_idx + 1) % b->num_buffers;

        b->status[samples_idx] = SYNC_BUFFER_FULL;
        b->status[next_idx] = SYNC_BUFFER_IN_FLIGHT;
        pthread_cond_signal(&b->buf_ready);
    } else {

        /* TODO propgate back the RX Overrun to the sync_rx() caller */
        log_debug("RX overrun @ buffer %u\r\n", samples_idx);

        next_idx = samples_idx;
        b->status[samples_idx] = SYNC_BUFFER_IN_FLIGHT;
    }

    next_buf = b->buffers[next_idx];

    log_verbose("%s worker: buf[%u] = full, buf[%u] = in_flight\n",
                MODULE_STR(s), samples_idx, next_idx);

    pthread_mutex_unlock(&b->lock);
    return next_buf;
}
Exemplo n.º 2
0
void *sync_worker_task(void *arg)
{
    sync_worker_state state = SYNC_WORKER_STATE_IDLE;
    struct bladerf_sync *s = (struct bladerf_sync *)arg;

    log_verbose("%s worker: task started\n", MODULE_STR(s));
    set_state(s->worker, state);
    log_verbose("%s worker: task state set\n", MODULE_STR(s));

    while (state != SYNC_WORKER_STATE_STOPPED) {

        switch (state) {
            case SYNC_WORKER_STATE_STARTUP:
                assert(!"Worker in unexepected state, shutting down. (STARTUP)");
                set_state(s->worker, SYNC_WORKER_STATE_SHUTTING_DOWN);
                break;

            case SYNC_WORKER_STATE_IDLE:
                state = exec_idle_state(s);
                set_state(s->worker, state);
                break;

            case SYNC_WORKER_STATE_RUNNING:
                exec_running_state(s);
                state = SYNC_WORKER_STATE_IDLE;
                set_state(s->worker, state);
                break;

            case SYNC_WORKER_STATE_SHUTTING_DOWN:
                log_verbose("%s worker: Shutting down...\n", MODULE_STR(s));

                state = SYNC_WORKER_STATE_STOPPED;
                set_state(s->worker, state);
                break;

            case SYNC_WORKER_STATE_STOPPED:
                assert(!"Worker in unexepected state: STOPPED");
                break;

            default:
                assert(!"Worker in unexepected state, shutting down. (UNKNOWN)");
                set_state(s->worker, SYNC_WORKER_STATE_SHUTTING_DOWN);
                break;
        }
    }

    return NULL;
}
Exemplo n.º 3
0
static sync_worker_state exec_idle_state(struct bladerf_sync *s)
{
    sync_worker_state next_state = SYNC_WORKER_STATE_IDLE;

    pthread_mutex_lock(&s->worker->request_lock);

    while (s->worker->requests == 0) {
        log_verbose("%s worker: Waiting for pending requests\n", MODULE_STR(s));

        pthread_cond_wait(&s->worker->requests_pending,
                          &s->worker->request_lock);
    }

    if (s->worker->requests & SYNC_WORKER_STOP) {
        log_verbose("%s worker: Got request to stop\n",
                module2str(s->stream_config.module));

        next_state = SYNC_WORKER_STATE_SHUTTING_DOWN;

    } else if (s->worker->requests & SYNC_WORKER_START) {
        log_verbose("%s worker: Got request to start\n",
                module2str(s->stream_config.module));

        next_state = SYNC_WORKER_STATE_RUNNING;
    } else {
        log_warning("Invalid request value encountered: 0x%08X\n",
                    s->worker->requests);
    }

    s->worker->requests = 0;
    pthread_mutex_unlock(&s->worker->request_lock);

    return next_state;
}
Exemplo n.º 4
0
static void *tx_callback(struct bladerf *dev,
                         struct bladerf_stream *stream,
                         struct bladerf_metadata *meta,
                         void *samples,
                         size_t num_samples,
                         void *user_data)
{
    unsigned int requests;      /* Pending requests */
    unsigned int completed_idx; /* Index of completed buffer */

    struct bladerf_sync *s = (struct bladerf_sync *)user_data;
    struct sync_worker  *w = s->worker;
    struct buffer_mgmt  *b = &s->buf_mgmt;

    /* Check if the caller has requested us to shut down. We'll keep the
     * SHUTDOWN bit set through our transition into the IDLE state so we
     * can act on it there. */
    pthread_mutex_lock(&w->request_lock);
    requests = w->requests;
    pthread_mutex_unlock(&w->request_lock);

    if (requests & SYNC_WORKER_STOP) {
        log_verbose("%s worker: Got STOP request upon entering callback. "
                    "Ending stream.\r\n", MODULE_STR(s));
        return NULL;
    }


    /* Mark the last transfer as being completed. Note that the first
     * callbacks we get have samples=NULL */
    if (samples != NULL) {

        pthread_mutex_lock(&b->lock);

        completed_idx = sync_buf2idx(b, samples);
        assert(b->status[completed_idx] == SYNC_BUFFER_IN_FLIGHT);
        b->status[completed_idx] = SYNC_BUFFER_EMPTY;

        pthread_cond_signal(&b->buf_ready);
        pthread_mutex_unlock(&b->lock);

        log_verbose("%s worker: Buffer %u emptied.\r\n",
                    MODULE_STR(s), completed_idx);
    }

    return BLADERF_STREAM_NO_DATA;
}
Exemplo n.º 5
0
static void exec_running_state(struct bladerf_sync *s)
{
    int status;
    unsigned int i;

    pthread_mutex_lock(&s->buf_mgmt.lock);

    if (s->stream_config.module == BLADERF_MODULE_TX) {
        /* If we've previously timed out on a stream, we'll likely have some
         * stale buffers marked "in-flight" that have since been cancelled. */
        for (i = 0; i < s->buf_mgmt.num_buffers; i++) {
            if (s->buf_mgmt.status[i] == SYNC_BUFFER_IN_FLIGHT) {
                s->buf_mgmt.status[i] = SYNC_BUFFER_EMPTY;
            }
        }

        pthread_cond_signal(&s->buf_mgmt.buf_ready);
    } else {
        assert(s->stream_config.module == BLADERF_MODULE_RX);
        s->buf_mgmt.prod_i = s->stream_config.num_xfers;

        for (i = 0; i < s->buf_mgmt.num_buffers; i++) {
            if (i < s->stream_config.num_xfers) {
                s->buf_mgmt.status[i] = SYNC_BUFFER_IN_FLIGHT;
            } else if (s->buf_mgmt.status[i] == SYNC_BUFFER_IN_FLIGHT) {
                s->buf_mgmt.status[i] = SYNC_BUFFER_EMPTY;
            }
        }
    }

    pthread_mutex_unlock(&s->buf_mgmt.lock);

    status = bladerf_stream(s->worker->stream, s->stream_config.module);

    log_verbose("%s worker: stream ended with: %s\n",
                MODULE_STR(s), bladerf_strerror(status));

    /* Save off the result of running the stream so we can report what
     * happened to the API caller */
    pthread_mutex_lock(&s->worker->state_lock);
    s->worker->err_code = status;
    pthread_mutex_unlock(&s->worker->state_lock);

    /* Wake the API-side if an error occurred, so that it can propagate
     * the stream error code back to the API caller */
    if (status != 0) {
        pthread_mutex_lock(&s->buf_mgmt.lock);
        pthread_cond_signal(&s->buf_mgmt.buf_ready);
        pthread_mutex_unlock(&s->buf_mgmt.lock);
    }
}
Exemplo n.º 6
0
static void exec_running_state(struct bladerf_sync *s)
{
    int status;
    unsigned int i;

    pthread_mutex_lock(&s->buf_mgmt.lock);

    if (s->stream_config.module == BLADERF_MODULE_TX) {
        /* If we've previously timed out on a stream, we'll likely have some
         * stale buffers marked "in-flight" that have since been cancelled. */
        for (i = 0; i < s->buf_mgmt.num_buffers; i++) {
            if (s->buf_mgmt.status[i] == SYNC_BUFFER_IN_FLIGHT) {
                s->buf_mgmt.status[i] = SYNC_BUFFER_EMPTY;
            }
        }

        pthread_cond_signal(&s->buf_mgmt.buf_ready);
    } else {
        assert(s->stream_config.module == BLADERF_MODULE_RX);
        s->buf_mgmt.prod_i = s->stream_config.num_xfers;

        for (i = 0; i < s->buf_mgmt.num_buffers; i++) {
            if (i < s->stream_config.num_xfers) {
                s->buf_mgmt.status[i] = SYNC_BUFFER_IN_FLIGHT;
            } else if (s->buf_mgmt.status[i] == SYNC_BUFFER_IN_FLIGHT) {
                s->buf_mgmt.status[i] = SYNC_BUFFER_EMPTY;
            }
        }
    }

    pthread_mutex_unlock(&s->buf_mgmt.lock);

    status = bladerf_stream(s->worker->stream, s->stream_config.module);

    log_verbose("%s worker: stream ended with: %s\n",
                MODULE_STR(s), bladerf_strerror(status));

    /* Suppress warning if log_verbose is disabled */
    (void)status;
}
Exemplo n.º 7
0
static void exec_running_state(struct bladerf_sync *s)
{
    int status;

    status = bladerf_stream(s->worker->stream, s->stream_config.module);

    log_verbose("%s worker: stream ended with: %s\n",
                MODULE_STR(s), bladerf_strerror(status));

    /* Save off the result of running the stream so we can report what
     * happened to the API caller */
    pthread_mutex_lock(&s->worker->state_lock);
    s->worker->err_code = status;
    pthread_mutex_unlock(&s->worker->state_lock);

    /* Wake the API-side if an error occurred, so that it can propagate
     * the stream error code back to the API caller */
    if (status != 0) {
        pthread_mutex_lock(&s->buf_mgmt.lock);
        pthread_cond_signal(&s->buf_mgmt.buf_ready);
        pthread_mutex_unlock(&s->buf_mgmt.lock);
    }
}
Exemplo n.º 8
0
static void *rx_callback(struct bladerf *dev,
                         struct bladerf_stream *stream,
                         struct bladerf_metadata *meta,
                         void *samples,
                         size_t num_samples,
                         void *user_data)
{
    unsigned int requests;      /* Pending requests */
    unsigned int next_idx;
    unsigned int samples_idx;
    void *next_buf = NULL;      /* Next buffer to submit for reception */

    struct bladerf_sync *s = (struct bladerf_sync *)user_data;
    struct sync_worker  *w = s->worker;
    struct buffer_mgmt  *b = &s->buf_mgmt;

    /* Check if the caller has requested us to shut down. We'll keep the
     * SHUTDOWN bit set through our transition into the IDLE state so we
     * can act on it there. */
    pthread_mutex_lock(&w->request_lock);
    requests = w->requests;
    pthread_mutex_unlock(&w->request_lock);

    if (requests & SYNC_WORKER_STOP) {
        log_verbose("%s worker: Got STOP request upon entering callback. "
                    "Ending stream.\n", MODULE_STR(s));
        return NULL;
    }

    pthread_mutex_lock(&b->lock);

    /* Get the index of the buffer that was just filled */
    samples_idx = sync_buf2idx(b, samples);

    if (b->resubmit_count == 0) {
        if (b->status[b->prod_i] == SYNC_BUFFER_EMPTY) {

            /* This buffer is now ready for the consumer */
            b->status[samples_idx] = SYNC_BUFFER_FULL;
            pthread_cond_signal(&b->buf_ready);

            /* Update the state of the buffer being submitted next */
            next_idx = b->prod_i;
            b->status[next_idx] = SYNC_BUFFER_IN_FLIGHT;
            next_buf = b->buffers[next_idx];

            /* Advance to the next buffer for the next callback */
            b->prod_i = (next_idx + 1) % b->num_buffers;

            log_verbose("%s worker: buf[%u] = full, buf[%u] = in_flight\n",
                        MODULE_STR(s), samples_idx, next_idx);

        } else {
            /* TODO propgate back the RX Overrun to the sync_rx() caller */
            log_debug("RX overrun @ buffer %u\r\n", samples_idx);

            next_buf = samples;
            b->resubmit_count = s->stream_config.num_xfers - 1;
        }
    } else {
        /* We're still recovering from an overrun at this point. Just
         * turn around and resubmit this buffer */
        next_buf = samples;
        b->resubmit_count--;
        log_verbose("Resubmitting buffer %u (%u resubmissions left)\r\n",
                    samples_idx, b->resubmit_count);
    }


    pthread_mutex_unlock(&b->lock);
    return next_buf;
}
Exemplo n.º 9
0
static sync_worker_state exec_idle_state(struct bladerf_sync *s)
{
    sync_worker_state next_state = SYNC_WORKER_STATE_IDLE;
    unsigned int requests;
    unsigned int i;

    pthread_mutex_lock(&s->worker->request_lock);

    while (s->worker->requests == 0) {
        log_verbose("%s worker: Waiting for pending requests\n", MODULE_STR(s));

        pthread_cond_wait(&s->worker->requests_pending,
                          &s->worker->request_lock);
    }

    requests = s->worker->requests;
    s->worker->requests = 0;
    pthread_mutex_unlock(&s->worker->request_lock);

    if (requests & SYNC_WORKER_STOP) {
        log_verbose("%s worker: Got request to stop\n",
                module2str(s->stream_config.module));

        next_state = SYNC_WORKER_STATE_SHUTTING_DOWN;

    } else if (requests & SYNC_WORKER_START) {
        log_verbose("%s worker: Got request to start\n",
                module2str(s->stream_config.module));
        pthread_mutex_lock(&s->buf_mgmt.lock);

        if (s->stream_config.module == BLADERF_MODULE_TX) {
            /* If we've previously timed out on a stream, we'll likely have some
            * stale buffers marked "in-flight" that have since been cancelled. */
            for (i = 0; i < s->buf_mgmt.num_buffers; i++) {
                if (s->buf_mgmt.status[i] == SYNC_BUFFER_IN_FLIGHT) {
                    s->buf_mgmt.status[i] = SYNC_BUFFER_EMPTY;
                }
            }

            pthread_cond_signal(&s->buf_mgmt.buf_ready);
        } else {
            assert(s->stream_config.module == BLADERF_MODULE_RX);
            s->buf_mgmt.prod_i = s->stream_config.num_xfers;

            for (i = 0; i < s->buf_mgmt.num_buffers; i++) {
                if (i < s->stream_config.num_xfers) {
                    s->buf_mgmt.status[i] = SYNC_BUFFER_IN_FLIGHT;
                } else if (s->buf_mgmt.status[i] == SYNC_BUFFER_IN_FLIGHT) {
                    s->buf_mgmt.status[i] = SYNC_BUFFER_EMPTY;
                }
            }
        }

        pthread_mutex_unlock(&s->buf_mgmt.lock);

        next_state = SYNC_WORKER_STATE_RUNNING;
    } else {
        log_warning("Invalid request value encountered: 0x%08X\n",
                    s->worker->requests);
    }

    return next_state;
}
Exemplo n.º 10
0
int sync_worker_init(struct bladerf_sync *s)
{
    int status = 0;
    s->worker = (struct sync_worker*) calloc(1, sizeof(*s->worker));

    if (s->worker == NULL) {
        status = BLADERF_ERR_MEM;
        goto worker_init_out;
    }

    s->worker->state = SYNC_WORKER_STATE_STARTUP;
    s->worker->err_code = 0;

    s->worker->cb = s->stream_config.module == BLADERF_MODULE_RX ?
                        rx_callback : tx_callback;

    status = bladerf_init_stream(&s->worker->stream,
                                 s->dev,
                                 s->worker->cb,
                                 &s->buf_mgmt.buffers,
                                 s->buf_mgmt.num_buffers,
                                 s->stream_config.format,
                                 s->stream_config.samples_per_buffer,
                                 s->stream_config.num_xfers,
                                 s);

    if (status != 0) {
        log_debug("%s worker: Failed to init stream: %s\n", MODULE_STR(s),
                  bladerf_strerror(status));
        goto worker_init_out;
    }


    status = pthread_mutex_init(&s->worker->state_lock, NULL);
    if (status != 0) {
        status = BLADERF_ERR_UNEXPECTED;
        goto worker_init_out;
    }

    status = pthread_cond_init(&s->worker->state_changed, NULL);
    if (status != 0) {
        status = BLADERF_ERR_UNEXPECTED;
        goto worker_init_out;
    }

    status = pthread_mutex_init(&s->worker->request_lock, NULL);
    if (status != 0) {
        status = BLADERF_ERR_UNEXPECTED;
        goto worker_init_out;
    }

    status = pthread_cond_init(&s->worker->requests_pending, NULL);
    if (status != 0) {
        status = BLADERF_ERR_UNEXPECTED;
        goto worker_init_out;
    }

    status = pthread_create(&s->worker->thread, NULL, sync_worker_task, s);
    if (status != 0) {
        status = BLADERF_ERR_UNEXPECTED;
        goto worker_init_out;
    }

    /* Wait until the worker thread has initialized and is ready to go */
    status = sync_worker_wait_for_state(s->worker, SYNC_WORKER_STATE_IDLE, 1000);
    if (status != 0) {
        status = BLADERF_ERR_TIMEOUT;
        goto worker_init_out;
    }

worker_init_out:
    if (status != 0) {
        free(s->worker);
        s->worker = NULL;
    }

    return status;
}