|
|
|
@ -19,17 +19,18 @@
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <uhd.h>
|
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
#include <pthread.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
#include <uhd.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <pthread.h>
|
|
|
|
|
|
|
|
|
|
#include "srslte/srslte.h"
|
|
|
|
|
#include "rf_uhd_imp.h"
|
|
|
|
|
#include "rf_helper.h"
|
|
|
|
|
#include "srslte/srslte.h"
|
|
|
|
|
#include "uhd_c_api.h"
|
|
|
|
|
|
|
|
|
|
#include "rf_uhd_imp.h"
|
|
|
|
|
|
|
|
|
|
#define HAVE_ASYNC_THREAD 1
|
|
|
|
|
|
|
|
|
|
#if UHD_VERSION < 3130000
|
|
|
|
@ -37,7 +38,7 @@
|
|
|
|
|
#endif /* UHD_VERSION < 3140000 */
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
char *devname;
|
|
|
|
|
char* devname;
|
|
|
|
|
uhd_usrp_handle usrp;
|
|
|
|
|
uhd_rx_streamer_handle rx_stream;
|
|
|
|
|
uhd_tx_streamer_handle tx_stream;
|
|
|
|
@ -64,14 +65,15 @@ typedef struct {
|
|
|
|
|
pthread_mutex_t tx_mutex;
|
|
|
|
|
} rf_uhd_handler_t;
|
|
|
|
|
|
|
|
|
|
void suppress_handler(const char *x)
|
|
|
|
|
void suppress_handler(const char* x)
|
|
|
|
|
{
|
|
|
|
|
// do nothing
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cf_t zero_mem[64*1024];
|
|
|
|
|
cf_t zero_mem[64 * 1024];
|
|
|
|
|
|
|
|
|
|
static void log_overflow(rf_uhd_handler_t *h) {
|
|
|
|
|
static void log_overflow(rf_uhd_handler_t* h)
|
|
|
|
|
{
|
|
|
|
|
if (h->uhd_error_handler) {
|
|
|
|
|
srslte_rf_error_t error;
|
|
|
|
|
bzero(&error, sizeof(srslte_rf_error_t));
|
|
|
|
@ -80,18 +82,20 @@ static void log_overflow(rf_uhd_handler_t *h) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void log_late(rf_uhd_handler_t *h, bool is_rx) {
|
|
|
|
|
static void log_late(rf_uhd_handler_t* h, bool is_rx)
|
|
|
|
|
{
|
|
|
|
|
if (h->uhd_error_handler) {
|
|
|
|
|
srslte_rf_error_t error;
|
|
|
|
|
bzero(&error, sizeof(srslte_rf_error_t));
|
|
|
|
|
error.opt = is_rx?1:0;
|
|
|
|
|
error.opt = is_rx ? 1 : 0;
|
|
|
|
|
error.type = SRSLTE_RF_ERROR_LATE;
|
|
|
|
|
h->uhd_error_handler(error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if HAVE_ASYNC_THREAD
|
|
|
|
|
static void log_underflow(rf_uhd_handler_t *h) {
|
|
|
|
|
static void log_underflow(rf_uhd_handler_t* h)
|
|
|
|
|
{
|
|
|
|
|
if (h->uhd_error_handler) {
|
|
|
|
|
srslte_rf_error_t error;
|
|
|
|
|
bzero(&error, sizeof(srslte_rf_error_t));
|
|
|
|
@ -101,7 +105,8 @@ static void log_underflow(rf_uhd_handler_t *h) {
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static void log_rx_error(rf_uhd_handler_t *h) {
|
|
|
|
|
static void log_rx_error(rf_uhd_handler_t* h)
|
|
|
|
|
{
|
|
|
|
|
if (h->uhd_error_handler) {
|
|
|
|
|
char error_string[512];
|
|
|
|
|
uhd_usrp_last_error(h->usrp, error_string, 512);
|
|
|
|
@ -115,11 +120,12 @@ static void log_rx_error(rf_uhd_handler_t *h) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if HAVE_ASYNC_THREAD
|
|
|
|
|
static void* async_thread(void *h) {
|
|
|
|
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
|
|
|
|
static void* async_thread(void* h)
|
|
|
|
|
{
|
|
|
|
|
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
|
|
|
|
|
uhd_async_metadata_handle md;
|
|
|
|
|
uhd_async_metadata_make(&md);
|
|
|
|
|
while(handler->async_thread_running) {
|
|
|
|
|
while (handler->async_thread_running) {
|
|
|
|
|
bool valid;
|
|
|
|
|
uhd_error err = uhd_tx_streamer_recv_async_msg(handler->tx_stream, &md, 0.5, &valid);
|
|
|
|
|
if (err == UHD_ERROR_NONE) {
|
|
|
|
@ -143,22 +149,23 @@ static void* async_thread(void *h) {
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
void rf_uhd_suppress_stdout(void *h) {
|
|
|
|
|
void rf_uhd_suppress_stdout(void* h)
|
|
|
|
|
{
|
|
|
|
|
rf_uhd_register_msg_handler_c(suppress_handler);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void rf_uhd_register_error_handler(void *h, srslte_rf_error_handler_t new_handler)
|
|
|
|
|
void rf_uhd_register_error_handler(void* h, srslte_rf_error_handler_t new_handler)
|
|
|
|
|
{
|
|
|
|
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
|
|
|
|
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
|
|
|
|
|
handler->uhd_error_handler = new_handler;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool find_string(uhd_string_vector_handle h, char *str)
|
|
|
|
|
static bool find_string(uhd_string_vector_handle h, char* str)
|
|
|
|
|
{
|
|
|
|
|
char buff[128];
|
|
|
|
|
size_t n;
|
|
|
|
|
uhd_string_vector_size(h, &n);
|
|
|
|
|
for (int i=0;i<n;i++) {
|
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
|
uhd_string_vector_at(h, i, buff, 128);
|
|
|
|
|
if (strstr(buff, str)) {
|
|
|
|
|
return true;
|
|
|
|
@ -167,76 +174,91 @@ static bool find_string(uhd_string_vector_handle h, char *str)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool isLocked(rf_uhd_handler_t *handler, char *sensor_name, bool is_rx, uhd_sensor_value_handle *value_h)
|
|
|
|
|
// timeout in ms
|
|
|
|
|
static uhd_error
|
|
|
|
|
wait_sensor_locked(rf_uhd_handler_t* handler, char* sensor_name, bool is_mboard, int timeout, bool* is_locked)
|
|
|
|
|
{
|
|
|
|
|
bool val_out = false;
|
|
|
|
|
uhd_error error;
|
|
|
|
|
*is_locked = false;
|
|
|
|
|
|
|
|
|
|
if (sensor_name) {
|
|
|
|
|
if (is_rx) {
|
|
|
|
|
uhd_usrp_get_rx_sensor(handler->usrp, sensor_name, 0, value_h);
|
|
|
|
|
uhd_sensor_value_handle value_h;
|
|
|
|
|
uhd_string_vector_handle sensors;
|
|
|
|
|
|
|
|
|
|
uhd_string_vector_make(&sensors);
|
|
|
|
|
uhd_sensor_value_make_from_bool(&value_h, "", true, "True", "False");
|
|
|
|
|
if (is_mboard) {
|
|
|
|
|
// motherboard sensor
|
|
|
|
|
error = uhd_usrp_get_mboard_sensor_names(handler->usrp, 0, &sensors);
|
|
|
|
|
} else {
|
|
|
|
|
uhd_usrp_get_mboard_sensor(handler->usrp, sensor_name, 0, value_h);
|
|
|
|
|
// daughterboard sensor
|
|
|
|
|
error = uhd_usrp_get_rx_sensor_names(handler->usrp, 0, &sensors);
|
|
|
|
|
}
|
|
|
|
|
uhd_sensor_value_to_bool(*value_h, &val_out);
|
|
|
|
|
|
|
|
|
|
if (error == UHD_ERROR_NONE && find_string(sensors, sensor_name)) {
|
|
|
|
|
do {
|
|
|
|
|
if (is_mboard) {
|
|
|
|
|
error = uhd_usrp_get_mboard_sensor(handler->usrp, sensor_name, 0, &value_h);
|
|
|
|
|
} else {
|
|
|
|
|
usleep(500);
|
|
|
|
|
val_out = true;
|
|
|
|
|
error = uhd_usrp_get_rx_sensor(handler->usrp, sensor_name, 0, &value_h);
|
|
|
|
|
}
|
|
|
|
|
if (error != UHD_ERROR_NONE) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
uhd_sensor_value_to_bool(value_h, is_locked);
|
|
|
|
|
usleep(1000); // 1ms
|
|
|
|
|
timeout -= 1; // 1ms
|
|
|
|
|
} while (*is_locked == false && timeout > 0);
|
|
|
|
|
}
|
|
|
|
|
if (error != UHD_ERROR_NONE) {
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
"%s has no sensor \"%s\", or reading failed. UHD error: %i\n",
|
|
|
|
|
is_mboard ? "Motherboard" : "Daugherboard",
|
|
|
|
|
sensor_name,
|
|
|
|
|
error);
|
|
|
|
|
// board doesn't have this sensor, sleep for timeout
|
|
|
|
|
*is_locked = true;
|
|
|
|
|
usleep(timeout * 1000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return val_out;
|
|
|
|
|
uhd_string_vector_free(&sensors);
|
|
|
|
|
uhd_sensor_value_free(&value_h);
|
|
|
|
|
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char* rf_uhd_devname(void* h)
|
|
|
|
|
{
|
|
|
|
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
|
|
|
|
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
|
|
|
|
|
return handler->devname;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool rf_uhd_rx_wait_lo_locked(void *h)
|
|
|
|
|
bool rf_uhd_rx_wait_lo_locked(void* h)
|
|
|
|
|
{
|
|
|
|
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
|
|
|
|
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
|
|
|
|
|
|
|
|
|
|
uhd_string_vector_handle mb_sensors;
|
|
|
|
|
uhd_string_vector_handle rx_sensors;
|
|
|
|
|
char *sensor_name;
|
|
|
|
|
uhd_sensor_value_handle value_h;
|
|
|
|
|
uhd_string_vector_make(&mb_sensors);
|
|
|
|
|
uhd_string_vector_make(&rx_sensors);
|
|
|
|
|
uhd_sensor_value_make_from_bool(&value_h, "", true, "True", "False");
|
|
|
|
|
uhd_usrp_get_mboard_sensor_names(handler->usrp, 0, &mb_sensors);
|
|
|
|
|
uhd_usrp_get_rx_sensor_names(handler->usrp, 0, &rx_sensors);
|
|
|
|
|
// wait for clock source to lock
|
|
|
|
|
char* sensor_name = "lo_locked";
|
|
|
|
|
bool is_locked = false;
|
|
|
|
|
|
|
|
|
|
/*if (find_string(rx_sensors, "lo_locked")) {
|
|
|
|
|
sensor_name = "lo_locked";
|
|
|
|
|
} else */if (find_string(mb_sensors, "ref_locked")) {
|
|
|
|
|
sensor_name = "ref_locked";
|
|
|
|
|
} else {
|
|
|
|
|
sensor_name = NULL;
|
|
|
|
|
}
|
|
|
|
|
// blocks until sensor is blocked
|
|
|
|
|
uhd_error error = wait_sensor_locked(handler, sensor_name, false, 300, &is_locked);
|
|
|
|
|
|
|
|
|
|
double report = 0.0;
|
|
|
|
|
while (!isLocked(handler, sensor_name, false, &value_h) && report < 30.0) {
|
|
|
|
|
report += 0.1;
|
|
|
|
|
usleep(1000);
|
|
|
|
|
if (!is_locked || error != UHD_ERROR_NONE) {
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
"Could not lock reference clock source. Sensor: %s=%s, UHD error: %i\n",
|
|
|
|
|
sensor_name,
|
|
|
|
|
is_locked ? "true" : "false",
|
|
|
|
|
error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool val = isLocked(handler, sensor_name, false, &value_h);
|
|
|
|
|
|
|
|
|
|
uhd_string_vector_free(&mb_sensors);
|
|
|
|
|
uhd_string_vector_free(&rx_sensors);
|
|
|
|
|
uhd_sensor_value_free(&value_h);
|
|
|
|
|
|
|
|
|
|
return val;
|
|
|
|
|
return is_locked;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int rf_uhd_start_rx_stream(void *h, bool now)
|
|
|
|
|
int rf_uhd_start_rx_stream(void* h, bool now)
|
|
|
|
|
{
|
|
|
|
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
|
|
|
|
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
|
|
|
|
|
|
|
|
|
|
uhd_stream_cmd_t stream_cmd = {
|
|
|
|
|
.stream_mode = UHD_STREAM_MODE_START_CONTINUOUS,
|
|
|
|
|
.stream_now = now
|
|
|
|
|
};
|
|
|
|
|
uhd_stream_cmd_t stream_cmd = {.stream_mode = UHD_STREAM_MODE_START_CONTINUOUS, .stream_now = now};
|
|
|
|
|
if (!now) {
|
|
|
|
|
uhd_usrp_get_time_now(handler->usrp, 0, &stream_cmd.time_spec_full_secs, &stream_cmd.time_spec_frac_secs);
|
|
|
|
|
stream_cmd.time_spec_frac_secs += 0.2;
|
|
|
|
@ -249,35 +271,34 @@ int rf_uhd_start_rx_stream(void *h, bool now)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int rf_uhd_stop_rx_stream(void *h)
|
|
|
|
|
int rf_uhd_stop_rx_stream(void* h)
|
|
|
|
|
{
|
|
|
|
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
|
|
|
|
uhd_stream_cmd_t stream_cmd = {
|
|
|
|
|
.stream_mode = UHD_STREAM_MODE_STOP_CONTINUOUS,
|
|
|
|
|
.stream_now = true
|
|
|
|
|
};
|
|
|
|
|
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
|
|
|
|
|
uhd_stream_cmd_t stream_cmd = {.stream_mode = UHD_STREAM_MODE_STOP_CONTINUOUS, .stream_now = true};
|
|
|
|
|
uhd_rx_streamer_issue_stream_cmd(handler->rx_stream, &stream_cmd);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void rf_uhd_flush_buffer(void *h)
|
|
|
|
|
void rf_uhd_flush_buffer(void* h)
|
|
|
|
|
{
|
|
|
|
|
int n;
|
|
|
|
|
cf_t tmp1[1024];
|
|
|
|
|
cf_t tmp2[1024];
|
|
|
|
|
void *data[2] = {tmp1, tmp2};
|
|
|
|
|
void* data[2] = {tmp1, tmp2};
|
|
|
|
|
do {
|
|
|
|
|
n = rf_uhd_recv_with_time_multi(h, data, 1024, 0, NULL, NULL);
|
|
|
|
|
} while (n > 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool rf_uhd_has_rssi(void *h) {
|
|
|
|
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
|
|
|
|
bool rf_uhd_has_rssi(void* h)
|
|
|
|
|
{
|
|
|
|
|
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
|
|
|
|
|
return handler->has_rssi;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool get_has_rssi(void *h) {
|
|
|
|
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
|
|
|
|
bool get_has_rssi(void* h)
|
|
|
|
|
{
|
|
|
|
|
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
|
|
|
|
|
uhd_string_vector_handle rx_sensors;
|
|
|
|
|
uhd_string_vector_make(&rx_sensors);
|
|
|
|
|
uhd_usrp_get_rx_sensor_names(handler->usrp, 0, &rx_sensors);
|
|
|
|
@ -286,8 +307,9 @@ bool get_has_rssi(void *h) {
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float rf_uhd_get_rssi(void *h) {
|
|
|
|
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
|
|
|
|
float rf_uhd_get_rssi(void* h)
|
|
|
|
|
{
|
|
|
|
|
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
|
|
|
|
|
if (handler->has_rssi) {
|
|
|
|
|
double val_out;
|
|
|
|
|
|
|
|
|
@ -303,17 +325,17 @@ float rf_uhd_get_rssi(void *h) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int rf_uhd_open(char *args, void **h)
|
|
|
|
|
int rf_uhd_open(char* args, void** h)
|
|
|
|
|
{
|
|
|
|
|
return rf_uhd_open_multi(args, h, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
|
|
|
|
|
int rf_uhd_open_multi(char* args, void** h, uint32_t nof_channels)
|
|
|
|
|
{
|
|
|
|
|
if (h) {
|
|
|
|
|
*h = NULL;
|
|
|
|
|
|
|
|
|
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) malloc(sizeof(rf_uhd_handler_t));
|
|
|
|
|
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)malloc(sizeof(rf_uhd_handler_t));
|
|
|
|
|
if (!handler) {
|
|
|
|
|
perror("malloc");
|
|
|
|
|
return -1;
|
|
|
|
@ -347,10 +369,10 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
|
|
|
|
|
// Initialize handler
|
|
|
|
|
handler->uhd_error_handler = NULL;
|
|
|
|
|
|
|
|
|
|
bzero(zero_mem, sizeof(cf_t)*64*1024);
|
|
|
|
|
bzero(zero_mem, sizeof(cf_t) * 64 * 1024);
|
|
|
|
|
|
|
|
|
|
// Check external clock argument
|
|
|
|
|
enum {DEFAULT, EXTERNAL, GPSDO} clock_src;
|
|
|
|
|
enum { DEFAULT, EXTERNAL, GPSDO } clock_src;
|
|
|
|
|
if (strstr(args, "clock=external")) {
|
|
|
|
|
REMOVE_SUBSTRING_WITHCOMAS(args, "clock=external");
|
|
|
|
|
clock_src = EXTERNAL;
|
|
|
|
@ -371,7 +393,7 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Set over the wire format
|
|
|
|
|
char *otw_format = "sc16";
|
|
|
|
|
char* otw_format = "sc16";
|
|
|
|
|
if (strstr(args, "otw_format=sc12")) {
|
|
|
|
|
REMOVE_SUBSTRING_WITHCOMAS(args, "otw_format=sc12");
|
|
|
|
|
otw_format = "sc12";
|
|
|
|
@ -386,7 +408,7 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
|
|
|
|
|
// Set transmitter subdevice spec string
|
|
|
|
|
const char tx_subdev_arg[] = "tx_subdev_spec=";
|
|
|
|
|
char tx_subdev_str[64] = {0};
|
|
|
|
|
char *tx_subdev_ptr = strstr(args, tx_subdev_arg);
|
|
|
|
|
char* tx_subdev_ptr = strstr(args, tx_subdev_arg);
|
|
|
|
|
if (tx_subdev_ptr) {
|
|
|
|
|
copy_subdev_string(tx_subdev_str, tx_subdev_ptr + strlen(tx_subdev_arg));
|
|
|
|
|
}
|
|
|
|
@ -394,7 +416,7 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
|
|
|
|
|
// Set receiver subdevice spec string
|
|
|
|
|
const char rx_subdev_arg[] = "rx_subdev_spec=";
|
|
|
|
|
char rx_subdev_str[64] = {0};
|
|
|
|
|
char *rx_subdev_ptr = strstr(args, rx_subdev_arg);
|
|
|
|
|
char* rx_subdev_ptr = strstr(args, rx_subdev_arg);
|
|
|
|
|
if (rx_subdev_ptr) {
|
|
|
|
|
copy_subdev_string(rx_subdev_str, rx_subdev_ptr + strlen(rx_subdev_arg));
|
|
|
|
|
}
|
|
|
|
@ -410,7 +432,7 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If device type or name not given in args, choose a B200 */
|
|
|
|
|
if (args[0]=='\0') {
|
|
|
|
|
if (args[0] == '\0') {
|
|
|
|
|
if (find_string(devices_str, "type=b200") && !strstr(args, "recv_frame_size")) {
|
|
|
|
|
// If B200 is available, use it
|
|
|
|
|
args = "type=b200,master_clock_rate=23.04e6";
|
|
|
|
@ -437,7 +459,7 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
|
|
|
|
|
} else {
|
|
|
|
|
// If args is set and x300 type is specified, make sure master_clock_rate is defined
|
|
|
|
|
if (strstr(args, "type=x300") && !strstr(args, "master_clock_rate")) {
|
|
|
|
|
sprintf(args2, "%s,master_clock_rate=184.32e6",args);
|
|
|
|
|
sprintf(args2, "%s,master_clock_rate=184.32e6", args);
|
|
|
|
|
args = args2;
|
|
|
|
|
handler->current_master_clock = 184320000;
|
|
|
|
|
handler->dynamic_rate = false;
|
|
|
|
@ -509,13 +531,31 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
|
|
|
|
|
handler->devname = "uhd_unknown";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool is_locked = false;
|
|
|
|
|
char* sensor_name = "";
|
|
|
|
|
|
|
|
|
|
// Set external clock reference
|
|
|
|
|
if (clock_src == EXTERNAL) {
|
|
|
|
|
uhd_usrp_set_clock_source(handler->usrp, "external", 0);
|
|
|
|
|
uhd_usrp_set_time_source(handler->usrp, "external", 0);
|
|
|
|
|
sensor_name = "ref_locked";
|
|
|
|
|
} else if (clock_src == GPSDO) {
|
|
|
|
|
uhd_usrp_set_clock_source(handler->usrp, "gpsdo", 0);
|
|
|
|
|
uhd_usrp_set_time_source(handler->usrp, "gpsdo", 0);
|
|
|
|
|
sensor_name = "gps_locked";
|
|
|
|
|
}
|
|
|
|
|
// wait until external reference / GPS is locked
|
|
|
|
|
if (clock_src != DEFAULT) {
|
|
|
|
|
// blocks until clock source is locked
|
|
|
|
|
error = wait_sensor_locked(handler, sensor_name, true, 300, &is_locked);
|
|
|
|
|
|
|
|
|
|
if (!is_locked || error != UHD_ERROR_NONE) {
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
"Could not lock reference clock source. Sensor: %s=%s, UHD error: %i\n",
|
|
|
|
|
sensor_name,
|
|
|
|
|
is_locked ? "true" : "false",
|
|
|
|
|
error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handler->has_rssi = get_has_rssi(handler);
|
|
|
|
@ -533,7 +573,7 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
|
|
|
|
|
handler->nof_tx_channels = nof_channels;
|
|
|
|
|
|
|
|
|
|
/* Set default rate to avoid decimation warnings */
|
|
|
|
|
for (int i=0;i<nof_channels;i++) {
|
|
|
|
|
for (int i = 0; i < nof_channels; i++) {
|
|
|
|
|
uhd_usrp_set_rx_rate(handler->usrp, 1.92e6, i);
|
|
|
|
|
uhd_usrp_set_tx_rate(handler->usrp, 1.92e6, i);
|
|
|
|
|
}
|
|
|
|
@ -578,7 +618,7 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
|
|
|
|
|
uhd_tx_metadata_make(&handler->tx_md, false, 0, 0, false, false);
|
|
|
|
|
|
|
|
|
|
// Set starting gain to half maximum in case of using AGC
|
|
|
|
|
rf_uhd_set_rx_gain(handler, handler->info.max_rx_gain*0.7);
|
|
|
|
|
rf_uhd_set_rx_gain(handler, handler->info.max_rx_gain * 0.7);
|
|
|
|
|
|
|
|
|
|
#if HAVE_ASYNC_THREAD
|
|
|
|
|
if (start_async_thread) {
|
|
|
|
@ -600,12 +640,11 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int rf_uhd_close(void *h)
|
|
|
|
|
int rf_uhd_close(void* h)
|
|
|
|
|
{
|
|
|
|
|
rf_uhd_stop_rx_stream(h);
|
|
|
|
|
|
|
|
|
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
|
|
|
|
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
|
|
|
|
|
|
|
|
|
|
uhd_tx_metadata_free(&handler->tx_md);
|
|
|
|
|
uhd_rx_metadata_free(&handler->rx_md_first);
|
|
|
|
@ -628,8 +667,9 @@ int rf_uhd_close(void *h)
|
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void rf_uhd_set_master_clock_rate(void *h, double rate) {
|
|
|
|
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
|
|
|
|
void rf_uhd_set_master_clock_rate(void* h, double rate)
|
|
|
|
|
{
|
|
|
|
|
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
|
|
|
|
|
if (fmod(handler->current_master_clock, rate)) {
|
|
|
|
|
if (handler->dynamic_rate) {
|
|
|
|
|
uhd_usrp_set_master_clock_rate(handler->usrp, rate, 0);
|
|
|
|
@ -638,21 +678,25 @@ void rf_uhd_set_master_clock_rate(void *h, double rate) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool rf_uhd_is_master_clock_dynamic(void *h) {
|
|
|
|
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
|
|
|
|
bool rf_uhd_is_master_clock_dynamic(void* h)
|
|
|
|
|
{
|
|
|
|
|
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
|
|
|
|
|
return handler->dynamic_rate;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double rf_uhd_set_rx_srate(void *h, double freq)
|
|
|
|
|
double rf_uhd_set_rx_srate(void* h, double freq)
|
|
|
|
|
{
|
|
|
|
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
|
|
|
|
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
|
|
|
|
|
if (handler->nof_rx_channels > 1) {
|
|
|
|
|
#ifdef UHD_SUPPORTS_COMMAND_TIME
|
|
|
|
|
time_t full;
|
|
|
|
|
double frac;
|
|
|
|
|
uhd_usrp_get_time_now(handler->usrp, 0, &full, &frac);
|
|
|
|
|
frac += 0.100;
|
|
|
|
|
if (frac >= 1.0) { full++; frac -= 1.0; };
|
|
|
|
|
if (frac >= 1.0) {
|
|
|
|
|
full++;
|
|
|
|
|
frac -= 1.0;
|
|
|
|
|
};
|
|
|
|
|
uhd_usrp_set_command_time(handler->usrp, full, frac, 0);
|
|
|
|
|
#endif /* UHD_SUPPORTS_COMMAND_TIME */
|
|
|
|
|
for (int i = 0; i < handler->nof_rx_channels; i++) {
|
|
|
|
@ -667,16 +711,19 @@ double rf_uhd_set_rx_srate(void *h, double freq)
|
|
|
|
|
return freq;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double rf_uhd_set_tx_srate(void *h, double freq)
|
|
|
|
|
double rf_uhd_set_tx_srate(void* h, double freq)
|
|
|
|
|
{
|
|
|
|
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
|
|
|
|
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
|
|
|
|
|
if (handler->nof_tx_channels > 1) {
|
|
|
|
|
#ifdef UHD_SUPPORTS_COMMAND_TIME
|
|
|
|
|
time_t full;
|
|
|
|
|
double frac;
|
|
|
|
|
uhd_usrp_get_time_now(handler->usrp, 0, &full, &frac);
|
|
|
|
|
frac += 0.100;
|
|
|
|
|
if (frac >= 1.0) { full++; frac -= 1.0; };
|
|
|
|
|
if (frac >= 1.0) {
|
|
|
|
|
full++;
|
|
|
|
|
frac -= 1.0;
|
|
|
|
|
};
|
|
|
|
|
uhd_usrp_set_command_time(handler->usrp, full, frac, 0);
|
|
|
|
|
#endif /* UHD_SUPPORTS_COMMAND_TIME */
|
|
|
|
|
for (int i = 0; i < handler->nof_tx_channels; i++) {
|
|
|
|
@ -692,45 +739,45 @@ double rf_uhd_set_tx_srate(void *h, double freq)
|
|
|
|
|
return freq;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double rf_uhd_set_rx_gain(void *h, double gain)
|
|
|
|
|
double rf_uhd_set_rx_gain(void* h, double gain)
|
|
|
|
|
{
|
|
|
|
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
|
|
|
|
for (int i=0;i<handler->nof_rx_channels;i++) {
|
|
|
|
|
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
|
|
|
|
|
for (int i = 0; i < handler->nof_rx_channels; i++) {
|
|
|
|
|
uhd_usrp_set_rx_gain(handler->usrp, gain, i, "");
|
|
|
|
|
}
|
|
|
|
|
return gain;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double rf_uhd_set_tx_gain(void *h, double gain)
|
|
|
|
|
double rf_uhd_set_tx_gain(void* h, double gain)
|
|
|
|
|
{
|
|
|
|
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
|
|
|
|
for (int i=0;i<handler->nof_tx_channels;i++) {
|
|
|
|
|
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
|
|
|
|
|
for (int i = 0; i < handler->nof_tx_channels; i++) {
|
|
|
|
|
uhd_usrp_set_tx_gain(handler->usrp, gain, i, "");
|
|
|
|
|
}
|
|
|
|
|
return gain;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double rf_uhd_get_rx_gain(void *h)
|
|
|
|
|
double rf_uhd_get_rx_gain(void* h)
|
|
|
|
|
{
|
|
|
|
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
|
|
|
|
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
|
|
|
|
|
double gain;
|
|
|
|
|
uhd_usrp_get_rx_gain(handler->usrp, 0, "", &gain);
|
|
|
|
|
return gain;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double rf_uhd_get_tx_gain(void *h)
|
|
|
|
|
double rf_uhd_get_tx_gain(void* h)
|
|
|
|
|
{
|
|
|
|
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
|
|
|
|
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
|
|
|
|
|
double gain;
|
|
|
|
|
uhd_usrp_get_tx_gain(handler->usrp, 0, "", &gain);
|
|
|
|
|
return gain;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
srslte_rf_info_t *rf_uhd_get_info(void *h)
|
|
|
|
|
srslte_rf_info_t* rf_uhd_get_info(void* h)
|
|
|
|
|
{
|
|
|
|
|
srslte_rf_info_t *info = NULL;
|
|
|
|
|
srslte_rf_info_t* info = NULL;
|
|
|
|
|
if (h) {
|
|
|
|
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
|
|
|
|
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
|
|
|
|
|
info = &handler->info;
|
|
|
|
|
}
|
|
|
|
|
return info;
|
|
|
|
@ -744,7 +791,7 @@ double rf_uhd_set_rx_freq(void* h, uint32_t ch, double freq)
|
|
|
|
|
.dsp_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO,
|
|
|
|
|
};
|
|
|
|
|
uhd_tune_result_t tune_result;
|
|
|
|
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
|
|
|
|
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
|
|
|
|
|
if (ch < handler->nof_rx_channels) {
|
|
|
|
|
uhd_usrp_set_rx_freq(handler->usrp, &tune_request, ch, &tune_result);
|
|
|
|
|
} else {
|
|
|
|
@ -763,7 +810,7 @@ double rf_uhd_set_tx_freq(void* h, uint32_t ch, double freq)
|
|
|
|
|
.dsp_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO,
|
|
|
|
|
};
|
|
|
|
|
uhd_tune_result_t tune_result;
|
|
|
|
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
|
|
|
|
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
|
|
|
|
|
if (ch < handler->nof_tx_channels) {
|
|
|
|
|
uhd_usrp_set_tx_freq(handler->usrp, &tune_request, ch, &tune_result);
|
|
|
|
|
} else {
|
|
|
|
@ -774,9 +821,9 @@ double rf_uhd_set_tx_freq(void* h, uint32_t ch, double freq)
|
|
|
|
|
return freq;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void rf_uhd_get_time(void *h, time_t *secs, double *frac_secs) {
|
|
|
|
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
|
|
|
|
void rf_uhd_get_time(void* h, time_t* secs, double* frac_secs)
|
|
|
|
|
{
|
|
|
|
|
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
|
|
|
|
|
uhd_usrp_get_time_now(handler->usrp, 0, secs, frac_secs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -788,33 +835,24 @@ void rf_uhd_sync_pps(void* h)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int rf_uhd_recv_with_time(void *h,
|
|
|
|
|
void *data,
|
|
|
|
|
uint32_t nsamples,
|
|
|
|
|
bool blocking,
|
|
|
|
|
time_t *secs,
|
|
|
|
|
double *frac_secs)
|
|
|
|
|
int rf_uhd_recv_with_time(void* h, void* data, uint32_t nsamples, bool blocking, time_t* secs, double* frac_secs)
|
|
|
|
|
{
|
|
|
|
|
return rf_uhd_recv_with_time_multi(h, &data, nsamples, blocking, secs, frac_secs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int rf_uhd_recv_with_time_multi(void *h,
|
|
|
|
|
void *data[SRSLTE_MAX_PORTS],
|
|
|
|
|
uint32_t nsamples,
|
|
|
|
|
bool blocking,
|
|
|
|
|
time_t *secs,
|
|
|
|
|
double *frac_secs)
|
|
|
|
|
int rf_uhd_recv_with_time_multi(
|
|
|
|
|
void* h, void* data[SRSLTE_MAX_PORTS], uint32_t nsamples, bool blocking, time_t* secs, double* frac_secs)
|
|
|
|
|
{
|
|
|
|
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
|
|
|
|
uhd_rx_metadata_handle *md = &handler->rx_md_first;
|
|
|
|
|
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
|
|
|
|
|
uhd_rx_metadata_handle* md = &handler->rx_md_first;
|
|
|
|
|
size_t rxd_samples = 0;
|
|
|
|
|
size_t rxd_samples_total = 0;
|
|
|
|
|
int trials = 0;
|
|
|
|
|
if (blocking) {
|
|
|
|
|
while (rxd_samples_total < nsamples && trials < 100) {
|
|
|
|
|
void *buffs_ptr[4];
|
|
|
|
|
for (int i=0;i<handler->nof_rx_channels;i++) {
|
|
|
|
|
cf_t *data_c = (cf_t*) data[i];
|
|
|
|
|
void* buffs_ptr[4];
|
|
|
|
|
for (int i = 0; i < handler->nof_rx_channels; i++) {
|
|
|
|
|
cf_t* data_c = (cf_t*)data[i];
|
|
|
|
|
buffs_ptr[i] = &data_c[rxd_samples_total];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -822,8 +860,8 @@ int rf_uhd_recv_with_time_multi(void *h,
|
|
|
|
|
size_t num_rx_samples = (num_samps_left > handler->rx_nof_samples) ? handler->rx_nof_samples : num_samps_left;
|
|
|
|
|
|
|
|
|
|
rxd_samples = 0;
|
|
|
|
|
uhd_error error = uhd_rx_streamer_recv(handler->rx_stream, buffs_ptr,
|
|
|
|
|
num_rx_samples, md, 1.0, false, &rxd_samples);
|
|
|
|
|
uhd_error error =
|
|
|
|
|
uhd_rx_streamer_recv(handler->rx_stream, buffs_ptr, num_rx_samples, md, 1.0, false, &rxd_samples);
|
|
|
|
|
if (error) {
|
|
|
|
|
ERROR("Error receiving from UHD: %d\n", error);
|
|
|
|
|
log_rx_error(handler);
|
|
|
|
@ -864,8 +902,8 @@ int rf_uhd_recv_with_time_multi(void *h,
|
|
|
|
|
return rxd_samples_total;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int rf_uhd_send_timed(void *h,
|
|
|
|
|
void *data,
|
|
|
|
|
int rf_uhd_send_timed(void* h,
|
|
|
|
|
void* data,
|
|
|
|
|
int nsamples,
|
|
|
|
|
time_t secs,
|
|
|
|
|
double frac_secs,
|
|
|
|
@ -874,13 +912,14 @@ int rf_uhd_send_timed(void *h,
|
|
|
|
|
bool is_start_of_burst,
|
|
|
|
|
bool is_end_of_burst)
|
|
|
|
|
{
|
|
|
|
|
void *_data[SRSLTE_MAX_PORTS]= {data, zero_mem, zero_mem, zero_mem};
|
|
|
|
|
void* _data[SRSLTE_MAX_PORTS] = {data, zero_mem, zero_mem, zero_mem};
|
|
|
|
|
|
|
|
|
|
return rf_uhd_send_timed_multi(h, _data, nsamples, secs, frac_secs, has_time_spec, blocking, is_start_of_burst, is_end_of_burst);
|
|
|
|
|
return rf_uhd_send_timed_multi(
|
|
|
|
|
h, _data, nsamples, secs, frac_secs, has_time_spec, blocking, is_start_of_burst, is_end_of_burst);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int rf_uhd_send_timed_multi(void *h,
|
|
|
|
|
void *data[4],
|
|
|
|
|
int rf_uhd_send_timed_multi(void* h,
|
|
|
|
|
void* data[4],
|
|
|
|
|
int nsamples,
|
|
|
|
|
time_t secs,
|
|
|
|
|
double frac_secs,
|
|
|
|
@ -889,7 +928,7 @@ int rf_uhd_send_timed_multi(void *h,
|
|
|
|
|
bool is_start_of_burst,
|
|
|
|
|
bool is_end_of_burst)
|
|
|
|
|
{
|
|
|
|
|
rf_uhd_handler_t* handler = (rf_uhd_handler_t*) h;
|
|
|
|
|
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
|
|
|
|
|
|
|
|
|
|
pthread_mutex_lock(&handler->tx_mutex);
|
|
|
|
|
int ret = -1;
|
|
|
|
@ -907,7 +946,7 @@ int rf_uhd_send_timed_multi(void *h,
|
|
|
|
|
uhd_tx_metadata_set_time_spec(&handler->tx_md, secs, frac_secs);
|
|
|
|
|
}
|
|
|
|
|
int n = 0;
|
|
|
|
|
cf_t *data_c[4];
|
|
|
|
|
cf_t* data_c[4];
|
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
|
data_c[i] = data[i] ? data[i] : zero_mem;
|
|
|
|
|
}
|
|
|
|
@ -929,19 +968,19 @@ int rf_uhd_send_timed_multi(void *h,
|
|
|
|
|
uhd_tx_metadata_set_end(&handler->tx_md, is_end_of_burst);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const void *buffs_ptr[4];
|
|
|
|
|
const void* buffs_ptr[4];
|
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
|
void *buff = (void*) &data_c[i][n];
|
|
|
|
|
void* buff = (void*)&data_c[i][n];
|
|
|
|
|
buffs_ptr[i] = buff;
|
|
|
|
|
}
|
|
|
|
|
uhd_error error = uhd_tx_streamer_send(handler->tx_stream, buffs_ptr,
|
|
|
|
|
tx_samples, &handler->tx_md, 1.0, &txd_samples);
|
|
|
|
|
uhd_error error =
|
|
|
|
|
uhd_tx_streamer_send(handler->tx_stream, buffs_ptr, tx_samples, &handler->tx_md, 1.0, &txd_samples);
|
|
|
|
|
if (error) {
|
|
|
|
|
ERROR("Error sending to UHD: %d\n", error);
|
|
|
|
|
goto unlock;
|
|
|
|
|
}
|
|
|
|
|
// Increase time spec
|
|
|
|
|
uhd_tx_metadata_add_time_spec(&handler->tx_md, txd_samples/handler->tx_rate);
|
|
|
|
|
uhd_tx_metadata_add_time_spec(&handler->tx_md, txd_samples / handler->tx_rate);
|
|
|
|
|
n += txd_samples;
|
|
|
|
|
trials++;
|
|
|
|
|
} while (n < nsamples && trials < 100);
|
|
|
|
@ -950,7 +989,7 @@ int rf_uhd_send_timed_multi(void *h,
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
const void *buffs_ptr[4];
|
|
|
|
|
const void* buffs_ptr[4];
|
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
|
buffs_ptr[i] = data[i];
|
|
|
|
|
}
|
|
|
|
@ -964,10 +1003,8 @@ int rf_uhd_send_timed_multi(void *h,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = txd_samples;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
unlock:
|
|
|
|
|
pthread_mutex_unlock(&handler->tx_mutex);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|