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; }
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; }
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; }