void *tx_task(void *arg) { sim_t *s = (sim_t *)arg; size_t samples_populated; while (1) { int16_t *tx_buffer_current = s->tx.buffer; unsigned int buffer_samples_remaining = SAMPLES_PER_BUFFER; while (buffer_samples_remaining > 0) { samples_populated = fifo_read(tx_buffer_current, buffer_samples_remaining, s); if (is_fifo_write_ready(s)) { pthread_cond_signal(&(s->fifo_write_ready)); /* printf("\rTime = %4.1f", s->time); s->time += 0.1; fflush(stdout); */ } // Advance the buffer pointer. buffer_samples_remaining -= (unsigned int)samples_populated; tx_buffer_current += (2 * samples_populated); } // If there were no errors, transmit the data buffer. bladerf_sync_tx(s->tx.dev, s->tx.buffer, SAMPLES_PER_BUFFER, NULL, TIMEOUT_MS); } }
static inline int dummy_tx(struct bladerf *dev) { int status; const unsigned int buf_len = CAL_BUF_LEN; uint16_t *buf = (uint16_t*) calloc(2 * buf_len, sizeof(buf[0])); if (buf == NULL) { return BLADERF_ERR_MEM; } status = bladerf_sync_config(dev, BLADERF_MODULE_TX, BLADERF_FORMAT_SC16_Q11, CAL_NUM_BUFS, buf_len, CAL_NUM_XFERS, CAL_TIMEOUT); if (status != 0) { goto error; } status = bladerf_sync_tx(dev, buf, buf_len, NULL, CAL_TIMEOUT); error: free(buf); return status; }
void BladeRfTxComponent::process() { //Get a DataSet from the input DataBuffer DataSet< complex<float> >* readDataSet = NULL; inBuf_->getReadData(readDataSet); // Check if we have to append dummy frames, samps must be multiple of 1024 size_t size = readDataSet->data.size(); if (size % BLADERF_SAMPLE_BLOCK_SIZE != 0) { int num_samps_to_append = BLADERF_SAMPLE_BLOCK_SIZE - (size % BLADERF_SAMPLE_BLOCK_SIZE); std::vector<std::complex<float> > samples(num_samps_to_append, std::complex<float>(0.0, 0.0)); readDataSet->data.insert(readDataSet->data.end(), samples.begin(), samples.end()); size += num_samps_to_append; } // Adjust raw buffer if needed if (rawSampleBuffer_.data.capacity() < size) rawSampleBuffer_.data.resize(size); // convert samples to bladeRF format for (int i = 0; i < size; i++) { rawSampleBuffer_.data[i].real(0xa000 | (int16_t)((readDataSet->data[i].real()) * 2000)); rawSampleBuffer_.data[i].imag(0x5000 | (int16_t)((readDataSet->data[i].imag()) * 2000)); } // Write samples to device int ret = bladerf_sync_tx(device_, &(rawSampleBuffer_.data.front()), size, NULL, BLADERF_SYNC_TIMEOUT_MS); if (ret != 0) { throw IrisException("Failed to send samples to device!"); LOG(LERROR) << bladerf_strerror(ret); } //Release the DataSet inBuf_->releaseReadData(readDataSet); }
static void * exec_tx_task(void *args) { bool run; int status = 0; struct cal_tx_task *task = (struct cal_tx_task*) args; MUTEX_LOCK(&task->lock); run = task->run; MUTEX_UNLOCK(&task->lock); while (run && status == 0) { status = bladerf_sync_tx(task->s->dev, task->samples, CAL_BUF_LEN, NULL, CAL_TIMEOUT); MUTEX_LOCK(&task->lock); run = task->run; MUTEX_UNLOCK(&task->lock); } MUTEX_LOCK(&task->lock); task->status = status; MUTEX_UNLOCK(&task->lock); return NULL; }
/** [tx_meta_now] */ int sync_tx_meta_now_example(struct bladerf *dev, int16_t *samples, unsigned int num_samples, unsigned int tx_count, unsigned int timeout_ms) { int status = 0; struct bladerf_metadata meta; unsigned int i; memset(&meta, 0, sizeof(meta)); /* Send entire burst worth of samples in one function call */ meta.flags = BLADERF_META_FLAG_TX_BURST_START | BLADERF_META_FLAG_TX_NOW | BLADERF_META_FLAG_TX_BURST_END; for (i = 0; i < tx_count && status == 0; i++) { /* Fetch or produce IQ samples...*/ produce_samples(samples, num_samples); status = bladerf_sync_tx(dev, samples, num_samples, &meta, timeout_ms); if (status != 0) { fprintf(stderr, "TX failed: %s\n", bladerf_strerror(status)); } else { uint64_t curr_ts; status = bladerf_get_timestamp(dev, BLADERF_MODULE_TX, &curr_ts); if (status != 0) { fprintf(stderr, "Failed to get current TX timestamp: %s\n", bladerf_strerror(status)); } else { printf("TX'd at approximately t=%016"PRIu64"\n", curr_ts); } /* Delay next transmission by approximately 5 ms * * This is a very imprecise, "quick and dirty" means to do so in * cases where no particular intra-burst time is required. */ usleep(5000); } } /* Wait for samples to be TX'd before completing. */ if (status == 0) { status = bladerf_get_timestamp(dev, BLADERF_MODULE_TX, &meta.timestamp); if (status != 0) { fprintf(stderr, "Failed to get current TX timestamp: %s\n", bladerf_strerror(status)); return status; } else { status = wait_for_timestamp(dev, BLADERF_MODULE_TX, meta.timestamp + 2 * num_samples, timeout_ms); if (status != 0) { fprintf(stderr, "Failed to wait for timestamp.\n"); } } } return status; }
void *tx_task(void *arg) { sim_t *s = (sim_t *)arg; size_t samples_populated; while (1) { int16_t *tx_buffer_current = s->tx.buffer; unsigned int buffer_samples_remaining = SAMPLES_PER_BUFFER; while (buffer_samples_remaining > 0) { pthread_mutex_lock(&(s->gps.lock)); while (get_sample_length(s) == 0) { pthread_cond_wait(&(s->fifo_read_ready), &(s->gps.lock)); } // assert(get_sample_length(s) > 0); samples_populated = fifo_read(tx_buffer_current, buffer_samples_remaining, s); pthread_mutex_unlock(&(s->gps.lock)); pthread_cond_signal(&(s->fifo_write_ready)); #if 0 if (is_fifo_write_ready(s)) { /* printf("\rTime = %4.1f", s->time); s->time += 0.1; fflush(stdout); */ } else if (is_finished_generation(s)) { goto out; } #endif // Advance the buffer pointer. buffer_samples_remaining -= (unsigned int)samples_populated; tx_buffer_current += (2 * samples_populated); } // If there were no errors, transmit the data buffer. bladerf_sync_tx(s->tx.dev, s->tx.buffer, SAMPLES_PER_BUFFER, NULL, TIMEOUT_MS); if (is_fifo_write_ready(s)) { /* printf("\rTime = %4.1f", s->time); s->time += 0.1; fflush(stdout); */ } else if (is_finished_generation(s)) { goto out; } } out: return NULL; }
static void * exec_tx_task(void *args) { bool run; int status = 0; struct cal_tx_task *task = (struct cal_tx_task*) args; pthread_mutex_lock(&task->lock); run = task->run; pthread_mutex_unlock(&task->lock); while (run && status == 0) { status = bladerf_sync_tx(task->dev, task->samples, CAL_BUF_LEN, NULL, CAL_TIMEOUT); pthread_mutex_lock(&task->lock); run = task->run; pthread_mutex_unlock(&task->lock); } pthread_mutex_lock(&task->lock); task->status = status; pthread_mutex_unlock(&task->lock); return NULL; }
/** [tx_meta_sched] */ int sync_tx_meta_sched_example(struct bladerf *dev, int16_t *samples, unsigned int num_samples, unsigned int tx_count, unsigned int samplerate, unsigned int timeout_ms) { int status = 0; unsigned int i; struct bladerf_metadata meta; memset(&meta, 0, sizeof(meta)); /* Send entire burst worth of samples in one function call */ meta.flags = BLADERF_META_FLAG_TX_BURST_START | BLADERF_META_FLAG_TX_BURST_END; /* Retrieve the current timestamp so we can schedule our transmission * in the future. */ status = bladerf_get_timestamp(dev, BLADERF_MODULE_TX, &meta.timestamp); if (status != 0) { fprintf(stderr, "Failed to get current TX timestamp: %s\n", bladerf_strerror(status)); return status; } else { printf("Current TX timestamp: %016"PRIu64"\n", meta.timestamp); } for (i = 0; i < tx_count && status == 0; i++) { /* Get sample to transmit... */ produce_samples(samples, num_samples); /* Schedule burst 5 ms into the future */ meta.timestamp += samplerate / 200; status = bladerf_sync_tx(dev, samples, num_samples, &meta, timeout_ms); if (status != 0) { fprintf(stderr, "TX failed: %s\n", bladerf_strerror(status)); return status; } else { printf("TX'd @ t=%016"PRIu64"\n", meta.timestamp); } } /* Wait for samples to finish being transmitted. */ if (status == 0) { meta.timestamp += 2 * num_samples; status = wait_for_timestamp(dev, BLADERF_MODULE_TX, meta.timestamp, timeout_ms); if (status != 0) { fprintf(stderr, "Failed to wait for timestamp.\n"); } } return status; }
int sync_rx_example(struct bladerf *dev) { int status, ret; bool done = false; bool have_tx_data = false; /** [user_buffers] */ /* "User" samples buffers and their associated sizes, in units of samples. * Recall that one sample = two int16_t values. */ int16_t *rx_samples = NULL; int16_t *tx_samples = NULL; const unsigned int samples_len = 10000; /* May be any (reasonable) size */ /* Allocate a buffer to store received samples in */ rx_samples = malloc(samples_len * 2 * 1 * sizeof(int16_t)); if (rx_samples == NULL) { perror("malloc"); return BLADERF_ERR_MEM; } /* Allocate a buffer to prepare transmit data in */ tx_samples = malloc(samples_len * 2 * 1 * sizeof(int16_t)); if (tx_samples == NULL) { perror("malloc"); free(rx_samples); return BLADERF_ERR_MEM; } /** [user_buffers] */ /* Initialize synch interface on RX and TX */ status = init_sync(dev); if (status != 0) { goto out; } /** [enable_modules] */ status = bladerf_enable_module(dev, BLADERF_RX, true); if (status != 0) { fprintf(stderr, "Failed to enable RX: %s\n", bladerf_strerror(status)); goto out; } status = bladerf_enable_module(dev, BLADERF_TX, true); if (status != 0) { fprintf(stderr, "Failed to enable TX: %s\n", bladerf_strerror(status)); goto out; } /** [enable_modules] */ /** [rxtx_loop] */ while (status == 0 && !done) { /* Receive samples */ status = bladerf_sync_rx(dev, rx_samples, samples_len, NULL, 5000); if (status == 0) { /* Process these samples, and potentially produce a response * to transmit */ done = do_work(rx_samples, samples_len, &have_tx_data, tx_samples, samples_len); if (!done && have_tx_data) { /* Transmit a response */ status = bladerf_sync_tx(dev, tx_samples, samples_len, NULL, 5000); if (status != 0) { fprintf(stderr, "Failed to TX samples: %s\n", bladerf_strerror(status)); } } } else { fprintf(stderr, "Failed to RX samples: %s\n", bladerf_strerror(status)); } } if (status == 0) { /* Wait a few seconds for any remaining TX samples to finish * reaching the RF front-end */ usleep(2000000); } /** [rxtx_loop] */ out: ret = status; /** [disable_modules] */ /* Disable RX, shutting down our underlying RX stream */ status = bladerf_enable_module(dev, BLADERF_RX, false); if (status != 0) { fprintf(stderr, "Failed to disable RX: %s\n", bladerf_strerror(status)); } /* Disable TX, shutting down our underlying TX stream */ status = bladerf_enable_module(dev, BLADERF_TX, false); if (status != 0) { fprintf(stderr, "Failed to disable TX: %s\n", bladerf_strerror(status)); } /* Free up our resources */ free(rx_samples); free(tx_samples); /** [disable_modules] */ return ret; }
static void * tx_task(void *args) { int status; int16_t *samples; unsigned int i; struct bladerf_metadata meta; uint64_t samples_left; struct test *t = (struct test *) args; bool stop = false; int16_t zeros[] = { 0, 0, 0, 0 }; samples = (int16_t*) malloc(2 * sizeof(samples[0]) * t->params->buf_size); if (samples == NULL) { perror("malloc"); return NULL; } memset(&meta, 0, sizeof(meta)); for (i = 0; i < (2 * t->params->buf_size); i += 2) { samples[i] = samples[i + 1] = TX_MAGNITUDE; } status = bladerf_get_timestamp(t->dev, BLADERF_MODULE_TX, &meta.timestamp); if (status != 0) { fprintf(stderr, "Failed to get current timestamp: %s\n", bladerf_strerror(status)); } meta.timestamp += 400000; for (i = 0; i < t->num_bursts && !stop; i++) { meta.flags = BLADERF_META_FLAG_TX_BURST_START; samples_left = t->bursts[i].duration; assert(samples_left <= UINT_MAX); if (i != 0) { meta.timestamp += (t->bursts[i-1].duration + t->bursts[i].gap); } while (samples_left != 0 && status == 0) { unsigned int to_send = uint_min(t->params->buf_size, (unsigned int) samples_left); status = bladerf_sync_tx(t->dev, samples, to_send, &meta, t->params->timeout_ms); if (status != 0) { fprintf(stderr, "Failed to TX @ burst %-4u with %"PRIu64 " samples left: %s\n", i + 1, samples_left, bladerf_strerror(status)); /* Stop the RX worker */ pthread_mutex_lock(&t->lock); t->stop = true; pthread_mutex_unlock(&t->lock); } meta.flags &= ~BLADERF_META_FLAG_TX_BURST_START; samples_left -= to_send; } /* Flush TX samples by ensuring we have 2 zero samples at the end * of our burst (as required by libbladeRF) */ if (status == 0) { meta.flags = BLADERF_META_FLAG_TX_BURST_END; status = bladerf_sync_tx(t->dev, zeros, 2, &meta, t->params->timeout_ms); if (status != 0) { fprintf(stderr, "Failed to flush TX: %s\n", bladerf_strerror(status)); /* Stop the RX worker */ pthread_mutex_lock(&t->lock); t->stop = true; pthread_mutex_unlock(&t->lock); } } pthread_mutex_lock(&t->lock); stop = t->stop; pthread_mutex_unlock(&t->lock); } /* Wait for samples to finish */ printf("TX: Waiting for samples to finish.\n"); fflush(stdout); status = wait_for_timestamp(t->dev, BLADERF_MODULE_TX, meta.timestamp + t->bursts[i - 1].duration, 3000); if (status != 0) { fprintf(stderr, "Failed to wait for TX to complete: %s\n", bladerf_strerror(status)); } free(samples); printf("TX: Exiting task.\n"); fflush(stdout); return NULL; }
/** [tx_meta_update] */ int sync_tx_meta_update_example(struct bladerf *dev, int16_t *samples, unsigned int num_samples, unsigned int tx_count, unsigned int samplerate, unsigned int timeout_ms) { int status = 0; unsigned int i; struct bladerf_metadata meta; int16_t zeros[] = { 0, 0, 0, 0 }; /* Two 0+0j samples */ memset(&meta, 0, sizeof(meta)); /* The first call to bladerf_sync_tx() will start our long "burst" at * a specific timestamp. * * In successive calls, we'll break this long "burst" up into shorter bursts * by using the BLADERF_META_FLAG_TX_UPDATE_TIMESTAMP flag with new * timestamps. The discontinuities will be zero-padded. */ meta.flags = BLADERF_META_FLAG_TX_BURST_START; /* Retrieve the current timestamp so we can schedule our transmission * in the future. */ status = bladerf_get_timestamp(dev, BLADERF_MODULE_TX, &meta.timestamp); if (status != 0) { fprintf(stderr, "Failed to get current TX timestamp: %s\n", bladerf_strerror(status)); return status; } else { printf("Current TX timestamp: %016"PRIu64"\n", meta.timestamp); } /* Start 5 ms in the future */ meta.timestamp += samplerate / 200; for (i = 0; i < tx_count && status == 0; i++) { /* Get sample to transmit... */ produce_samples(samples, num_samples); status = bladerf_sync_tx(dev, samples, num_samples, &meta, timeout_ms); if (status != 0) { fprintf(stderr, "TX failed: %s\n", bladerf_strerror(status)); return status; } else { printf("TX'd @ t=%016"PRIu64"\n", meta.timestamp); } /* Instruct bladerf_sync_tx() to position samples within this burst at * the specified timestamp. 0+0j will be transmitted up until that * point. */ meta.flags = BLADERF_META_FLAG_TX_UPDATE_TIMESTAMP; /* Schedule samples to be transmitted 1.25 ms after the completion of * the previous burst */ meta.timestamp += num_samples + samplerate / 800; } /* End the burst and flush remaining samples. */ meta.flags = BLADERF_META_FLAG_TX_BURST_END; status = bladerf_sync_tx(dev, zeros, 2, &meta, timeout_ms); /* Wait for samples to finish being transmitted. */ if (status == 0) { meta.timestamp += 2 * num_samples; status = wait_for_timestamp(dev, BLADERF_MODULE_TX, meta.timestamp, timeout_ms); if (status != 0) { fprintf(stderr, "Failed to wait for timestamp.\n"); } } else { fprintf(stderr, "Failed to complete burst: %s\n", bladerf_strerror(status)); } return status; }
int rf_blade_send_timed(void *h, void *data, int nsamples, time_t secs, double frac_secs, bool has_time_spec, bool blocking, bool is_start_of_burst, bool is_end_of_burst) { rf_blade_handler_t *handler = (rf_blade_handler_t*) h; struct bladerf_metadata meta; int status; if (!handler->tx_stream_enabled) { rf_blade_start_tx_stream(h); } if (2*nsamples > CONVERT_BUFFER_SIZE) { fprintf(stderr, "TX failed: nsamples exceeds buffer size (%d>%d)\n", nsamples, CONVERT_BUFFER_SIZE); return -1; } srslte_vec_convert_fi(data, handler->tx_buffer, 2048, 2*nsamples); memset(&meta, 0, sizeof(meta)); if (is_start_of_burst) { if (has_time_spec) { secs_to_timestamps(handler->tx_rate, secs, frac_secs, &meta.timestamp); } else { meta.flags |= BLADERF_META_FLAG_TX_NOW; } meta.flags |= BLADERF_META_FLAG_TX_BURST_START; } if (is_end_of_burst) { meta.flags |= BLADERF_META_FLAG_TX_BURST_END; } srslte_rf_error_t error; bzero(&error, sizeof(srslte_rf_error_t)); status = bladerf_sync_tx(handler->dev, handler->tx_buffer, nsamples, &meta, 2000); if (status == BLADERF_ERR_TIME_PAST) { if (blade_error_handler) { error.type = SRSLTE_RF_ERROR_LATE; blade_error_handler(error); } else { fprintf(stderr, "TX failed: %s\n", bladerf_strerror(status)); } } else if (status) { fprintf(stderr, "TX failed: %s\n", bladerf_strerror(status)); return status; } else if (meta.status == BLADERF_META_STATUS_UNDERRUN) { if (blade_error_handler) { error.type = SRSLTE_RF_ERROR_UNDERFLOW; blade_error_handler(error); } else { fprintf(stderr, "TX warning: underflow detected.\n"); } } return nsamples; }
/* We've found that running samples through the LMS6 tends to be required * for the TX LPF calibration to converge */ static inline int tx_lpf_dummy_tx(struct bladerf *dev) { int status; int retval = 0; struct bladerf_metadata meta; int16_t zero_sample[] = { 0, 0 }; bladerf_loopback loopback_backup; struct bladerf_rational_rate sample_rate_backup; memset(&meta, 0, sizeof(meta)); status = bladerf_get_loopback(dev, &loopback_backup); if (status != 0) { return status; } status = bladerf_get_rational_sample_rate(dev, BLADERF_MODULE_TX, &sample_rate_backup); if (status != 0) { return status; } status = bladerf_set_loopback(dev, BLADERF_LB_BB_TXVGA1_RXVGA2); if (status != 0) { goto out; } status = bladerf_set_sample_rate(dev, BLADERF_MODULE_TX, 3000000, NULL); if (status != 0) { goto out; } status = bladerf_sync_config(dev, BLADERF_MODULE_TX, BLADERF_FORMAT_SC16_Q11_META, 64, 16384, 16, 1000); if (status != 0) { goto out; } status = bladerf_enable_module(dev, BLADERF_MODULE_TX, true); if (status != 0) { goto out; } meta.flags = BLADERF_META_FLAG_TX_BURST_START | BLADERF_META_FLAG_TX_BURST_END | BLADERF_META_FLAG_TX_NOW; status = bladerf_sync_tx(dev, zero_sample, 1, &meta, 2000); if (status != 0) { goto out; } out: status = bladerf_enable_module(dev, BLADERF_MODULE_TX, false); if (status != 0 && retval == 0) { retval = status; } status = bladerf_set_rational_sample_rate(dev, BLADERF_MODULE_TX, &sample_rate_backup, NULL); if (status != 0 && retval == 0) { retval = status; } status = bladerf_set_loopback(dev, loopback_backup); if (status != 0 && retval == 0) { retval = status; } return retval; }
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; }
/** [example_snippet] */ int sync_rx_example(struct bladerf *dev) { int status, ret; bool done = false; /* "User" samples buffers and their associated sizes, in units of samples. * Recall that one sample = two int16_t values. */ int16_t *rx_samples = NULL; int16_t *tx_samples = NULL; const unsigned int samples_len = 10000; /* May be any (reasonable) size */ /* These items configure the underlying asynch stream used by the sync * interface. The "buffer" here refers to those used internally by worker * threads, not the `samples` buffer above. */ const unsigned int num_buffers = 16; const unsigned int buffer_size = 8192; /* Must be a multiple of 1024 */ const unsigned int num_transfers = 8; const unsigned int timeout_ms = 3500; /* Allocate a buffer to store received samples in */ rx_samples = malloc(samples_len * 2 * sizeof(int16_t)); if (rx_samples == NULL) { perror("malloc"); return BLADERF_ERR_MEM; } /* Allocate a buffer to prepare transmit data in */ tx_samples = malloc(samples_len * 2 * sizeof(int16_t)); if (tx_samples == NULL) { perror("malloc"); free(rx_samples); return BLADERF_ERR_MEM; } /* Configure both the device's RX and TX modules for use with the synchronous * interface. SC16 Q11 samples *without* metadata are used. */ status = bladerf_sync_config(dev, BLADERF_MODULE_RX, BLADERF_FORMAT_SC16_Q11, num_buffers, buffer_size, num_transfers, timeout_ms); if (status != 0) { fprintf(stderr, "Failed to configure RX sync interface: %s\n", bladerf_strerror(status)); goto out; } status = bladerf_sync_config(dev, BLADERF_MODULE_TX, BLADERF_FORMAT_SC16_Q11, num_buffers, buffer_size, num_transfers, timeout_ms); if (status != 0) { fprintf(stderr, "Failed to configure TX sync interface: %s\n", bladerf_strerror(status)); goto out; } /* We must always enable the modules *after* calling bladerf_sync_config(), * and *before* attempting to RX or TX samples. */ status = bladerf_enable_module(dev, BLADERF_MODULE_RX, true); if (status != 0) { fprintf(stderr, "Failed to enable RX module: %s\n", bladerf_strerror(status)); goto out; } status = bladerf_enable_module(dev, BLADERF_MODULE_TX, true); if (status != 0) { fprintf(stderr, "Failed to enable RX module: %s\n", bladerf_strerror(status)); goto out; } /* Receive samples and do work on them and then transmit a response. * * Note we transmit more than `buffer_size` samples to ensure that our * samples are written to the FPGA. (The samples are sent when the * synchronous interface's internal buffer of `buffer_size` samples is * filled.) This is generally not nececssary if you are continuously * streaming TX data. Otherwise, you may need to zero-pad your TX data to * achieve this. */ while (status == 0 && !done) { status = bladerf_sync_rx(dev, rx_samples, samples_len, NULL, 5000); if (status == 0) { done = do_work(rx_samples, samples_len, tx_samples, samples_len); if (!done) { status = bladerf_sync_tx(dev, tx_samples, samples_len, NULL, 5000); if (status != 0) { fprintf(stderr, "Failed to TX samples: %s\n", bladerf_strerror(status)); } } } else { fprintf(stderr, "Failed to RX samples: %s\n", bladerf_strerror(status)); } } if (status == 0) { /* Wait a few seconds for any remaining TX samples to finish */ usleep(2000000); } out: ret = status; /* Disable RX module, shutting down our underlying RX stream */ status = bladerf_enable_module(dev, BLADERF_MODULE_RX, false); if (status != 0) { fprintf(stderr, "Failed to disable RX module: %s\n", bladerf_strerror(status)); } /* Disable TX module, shutting down our underlying TX stream */ status = bladerf_enable_module(dev, BLADERF_MODULE_TX, false); if (status != 0) { fprintf(stderr, "Failed to disable TX module: %s\n", bladerf_strerror(status)); } /* Free up our resources */ free(rx_samples); free(tx_samples); return ret; }
static int run(struct bladerf *dev, struct app_params *p, const struct test_case *t) { int status, status_out, status_wait; unsigned int samples_left; size_t i; struct bladerf_metadata meta; int16_t *samples, *buf; samples = calloc(2 * sizeof(int16_t), t->burst_len + 2); if (samples == NULL) { perror("malloc"); return BLADERF_ERR_MEM; } /* Leave the last two samples zero */ for (i = 0; i < (2 * t->burst_len); i += 2) { samples[i] = samples[i + 1] = MAGNITUDE; } memset(&meta, 0, sizeof(meta)); status = perform_sync_init(dev, BLADERF_MODULE_TX, t->buf_len, p); if (status != 0) { goto out; } status = bladerf_get_timestamp(dev, BLADERF_MODULE_TX, &meta.timestamp); if (status != 0) { fprintf(stderr, "Failed to get timestamp: %s\n", bladerf_strerror(status)); goto out; } else { printf("Initial timestamp: 0x%016"PRIx64"\n", meta.timestamp); } meta.timestamp += 200000; for (i = 0; i < t->iterations && status == 0; i++) { meta.flags = BLADERF_META_FLAG_TX_BURST_START; samples_left = t->burst_len + 2; buf = samples; printf("Sending burst @ %llu\n", (unsigned long long) meta.timestamp); while (samples_left && status == 0) { unsigned int to_send = uint_min(p->buf_size, samples_left); if (to_send == samples_left) { meta.flags |= BLADERF_META_FLAG_TX_BURST_END; } else { meta.flags &= ~BLADERF_META_FLAG_TX_BURST_END; } status = bladerf_sync_tx(dev, buf, to_send, &meta, 10000); //p->timeout_ms); if (status != 0) { fprintf(stderr, "TX failed @ iteration (%u) %s\n", (unsigned int )i, bladerf_strerror(status)); } meta.flags &= ~BLADERF_META_FLAG_TX_BURST_START; samples_left -= to_send; buf += 2 * to_send; } meta.timestamp += (t->burst_len + t->gap_len - 2); } printf("Waiting for samples to finish...\n"); fflush(stdout); /* Wait for samples to be transmitted before shutting down the TX module */ status_wait = wait_for_timestamp(dev, BLADERF_MODULE_TX, meta.timestamp - t->gap_len + 2, 3000); if (status_wait != 0) { status = first_error(status, status_wait); fprintf(stderr, "Failed to wait for TX to finish: %s\n", bladerf_strerror(status_wait)); } out: status_out = bladerf_enable_module(dev, BLADERF_MODULE_TX, false); if (status_out != 0) { fprintf(stderr, "Failed to disable TX module: %s\n", bladerf_strerror(status)); } else { printf("Done waiting.\n"); fflush(stdout); } status = first_error(status, status_out); free(samples); return status; }