mirror of https://github.com/pvnis/srsRAN_4G.git
Merge branch 'next' into maint
commit
3db5c062d2
@ -0,0 +1,27 @@
|
|||||||
|
if(NOT BLADERF_FOUND)
|
||||||
|
pkg_check_modules (BLADERF_PKG libbladeRF)
|
||||||
|
find_path(BLADERF_INCLUDE_DIRS NAMES libbladeRF.h
|
||||||
|
PATHS
|
||||||
|
${BLADERF_PKG_INCLUDE_DIRS}
|
||||||
|
/usr/include
|
||||||
|
/usr/local/include
|
||||||
|
)
|
||||||
|
|
||||||
|
find_library(BLADERF_LIBRARIES NAMES bladeRF
|
||||||
|
PATHS
|
||||||
|
${BLADERF_PKG_LIBRARY_DIRS}
|
||||||
|
/usr/lib
|
||||||
|
/usr/local/lib
|
||||||
|
)
|
||||||
|
|
||||||
|
if(BLADERF_INCLUDE_DIRS AND BLADERF_LIBRARIES)
|
||||||
|
set(BLADERF_FOUND TRUE CACHE INTERNAL "libbladeRF found")
|
||||||
|
message(STATUS "Found libbladeRF: ${BLADERF_INCLUDE_DIRS}, ${BLADERF_LIBRARIES}")
|
||||||
|
else(BLADERF_INCLUDE_DIRS AND BLADERF_LIBRARIES)
|
||||||
|
set(BLADERF_FOUND FALSE CACHE INTERNAL "libbladeRF found")
|
||||||
|
message(STATUS "libbladeRF not found.")
|
||||||
|
endif(BLADERF_INCLUDE_DIRS AND BLADERF_LIBRARIES)
|
||||||
|
|
||||||
|
mark_as_advanced(BLADERF_LIBRARIES BLADERF_INCLUDE_DIRS)
|
||||||
|
|
||||||
|
endif(NOT BLADERF_FOUND)
|
@ -1,52 +0,0 @@
|
|||||||
# - Try to find openLTE's liblte
|
|
||||||
|
|
||||||
find_package(PkgConfig)
|
|
||||||
pkg_check_modules(PC_OPENLTE QUIET srslte)
|
|
||||||
set(OPENLTE_DEFINITIONS ${PC_OPENLTE_CFLAGS_OTHER})
|
|
||||||
|
|
||||||
FIND_PATH(
|
|
||||||
OPENLTE_LIBLTE_DIRS
|
|
||||||
NAMES liblte_common.h typedefs.h
|
|
||||||
HINTS ${PC_OPENLTE_SRCDIR}/liblte/hdr
|
|
||||||
${PC_OPENLTE_INCLUDEDIR}
|
|
||||||
${PC_OPENLTE_INCLUDE_DIRS}
|
|
||||||
$ENV{OPENLTE_DIR}/liblte/hdr
|
|
||||||
PATHS /usr/local/include
|
|
||||||
/usr/include
|
|
||||||
)
|
|
||||||
|
|
||||||
FIND_PATH(
|
|
||||||
OPENLTE_COMMON_DIRS
|
|
||||||
NAMES typedefs.h
|
|
||||||
HINTS ${PC_OPENLTE_SRCDIR}/cmn_hdr
|
|
||||||
${PC_OPENLTE_INCLUDEDIR}
|
|
||||||
${PC_OPENLTE_INCLUDE_DIRS}
|
|
||||||
$ENV{OPENLTE_DIR}/liblte/hdr
|
|
||||||
PATHS /usr/local/include
|
|
||||||
/usr/include
|
|
||||||
)
|
|
||||||
|
|
||||||
FIND_LIBRARY(
|
|
||||||
OPENLTE_LIBRARIES
|
|
||||||
NAMES lte
|
|
||||||
HINTS ${PC_OPENLTE_BUILDDIR}/liblte
|
|
||||||
${CMAKE_INSTALL_PREFIX}/lib
|
|
||||||
${CMAKE_INSTALL_PREFIX}/lib64
|
|
||||||
$ENV{OPENLTE_DIR}/lib
|
|
||||||
PATHS /usr/local/lib
|
|
||||||
/usr/local/lib64
|
|
||||||
/usr/lib
|
|
||||||
/usr/lib64
|
|
||||||
)
|
|
||||||
|
|
||||||
IF(OPENLTE_LIBLTE_DIRS AND OPENLTE_COMMON_DIRS)
|
|
||||||
SET(OPENLTE_INCLUDE_DIRS ${OPENLTE_LIBLTE_DIRS} ${OPENLTE_COMMON_DIRS})
|
|
||||||
ENDIF(OPENLTE_LIBLTE_DIRS AND OPENLTE_COMMON_DIRS)
|
|
||||||
|
|
||||||
message(STATUS "OPENLTE LIBRARIES " ${OPENLTE_LIBRARIES})
|
|
||||||
message(STATUS "OPENLTE INCLUDE DIRS " ${OPENLTE_INCLUDE_DIRS})
|
|
||||||
|
|
||||||
INCLUDE(FindPackageHandleStandardArgs)
|
|
||||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(OPENLTE DEFAULT_MSG OPENLTE_LIBRARIES OPENLTE_INCLUDE_DIRS)
|
|
||||||
MARK_AS_ADVANCED(OPENLTE_LIBRARIES OPENLTE_INCLUDE_DIRS)
|
|
||||||
|
|
@ -1,167 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
* \section COPYRIGHT
|
|
||||||
*
|
|
||||||
* Copyright 2013-2015 Software Radio Systems Limited
|
|
||||||
*
|
|
||||||
* \section LICENSE
|
|
||||||
*
|
|
||||||
* This file is part of the srsLTE library.
|
|
||||||
*
|
|
||||||
* srsLTE is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as
|
|
||||||
* published by the Free Software Foundation, either version 3 of
|
|
||||||
* the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* srsLTE is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* A copy of the GNU Affero General Public License can be found in
|
|
||||||
* the LICENSE file in the top-level directory of this distribution
|
|
||||||
* and at http://www.gnu.org/licenses/.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "srslte/config.h"
|
|
||||||
|
|
||||||
typedef void (*cuhd_msg_handler_t)(const char*);
|
|
||||||
|
|
||||||
SRSLTE_API int cuhd_open(char *args,
|
|
||||||
void **handler);
|
|
||||||
|
|
||||||
SRSLTE_API int cuhd_open_th(char *args,
|
|
||||||
void **handler,
|
|
||||||
bool tx_gain_same_rx);
|
|
||||||
|
|
||||||
SRSLTE_API int cuhd_close(void *h);
|
|
||||||
|
|
||||||
SRSLTE_API int cuhd_start_rx_stream(void *h);
|
|
||||||
|
|
||||||
SRSLTE_API int cuhd_start_rx_stream_nsamples(void *h,
|
|
||||||
uint32_t nsamples);
|
|
||||||
|
|
||||||
SRSLTE_API int cuhd_stop_rx_stream(void *h);
|
|
||||||
|
|
||||||
SRSLTE_API void cuhd_flush_buffer(void *h);
|
|
||||||
|
|
||||||
SRSLTE_API bool cuhd_has_rssi(void *h);
|
|
||||||
|
|
||||||
SRSLTE_API float cuhd_get_rssi(void *h);
|
|
||||||
|
|
||||||
SRSLTE_API bool cuhd_rx_wait_lo_locked(void *h);
|
|
||||||
|
|
||||||
SRSLTE_API void cuhd_set_master_clock_rate(void *h,
|
|
||||||
double rate);
|
|
||||||
|
|
||||||
SRSLTE_API bool cuhd_is_master_clock_dynamic(void *h);
|
|
||||||
|
|
||||||
SRSLTE_API double cuhd_set_rx_srate(void *h,
|
|
||||||
double freq);
|
|
||||||
|
|
||||||
SRSLTE_API double cuhd_set_rx_gain(void *h,
|
|
||||||
double gain);
|
|
||||||
|
|
||||||
SRSLTE_API void cuhd_set_tx_rx_gain_offset(void *h,
|
|
||||||
double offset);
|
|
||||||
|
|
||||||
SRSLTE_API double cuhd_set_rx_gain_th(void *h,
|
|
||||||
double gain);
|
|
||||||
|
|
||||||
SRSLTE_API double cuhd_set_tx_gain_th(void *h,
|
|
||||||
double gain);
|
|
||||||
|
|
||||||
SRSLTE_API float cuhd_get_rx_gain_offset(void *h);
|
|
||||||
|
|
||||||
SRSLTE_API double cuhd_get_rx_gain(void *h);
|
|
||||||
|
|
||||||
SRSLTE_API double cuhd_get_tx_gain(void *h);
|
|
||||||
|
|
||||||
SRSLTE_API void cuhd_suppress_stdout();
|
|
||||||
|
|
||||||
SRSLTE_API void cuhd_register_msg_handler(cuhd_msg_handler_t h);
|
|
||||||
|
|
||||||
SRSLTE_API double cuhd_set_rx_freq(void *h,
|
|
||||||
double freq);
|
|
||||||
|
|
||||||
SRSLTE_API double cuhd_set_rx_freq_offset(void *h,
|
|
||||||
double freq,
|
|
||||||
double off);
|
|
||||||
|
|
||||||
SRSLTE_API double cuhd_set_rx_freq_offset(void *h,
|
|
||||||
double freq,
|
|
||||||
double off);
|
|
||||||
|
|
||||||
SRSLTE_API int cuhd_recv(void *h,
|
|
||||||
void *data,
|
|
||||||
uint32_t nsamples,
|
|
||||||
bool blocking);
|
|
||||||
|
|
||||||
SRSLTE_API int cuhd_recv_with_time(void *h,
|
|
||||||
void *data,
|
|
||||||
uint32_t nsamples,
|
|
||||||
bool blocking,
|
|
||||||
time_t *secs,
|
|
||||||
double *frac_secs);
|
|
||||||
|
|
||||||
SRSLTE_API double cuhd_set_tx_srate(void *h,
|
|
||||||
double freq);
|
|
||||||
|
|
||||||
SRSLTE_API double cuhd_set_tx_gain(void *h,
|
|
||||||
double gain);
|
|
||||||
|
|
||||||
SRSLTE_API double cuhd_set_tx_freq(void *h,
|
|
||||||
double freq);
|
|
||||||
|
|
||||||
SRSLTE_API double cuhd_set_tx_freq_offset(void *h,
|
|
||||||
double freq,
|
|
||||||
double offset);
|
|
||||||
|
|
||||||
SRSLTE_API void cuhd_get_time(void *h,
|
|
||||||
time_t *secs,
|
|
||||||
double *frac_secs);
|
|
||||||
|
|
||||||
SRSLTE_API int cuhd_send(void *h,
|
|
||||||
void *data,
|
|
||||||
uint32_t nsamples,
|
|
||||||
bool blocking);
|
|
||||||
|
|
||||||
SRSLTE_API int cuhd_send2(void *h,
|
|
||||||
void *data,
|
|
||||||
uint32_t nsamples,
|
|
||||||
bool blocking,
|
|
||||||
bool start_of_burst,
|
|
||||||
bool end_of_burst);
|
|
||||||
|
|
||||||
SRSLTE_API int cuhd_send(void *h,
|
|
||||||
void *data,
|
|
||||||
uint32_t nsamples,
|
|
||||||
bool blocking);
|
|
||||||
|
|
||||||
|
|
||||||
SRSLTE_API int cuhd_send_timed(void *h,
|
|
||||||
void *data,
|
|
||||||
int nsamples,
|
|
||||||
time_t secs,
|
|
||||||
double frac_secs);
|
|
||||||
|
|
||||||
SRSLTE_API int cuhd_send_timed2(void *h,
|
|
||||||
void *data,
|
|
||||||
int nsamples,
|
|
||||||
time_t secs,
|
|
||||||
double frac_secs,
|
|
||||||
bool is_start_of_burst,
|
|
||||||
bool is_end_of_burst);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
@ -0,0 +1,188 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \section COPYRIGHT
|
||||||
|
*
|
||||||
|
* Copyright 2013-2015 Software Radio Systems Limited
|
||||||
|
*
|
||||||
|
* \section LICENSE
|
||||||
|
*
|
||||||
|
* This file is part of the srsLTE library.
|
||||||
|
*
|
||||||
|
* srsLTE is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* srsLTE is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* A copy of the GNU Affero General Public License can be found in
|
||||||
|
* the LICENSE file in the top-level directory of this distribution
|
||||||
|
* and at http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RF_H
|
||||||
|
#define RF_H
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "srslte/config.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void *handler;
|
||||||
|
void *dev;
|
||||||
|
|
||||||
|
// The following variables are for threaded RX gain control
|
||||||
|
pthread_t thread_gain;
|
||||||
|
pthread_cond_t cond;
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
double cur_rx_gain;
|
||||||
|
double new_rx_gain;
|
||||||
|
bool tx_gain_same_rx;
|
||||||
|
float tx_rx_gain_offset;
|
||||||
|
} srslte_rf_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float dc_gain;
|
||||||
|
float dc_phase;
|
||||||
|
float iq_i;
|
||||||
|
float iq_q;
|
||||||
|
} srslte_rf_cal_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
enum {
|
||||||
|
SRSLTE_RF_ERROR_LATE,
|
||||||
|
SRSLTE_RF_ERROR_UNDERFLOW,
|
||||||
|
SRSLTE_RF_ERROR_OVERFLOW,
|
||||||
|
SRSLTE_RF_ERROR_OTHER
|
||||||
|
} type;
|
||||||
|
int opt;
|
||||||
|
const char *msg;
|
||||||
|
} srslte_rf_error_t;
|
||||||
|
|
||||||
|
typedef void (*srslte_rf_error_handler_t)(srslte_rf_error_t error);
|
||||||
|
|
||||||
|
SRSLTE_API int srslte_rf_open(srslte_rf_t *h,
|
||||||
|
char *args);
|
||||||
|
|
||||||
|
SRSLTE_API int srslte_rf_open_devname(srslte_rf_t *h,
|
||||||
|
char *devname,
|
||||||
|
char *args);
|
||||||
|
|
||||||
|
SRSLTE_API const char *srslte_rf_name(srslte_rf_t *h);
|
||||||
|
|
||||||
|
SRSLTE_API int srslte_rf_start_gain_thread(srslte_rf_t *rf,
|
||||||
|
bool tx_gain_same_rx);
|
||||||
|
|
||||||
|
SRSLTE_API int srslte_rf_close(srslte_rf_t *h);
|
||||||
|
|
||||||
|
SRSLTE_API void srslte_rf_set_tx_cal(srslte_rf_t *h, srslte_rf_cal_t *cal);
|
||||||
|
|
||||||
|
SRSLTE_API void srslte_rf_set_rx_cal(srslte_rf_t *h, srslte_rf_cal_t *cal);
|
||||||
|
|
||||||
|
SRSLTE_API int srslte_rf_start_rx_stream(srslte_rf_t *h);
|
||||||
|
|
||||||
|
SRSLTE_API int srslte_rf_stop_rx_stream(srslte_rf_t *h);
|
||||||
|
|
||||||
|
SRSLTE_API void srslte_rf_flush_buffer(srslte_rf_t *h);
|
||||||
|
|
||||||
|
SRSLTE_API bool srslte_rf_has_rssi(srslte_rf_t *h);
|
||||||
|
|
||||||
|
SRSLTE_API float srslte_rf_get_rssi(srslte_rf_t *h);
|
||||||
|
|
||||||
|
SRSLTE_API bool srslte_rf_rx_wait_lo_locked(srslte_rf_t *h);
|
||||||
|
|
||||||
|
SRSLTE_API void srslte_rf_set_master_clock_rate(srslte_rf_t *h,
|
||||||
|
double rate);
|
||||||
|
|
||||||
|
SRSLTE_API bool srslte_rf_is_master_clock_dynamic(srslte_rf_t *h);
|
||||||
|
|
||||||
|
SRSLTE_API double srslte_rf_set_rx_srate(srslte_rf_t *h,
|
||||||
|
double freq);
|
||||||
|
|
||||||
|
SRSLTE_API double srslte_rf_set_rx_gain(srslte_rf_t *h,
|
||||||
|
double gain);
|
||||||
|
|
||||||
|
SRSLTE_API void srslte_rf_set_tx_rx_gain_offset(srslte_rf_t *h,
|
||||||
|
double offset);
|
||||||
|
|
||||||
|
SRSLTE_API double srslte_rf_set_rx_gain_th(srslte_rf_t *h,
|
||||||
|
double gain);
|
||||||
|
|
||||||
|
SRSLTE_API double srslte_rf_get_rx_gain(srslte_rf_t *h);
|
||||||
|
|
||||||
|
SRSLTE_API double srslte_rf_get_tx_gain(srslte_rf_t *h);
|
||||||
|
|
||||||
|
SRSLTE_API void srslte_rf_suppress_stdout(srslte_rf_t *h);
|
||||||
|
|
||||||
|
SRSLTE_API void srslte_rf_register_error_handler(srslte_rf_t *h,
|
||||||
|
srslte_rf_error_handler_t error_handler);
|
||||||
|
|
||||||
|
SRSLTE_API double srslte_rf_set_rx_freq(srslte_rf_t *h,
|
||||||
|
double freq);
|
||||||
|
|
||||||
|
SRSLTE_API int srslte_rf_recv(srslte_rf_t *h,
|
||||||
|
void *data,
|
||||||
|
uint32_t nsamples,
|
||||||
|
bool blocking);
|
||||||
|
|
||||||
|
SRSLTE_API int srslte_rf_recv_with_time(srslte_rf_t *h,
|
||||||
|
void *data,
|
||||||
|
uint32_t nsamples,
|
||||||
|
bool blocking,
|
||||||
|
time_t *secs,
|
||||||
|
double *frac_secs);
|
||||||
|
|
||||||
|
SRSLTE_API double srslte_rf_set_tx_srate(srslte_rf_t *h,
|
||||||
|
double freq);
|
||||||
|
|
||||||
|
SRSLTE_API double srslte_rf_set_tx_gain(srslte_rf_t *h,
|
||||||
|
double gain);
|
||||||
|
|
||||||
|
SRSLTE_API double srslte_rf_set_tx_freq(srslte_rf_t *h,
|
||||||
|
double freq);
|
||||||
|
|
||||||
|
SRSLTE_API void srslte_rf_get_time(srslte_rf_t *h,
|
||||||
|
time_t *secs,
|
||||||
|
double *frac_secs);
|
||||||
|
|
||||||
|
SRSLTE_API int srslte_rf_send(srslte_rf_t *h,
|
||||||
|
void *data,
|
||||||
|
uint32_t nsamples,
|
||||||
|
bool blocking);
|
||||||
|
|
||||||
|
SRSLTE_API int srslte_rf_send2(srslte_rf_t *h,
|
||||||
|
void *data,
|
||||||
|
uint32_t nsamples,
|
||||||
|
bool blocking,
|
||||||
|
bool start_of_burst,
|
||||||
|
bool end_of_burst);
|
||||||
|
|
||||||
|
SRSLTE_API int srslte_rf_send(srslte_rf_t *h,
|
||||||
|
void *data,
|
||||||
|
uint32_t nsamples,
|
||||||
|
bool blocking);
|
||||||
|
|
||||||
|
|
||||||
|
SRSLTE_API int srslte_rf_send_timed(srslte_rf_t *h,
|
||||||
|
void *data,
|
||||||
|
int nsamples,
|
||||||
|
time_t secs,
|
||||||
|
double frac_secs);
|
||||||
|
|
||||||
|
SRSLTE_API int srslte_rf_send_timed2(srslte_rf_t *h,
|
||||||
|
void *data,
|
||||||
|
int nsamples,
|
||||||
|
time_t secs,
|
||||||
|
double frac_secs,
|
||||||
|
bool is_start_of_burst,
|
||||||
|
bool is_end_of_burst);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -1,55 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
* \section COPYRIGHT
|
|
||||||
*
|
|
||||||
* Copyright 2013-2015 The srsLTE Developers. See the
|
|
||||||
* COPYRIGHT file at the top-level directory of this distribution.
|
|
||||||
*
|
|
||||||
* \section LICENSE
|
|
||||||
*
|
|
||||||
* This file is part of the srsLTE library.
|
|
||||||
*
|
|
||||||
* srsLTE is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as
|
|
||||||
* published by the Free Software Foundation, either version 3 of
|
|
||||||
* the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* srsLTE is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* A copy of the GNU Affero General Public License can be found in
|
|
||||||
* the LICENSE file in the top-level directory of this distribution
|
|
||||||
* and at http://www.gnu.org/licenses/.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <uhd/usrp/multi_usrp.hpp>
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
class cuhd_handler {
|
|
||||||
public:
|
|
||||||
uhd::usrp::multi_usrp::sptr usrp;
|
|
||||||
uhd::rx_streamer::sptr rx_stream;
|
|
||||||
bool rx_stream_enable;
|
|
||||||
uhd::tx_streamer::sptr tx_stream;
|
|
||||||
|
|
||||||
// The following variables are for threaded RX gain control
|
|
||||||
pthread_t thread_gain;
|
|
||||||
pthread_cond_t cond;
|
|
||||||
pthread_mutex_t mutex;
|
|
||||||
double cur_rx_gain;
|
|
||||||
double new_rx_gain;
|
|
||||||
double cur_tx_gain;
|
|
||||||
double new_tx_gain;
|
|
||||||
bool tx_gain_same_rx;
|
|
||||||
float tx_rx_gain_offset;
|
|
||||||
uhd::gain_range_t rx_gain_range;
|
|
||||||
uhd::gain_range_t tx_gain_range;
|
|
||||||
size_t rx_nof_samples;
|
|
||||||
size_t tx_nof_samples;
|
|
||||||
double tx_rate;
|
|
||||||
bool dynamic_rate;
|
|
||||||
};
|
|
@ -1,521 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
* \section COPYRIGHT
|
|
||||||
*
|
|
||||||
* Copyright 2013-2015 Software Radio Systems Limited
|
|
||||||
*
|
|
||||||
* \section LICENSE
|
|
||||||
*
|
|
||||||
* This file is part of the srsLTE library.
|
|
||||||
*
|
|
||||||
* srsLTE is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as
|
|
||||||
* published by the Free Software Foundation, either version 3 of
|
|
||||||
* the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* srsLTE is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* A copy of the GNU Affero General Public License can be found in
|
|
||||||
* the LICENSE file in the top-level directory of this distribution
|
|
||||||
* and at http://www.gnu.org/licenses/.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <uhd/utils/thread_priority.hpp>
|
|
||||||
#include <uhd/usrp/multi_usrp.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
#include <complex>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <uhd/utils/msg.hpp>
|
|
||||||
#include <sys/time.h>
|
|
||||||
|
|
||||||
#include "cuhd_handler.hpp"
|
|
||||||
#include "srslte/cuhd/cuhd.h"
|
|
||||||
#include "srslte/srslte.h"
|
|
||||||
|
|
||||||
//#define METADATA_VERBOSE
|
|
||||||
|
|
||||||
cuhd_msg_handler_t msg_handler;
|
|
||||||
|
|
||||||
void suppress_handler(uhd::msg::type_t type, const std::string & msg)
|
|
||||||
{
|
|
||||||
//handle the message...
|
|
||||||
}
|
|
||||||
|
|
||||||
void translate_handler(uhd::msg::type_t type, const std::string & msg)
|
|
||||||
{
|
|
||||||
if(msg_handler)
|
|
||||||
msg_handler(msg.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef _Complex float complex_t;
|
|
||||||
|
|
||||||
#define SAMPLE_SZ sizeof(complex_t)
|
|
||||||
|
|
||||||
bool isLocked(void *h)
|
|
||||||
{
|
|
||||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
|
||||||
std::vector < std::string > mb_sensors =
|
|
||||||
handler->usrp->get_mboard_sensor_names();
|
|
||||||
std::vector < std::string > rx_sensors =
|
|
||||||
handler->usrp->get_rx_sensor_names(0);
|
|
||||||
if (std::find(rx_sensors.begin(), rx_sensors.end(), "lo_locked") !=
|
|
||||||
rx_sensors.end()) {
|
|
||||||
return handler->usrp->get_rx_sensor("lo_locked", 0).to_bool();
|
|
||||||
} else if (std::find(mb_sensors.begin(), mb_sensors.end(), "ref_locked") !=
|
|
||||||
mb_sensors.end()) {
|
|
||||||
return handler->usrp->get_mboard_sensor("ref_locked", 0).to_bool();
|
|
||||||
} else {
|
|
||||||
usleep(500);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cuhd_rx_wait_lo_locked(void *h)
|
|
||||||
{
|
|
||||||
|
|
||||||
double report = 0.0;
|
|
||||||
while (isLocked(h) && report < 30.0) {
|
|
||||||
report += 0.1;
|
|
||||||
usleep(1000);
|
|
||||||
}
|
|
||||||
return isLocked(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cuhd_start_rx_stream(void *h)
|
|
||||||
{
|
|
||||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
|
||||||
uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
|
|
||||||
cmd.time_spec = handler->usrp->get_time_now();
|
|
||||||
cmd.stream_now = true;
|
|
||||||
handler->usrp->issue_stream_cmd(cmd);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cuhd_stop_rx_stream(void *h)
|
|
||||||
{
|
|
||||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
|
||||||
uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
|
|
||||||
cmd.time_spec = handler->usrp->get_time_now();
|
|
||||||
cmd.stream_now = true;
|
|
||||||
handler->usrp->issue_stream_cmd(cmd);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cuhd_flush_buffer(void *h)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
_Complex float tmp[1024];
|
|
||||||
do {
|
|
||||||
n = cuhd_recv(h, tmp, 1024, 0);
|
|
||||||
} while (n > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cuhd_has_rssi(void *h) {
|
|
||||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
|
||||||
std::vector < std::string > mb_sensors = handler->usrp->get_mboard_sensor_names();
|
|
||||||
std::vector < std::string > rx_sensors = handler->usrp->get_rx_sensor_names(0);
|
|
||||||
if (std::find(rx_sensors.begin(), rx_sensors.end(), "rssi") != rx_sensors.end()) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float cuhd_get_rssi(void *h) {
|
|
||||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
|
||||||
if (cuhd_has_rssi(h)) {
|
|
||||||
uhd::sensor_value_t value = handler->usrp->get_rx_sensor("rssi");
|
|
||||||
return value.to_real();
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int cuhd_start_rx_stream_nsamples(void *h, uint32_t nsamples)
|
|
||||||
{
|
|
||||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
|
||||||
uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE);
|
|
||||||
cmd.time_spec = handler->usrp->get_time_now();
|
|
||||||
cmd.stream_now = true;
|
|
||||||
cmd.num_samps = nsamples;
|
|
||||||
handler->usrp->issue_stream_cmd(cmd);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
double cuhd_set_rx_gain_th(void *h, double gain)
|
|
||||||
{
|
|
||||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
|
||||||
gain = handler->rx_gain_range.clip(gain);
|
|
||||||
if (gain > handler->new_rx_gain + 0.5 || gain < handler->new_rx_gain - 0.5) {
|
|
||||||
pthread_mutex_lock(&handler->mutex);
|
|
||||||
handler->new_rx_gain = gain;
|
|
||||||
pthread_cond_signal(&handler->cond);
|
|
||||||
pthread_mutex_unlock(&handler->mutex);
|
|
||||||
}
|
|
||||||
return gain;
|
|
||||||
}
|
|
||||||
|
|
||||||
double cuhd_set_tx_gain_th(void *h, double gain)
|
|
||||||
{
|
|
||||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
|
||||||
gain = handler->tx_gain_range.clip(gain);
|
|
||||||
if (gain > handler->new_tx_gain + 0.5 || gain < handler->new_tx_gain - 0.5) {
|
|
||||||
pthread_mutex_lock(&handler->mutex);
|
|
||||||
handler->new_tx_gain = gain;
|
|
||||||
pthread_cond_signal(&handler->cond);
|
|
||||||
pthread_mutex_unlock(&handler->mutex);
|
|
||||||
}
|
|
||||||
return gain;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cuhd_set_tx_rx_gain_offset(void *h, double offset) {
|
|
||||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
|
||||||
handler->tx_rx_gain_offset = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This thread listens for set_rx_gain commands to the USRP */
|
|
||||||
static void* thread_gain_fcn(void *h) {
|
|
||||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
|
||||||
while(1) {
|
|
||||||
pthread_mutex_lock(&handler->mutex);
|
|
||||||
while(handler->cur_rx_gain == handler->new_rx_gain &&
|
|
||||||
handler->cur_tx_gain == handler->new_tx_gain)
|
|
||||||
{
|
|
||||||
pthread_cond_wait(&handler->cond, &handler->mutex);
|
|
||||||
}
|
|
||||||
if (handler->new_rx_gain != handler->cur_rx_gain) {
|
|
||||||
handler->cur_rx_gain = handler->new_rx_gain;
|
|
||||||
cuhd_set_rx_gain(h, handler->cur_rx_gain);
|
|
||||||
}
|
|
||||||
if (handler->tx_gain_same_rx) {
|
|
||||||
cuhd_set_tx_gain(h, handler->cur_rx_gain+handler->tx_rx_gain_offset);
|
|
||||||
} else if (handler->new_tx_gain != handler->cur_tx_gain) {
|
|
||||||
handler->cur_tx_gain = handler->new_tx_gain;
|
|
||||||
cuhd_set_tx_gain(h, handler->cur_tx_gain);
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&handler->mutex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float cuhd_get_rx_gain_offset(void *h) {
|
|
||||||
return 15;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cuhd_suppress_stdout() {
|
|
||||||
uhd::msg::register_handler(suppress_handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cuhd_register_msg_handler(cuhd_msg_handler_t h)
|
|
||||||
{
|
|
||||||
msg_handler = h;
|
|
||||||
uhd::msg::register_handler(translate_handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cuhd_open_(char *args, void **h, bool create_thread_gain, bool tx_gain_same_rx)
|
|
||||||
{
|
|
||||||
|
|
||||||
*h = NULL;
|
|
||||||
|
|
||||||
/* Set priority to UHD threads */
|
|
||||||
uhd::set_thread_priority_safe();
|
|
||||||
|
|
||||||
|
|
||||||
/* Get multiusrp handler */
|
|
||||||
cuhd_handler *handler = new cuhd_handler();
|
|
||||||
std::string _args = std::string(args);
|
|
||||||
handler->usrp = uhd::usrp::multi_usrp::make(_args);// + ", recv_frame_size=9232,num_recv_frames=64,send_frame_size=9232,num_send_frames=64");
|
|
||||||
|
|
||||||
/* Initialize rx and tx stremers */
|
|
||||||
std::string otw, cpu;
|
|
||||||
otw = "sc16";
|
|
||||||
cpu = "fc32";
|
|
||||||
uhd::stream_args_t stream_args(cpu, otw);
|
|
||||||
handler->rx_stream = handler->usrp->get_rx_stream(stream_args);
|
|
||||||
handler->tx_stream = handler->usrp->get_tx_stream(stream_args);
|
|
||||||
|
|
||||||
handler->rx_nof_samples = handler->rx_stream->get_max_num_samps();
|
|
||||||
handler->tx_nof_samples = handler->tx_stream->get_max_num_samps();
|
|
||||||
|
|
||||||
handler->tx_gain_same_rx = tx_gain_same_rx;
|
|
||||||
handler->tx_rx_gain_offset = 0.0;
|
|
||||||
handler->rx_gain_range = handler->usrp->get_rx_gain_range();
|
|
||||||
handler->tx_gain_range = handler->usrp->get_tx_gain_range();
|
|
||||||
|
|
||||||
/* Create auxiliary thread and mutexes for AGC */
|
|
||||||
if (create_thread_gain) {
|
|
||||||
if (pthread_mutex_init(&handler->mutex, NULL)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (pthread_cond_init(&handler->cond, NULL)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pthread_create(&handler->thread_gain, NULL, thread_gain_fcn, handler)) {
|
|
||||||
perror("pthread_create");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find out if the master clock rate is configurable */
|
|
||||||
double cur_clock = handler->usrp->get_master_clock_rate();
|
|
||||||
printf("Trying to dynamically change Master clock...\n");
|
|
||||||
handler->usrp->set_master_clock_rate(cur_clock/2);
|
|
||||||
if (handler->usrp->get_master_clock_rate() == cur_clock) {
|
|
||||||
handler->dynamic_rate = false;
|
|
||||||
/* Master clock rate is not configurable. Check if it is compatible with LTE */
|
|
||||||
int cur_clock_i = (int) cur_clock;
|
|
||||||
if (cur_clock_i % 1920000) {
|
|
||||||
fprintf(stderr, "Error: LTE sampling rates are not supported. Master clock rate is %.1f MHz\n", cur_clock/1e6);
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
printf("Master clock is not configurable. Using standard symbol sizes and sampling rates.\n");
|
|
||||||
srslte_use_standard_symbol_size(true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
printf("Master clock is configurable. Using reduced symbol sizes and sampling rates.\n");
|
|
||||||
handler->dynamic_rate = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
*h = handler;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cuhd_open(char *args, void **h) {
|
|
||||||
return cuhd_open_(args, h, false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cuhd_open_th(char *args, void **h, bool tx_gain_same_rx) {
|
|
||||||
return cuhd_open_(args, h, true, tx_gain_same_rx);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int cuhd_close(void *h)
|
|
||||||
{
|
|
||||||
cuhd_stop_rx_stream(h);
|
|
||||||
/** Something else to close the USRP?? */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cuhd_set_master_clock_rate(void *h, double rate) {
|
|
||||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
|
||||||
if (handler->dynamic_rate) {
|
|
||||||
handler->usrp->set_master_clock_rate(rate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cuhd_is_master_clock_dynamic(void *h) {
|
|
||||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
|
||||||
return handler->dynamic_rate;
|
|
||||||
}
|
|
||||||
|
|
||||||
double cuhd_set_rx_srate(void *h, double freq)
|
|
||||||
{
|
|
||||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
|
||||||
handler->usrp->set_rx_rate(freq);
|
|
||||||
return handler->usrp->get_rx_rate();
|
|
||||||
}
|
|
||||||
|
|
||||||
double cuhd_set_rx_gain(void *h, double gain)
|
|
||||||
{
|
|
||||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
|
||||||
handler->usrp->set_rx_gain(gain);
|
|
||||||
return handler->usrp->get_rx_gain();
|
|
||||||
}
|
|
||||||
|
|
||||||
double cuhd_get_rx_gain(void *h)
|
|
||||||
{
|
|
||||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
|
||||||
return handler->usrp->get_rx_gain();
|
|
||||||
}
|
|
||||||
|
|
||||||
double cuhd_get_tx_gain(void *h)
|
|
||||||
{
|
|
||||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
|
||||||
return handler->usrp->get_tx_gain();
|
|
||||||
}
|
|
||||||
|
|
||||||
double cuhd_set_rx_freq(void *h, double freq)
|
|
||||||
{
|
|
||||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
|
||||||
handler->usrp->set_rx_freq(freq);
|
|
||||||
return freq;
|
|
||||||
}
|
|
||||||
|
|
||||||
double cuhd_set_rx_freq_offset(void *h, double freq, double off) {
|
|
||||||
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
|
|
||||||
handler->usrp->set_rx_freq(uhd::tune_request_t(freq, off));
|
|
||||||
return handler->usrp->get_rx_freq();
|
|
||||||
}
|
|
||||||
|
|
||||||
int cuhd_recv(void *h, void *data, uint32_t nsamples, bool blocking)
|
|
||||||
{
|
|
||||||
return cuhd_recv_with_time(h, data, nsamples, blocking, NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cuhd_recv_with_time(void *h,
|
|
||||||
void *data,
|
|
||||||
uint32_t nsamples,
|
|
||||||
bool blocking,
|
|
||||||
time_t *secs,
|
|
||||||
double *frac_secs)
|
|
||||||
{
|
|
||||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
|
||||||
uhd::rx_metadata_t md, md_first;
|
|
||||||
if (blocking) {
|
|
||||||
int n = 0, p;
|
|
||||||
complex_t *data_c = (complex_t *) data;
|
|
||||||
do {
|
|
||||||
size_t rx_samples = handler->rx_nof_samples;
|
|
||||||
if (rx_samples > nsamples - n) {
|
|
||||||
rx_samples = nsamples - n;
|
|
||||||
}
|
|
||||||
p = handler->rx_stream->recv(&data_c[n], rx_samples, n==0?md_first:md);
|
|
||||||
if (p == -1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
n += p;
|
|
||||||
#ifdef METADATA_VERBOSE
|
|
||||||
if (md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE) {
|
|
||||||
std::cout << "\nError code: " << md.to_pp_string() << "\n\n";
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
} while (n < nsamples &&
|
|
||||||
md.error_code == uhd::rx_metadata_t::ERROR_CODE_NONE);
|
|
||||||
} else {
|
|
||||||
return handler->rx_stream->recv(data, nsamples, md, 0.0);
|
|
||||||
}
|
|
||||||
if (secs) {
|
|
||||||
*secs = md_first.time_spec.get_full_secs();
|
|
||||||
}
|
|
||||||
if (frac_secs) {
|
|
||||||
*frac_secs = md_first.time_spec.get_frac_secs();
|
|
||||||
}
|
|
||||||
return nsamples;
|
|
||||||
}
|
|
||||||
double cuhd_set_tx_gain(void *h, double gain)
|
|
||||||
{
|
|
||||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
|
||||||
handler->usrp->set_tx_gain(gain);
|
|
||||||
return gain;
|
|
||||||
}
|
|
||||||
|
|
||||||
double cuhd_set_tx_srate(void *h, double freq)
|
|
||||||
{
|
|
||||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
|
||||||
handler->usrp->set_tx_rate(freq);
|
|
||||||
handler->tx_rate = handler->usrp->get_tx_rate();
|
|
||||||
return handler->tx_rate;
|
|
||||||
}
|
|
||||||
|
|
||||||
double cuhd_set_tx_freq(void *h, double freq)
|
|
||||||
{
|
|
||||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
|
||||||
handler->usrp->set_tx_freq(freq);
|
|
||||||
return handler->usrp->get_tx_freq();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
double cuhd_set_tx_freq_offset(void *h, double freq, double off) {
|
|
||||||
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
|
|
||||||
handler->usrp->set_tx_freq(uhd::tune_request_t(freq, off));
|
|
||||||
return handler->usrp->get_tx_freq();
|
|
||||||
}
|
|
||||||
|
|
||||||
void cuhd_get_time(void *h, time_t *secs, double *frac_secs) {
|
|
||||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
|
||||||
uhd::time_spec_t now = handler->usrp->get_time_now();
|
|
||||||
if (secs) {
|
|
||||||
*secs = now.get_full_secs();
|
|
||||||
}
|
|
||||||
if (frac_secs) {
|
|
||||||
*frac_secs = now.get_frac_secs();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int cuhd_send_timed3(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)
|
|
||||||
{
|
|
||||||
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
|
|
||||||
uhd::tx_metadata_t md;
|
|
||||||
md.has_time_spec = has_time_spec;
|
|
||||||
if (has_time_spec) {
|
|
||||||
md.time_spec = uhd::time_spec_t(secs, frac_secs);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blocking) {
|
|
||||||
int n = 0, p;
|
|
||||||
complex_t *data_c = (complex_t *) data;
|
|
||||||
do {
|
|
||||||
size_t tx_samples = handler->tx_nof_samples;
|
|
||||||
|
|
||||||
// First packet is start of burst if so defined, others are never
|
|
||||||
if (n == 0) {
|
|
||||||
md.start_of_burst = is_start_of_burst;
|
|
||||||
} else {
|
|
||||||
md.start_of_burst = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// middle packets are never end of burst, last one as defined
|
|
||||||
if (nsamples - n > tx_samples) {
|
|
||||||
md.end_of_burst = false;
|
|
||||||
} else {
|
|
||||||
tx_samples = nsamples - n;
|
|
||||||
md.end_of_burst = is_end_of_burst;
|
|
||||||
}
|
|
||||||
p = handler->tx_stream->send(&data_c[n], tx_samples, md);
|
|
||||||
if (p == -1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
// Increase time spec
|
|
||||||
md.time_spec += tx_samples/handler->tx_rate;
|
|
||||||
n += p;
|
|
||||||
} while (n < nsamples);
|
|
||||||
return nsamples;
|
|
||||||
} else {
|
|
||||||
return handler->tx_stream->send(data, nsamples, md, 0.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int cuhd_send(void *h, void *data, uint32_t nsamples, bool blocking)
|
|
||||||
{
|
|
||||||
return cuhd_send2(h, data, nsamples, blocking, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cuhd_send2(void *h, void *data, uint32_t nsamples, bool blocking, bool start_of_burst, bool end_of_burst)
|
|
||||||
{
|
|
||||||
return cuhd_send_timed3(h, data, nsamples, 0, 0, false, blocking, start_of_burst, end_of_burst);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int cuhd_send_timed(void *h,
|
|
||||||
void *data,
|
|
||||||
int nsamples,
|
|
||||||
time_t secs,
|
|
||||||
double frac_secs)
|
|
||||||
{
|
|
||||||
return cuhd_send_timed2(h, data, nsamples, secs, frac_secs, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cuhd_send_timed2(void *h,
|
|
||||||
void *data,
|
|
||||||
int nsamples,
|
|
||||||
time_t secs,
|
|
||||||
double frac_secs,
|
|
||||||
bool is_start_of_burst,
|
|
||||||
bool is_end_of_burst)
|
|
||||||
{
|
|
||||||
return cuhd_send_timed3(h, data, nsamples, secs, frac_secs, true, true, is_start_of_burst, is_end_of_burst);
|
|
||||||
}
|
|
@ -0,0 +1,497 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \section COPYRIGHT
|
||||||
|
*
|
||||||
|
* Copyright 2013-2015 Software Radio Systems Limited
|
||||||
|
*
|
||||||
|
* \section LICENSE
|
||||||
|
*
|
||||||
|
* This file is part of the srsLTE library.
|
||||||
|
*
|
||||||
|
* srsLTE is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* srsLTE is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* A copy of the GNU Affero General Public License can be found in
|
||||||
|
* the LICENSE file in the top-level directory of this distribution
|
||||||
|
* and at http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libbladeRF.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "srslte/srslte.h"
|
||||||
|
#include "rf_blade_imp.h"
|
||||||
|
#include "srslte/rf/rf.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define CONVERT_BUFFER_SIZE 240*1024
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct bladerf *dev;
|
||||||
|
uint32_t rx_rate;
|
||||||
|
uint32_t tx_rate;
|
||||||
|
int16_t rx_buffer[CONVERT_BUFFER_SIZE];
|
||||||
|
int16_t tx_buffer[CONVERT_BUFFER_SIZE];
|
||||||
|
bool rx_stream_enabled;
|
||||||
|
bool tx_stream_enabled;
|
||||||
|
} rf_blade_handler_t;
|
||||||
|
|
||||||
|
srslte_rf_error_handler_t blade_error_handler = NULL;
|
||||||
|
|
||||||
|
void rf_blade_suppress_stdout(void *h) {
|
||||||
|
bladerf_log_set_verbosity(BLADERF_LOG_LEVEL_SILENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rf_blade_register_error_handler(void *notused, srslte_rf_error_handler_t new_handler)
|
||||||
|
{
|
||||||
|
new_handler = blade_error_handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rf_blade_rx_wait_lo_locked(void *h)
|
||||||
|
{
|
||||||
|
usleep(1000);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned int num_buffers = 256;
|
||||||
|
const unsigned int ms_buffer_size_rx = 1024;
|
||||||
|
const unsigned int buffer_size_tx = 1024;
|
||||||
|
const unsigned int num_transfers = 32;
|
||||||
|
const unsigned int timeout_ms = 4000;
|
||||||
|
|
||||||
|
|
||||||
|
int rf_blade_start_tx_stream(void *h)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
rf_blade_handler_t *handler = (rf_blade_handler_t*) h;
|
||||||
|
|
||||||
|
status = bladerf_sync_config(handler->dev,
|
||||||
|
BLADERF_MODULE_TX,
|
||||||
|
BLADERF_FORMAT_SC16_Q11_META,
|
||||||
|
num_buffers,
|
||||||
|
buffer_size_tx,
|
||||||
|
num_transfers,
|
||||||
|
timeout_ms);
|
||||||
|
if (status != 0) {
|
||||||
|
fprintf(stderr, "Failed to configure TX sync interface: %s\n", bladerf_strerror(status));
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
status = bladerf_enable_module(handler->dev, BLADERF_MODULE_TX, true);
|
||||||
|
if (status != 0) {
|
||||||
|
fprintf(stderr, "Failed to enable TX module: %s\n", bladerf_strerror(status));
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
handler->tx_stream_enabled = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rf_blade_start_rx_stream(void *h)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
rf_blade_handler_t *handler = (rf_blade_handler_t*) h;
|
||||||
|
|
||||||
|
/* Configure the device's RX module for use with the sync interface.
|
||||||
|
* SC16 Q11 samples *with* metadata are used. */
|
||||||
|
uint32_t buffer_size_rx = ms_buffer_size_rx*(handler->rx_rate/1000/1024);
|
||||||
|
|
||||||
|
status = bladerf_sync_config(handler->dev,
|
||||||
|
BLADERF_MODULE_RX,
|
||||||
|
BLADERF_FORMAT_SC16_Q11_META,
|
||||||
|
num_buffers,
|
||||||
|
buffer_size_rx,
|
||||||
|
num_transfers,
|
||||||
|
timeout_ms);
|
||||||
|
if (status != 0) {
|
||||||
|
fprintf(stderr, "Failed to configure RX sync interface: %s\n", bladerf_strerror(status));
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
status = bladerf_sync_config(handler->dev,
|
||||||
|
BLADERF_MODULE_TX,
|
||||||
|
BLADERF_FORMAT_SC16_Q11_META,
|
||||||
|
num_buffers,
|
||||||
|
buffer_size_tx,
|
||||||
|
num_transfers,
|
||||||
|
timeout_ms);
|
||||||
|
if (status != 0) {
|
||||||
|
fprintf(stderr, "Failed to configure TX sync interface: %s\n", bladerf_strerror(status));
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
status = bladerf_enable_module(handler->dev, BLADERF_MODULE_RX, true);
|
||||||
|
if (status != 0) {
|
||||||
|
fprintf(stderr, "Failed to enable RX module: %s\n", bladerf_strerror(status));
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
status = bladerf_enable_module(handler->dev, BLADERF_MODULE_TX, true);
|
||||||
|
if (status != 0) {
|
||||||
|
fprintf(stderr, "Failed to enable TX module: %s\n", bladerf_strerror(status));
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
handler->rx_stream_enabled = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rf_blade_stop_rx_stream(void *h)
|
||||||
|
{
|
||||||
|
rf_blade_handler_t *handler = (rf_blade_handler_t*) h;
|
||||||
|
int status = bladerf_enable_module(handler->dev, BLADERF_MODULE_RX, false);
|
||||||
|
if (status != 0) {
|
||||||
|
fprintf(stderr, "Failed to enable RX module: %s\n", bladerf_strerror(status));
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
status = bladerf_enable_module(handler->dev, BLADERF_MODULE_TX, false);
|
||||||
|
if (status != 0) {
|
||||||
|
fprintf(stderr, "Failed to enable TX module: %s\n", bladerf_strerror(status));
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
handler->rx_stream_enabled = false;
|
||||||
|
handler->tx_stream_enabled = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rf_blade_flush_buffer(void *h)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rf_blade_has_rssi(void *h)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float rf_blade_get_rssi(void *h)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rf_blade_open(char *args, void **h)
|
||||||
|
{
|
||||||
|
*h = NULL;
|
||||||
|
|
||||||
|
rf_blade_handler_t *handler = (rf_blade_handler_t*) malloc(sizeof(rf_blade_handler_t));
|
||||||
|
if (!handler) {
|
||||||
|
perror("malloc");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*h = handler;
|
||||||
|
|
||||||
|
printf("Opening bladeRF...\n");
|
||||||
|
int status = bladerf_open(&handler->dev, args);
|
||||||
|
if (status) {
|
||||||
|
fprintf(stderr, "Unable to open device: %s\n", bladerf_strerror(status));
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
//bladerf_log_set_verbosity(BLADERF_LOG_LEVEL_VERBOSE);
|
||||||
|
|
||||||
|
/* Configure the gains of the RX LNA and RX VGA1*/
|
||||||
|
status = bladerf_set_lna_gain(handler->dev, BLADERF_LNA_GAIN_MAX);
|
||||||
|
if (status != 0) {
|
||||||
|
fprintf(stderr, "Failed to set RX LNA gain: %s\n", bladerf_strerror(status));
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
status = bladerf_set_rxvga1(handler->dev, 27);
|
||||||
|
if (status != 0) {
|
||||||
|
fprintf(stderr, "Failed to set RX VGA1 gain: %s\n", bladerf_strerror(status));
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
status = bladerf_set_txvga1(handler->dev, BLADERF_TXVGA1_GAIN_MAX);
|
||||||
|
if (status != 0) {
|
||||||
|
fprintf(stderr, "Failed to set TX VGA1 gain: %s\n", bladerf_strerror(status));
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
handler->rx_stream_enabled = false;
|
||||||
|
handler->tx_stream_enabled = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int rf_blade_close(void *h)
|
||||||
|
{
|
||||||
|
rf_blade_handler_t *handler = (rf_blade_handler_t*) h;
|
||||||
|
bladerf_close(handler->dev);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rf_blade_set_master_clock_rate(void *h, double rate)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rf_blade_is_master_clock_dynamic(void *h)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
double rf_blade_set_rx_srate(void *h, double freq)
|
||||||
|
{
|
||||||
|
uint32_t bw;
|
||||||
|
rf_blade_handler_t *handler = (rf_blade_handler_t*) h;
|
||||||
|
int status = bladerf_set_sample_rate(handler->dev, BLADERF_MODULE_RX, (uint32_t) freq, &handler->rx_rate);
|
||||||
|
if (status != 0) {
|
||||||
|
fprintf(stderr, "Failed to set samplerate = %u: %s\n", (uint32_t) freq, bladerf_strerror(status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
status = bladerf_set_bandwidth(handler->dev, BLADERF_MODULE_RX, handler->rx_rate, &bw);
|
||||||
|
if (status != 0) {
|
||||||
|
fprintf(stderr, "Failed to set bandwidth = %u: %s\n", handler->rx_rate, bladerf_strerror(status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf("Set RX sampling rate %.2f Mhz, filter BW: %.2f Mhz\n", (float) handler->rx_rate/1e6, (float) bw/1e6);
|
||||||
|
return (double) handler->rx_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
double rf_blade_set_tx_srate(void *h, double freq)
|
||||||
|
{
|
||||||
|
uint32_t bw;
|
||||||
|
rf_blade_handler_t *handler = (rf_blade_handler_t*) h;
|
||||||
|
int status = bladerf_set_sample_rate(handler->dev, BLADERF_MODULE_TX, (uint32_t) freq, &handler->tx_rate);
|
||||||
|
if (status != 0) {
|
||||||
|
fprintf(stderr, "Failed to set samplerate = %u: %s\n", (uint32_t) freq, bladerf_strerror(status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
status = bladerf_set_bandwidth(handler->dev, BLADERF_MODULE_TX, handler->tx_rate, &bw);
|
||||||
|
if (status != 0) {
|
||||||
|
fprintf(stderr, "Failed to set bandwidth = %u: %s\n", handler->tx_rate, bladerf_strerror(status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return (double) handler->tx_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
double rf_blade_set_rx_gain(void *h, double gain)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
rf_blade_handler_t *handler = (rf_blade_handler_t*) h;
|
||||||
|
status = bladerf_set_rxvga2(handler->dev, (int) gain);
|
||||||
|
if (status != 0) {
|
||||||
|
fprintf(stderr, "Failed to set RX VGA2 gain: %s\n", bladerf_strerror(status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return rf_blade_get_rx_gain(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
double rf_blade_set_tx_gain(void *h, double gain)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
rf_blade_handler_t *handler = (rf_blade_handler_t*) h;
|
||||||
|
status = bladerf_set_txvga2(handler->dev, (int) gain);
|
||||||
|
if (status != 0) {
|
||||||
|
fprintf(stderr, "Failed to set TX VGA2 gain: %s\n", bladerf_strerror(status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return rf_blade_get_tx_gain(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
double rf_blade_get_rx_gain(void *h)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
int gain;
|
||||||
|
rf_blade_handler_t *handler = (rf_blade_handler_t*) h;
|
||||||
|
status = bladerf_get_rxvga2(handler->dev, &gain);
|
||||||
|
if (status != 0) {
|
||||||
|
fprintf(stderr, "Failed to get RX VGA2 gain: %s\n",
|
||||||
|
bladerf_strerror(status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return gain; // Add rxvga1 and LNA
|
||||||
|
}
|
||||||
|
|
||||||
|
double rf_blade_get_tx_gain(void *h)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
int gain;
|
||||||
|
rf_blade_handler_t *handler = (rf_blade_handler_t*) h;
|
||||||
|
status = bladerf_get_txvga2(handler->dev, &gain);
|
||||||
|
if (status != 0) {
|
||||||
|
fprintf(stderr, "Failed to get TX VGA2 gain: %s\n",
|
||||||
|
bladerf_strerror(status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return gain; // Add txvga1
|
||||||
|
}
|
||||||
|
|
||||||
|
double rf_blade_set_rx_freq(void *h, double freq)
|
||||||
|
{
|
||||||
|
rf_blade_handler_t *handler = (rf_blade_handler_t*) h;
|
||||||
|
uint32_t f_int = (uint32_t) round(freq);
|
||||||
|
int status = bladerf_set_frequency(handler->dev, BLADERF_MODULE_RX, f_int);
|
||||||
|
if (status != 0) {
|
||||||
|
fprintf(stderr, "Failed to set samplerate = %u: %s\n",
|
||||||
|
(uint32_t) freq, bladerf_strerror(status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
double rf_blade_set_tx_freq(void *h, double freq)
|
||||||
|
{
|
||||||
|
rf_blade_handler_t *handler = (rf_blade_handler_t*) h;
|
||||||
|
uint32_t f_int = (uint32_t) round(freq);
|
||||||
|
int status = bladerf_set_frequency(handler->dev, BLADERF_MODULE_TX, f_int);
|
||||||
|
if (status != 0) {
|
||||||
|
fprintf(stderr, "Failed to set samplerate = %u: %s\n",
|
||||||
|
(uint32_t) freq, bladerf_strerror(status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rf_blade_set_tx_cal(void *h, srslte_rf_cal_t *cal) {
|
||||||
|
rf_blade_handler_t *handler = (rf_blade_handler_t*) h;
|
||||||
|
bladerf_set_correction(handler->dev, BLADERF_MODULE_TX, BLADERF_CORR_FPGA_PHASE, cal->dc_gain);
|
||||||
|
bladerf_set_correction(handler->dev, BLADERF_MODULE_TX, BLADERF_CORR_FPGA_GAIN, cal->dc_phase);
|
||||||
|
bladerf_set_correction(handler->dev, BLADERF_MODULE_TX, BLADERF_CORR_LMS_DCOFF_I, cal->iq_i);
|
||||||
|
bladerf_set_correction(handler->dev, BLADERF_MODULE_TX, BLADERF_CORR_LMS_DCOFF_Q, cal->iq_q);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rf_blade_set_rx_cal(void *h, srslte_rf_cal_t *cal) {
|
||||||
|
rf_blade_handler_t *handler = (rf_blade_handler_t*) h;
|
||||||
|
bladerf_set_correction(handler->dev, BLADERF_MODULE_RX, BLADERF_CORR_FPGA_PHASE, cal->dc_gain);
|
||||||
|
bladerf_set_correction(handler->dev, BLADERF_MODULE_RX, BLADERF_CORR_FPGA_GAIN, cal->dc_phase);
|
||||||
|
bladerf_set_correction(handler->dev, BLADERF_MODULE_RX, BLADERF_CORR_LMS_DCOFF_I, cal->iq_i);
|
||||||
|
bladerf_set_correction(handler->dev, BLADERF_MODULE_RX, BLADERF_CORR_LMS_DCOFF_Q, cal->iq_q);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void timestamp_to_secs(uint32_t rate, uint64_t timestamp, time_t *secs, double *frac_secs) {
|
||||||
|
double totalsecs = (double) timestamp/rate;
|
||||||
|
time_t secs_i = (time_t) totalsecs;
|
||||||
|
if (secs) {
|
||||||
|
*secs = secs_i;
|
||||||
|
}
|
||||||
|
if (frac_secs) {
|
||||||
|
*frac_secs = totalsecs-secs_i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secs_to_timestamps(uint32_t rate, time_t secs, double frac_secs, uint64_t *timestamp) {
|
||||||
|
double totalsecs = (double) secs + frac_secs;
|
||||||
|
if (timestamp) {
|
||||||
|
*timestamp = rate * totalsecs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rf_blade_get_time(void *h, time_t *secs, double *frac_secs)
|
||||||
|
{
|
||||||
|
rf_blade_handler_t *handler = (rf_blade_handler_t*) h;
|
||||||
|
struct bladerf_metadata meta;
|
||||||
|
|
||||||
|
int status = bladerf_get_timestamp(handler->dev, BLADERF_MODULE_RX, &meta.timestamp);
|
||||||
|
if (status != 0) {
|
||||||
|
fprintf(stderr, "Failed to get current RX timestamp: %s\n",
|
||||||
|
bladerf_strerror(status));
|
||||||
|
}
|
||||||
|
timestamp_to_secs(handler->rx_rate, meta.timestamp, secs, frac_secs);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rf_blade_recv_with_time(void *h,
|
||||||
|
void *data,
|
||||||
|
uint32_t nsamples,
|
||||||
|
bool blocking,
|
||||||
|
time_t *secs,
|
||||||
|
double *frac_secs)
|
||||||
|
{
|
||||||
|
rf_blade_handler_t *handler = (rf_blade_handler_t*) h;
|
||||||
|
struct bladerf_metadata meta;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
memset(&meta, 0, sizeof(meta));
|
||||||
|
meta.flags = BLADERF_META_FLAG_RX_NOW;
|
||||||
|
|
||||||
|
if (2*nsamples > CONVERT_BUFFER_SIZE) {
|
||||||
|
fprintf(stderr, "RX failed: nsamples exceeds buffer size (%d>%d)\n", nsamples, CONVERT_BUFFER_SIZE);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
status = bladerf_sync_rx(handler->dev, handler->rx_buffer, nsamples, &meta, 2000);
|
||||||
|
if (status) {
|
||||||
|
fprintf(stderr, "RX failed: %s\n\n", bladerf_strerror(status));
|
||||||
|
return -1;
|
||||||
|
} else if (meta.status & BLADERF_META_STATUS_OVERRUN) {
|
||||||
|
if (blade_error_handler) {
|
||||||
|
srslte_rf_error_t error;
|
||||||
|
error.opt = meta.actual_count;
|
||||||
|
error.type = SRSLTE_RF_ERROR_OVERFLOW;
|
||||||
|
blade_error_handler(error);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Overrun detected in scheduled RX. "
|
||||||
|
"%u valid samples were read.\n\n", meta.actual_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
timestamp_to_secs(handler->rx_rate, meta.timestamp, secs, frac_secs);
|
||||||
|
srslte_vec_convert_if(handler->rx_buffer, data, 2048, 2*nsamples);
|
||||||
|
|
||||||
|
return nsamples;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
status = bladerf_sync_tx(handler->dev, handler->tx_buffer, nsamples, &meta, 2000);
|
||||||
|
if (status == BLADERF_ERR_TIME_PAST) {
|
||||||
|
if (blade_error_handler) {
|
||||||
|
srslte_rf_error_t error;
|
||||||
|
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) {
|
||||||
|
srslte_rf_error_t error;
|
||||||
|
error.type = SRSLTE_RF_ERROR_UNDERFLOW;
|
||||||
|
blade_error_handler(error);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "TX warning: underflow detected.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nsamples;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,110 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \section COPYRIGHT
|
||||||
|
*
|
||||||
|
* Copyright 2013-2015 Software Radio Systems Limited
|
||||||
|
*
|
||||||
|
* \section LICENSE
|
||||||
|
*
|
||||||
|
* This file is part of the srsLTE library.
|
||||||
|
*
|
||||||
|
* srsLTE is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* srsLTE is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* A copy of the GNU Affero General Public License can be found in
|
||||||
|
* the LICENSE file in the top-level directory of this distribution
|
||||||
|
* and at http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "srslte/config.h"
|
||||||
|
#include "srslte/rf/rf.h"
|
||||||
|
|
||||||
|
SRSLTE_API int rf_blade_open(char *args,
|
||||||
|
void **handler);
|
||||||
|
|
||||||
|
SRSLTE_API int rf_blade_close(void *h);
|
||||||
|
|
||||||
|
SRSLTE_API void rf_blade_set_tx_cal(void *h, srslte_rf_cal_t *cal);
|
||||||
|
|
||||||
|
SRSLTE_API void rf_blade_set_rx_cal(void *h, srslte_rf_cal_t *cal);
|
||||||
|
|
||||||
|
SRSLTE_API int rf_blade_start_rx_stream(void *h);
|
||||||
|
|
||||||
|
SRSLTE_API int rf_blade_start_rx_stream_nsamples(void *h,
|
||||||
|
uint32_t nsamples);
|
||||||
|
|
||||||
|
SRSLTE_API int rf_blade_stop_rx_stream(void *h);
|
||||||
|
|
||||||
|
SRSLTE_API void rf_blade_flush_buffer(void *h);
|
||||||
|
|
||||||
|
SRSLTE_API bool rf_blade_has_rssi(void *h);
|
||||||
|
|
||||||
|
SRSLTE_API float rf_blade_get_rssi(void *h);
|
||||||
|
|
||||||
|
SRSLTE_API bool rf_blade_rx_wait_lo_locked(void *h);
|
||||||
|
|
||||||
|
SRSLTE_API void rf_blade_set_master_clock_rate(void *h,
|
||||||
|
double rate);
|
||||||
|
|
||||||
|
SRSLTE_API bool rf_blade_is_master_clock_dynamic(void *h);
|
||||||
|
|
||||||
|
SRSLTE_API double rf_blade_set_rx_srate(void *h,
|
||||||
|
double freq);
|
||||||
|
|
||||||
|
SRSLTE_API double rf_blade_set_rx_gain(void *h,
|
||||||
|
double gain);
|
||||||
|
|
||||||
|
SRSLTE_API float rf_blade_get_rx_gain_offset(void *h);
|
||||||
|
|
||||||
|
SRSLTE_API double rf_blade_get_rx_gain(void *h);
|
||||||
|
|
||||||
|
SRSLTE_API double rf_blade_get_tx_gain(void *h);
|
||||||
|
|
||||||
|
SRSLTE_API void rf_blade_suppress_stdout(void *h);
|
||||||
|
|
||||||
|
SRSLTE_API void rf_blade_register_error_handler(void *h,
|
||||||
|
srslte_rf_error_handler_t error_handler);
|
||||||
|
|
||||||
|
SRSLTE_API double rf_blade_set_rx_freq(void *h,
|
||||||
|
double freq);
|
||||||
|
|
||||||
|
SRSLTE_API int rf_blade_recv_with_time(void *h,
|
||||||
|
void *data,
|
||||||
|
uint32_t nsamples,
|
||||||
|
bool blocking,
|
||||||
|
time_t *secs,
|
||||||
|
double *frac_secs);
|
||||||
|
|
||||||
|
SRSLTE_API double rf_blade_set_tx_srate(void *h,
|
||||||
|
double freq);
|
||||||
|
|
||||||
|
SRSLTE_API double rf_blade_set_tx_gain(void *h,
|
||||||
|
double gain);
|
||||||
|
|
||||||
|
SRSLTE_API double rf_blade_set_tx_freq(void *h,
|
||||||
|
double freq);
|
||||||
|
|
||||||
|
SRSLTE_API void rf_blade_get_time(void *h,
|
||||||
|
time_t *secs,
|
||||||
|
double *frac_secs);
|
||||||
|
|
||||||
|
SRSLTE_API 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);
|
||||||
|
|
||||||
|
|
@ -0,0 +1,141 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \section COPYRIGHT
|
||||||
|
*
|
||||||
|
* Copyright 2013-2015 Software Radio Systems Limited
|
||||||
|
*
|
||||||
|
* \section LICENSE
|
||||||
|
*
|
||||||
|
* This file is part of the srsLTE library.
|
||||||
|
*
|
||||||
|
* srsLTE is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* srsLTE is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* A copy of the GNU Affero General Public License can be found in
|
||||||
|
* the LICENSE file in the top-level directory of this distribution
|
||||||
|
* and at http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* RF frontend API */
|
||||||
|
typedef struct {
|
||||||
|
const char *name;
|
||||||
|
bool (*srslte_rf_rx_wait_lo_locked) (void*);
|
||||||
|
int (*srslte_rf_start_rx_stream)(void *h);
|
||||||
|
int (*srslte_rf_stop_rx_stream)(void *h);
|
||||||
|
void (*srslte_rf_flush_buffer)(void *h);
|
||||||
|
bool (*srslte_rf_has_rssi)(void *h);
|
||||||
|
float (*srslte_rf_get_rssi)(void *h);
|
||||||
|
void (*srslte_rf_suppress_stdout)(void *h);
|
||||||
|
void (*srslte_rf_register_error_handler)(void *h, srslte_rf_error_handler_t error_handler);
|
||||||
|
int (*srslte_rf_open)(char *args, void **h);
|
||||||
|
int (*srslte_rf_close)(void *h);
|
||||||
|
void (*srslte_rf_set_master_clock_rate)(void *h, double rate);
|
||||||
|
bool (*srslte_rf_is_master_clock_dynamic)(void *h);
|
||||||
|
double (*srslte_rf_set_rx_srate)(void *h, double freq);
|
||||||
|
double (*srslte_rf_set_rx_gain)(void *h, double gain);
|
||||||
|
double (*srslte_rf_set_tx_gain)(void *h, double gain);
|
||||||
|
double (*srslte_rf_get_rx_gain)(void *h);
|
||||||
|
double (*srslte_rf_get_tx_gain)(void *h);
|
||||||
|
double (*srslte_rf_set_rx_freq)(void *h, double freq);
|
||||||
|
double (*srslte_rf_set_tx_srate)(void *h, double freq);
|
||||||
|
double (*srslte_rf_set_tx_freq)(void *h, double freq);
|
||||||
|
void (*srslte_rf_get_time)(void *h, time_t *secs, double *frac_secs);
|
||||||
|
int (*srslte_rf_recv_with_time)(void *h, void *data, uint32_t nsamples,
|
||||||
|
bool blocking, time_t *secs,double *frac_secs);
|
||||||
|
int (*srslte_rf_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);
|
||||||
|
void (*srslte_rf_set_tx_cal)(void *h, srslte_rf_cal_t *cal);
|
||||||
|
|
||||||
|
void (*srslte_rf_set_rx_cal)(void *h, srslte_rf_cal_t *cal);
|
||||||
|
|
||||||
|
} rf_dev_t;
|
||||||
|
|
||||||
|
/* Define implementation for UHD */
|
||||||
|
#ifdef ENABLE_UHD
|
||||||
|
|
||||||
|
#include "rf_uhd_imp.h"
|
||||||
|
|
||||||
|
static rf_dev_t dev_uhd = {
|
||||||
|
"UHD",
|
||||||
|
rf_uhd_rx_wait_lo_locked,
|
||||||
|
rf_uhd_start_rx_stream,
|
||||||
|
rf_uhd_stop_rx_stream,
|
||||||
|
rf_uhd_flush_buffer,
|
||||||
|
rf_uhd_has_rssi,
|
||||||
|
rf_uhd_get_rssi,
|
||||||
|
rf_uhd_suppress_stdout,
|
||||||
|
rf_uhd_register_error_handler,
|
||||||
|
rf_uhd_open,
|
||||||
|
rf_uhd_close,
|
||||||
|
rf_uhd_set_master_clock_rate,
|
||||||
|
rf_uhd_is_master_clock_dynamic,
|
||||||
|
rf_uhd_set_rx_srate,
|
||||||
|
rf_uhd_set_rx_gain,
|
||||||
|
rf_uhd_set_tx_gain,
|
||||||
|
rf_uhd_get_rx_gain,
|
||||||
|
rf_uhd_get_tx_gain,
|
||||||
|
rf_uhd_set_rx_freq,
|
||||||
|
rf_uhd_set_tx_srate,
|
||||||
|
rf_uhd_set_tx_freq,
|
||||||
|
rf_uhd_get_time,
|
||||||
|
rf_uhd_recv_with_time,
|
||||||
|
rf_uhd_send_timed,
|
||||||
|
rf_uhd_set_tx_cal,
|
||||||
|
rf_uhd_set_rx_cal
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Define implementation for bladeRF */
|
||||||
|
#ifdef ENABLE_BLADERF
|
||||||
|
|
||||||
|
#include "rf_blade_imp.h"
|
||||||
|
|
||||||
|
static rf_dev_t dev_blade = {
|
||||||
|
"bladeRF",
|
||||||
|
rf_blade_rx_wait_lo_locked,
|
||||||
|
rf_blade_start_rx_stream,
|
||||||
|
rf_blade_stop_rx_stream,
|
||||||
|
rf_blade_flush_buffer,
|
||||||
|
rf_blade_has_rssi,
|
||||||
|
rf_blade_get_rssi,
|
||||||
|
rf_blade_suppress_stdout,
|
||||||
|
rf_blade_register_error_handler,
|
||||||
|
rf_blade_open,
|
||||||
|
rf_blade_close,
|
||||||
|
rf_blade_set_master_clock_rate,
|
||||||
|
rf_blade_is_master_clock_dynamic,
|
||||||
|
rf_blade_set_rx_srate,
|
||||||
|
rf_blade_set_rx_gain,
|
||||||
|
rf_blade_set_tx_gain,
|
||||||
|
rf_blade_get_rx_gain,
|
||||||
|
rf_blade_get_tx_gain,
|
||||||
|
rf_blade_set_rx_freq,
|
||||||
|
rf_blade_set_tx_srate,
|
||||||
|
rf_blade_set_tx_freq,
|
||||||
|
rf_blade_get_time,
|
||||||
|
rf_blade_recv_with_time,
|
||||||
|
rf_blade_send_timed,
|
||||||
|
rf_blade_set_tx_cal,
|
||||||
|
rf_blade_set_rx_cal
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static rf_dev_t *available_devices[] = {
|
||||||
|
#ifdef ENABLE_UHD
|
||||||
|
&dev_uhd,
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_BLADERF
|
||||||
|
&dev_blade,
|
||||||
|
#endif
|
||||||
|
NULL
|
||||||
|
};
|
@ -0,0 +1,309 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \section COPYRIGHT
|
||||||
|
*
|
||||||
|
* Copyright 2013-2015 Software Radio Systems Limited
|
||||||
|
*
|
||||||
|
* \section LICENSE
|
||||||
|
*
|
||||||
|
* This file is part of the srsLTE library.
|
||||||
|
*
|
||||||
|
* srsLTE is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* srsLTE is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* A copy of the GNU Affero General Public License can be found in
|
||||||
|
* the LICENSE file in the top-level directory of this distribution
|
||||||
|
* and at http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "srslte/rf/rf.h"
|
||||||
|
#include "srslte/srslte.h"
|
||||||
|
#include "rf_dev.h"
|
||||||
|
|
||||||
|
int rf_get_available_devices(char **devnames, int max_strlen) {
|
||||||
|
int i=0;
|
||||||
|
while(available_devices[i]->name) {
|
||||||
|
strncpy(devnames[i], available_devices[i]->name, max_strlen);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
double srslte_rf_set_rx_gain_th(srslte_rf_t *rf, double gain)
|
||||||
|
{
|
||||||
|
if (gain > rf->new_rx_gain + 0.5 || gain < rf->new_rx_gain - 0.5) {
|
||||||
|
pthread_mutex_lock(&rf->mutex);
|
||||||
|
rf->new_rx_gain = gain;
|
||||||
|
pthread_cond_signal(&rf->cond);
|
||||||
|
pthread_mutex_unlock(&rf->mutex);
|
||||||
|
}
|
||||||
|
return gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
void srslte_rf_set_tx_rx_gain_offset(srslte_rf_t *rf, double offset) {
|
||||||
|
rf->tx_rx_gain_offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This thread listens for set_rx_gain commands to the USRP */
|
||||||
|
static void* thread_gain_fcn(void *h) {
|
||||||
|
srslte_rf_t* rf = (srslte_rf_t*) h;
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
pthread_mutex_lock(&rf->mutex);
|
||||||
|
while(rf->cur_rx_gain == rf->new_rx_gain)
|
||||||
|
{
|
||||||
|
pthread_cond_wait(&rf->cond, &rf->mutex);
|
||||||
|
}
|
||||||
|
if (rf->new_rx_gain != rf->cur_rx_gain) {
|
||||||
|
rf->cur_rx_gain = rf->new_rx_gain;
|
||||||
|
srslte_rf_set_rx_gain(h, rf->cur_rx_gain);
|
||||||
|
}
|
||||||
|
if (rf->tx_gain_same_rx) {
|
||||||
|
srslte_rf_set_tx_gain(h, rf->cur_rx_gain+rf->tx_rx_gain_offset);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&rf->mutex);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Create auxiliary thread and mutexes for AGC */
|
||||||
|
int srslte_rf_start_gain_thread(srslte_rf_t *rf, bool tx_gain_same_rx) {
|
||||||
|
rf->tx_gain_same_rx = tx_gain_same_rx;
|
||||||
|
rf->tx_rx_gain_offset = 0.0;
|
||||||
|
if (pthread_mutex_init(&rf->mutex, NULL)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (pthread_cond_init(&rf->cond, NULL)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (pthread_create(&rf->thread_gain, NULL, thread_gain_fcn, rf)) {
|
||||||
|
perror("pthread_create");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* srslte_rf_get_devname(srslte_rf_t *rf) {
|
||||||
|
return ((rf_dev_t*) rf->dev)->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
int srslte_rf_open_devname(srslte_rf_t *rf, char *devname, char *args) {
|
||||||
|
/* Try to open the device if name is provided */
|
||||||
|
if (devname) {
|
||||||
|
if (devname[0] != '\0') {
|
||||||
|
int i=0;
|
||||||
|
while(available_devices[i] != NULL) {
|
||||||
|
if (!strcmp(available_devices[i]->name, devname)) {
|
||||||
|
rf->dev = available_devices[i];
|
||||||
|
return available_devices[i]->srslte_rf_open(args, &rf->handler);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
printf("Device %s not found. Switching to auto mode\n", devname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If in auto mode or provided device not found, try to open in order of apperance in available_devices[] array */
|
||||||
|
int i=0;
|
||||||
|
while(available_devices[i] != NULL) {
|
||||||
|
if (!available_devices[i]->srslte_rf_open(args, &rf->handler)) {
|
||||||
|
rf->dev = available_devices[i];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "No compatible RF frontend found\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void srslte_rf_set_tx_cal(srslte_rf_t *rf, srslte_rf_cal_t *cal) {
|
||||||
|
return ((rf_dev_t*) rf->dev)->srslte_rf_set_tx_cal(rf->handler, cal);
|
||||||
|
}
|
||||||
|
|
||||||
|
void srslte_rf_set_rx_cal(srslte_rf_t *rf, srslte_rf_cal_t *cal) {
|
||||||
|
return ((rf_dev_t*) rf->dev)->srslte_rf_set_rx_cal(rf->handler, cal);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char* srslte_rf_name(srslte_rf_t *rf) {
|
||||||
|
return ((rf_dev_t*) rf->dev)->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool srslte_rf_rx_wait_lo_locked(srslte_rf_t *rf)
|
||||||
|
{
|
||||||
|
return ((rf_dev_t*) rf->dev)->srslte_rf_rx_wait_lo_locked(rf->handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
int srslte_rf_start_rx_stream(srslte_rf_t *rf)
|
||||||
|
{
|
||||||
|
return ((rf_dev_t*) rf->dev)->srslte_rf_start_rx_stream(rf->handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
int srslte_rf_stop_rx_stream(srslte_rf_t *rf)
|
||||||
|
{
|
||||||
|
return ((rf_dev_t*) rf->dev)->srslte_rf_stop_rx_stream(rf->handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void srslte_rf_flush_buffer(srslte_rf_t *rf)
|
||||||
|
{
|
||||||
|
((rf_dev_t*) rf->dev)->srslte_rf_flush_buffer(rf->handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool srslte_rf_has_rssi(srslte_rf_t *rf)
|
||||||
|
{
|
||||||
|
return ((rf_dev_t*) rf->dev)->srslte_rf_has_rssi(rf->handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
float srslte_rf_get_rssi(srslte_rf_t *rf)
|
||||||
|
{
|
||||||
|
return ((rf_dev_t*) rf->dev)->srslte_rf_get_rssi(rf->handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void srslte_rf_suppress_stdout(srslte_rf_t *rf)
|
||||||
|
{
|
||||||
|
((rf_dev_t*) rf->dev)->srslte_rf_suppress_stdout(rf->handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void srslte_rf_register_error_handler(srslte_rf_t *rf, srslte_rf_error_handler_t error_handler)
|
||||||
|
{
|
||||||
|
((rf_dev_t*) rf->dev)->srslte_rf_register_error_handler(rf->handler, error_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
int srslte_rf_open(srslte_rf_t *h, char *args)
|
||||||
|
{
|
||||||
|
return srslte_rf_open_devname(h, NULL, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
int srslte_rf_close(srslte_rf_t *rf)
|
||||||
|
{
|
||||||
|
return ((rf_dev_t*) rf->dev)->srslte_rf_close(rf->handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void srslte_rf_set_master_clock_rate(srslte_rf_t *rf, double rate)
|
||||||
|
{
|
||||||
|
((rf_dev_t*) rf->dev)->srslte_rf_set_master_clock_rate(rf->handler, rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool srslte_rf_is_master_clock_dynamic(srslte_rf_t *rf)
|
||||||
|
{
|
||||||
|
return ((rf_dev_t*) rf->dev)->srslte_rf_is_master_clock_dynamic(rf->handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
double srslte_rf_set_rx_srate(srslte_rf_t *rf, double freq)
|
||||||
|
{
|
||||||
|
return ((rf_dev_t*) rf->dev)->srslte_rf_set_rx_srate(rf->handler, freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
double srslte_rf_set_rx_gain(srslte_rf_t *rf, double gain)
|
||||||
|
{
|
||||||
|
return ((rf_dev_t*) rf->dev)->srslte_rf_set_rx_gain(rf->handler, gain);
|
||||||
|
}
|
||||||
|
|
||||||
|
double srslte_rf_get_rx_gain(srslte_rf_t *rf)
|
||||||
|
{
|
||||||
|
return ((rf_dev_t*) rf->dev)->srslte_rf_get_rx_gain(rf->handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
double srslte_rf_get_tx_gain(srslte_rf_t *rf)
|
||||||
|
{
|
||||||
|
return ((rf_dev_t*) rf->dev)->srslte_rf_get_tx_gain(rf->handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
double srslte_rf_set_rx_freq(srslte_rf_t *rf, double freq)
|
||||||
|
{
|
||||||
|
return ((rf_dev_t*) rf->dev)->srslte_rf_set_rx_freq(rf->handler, freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int srslte_rf_recv(srslte_rf_t *rf, void *data, uint32_t nsamples, bool blocking)
|
||||||
|
{
|
||||||
|
return srslte_rf_recv_with_time(rf, data, nsamples, blocking, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int srslte_rf_recv_with_time(srslte_rf_t *rf,
|
||||||
|
void *data,
|
||||||
|
uint32_t nsamples,
|
||||||
|
bool blocking,
|
||||||
|
time_t *secs,
|
||||||
|
double *frac_secs)
|
||||||
|
{
|
||||||
|
return ((rf_dev_t*) rf->dev)->srslte_rf_recv_with_time(rf->handler, data, nsamples, blocking, secs, frac_secs);
|
||||||
|
}
|
||||||
|
|
||||||
|
double srslte_rf_set_tx_gain(srslte_rf_t *rf, double gain)
|
||||||
|
{
|
||||||
|
return ((rf_dev_t*) rf->dev)->srslte_rf_set_tx_gain(rf->handler, gain);
|
||||||
|
}
|
||||||
|
|
||||||
|
double srslte_rf_set_tx_srate(srslte_rf_t *rf, double freq)
|
||||||
|
{
|
||||||
|
return ((rf_dev_t*) rf->dev)->srslte_rf_set_tx_srate(rf->handler, freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
double srslte_rf_set_tx_freq(srslte_rf_t *rf, double freq)
|
||||||
|
{
|
||||||
|
return ((rf_dev_t*) rf->dev)->srslte_rf_set_tx_freq(rf->handler, freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
void srslte_rf_get_time(srslte_rf_t *rf, time_t *secs, double *frac_secs)
|
||||||
|
{
|
||||||
|
return ((rf_dev_t*) rf->dev)->srslte_rf_get_time(rf->handler, secs, frac_secs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int srslte_rf_send_timed3(srslte_rf_t *rf,
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
|
||||||
|
return ((rf_dev_t*) rf->dev)->srslte_rf_send_timed(rf->handler, data, nsamples, secs, frac_secs,
|
||||||
|
has_time_spec, blocking, is_start_of_burst, is_end_of_burst);
|
||||||
|
}
|
||||||
|
|
||||||
|
int srslte_rf_send(srslte_rf_t *rf, void *data, uint32_t nsamples, bool blocking)
|
||||||
|
{
|
||||||
|
return srslte_rf_send2(rf, data, nsamples, blocking, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int srslte_rf_send2(srslte_rf_t *rf, void *data, uint32_t nsamples, bool blocking, bool start_of_burst, bool end_of_burst)
|
||||||
|
{
|
||||||
|
return srslte_rf_send_timed3(rf, data, nsamples, 0, 0, false, blocking, start_of_burst, end_of_burst);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int srslte_rf_send_timed(srslte_rf_t *rf,
|
||||||
|
void *data,
|
||||||
|
int nsamples,
|
||||||
|
time_t secs,
|
||||||
|
double frac_secs)
|
||||||
|
{
|
||||||
|
return srslte_rf_send_timed2(rf, data, nsamples, secs, frac_secs, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int srslte_rf_send_timed2(srslte_rf_t *rf,
|
||||||
|
void *data,
|
||||||
|
int nsamples,
|
||||||
|
time_t secs,
|
||||||
|
double frac_secs,
|
||||||
|
bool is_start_of_burst,
|
||||||
|
bool is_end_of_burst)
|
||||||
|
{
|
||||||
|
return srslte_rf_send_timed3(rf, data, nsamples, secs, frac_secs, true, true, is_start_of_burst, is_end_of_burst);
|
||||||
|
}
|
@ -0,0 +1,523 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \section COPYRIGHT
|
||||||
|
*
|
||||||
|
* Copyright 2013-2015 Software Radio Systems Limited
|
||||||
|
*
|
||||||
|
* \section LICENSE
|
||||||
|
*
|
||||||
|
* This file is part of the srsLTE library.
|
||||||
|
*
|
||||||
|
* srsLTE is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* srsLTE is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* A copy of the GNU Affero General Public License can be found in
|
||||||
|
* the LICENSE file in the top-level directory of this distribution
|
||||||
|
* and at http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <uhd.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "srslte/srslte.h"
|
||||||
|
#include "rf_uhd_imp.h"
|
||||||
|
#include "srslte/rf/rf.h"
|
||||||
|
#include "uhd_c_api.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uhd_usrp_handle usrp;
|
||||||
|
uhd_rx_streamer_handle rx_stream;
|
||||||
|
uhd_tx_streamer_handle tx_stream;
|
||||||
|
|
||||||
|
uhd_rx_metadata_handle rx_md, rx_md_first;
|
||||||
|
uhd_tx_metadata_handle tx_md;
|
||||||
|
|
||||||
|
uhd_meta_range_handle rx_gain_range;
|
||||||
|
size_t rx_nof_samples;
|
||||||
|
size_t tx_nof_samples;
|
||||||
|
double tx_rate;
|
||||||
|
bool dynamic_rate;
|
||||||
|
} rf_uhd_handler_t;
|
||||||
|
|
||||||
|
void suppress_handler(const char *x)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
srslte_rf_error_handler_t uhd_error_handler = NULL;
|
||||||
|
|
||||||
|
void msg_handler(const char *msg)
|
||||||
|
{
|
||||||
|
srslte_rf_error_t error;
|
||||||
|
if(0 == strcmp(msg, "O")) {
|
||||||
|
error.type = SRSLTE_RF_ERROR_OVERFLOW;
|
||||||
|
} else if(0 == strcmp(msg, "D")) {
|
||||||
|
error.type = SRSLTE_RF_ERROR_OVERFLOW;
|
||||||
|
}else if(0 == strcmp(msg, "U")) {
|
||||||
|
error.type = SRSLTE_RF_ERROR_UNDERFLOW;
|
||||||
|
} else if(0 == strcmp(msg, "L")) {
|
||||||
|
error.type = SRSLTE_RF_ERROR_LATE;
|
||||||
|
}
|
||||||
|
if (uhd_error_handler) {
|
||||||
|
uhd_error_handler(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rf_uhd_suppress_stdout(void *h) {
|
||||||
|
rf_uhd_register_msg_handler_c(suppress_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rf_uhd_register_error_handler(void *notused, srslte_rf_error_handler_t new_handler)
|
||||||
|
{
|
||||||
|
uhd_error_handler = new_handler;
|
||||||
|
rf_uhd_register_msg_handler_c(msg_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
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++) {
|
||||||
|
uhd_string_vector_at(h, i, buff, 128);
|
||||||
|
if (strstr(buff, str)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isLocked(rf_uhd_handler_t *handler, char *sensor_name, uhd_sensor_value_handle *value_h)
|
||||||
|
{
|
||||||
|
bool val_out = false;
|
||||||
|
|
||||||
|
if (sensor_name) {
|
||||||
|
uhd_usrp_get_rx_sensor(handler->usrp, sensor_name, 0, value_h);
|
||||||
|
uhd_sensor_value_to_bool(*value_h, &val_out);
|
||||||
|
} else {
|
||||||
|
usleep(500);
|
||||||
|
val_out = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return val_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rf_uhd_rx_wait_lo_locked(void *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);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
double report = 0.0;
|
||||||
|
while (!isLocked(handler, sensor_name, &value_h) && report < 30.0) {
|
||||||
|
report += 0.1;
|
||||||
|
usleep(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool val = isLocked(handler, sensor_name, &value_h);
|
||||||
|
|
||||||
|
uhd_string_vector_free(&mb_sensors);
|
||||||
|
uhd_string_vector_free(&rx_sensors);
|
||||||
|
uhd_sensor_value_free(&value_h);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rf_uhd_set_tx_cal(void *h, srslte_rf_cal_t *cal)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void rf_uhd_set_rx_cal(void *h, srslte_rf_cal_t *cal)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int rf_uhd_start_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_START_CONTINUOUS,
|
||||||
|
.stream_now = true
|
||||||
|
};
|
||||||
|
uhd_rx_streamer_issue_stream_cmd(handler->rx_stream, &stream_cmd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
};
|
||||||
|
uhd_rx_streamer_issue_stream_cmd(handler->rx_stream, &stream_cmd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rf_uhd_flush_buffer(void *h)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
cf_t tmp[1024];
|
||||||
|
do {
|
||||||
|
n = rf_uhd_recv_with_time(h, tmp, 1024, 0, NULL, NULL);
|
||||||
|
} while (n > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rf_uhd_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);
|
||||||
|
bool ret = find_string(rx_sensors, "rssi");
|
||||||
|
uhd_string_vector_free(&rx_sensors);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
float rf_uhd_get_rssi(void *h) {
|
||||||
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
||||||
|
uhd_sensor_value_handle value;
|
||||||
|
uhd_sensor_value_make_from_realnum(&value, "rssi", 0, "dBm", "%f");
|
||||||
|
uhd_usrp_get_rx_sensor(handler->usrp, "rssi", 0, &value);
|
||||||
|
double val_out;
|
||||||
|
uhd_sensor_value_to_realnum(value, &val_out);
|
||||||
|
uhd_sensor_value_free(&value);
|
||||||
|
return val_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rf_uhd_open(char *args, void **h)
|
||||||
|
{
|
||||||
|
if (h) {
|
||||||
|
*h = NULL;
|
||||||
|
|
||||||
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) malloc(sizeof(rf_uhd_handler_t));
|
||||||
|
if (!handler) {
|
||||||
|
perror("malloc");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*h = handler;
|
||||||
|
|
||||||
|
/* Set priority to UHD threads */
|
||||||
|
uhd_set_thread_priority(uhd_default_thread_priority, true);
|
||||||
|
|
||||||
|
/* Set correct options for the USRP device */
|
||||||
|
uhd_string_vector_handle devices_str;
|
||||||
|
uhd_string_vector_make(&devices_str);
|
||||||
|
uhd_usrp_find("", &devices_str);
|
||||||
|
|
||||||
|
// Allow NULL parameter
|
||||||
|
if (args == NULL) {
|
||||||
|
args = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If device type or name not given in args, choose a B200 */
|
||||||
|
if (args[0]=='\0') {
|
||||||
|
// If B200 is available, use it
|
||||||
|
if (find_string(devices_str, "type=b200") && !strstr(args, "recv_frame_size")) {
|
||||||
|
args = "type=b200,recv_frame_size=9232,send_frame_size=9232";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create UHD handler */
|
||||||
|
printf("Opening USRP with args: %s\n", args);
|
||||||
|
uhd_error error = uhd_usrp_make(&handler->usrp, args);
|
||||||
|
if (error) {
|
||||||
|
fprintf(stderr, "Error opening UHD: code %d\n", error);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t channel = 0;
|
||||||
|
uhd_stream_args_t stream_args = {
|
||||||
|
.cpu_format = "fc32",
|
||||||
|
.otw_format = "sc16",
|
||||||
|
.args = "",
|
||||||
|
.channel_list = &channel,
|
||||||
|
.n_channels = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Initialize rx and tx stremers */
|
||||||
|
uhd_rx_streamer_make(&handler->rx_stream);
|
||||||
|
error = uhd_usrp_get_rx_stream(handler->usrp, &stream_args, handler->rx_stream);
|
||||||
|
if (error) {
|
||||||
|
fprintf(stderr, "Error opening RX stream: %d\n", error);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
uhd_tx_streamer_make(&handler->tx_stream);
|
||||||
|
error = uhd_usrp_get_tx_stream(handler->usrp, &stream_args, handler->tx_stream);
|
||||||
|
if (error) {
|
||||||
|
fprintf(stderr, "Error opening TX stream: %d\n", error);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uhd_rx_streamer_max_num_samps(handler->rx_stream, &handler->rx_nof_samples);
|
||||||
|
uhd_tx_streamer_max_num_samps(handler->tx_stream, &handler->tx_nof_samples);
|
||||||
|
|
||||||
|
uhd_meta_range_make(&handler->rx_gain_range);
|
||||||
|
uhd_usrp_get_rx_gain_range(handler->usrp, "", 0, handler->rx_gain_range);
|
||||||
|
|
||||||
|
// Make metadata objects for RX/TX
|
||||||
|
uhd_rx_metadata_make(&handler->rx_md);
|
||||||
|
uhd_rx_metadata_make(&handler->rx_md_first);
|
||||||
|
uhd_tx_metadata_make(&handler->tx_md, false, 0, 0, false, false);
|
||||||
|
|
||||||
|
/* Find out if the master clock rate is configurable */
|
||||||
|
double cur_clock, new_clock;
|
||||||
|
uhd_usrp_get_master_clock_rate(handler->usrp, 0, &cur_clock);
|
||||||
|
printf("Trying to dynamically change Master clock...\n");
|
||||||
|
uhd_usrp_set_master_clock_rate(handler->usrp, cur_clock/2, 0);
|
||||||
|
uhd_usrp_get_master_clock_rate(handler->usrp, 0, &new_clock);
|
||||||
|
if (new_clock == cur_clock) {
|
||||||
|
handler->dynamic_rate = false;
|
||||||
|
/* Master clock rate is not configurable. Check if it is compatible with LTE */
|
||||||
|
int cur_clock_i = (int) cur_clock;
|
||||||
|
if (cur_clock_i % 1920000) {
|
||||||
|
fprintf(stderr, "Error: LTE sampling rates are not supported. Master clock rate is %.1f MHz\n", cur_clock/1e6);
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
printf("Master clock is not configurable. Using standard symbol sizes and sampling rates.\n");
|
||||||
|
srslte_use_standard_symbol_size(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("Master clock is configurable. Using reduced symbol sizes and sampling rates.\n");
|
||||||
|
handler->dynamic_rate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int rf_uhd_close(void *h)
|
||||||
|
{
|
||||||
|
rf_uhd_stop_rx_stream(h);
|
||||||
|
|
||||||
|
/** Something else to close the USRP?? */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rf_uhd_set_master_clock_rate(void *h, double rate) {
|
||||||
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
||||||
|
if (handler->dynamic_rate) {
|
||||||
|
uhd_usrp_set_master_clock_rate(handler->usrp, rate, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
||||||
|
uhd_usrp_set_rx_rate(handler->usrp, freq, 0);
|
||||||
|
uhd_usrp_get_rx_rate(handler->usrp, 0, &freq);
|
||||||
|
return freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
double rf_uhd_set_tx_srate(void *h, double freq)
|
||||||
|
{
|
||||||
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
||||||
|
uhd_usrp_set_tx_rate(handler->usrp, freq, 0);
|
||||||
|
uhd_usrp_get_tx_rate(handler->usrp, 0, &freq);
|
||||||
|
handler->tx_rate = freq;
|
||||||
|
return freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
double rf_uhd_set_rx_gain(void *h, double gain)
|
||||||
|
{
|
||||||
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
||||||
|
uhd_usrp_set_rx_gain(handler->usrp, gain, 0, "");
|
||||||
|
uhd_usrp_get_rx_gain(handler->usrp, 0, "", &gain);
|
||||||
|
return gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
double rf_uhd_set_tx_gain(void *h, double gain)
|
||||||
|
{
|
||||||
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
||||||
|
uhd_usrp_set_tx_gain(handler->usrp, gain, 0, "");
|
||||||
|
uhd_usrp_get_tx_gain(handler->usrp, 0, "", &gain);
|
||||||
|
return gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
double rf_uhd_get_rx_gain(void *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)
|
||||||
|
{
|
||||||
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
||||||
|
double gain;
|
||||||
|
uhd_usrp_get_tx_gain(handler->usrp, 0, "", &gain);
|
||||||
|
return gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
double rf_uhd_set_rx_freq(void *h, double freq)
|
||||||
|
{
|
||||||
|
uhd_tune_request_t tune_request = {
|
||||||
|
.target_freq = freq,
|
||||||
|
.rf_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO,
|
||||||
|
.dsp_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO,
|
||||||
|
};
|
||||||
|
uhd_tune_result_t tune_result;
|
||||||
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
||||||
|
uhd_usrp_set_rx_freq(handler->usrp, &tune_request, 0, &tune_result);
|
||||||
|
uhd_usrp_get_rx_freq(handler->usrp, 0, &freq);
|
||||||
|
return freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
double rf_uhd_set_tx_freq(void *h, double freq)
|
||||||
|
{
|
||||||
|
uhd_tune_request_t tune_request = {
|
||||||
|
.target_freq = freq,
|
||||||
|
.rf_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO,
|
||||||
|
.dsp_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO,
|
||||||
|
};
|
||||||
|
uhd_tune_result_t tune_result;
|
||||||
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
||||||
|
uhd_usrp_set_tx_freq(handler->usrp, &tune_request, 0, &tune_result);
|
||||||
|
uhd_usrp_get_tx_freq(handler->usrp, 0, &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;
|
||||||
|
uhd_usrp_get_time_now(handler->usrp, 0, secs, frac_secs);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rf_uhd_recv_with_time(void *h,
|
||||||
|
void *data,
|
||||||
|
uint32_t nsamples,
|
||||||
|
bool blocking,
|
||||||
|
time_t *secs,
|
||||||
|
double *frac_secs)
|
||||||
|
{
|
||||||
|
|
||||||
|
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
|
||||||
|
size_t rxd_samples;
|
||||||
|
uhd_rx_metadata_handle *md = &handler->rx_md_first;
|
||||||
|
if (blocking) {
|
||||||
|
int n = 0;
|
||||||
|
cf_t *data_c = (cf_t*) data;
|
||||||
|
do {
|
||||||
|
size_t rx_samples = handler->rx_nof_samples;
|
||||||
|
|
||||||
|
if (rx_samples > nsamples - n) {
|
||||||
|
rx_samples = nsamples - n;
|
||||||
|
}
|
||||||
|
void *buff = (void*) &data_c[n];
|
||||||
|
void **buffs_ptr = (void**) &buff;
|
||||||
|
uhd_error error = uhd_rx_streamer_recv(handler->rx_stream, buffs_ptr,
|
||||||
|
rx_samples, md, 5.0, false, &rxd_samples);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
fprintf(stderr, "Error receiving from UHD: %d\n", error);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
md = &handler->rx_md;
|
||||||
|
n += rxd_samples;
|
||||||
|
} while (n < nsamples);
|
||||||
|
} else {
|
||||||
|
void **buffs_ptr = (void**) &data;
|
||||||
|
return uhd_rx_streamer_recv(handler->rx_stream, buffs_ptr,
|
||||||
|
nsamples, md, 0.0, false, &rxd_samples);
|
||||||
|
}
|
||||||
|
if (secs && frac_secs) {
|
||||||
|
uhd_rx_metadata_time_spec(handler->rx_md_first, secs, frac_secs);
|
||||||
|
}
|
||||||
|
return nsamples;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rf_uhd_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_uhd_handler_t* handler = (rf_uhd_handler_t*) h;
|
||||||
|
|
||||||
|
size_t txd_samples;
|
||||||
|
if (has_time_spec) {
|
||||||
|
uhd_tx_metadata_set_time_spec(&handler->tx_md, secs, frac_secs);
|
||||||
|
}
|
||||||
|
if (blocking) {
|
||||||
|
int n = 0;
|
||||||
|
cf_t *data_c = (cf_t*) data;
|
||||||
|
do {
|
||||||
|
size_t tx_samples = handler->tx_nof_samples;
|
||||||
|
|
||||||
|
// First packet is start of burst if so defined, others are never
|
||||||
|
if (n == 0) {
|
||||||
|
uhd_tx_metadata_set_start(&handler->tx_md, is_start_of_burst);
|
||||||
|
} else {
|
||||||
|
uhd_tx_metadata_set_start(&handler->tx_md, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// middle packets are never end of burst, last one as defined
|
||||||
|
if (nsamples - n > tx_samples) {
|
||||||
|
uhd_tx_metadata_set_end(&handler->tx_md, false);
|
||||||
|
} else {
|
||||||
|
tx_samples = nsamples - n;
|
||||||
|
uhd_tx_metadata_set_end(&handler->tx_md, is_end_of_burst);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *buff = (void*) &data_c[n];
|
||||||
|
const void **buffs_ptr = (const void**) &buff;
|
||||||
|
uhd_error error = uhd_tx_streamer_send(handler->tx_stream, buffs_ptr,
|
||||||
|
tx_samples, &handler->tx_md, 3.0, &txd_samples);
|
||||||
|
if (error) {
|
||||||
|
fprintf(stderr, "Error sending to UHD: %d\n", error);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// Increase time spec
|
||||||
|
uhd_tx_metadata_add_time_spec(&handler->tx_md, txd_samples/handler->tx_rate);
|
||||||
|
n += txd_samples;
|
||||||
|
} while (n < nsamples);
|
||||||
|
return nsamples;
|
||||||
|
} else {
|
||||||
|
const void **buffs_ptr = (const void**) &data;
|
||||||
|
uhd_tx_metadata_set_start(&handler->tx_md, is_start_of_burst);
|
||||||
|
uhd_tx_metadata_set_end(&handler->tx_md, is_end_of_burst);
|
||||||
|
return uhd_tx_streamer_send(handler->tx_stream, buffs_ptr, nsamples, &handler->tx_md, 0.0, &txd_samples);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,108 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \section COPYRIGHT
|
||||||
|
*
|
||||||
|
* Copyright 2013-2015 Software Radio Systems Limited
|
||||||
|
*
|
||||||
|
* \section LICENSE
|
||||||
|
*
|
||||||
|
* This file is part of the srsLTE library.
|
||||||
|
*
|
||||||
|
* srsLTE is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* srsLTE is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* A copy of the GNU Affero General Public License can be found in
|
||||||
|
* the LICENSE file in the top-level directory of this distribution
|
||||||
|
* and at http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "srslte/config.h"
|
||||||
|
#include "srslte/rf/rf.h"
|
||||||
|
|
||||||
|
SRSLTE_API int rf_uhd_open(char *args,
|
||||||
|
void **handler);
|
||||||
|
|
||||||
|
SRSLTE_API int rf_uhd_close(void *h);
|
||||||
|
|
||||||
|
SRSLTE_API void rf_uhd_set_tx_cal(void *h, srslte_rf_cal_t *cal);
|
||||||
|
|
||||||
|
SRSLTE_API void rf_uhd_set_rx_cal(void *h, srslte_rf_cal_t *cal);
|
||||||
|
|
||||||
|
SRSLTE_API int rf_uhd_start_rx_stream(void *h);
|
||||||
|
|
||||||
|
SRSLTE_API int rf_uhd_start_rx_stream_nsamples(void *h,
|
||||||
|
uint32_t nsamples);
|
||||||
|
|
||||||
|
SRSLTE_API int rf_uhd_stop_rx_stream(void *h);
|
||||||
|
|
||||||
|
SRSLTE_API void rf_uhd_flush_buffer(void *h);
|
||||||
|
|
||||||
|
SRSLTE_API bool rf_uhd_has_rssi(void *h);
|
||||||
|
|
||||||
|
SRSLTE_API float rf_uhd_get_rssi(void *h);
|
||||||
|
|
||||||
|
SRSLTE_API bool rf_uhd_rx_wait_lo_locked(void *h);
|
||||||
|
|
||||||
|
SRSLTE_API void rf_uhd_set_master_clock_rate(void *h,
|
||||||
|
double rate);
|
||||||
|
|
||||||
|
SRSLTE_API bool rf_uhd_is_master_clock_dynamic(void *h);
|
||||||
|
|
||||||
|
SRSLTE_API double rf_uhd_set_rx_srate(void *h,
|
||||||
|
double freq);
|
||||||
|
|
||||||
|
SRSLTE_API double rf_uhd_set_rx_gain(void *h,
|
||||||
|
double gain);
|
||||||
|
|
||||||
|
SRSLTE_API double rf_uhd_get_rx_gain(void *h);
|
||||||
|
|
||||||
|
SRSLTE_API double rf_uhd_get_tx_gain(void *h);
|
||||||
|
|
||||||
|
SRSLTE_API void rf_uhd_suppress_stdout(void *h);
|
||||||
|
|
||||||
|
SRSLTE_API void rf_uhd_register_error_handler(void *h, srslte_rf_error_handler_t error_handler);
|
||||||
|
|
||||||
|
SRSLTE_API double rf_uhd_set_rx_freq(void *h,
|
||||||
|
double freq);
|
||||||
|
|
||||||
|
SRSLTE_API int rf_uhd_recv_with_time(void *h,
|
||||||
|
void *data,
|
||||||
|
uint32_t nsamples,
|
||||||
|
bool blocking,
|
||||||
|
time_t *secs,
|
||||||
|
double *frac_secs);
|
||||||
|
|
||||||
|
SRSLTE_API double rf_uhd_set_tx_srate(void *h,
|
||||||
|
double freq);
|
||||||
|
|
||||||
|
SRSLTE_API double rf_uhd_set_tx_gain(void *h,
|
||||||
|
double gain);
|
||||||
|
|
||||||
|
SRSLTE_API double rf_uhd_set_tx_freq(void *h,
|
||||||
|
double freq);
|
||||||
|
|
||||||
|
SRSLTE_API void rf_uhd_get_time(void *h,
|
||||||
|
time_t *secs,
|
||||||
|
double *frac_secs);
|
||||||
|
|
||||||
|
SRSLTE_API int rf_uhd_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);
|
||||||
|
|
@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
|
||||||
|
/* This file implements a few features not currently provided by the UHD C-API */
|
||||||
|
#include <uhd.h>
|
||||||
|
#include <uhd/usrp/multi_usrp.hpp>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "srslte/rf/rf.h"
|
||||||
|
#include "uhd_c_api.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
static void (*handler)(const char*);
|
||||||
|
|
||||||
|
void translate_handler(uhd::msg::type_t type, const std::string & msg)
|
||||||
|
{
|
||||||
|
if(handler)
|
||||||
|
handler(msg.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void rf_uhd_register_msg_handler_c(void (*new_handler)(const char*))
|
||||||
|
{
|
||||||
|
handler = new_handler;
|
||||||
|
uhd::msg::register_handler(translate_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhd_tx_metadata_set_time_spec(uhd_tx_metadata_handle *md, time_t secs, double frac_secs)
|
||||||
|
{
|
||||||
|
(*md)->tx_metadata_cpp.time_spec = uhd::time_spec_t(secs, frac_secs);
|
||||||
|
(*md)->tx_metadata_cpp.has_time_spec = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhd_tx_metadata_set_start(uhd_tx_metadata_handle *md, bool is_start_of_burst)
|
||||||
|
{
|
||||||
|
(*md)->tx_metadata_cpp.start_of_burst = is_start_of_burst;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhd_tx_metadata_set_end(uhd_tx_metadata_handle *md, bool is_end_of_burst)
|
||||||
|
{
|
||||||
|
(*md)->tx_metadata_cpp.end_of_burst = is_end_of_burst;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhd_tx_metadata_add_time_spec(uhd_tx_metadata_handle *md, double frac_secs)
|
||||||
|
{
|
||||||
|
(*md)->tx_metadata_cpp.time_spec += frac_secs;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
#include <uhd.h>
|
||||||
|
#include "srslte/config.h"
|
||||||
|
#include "srslte/rf/rf.h"
|
||||||
|
|
||||||
|
/* Declare functions not currently provided by the C-API */
|
||||||
|
SRSLTE_API void rf_uhd_register_msg_handler_c(void (*new_handler)(const char*));
|
||||||
|
SRSLTE_API void uhd_tx_metadata_set_time_spec(uhd_tx_metadata_handle *md, time_t secs, double frac_secs);
|
||||||
|
SRSLTE_API void uhd_tx_metadata_set_start(uhd_tx_metadata_handle *md, bool is_start_of_burst);
|
||||||
|
SRSLTE_API void uhd_tx_metadata_set_end(uhd_tx_metadata_handle *md, bool is_end_of_burst);
|
||||||
|
SRSLTE_API void uhd_tx_metadata_add_time_spec(uhd_tx_metadata_handle *md, double frac_secs);
|
Loading…
Reference in New Issue