diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index f52a3c465f6b7c75e2237e40c188425abcde4a33..d359b231b4ecc5742ab8d497146f4c0325ae10f6 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -159,7 +159,7 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_FCNTL_H=1 -DHAVE_ARPA_INET_H=1 -DHAVE_SYS_TIME_H=1 -DHAVE_SYS_SOCKET_H=1 -DHAVE_STRERROR=1 -DHAVE_SOCKET=1 -DHAVE_MEMSET=1 -DHAVE_GETTIMEOFDAY=1 -DHAVE_STDLIB_H=1 -DHAVE_MALLOC=1 -DHAVE_LIBSCTP" ) set(CMAKE_CXX_FLAGS - "${CMAKE_CXX_FLAGS} ${C_FLAGS_PROCESSOR}" + "${CMAKE_CXX_FLAGS} ${C_FLAGS_PROCESSOR} -std=c++11 " ) # set a flag for changes in the source code # these changes are related to hardcoded path to include .h files @@ -167,6 +167,7 @@ add_definitions(-DCMAKER) set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -g -DMALLOC_CHECK_=3") set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS} -g -DMALLOC_CHECK_=3 -O2") +Message("RF_BOARD is ${RF_BOARD}") # Below has been put in comment because does not work with # SVN authentication. # @@ -404,7 +405,9 @@ add_list1_option(NB_ANTENNAS_RX "2" "Number of antennas in reception" "1" "2" "4 add_list1_option(NB_ANTENNAS_TX "2" "Number of antennas in transmission" "1" "2" "4") add_list1_option(NB_ANTENNAS_TXRX "2" "Number of antennas in ????" "1" "2" "4") -add_list2_option(RF_BOARD "EXMIMO" "RF head type" "False" "EXMIMO" "OAI_USRP" "ETHERNET" "OAI_BLADERF" "CPRIGW") +add_list2_option(RF_BOARD "EXMIMO" "RF head type" "False" "EXMIMO" "OAI_USRP" "ETHERNET" "OAI_BLADERF" "OAI_SODERA" "CPRIGW") + +Message("RF_BOARD is ${RF_BOARD}") if (${RF_BOARD} STREQUAL "EXMIMO") set(DRIVER2013) @@ -434,6 +437,19 @@ elseif (${RF_BOARD} STREQUAL "OAI_BLADERF") set(option_HW_lib "bladeRF") #set(LOWLATENCY False) +elseif (${RF_BOARD} STREQUAL "OAI_SODERA") + include_directories("${OPENAIR_TARGETS}/ARCH/SODERA/USERSPACE/LIB/") + include_directories("${OPENAIR_TARGETS}/ARCH/SODERA/USERSPACE/LIB/SoDeRaV1_distro_01v/lms7suite_source_code/src/lms7002m") + include_directories("${OPENAIR_TARGETS}/ARCH/SODERA/USERSPACE/LIB/SoDeRaV1_distro_01v/lms7suite_source_code/src/Si5351C") + set(HW_SOURCE ${HW_SOURCE} + ${OPENAIR_TARGETS}/ARCH/SODERA/USERSPACE/LIB/sodera_lib.cpp + ) + LINK_DIRECTORIES("${OPENAIR_TARGETS}/ARCH/SODERA/USERSPACE/LIB/SoDeRaV1_distro_01v/lms7suite_source_code/build/lms7002m") + LINK_DIRECTORIES("/usr/lib/x86_64-linux-gnu") + set(option_HW_lib "usb-1.0") + set(LMS7002_LIB "libLMS7002M.a") + #set(LOWLATENCY False) + elseif (${RF_BOARD} STREQUAL "ETHERNET") include_directories ("${OPENAIR_TARGETS}/ARCH/ETHERNET/USERSPACE/LIB") set(HW_SOURCE ${HW_SOURCE} @@ -1431,7 +1447,7 @@ add_executable(lte-softmodem target_link_libraries (lte-softmodem -Wl,--start-group - RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${MIH_LIB} + RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${MIH_LIB} ${LMS7002_LIB} -Wl,--end-group ) diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index c723d8d6dc95e9acd0a24537d4b0d783e050fc9c..4a18e53f4771493cb8926a560d5bc962f3561850 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -90,7 +90,7 @@ Options default is Rel10, Rel8 limits the implementation to 3GPP Release 8 version -w | --hardware - EXMIMO (Default), USRP, BLADERF, ETHERNET, None + EXMIMO (Default), USRP, BLADERF, SODERA, ETHERNET, None Adds this RF board support (in external packages installation and in compilation) --oaisim Makes the oaisim simulator. Hardware will be defaulted to "NONE". @@ -181,6 +181,9 @@ function main() { if [ "$HW" == "BLADERF" ] ; then HW="OAI_BLADERF" fi + if [ "$HW" == "SODERA" ] ; then + HW="OAI_SODERA" + fi echo_info "setting hardware to: $HW" shift 2;; --oaisim) @@ -249,6 +252,7 @@ function main() { esac done + echo_info "RF HW set to $HW" #Now we set flags to enable deadline scheduler settings #By default: USRP: disable, #By default: BLADERF: enable, @@ -262,6 +266,8 @@ function main() { LOWLATENCY_FLAG_USER="False" elif [ "$HW" = "OAI_BLADERF" ] ; then LOWLATENCY_FLAG_USER="False" + elif [ "$HW" = "OAI_SODERA" ] ; then + LOWLATENCY_FLAG_USER="False" elif [ "$HW" = "None" ] ; then LOWLATENCY_FLAG_USER="False" else diff --git a/targets/ARCH/COMMON/common_lib.c b/targets/ARCH/COMMON/common_lib.c index bdf0e46278b1e72fffc7572372058d810d35619c..8ee25c5fdabf34e368c29fae91dd9207c21ea157 100644 --- a/targets/ARCH/COMMON/common_lib.c +++ b/targets/ARCH/COMMON/common_lib.c @@ -57,12 +57,14 @@ int openair0_device_init(openair0_device *device, openair0_config_t *openair0_cf openair0_dev_init_usrp(device, openair0_cfg); printf("openair0_dev_init_usrp ...\n"); return(openair0_dev_init_usrp(device, openair0_cfg)); - #elif OAI_BLADERF device->type=BLADERF_IF; printf(" openair0_dev_init_bladerf ...\n"); return(openair0_dev_init_bladerf(device, openair0_cfg)); - -#endif +#elif OAI_SODERA + device->type=OAI_SODERA; + printf(" openair0_dev_init_sodera ...\n"); + return(openair0_dev_init_sodera(device, openair0_cfg)); +#endif } diff --git a/targets/ARCH/COMMON/common_lib.h b/targets/ARCH/COMMON/common_lib.h index a3fe9e9dbd33973354db652203a8d9e4c6461164..8eaf3f781a43d977bd101871a732f0ee55458d93 100644 --- a/targets/ARCH/COMMON/common_lib.h +++ b/targets/ARCH/COMMON/common_lib.h @@ -164,6 +164,8 @@ typedef enum { USRP_X300_IF, /*!\brief device is BLADE RF*/ BLADERF_IF, + /*!\brief device is SODERA RF*/ + SODERARF_IF, /*!\brief device is NONE*/ NONE_IF, MAX_DEV_TYPE @@ -295,6 +297,7 @@ extern "C" /*! \brief Initialize Openair ETHERNET target. It returns 0 if OK */ int openair0_dev_init_eth(openair0_device *device, openair0_config_t *openair0_cfg); int openair0_dev_init_bladerf(openair0_device *device, openair0_config_t *openair0_cfg); + int openair0_dev_init_sodera(openair0_device *device, openair0_config_t *openair0_cfg); int openair0_dev_init_usrp(openair0_device* device, openair0_config_t *openair0_cfg); int openair0_dev_init_exmimo(openair0_device *device, openair0_config_t *openair0_cfg); /*@}*/ diff --git a/targets/ARCH/SODERA/USERSPACE/LIB/sodera_lib.cpp b/targets/ARCH/SODERA/USERSPACE/LIB/sodera_lib.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f8257fccf8f22e34d4de58c66817bcc0eda0d234 --- /dev/null +++ b/targets/ARCH/SODERA/USERSPACE/LIB/sodera_lib.cpp @@ -0,0 +1,442 @@ +/******************************************************************************* + OpenAirInterface + Copyright(c) 1999 - 2014 Eurecom + + OpenAirInterface is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + + OpenAirInterface 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OpenAirInterface.The full GNU General Public License is + included in this distribution in the file called "COPYING". If not, + see <http://www.gnu.org/licenses/>. + + Contact Information + OpenAirInterface Admin: openair_admin@eurecom.fr + OpenAirInterface Tech : openair_tech@eurecom.fr + OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr + + Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + + *******************************************************************************/ + +/** sodera_lib.c + * + * Author: Raymond Knopp + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <inttypes.h> +#include <string.h> +#include <pthread.h> +#include <unistd.h> + + +#include <iostream> +#include <complex> +#include <fstream> +#include <cmath> + +#include "common_lib.h" + +#include "lmsComms.h" +#include "Si5351C.h" +#ifdef __SSE4_1__ +# include <smmintrin.h> +#endif + +#ifdef __AVX2__ +# include <immintrin.h> +#endif + +int num_devices=0; +/*These items configure the underlying asynch stream used by the the sync interface. + */ + +typedef struct +{ + + // -------------------------------- + // variables for SoDeRa configuration + // -------------------------------- + /* + uhd::usrp::multi_usrp::sptr usrp; + //uhd::usrp::multi_usrp::sptr rx_usrp; + + //create a send streamer and a receive streamer + uhd::tx_streamer::sptr tx_stream; + uhd::rx_streamer::sptr rx_stream; + + uhd::tx_metadata_t tx_md; + uhd::rx_metadata_t rx_md; + + uhd::time_spec_t tm_spec; + //setup variables and allocate buffer + uhd::async_metadata_t async_md; + */ + + LMScomms mDataPort; + + double sample_rate; + // time offset between transmiter timestamp and receiver timestamp; + double tdiff; + + // -------------------------------- + // Debug and output control + // -------------------------------- + int num_underflows; + int num_overflows; + int num_seq_errors; + + int64_t tx_count; + int64_t rx_count; + openair0_timestamp rx_timestamp; + +} sodera_state_t; + + +static int trx_sodera_start(openair0_device *device) +{ + sodera_state_t *s = (sodera_state_t*)device->priv; + + // init recv and send streaming + + s->rx_count = 0; + s->tx_count = 0; + s->rx_timestamp = 0; + + return 0; +} + +static void trx_sodera_end(openair0_device *device) +{ + sodera_state_t *s = (sodera_state_t*)device->priv; + + + +} + +static int trx_sodera_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags) +{ + sodera_state_t *s = (sodera_state_t*)device->priv; + + if (cc>1) { + // s->tx_stream->send(buff_ptrs, nsamps, s->tx_md); + } + else + // s->tx_stream->send(buff[0], nsamps, s->tx_md); + + return 0; +} + +static int trx_sodera_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int cc) +{ + sodera_state_t *s = (sodera_state_t*)device->priv; + int samples_received=0,i,j; + int nsamps2; // aligned to upper 32 or 16 byte boundary +#if defined(__x86_64) || defined(__i386__) +#ifdef __AVX2__ + __m256i buff_tmp[2][nsamps>>3]; + nsamps2 = (nsamps+7)>>3; +#else + __m128i buff_tmp[2][nsamps>>2]; + nsamps2 = (nsamps+3)>>2; +#endif +#elif defined(__arm__) + int16x8_t buff_tmp[2][nsamps>>2]; + nsamps2 = (nsamps+3)>>2; +#endif + + + if (cc>1) { + // receive multiple channels (e.g. RF A and RF B) + + } else { + // receive a single channel (e.g. from connector RF A) + + } + + if (samples_received < nsamps) { + printf("[recv] received %d samples out of %d\n",samples_received,nsamps); + + } + + //handle the error code + + s->rx_count += nsamps; + // s->rx_timestamp = s->rx_md.time_spec.to_ticks(s->sample_rate); + *ptimestamp = s->rx_timestamp; + + return samples_received; +} + + + +static bool is_equal(double a, double b) +{ + return fabs(a-b) < 1e-6; +} + +int trx_sodera_set_freq(openair0_device* device, openair0_config_t *openair0_cfg, int dummy) { + + sodera_state_t *s = (sodera_state_t*)device->priv; + + // s->usrp->set_tx_freq(openair0_cfg[0].tx_freq[0]); + // s->usrp->set_rx_freq(openair0_cfg[0].rx_freq[0]); + + return(0); + +} + +int openair0_set_rx_frequencies(openair0_device* device, openair0_config_t *openair0_cfg) { + + sodera_state_t *s = (sodera_state_t*)device->priv; + static int first_call=1; + static double rf_freq,diff; + + // uhd::tune_request_t rx_tune_req(openair0_cfg[0].rx_freq[0]); + + // rx_tune_req.rf_freq_policy = uhd::tune_request_t::POLICY_MANUAL; + // rx_tune_req.rf_freq = openair0_cfg[0].rx_freq[0]; + // rf_freq=openair0_cfg[0].rx_freq[0]; + // s->usrp->set_rx_freq(rx_tune_req); + + return(0); + +} + +int trx_sodera_set_gains(openair0_device* device, + openair0_config_t *openair0_cfg) { + + sodera_state_t *s = (sodera_state_t*)device->priv; + + // s->usrp->set_tx_gain(openair0_cfg[0].tx_gain[0]); + // ::uhd::gain_range_t gain_range = s->usrp->get_rx_gain_range(0); + // limit to maximum gain + /* if (openair0_cfg[0].rx_gain[0]-openair0_cfg[0].rx_gain_offset[0] > gain_range.stop()) { + + printf("RX Gain 0 too high, reduce by %f dB\n", + openair0_cfg[0].rx_gain[0]-openair0_cfg[0].rx_gain_offset[0] - gain_range.stop()); + exit(-1); + } + s->usrp->set_rx_gain(openair0_cfg[0].rx_gain[0]-openair0_cfg[0].rx_gain_offset[0]); + printf("Setting SODERA RX gain to %f (rx_gain %f,gain_range.stop() %f)\n", openair0_cfg[0].rx_gain[0]-openair0_cfg[0].rx_gain_offset[0],openair0_cfg[0].rx_gain[0],gain_range.stop()); + */ + return(0); +} + +int trx_sodera_stop(int card) { + return(0); +} + + +rx_gain_calib_table_t calib_table_sodera[] = { + {3500000000.0,44.0}, + {2660000000.0,49.0}, + {2300000000.0,50.0}, + {1880000000.0,53.0}, + {816000000.0,58.0}, + {-1,0}}; + +void set_rx_gain_offset(openair0_config_t *openair0_cfg, int chain_index,int bw_gain_adjust) { + + int i=0; + // loop through calibration table to find best adjustment factor for RX frequency + double min_diff = 6e9,diff,gain_adj=0.0; + if (bw_gain_adjust==1) { + switch ((int)openair0_cfg[0].sample_rate) { + case 30720000: + break; + case 23040000: + gain_adj=1.25; + break; + case 15360000: + gain_adj=3.0; + break; + case 7680000: + gain_adj=6.0; + break; + case 3840000: + gain_adj=9.0; + break; + case 1920000: + gain_adj=12.0; + break; + default: + printf("unknown sampling rate %d\n",(int)openair0_cfg[0].sample_rate); + exit(-1); + break; + } + } + while (openair0_cfg->rx_gain_calib_table[i].freq>0) { + diff = fabs(openair0_cfg->rx_freq[chain_index] - openair0_cfg->rx_gain_calib_table[i].freq); + printf("cal %d: freq %f, offset %f, diff %f\n", + i, + openair0_cfg->rx_gain_calib_table[i].freq, + openair0_cfg->rx_gain_calib_table[i].offset,diff); + if (min_diff > diff) { + min_diff = diff; + openair0_cfg->rx_gain_offset[chain_index] = openair0_cfg->rx_gain_calib_table[i].offset+gain_adj; + } + i++; + } + +} + + +int trx_sodera_get_stats(openair0_device* device) { + + return(0); + +} +int trx_sodera_reset_stats(openair0_device* device) { + + return(0); + +} + + +int openair0_dev_init_sodera(openair0_device* device, openair0_config_t *openair0_cfg) +{ + + sodera_state_t *s = (sodera_state_t*)malloc(sizeof(sodera_state_t)); + size_t i; + memset(s, 0, sizeof(sodera_state_t)); + + // Initialize SODERA device + if (!s->mDataPort.Open(0)) { + printf("Cannot open SoDeRa\n"); + exit(-1); + } + + + int vers=0,subvers=0,subsubvers=0; + int bw_gain_adjust=0; + + + openair0_cfg[0].rx_gain_calib_table = calib_table_sodera; + + switch ((int)openair0_cfg[0].sample_rate) { + case 30720000: + // from usrp_time_offset + openair0_cfg[0].samples_per_packet = 2048; + openair0_cfg[0].tx_sample_advance = 15; + openair0_cfg[0].tx_bw = 20e6; + openair0_cfg[0].rx_bw = 20e6; + openair0_cfg[0].tx_scheduling_advance = 8*openair0_cfg[0].samples_per_packet; + break; + case 15360000: + openair0_cfg[0].samples_per_packet = 2048; + openair0_cfg[0].tx_sample_advance = 45; + openair0_cfg[0].tx_bw = 10e6; + openair0_cfg[0].rx_bw = 10e6; + openair0_cfg[0].tx_scheduling_advance = 5*openair0_cfg[0].samples_per_packet; + break; + case 7680000: + openair0_cfg[0].samples_per_packet = 1024; + openair0_cfg[0].tx_sample_advance = 50; + openair0_cfg[0].tx_bw = 5e6; + openair0_cfg[0].rx_bw = 5e6; + openair0_cfg[0].tx_scheduling_advance = 5*openair0_cfg[0].samples_per_packet; + break; + case 1920000: + openair0_cfg[0].samples_per_packet = 256; + openair0_cfg[0].tx_sample_advance = 50; + openair0_cfg[0].tx_bw = 1.25e6; + openair0_cfg[0].rx_bw = 1.25e6; + openair0_cfg[0].tx_scheduling_advance = 8*openair0_cfg[0].samples_per_packet; + break; + default: + printf("Error: unknown sampling rate %f\n",openair0_cfg[0].sample_rate); + exit(-1); + break; + } + + /* + for(i=0;i<s->usrp->get_rx_num_channels();i++) { + if (i<openair0_cfg[0].rx_num_channels) { + s->usrp->set_rx_rate(openair0_cfg[0].sample_rate,i); + s->usrp->set_rx_bandwidth(openair0_cfg[0].rx_bw,i); + printf("Setting rx freq/gain on channel %lu/%lu : BW %f (readback %f)\n",i,s->usrp->get_rx_num_channels(),openair0_cfg[0].rx_bw/1e6,s->usrp->get_rx_bandwidth(i)/1e6); + s->usrp->set_rx_freq(openair0_cfg[0].rx_freq[i],i); + set_rx_gain_offset(&openair0_cfg[0],i,bw_gain_adjust); + + ::uhd::gain_range_t gain_range = s->usrp->get_rx_gain_range(i); + // limit to maximum gain + if (openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i] > gain_range.stop()) { + + printf("RX Gain %lu too high, lower by %f dB\n",i,openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i] - gain_range.stop()); + exit(-1); + } + s->usrp->set_rx_gain(openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i],i); + printf("RX Gain %lu %f (%f) => %f (max %f)\n",i, + openair0_cfg[0].rx_gain[i],openair0_cfg[0].rx_gain_offset[i], + openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i],gain_range.stop()); + } + } + for(i=0;i<s->usrp->get_tx_num_channels();i++) { + if (i<openair0_cfg[0].tx_num_channels) { + s->usrp->set_tx_rate(openair0_cfg[0].sample_rate,i); + s->usrp->set_tx_bandwidth(openair0_cfg[0].tx_bw,i); + printf("Setting tx freq/gain on channel %lu/%lu: BW %f (readback %f)\n",i,s->usrp->get_tx_num_channels(),openair0_cfg[0].tx_bw/1e6,s->usrp->get_tx_bandwidth(i)/1e6); + s->usrp->set_tx_freq(openair0_cfg[0].tx_freq[i],i); + s->usrp->set_tx_gain(openair0_cfg[0].tx_gain[i],i); + } + } + */ + + // create tx & rx streamer + + //stream_args_rx.args["spp"] = str(boost::format("%d") % 2048);//(openair0_cfg[0].rx_num_channels*openair0_cfg[0].samples_per_packet)); + + /* + for (i=0;i<openair0_cfg[0].rx_num_channels;i++) { + if (i<openair0_cfg[0].rx_num_channels) { + printf("RX Channel %lu\n",i); + std::cout << boost::format("Actual RX sample rate: %fMSps...") % (s->usrp->get_rx_rate(i)/1e6) << std::endl; + std::cout << boost::format("Actual RX frequency: %fGHz...") % (s->usrp->get_rx_freq(i)/1e9) << std::endl; + std::cout << boost::format("Actual RX gain: %f...") % (s->usrp->get_rx_gain(i)) << std::endl; + std::cout << boost::format("Actual RX bandwidth: %fM...") % (s->usrp->get_rx_bandwidth(i)/1e6) << std::endl; + std::cout << boost::format("Actual RX antenna: %s...") % (s->usrp->get_rx_antenna(i)) << std::endl; + } + } + + for (i=0;i<openair0_cfg[0].tx_num_channels;i++) { + + if (i<openair0_cfg[0].tx_num_channels) { + printf("TX Channel %lu\n",i); + std::cout << std::endl<<boost::format("Actual TX sample rate: %fMSps...") % (s->usrp->get_tx_rate(i)/1e6) << std::endl; + std::cout << boost::format("Actual TX frequency: %fGHz...") % (s->usrp->get_tx_freq(i)/1e9) << std::endl; + std::cout << boost::format("Actual TX gain: %f...") % (s->usrp->get_tx_gain(i)) << std::endl; + std::cout << boost::format("Actual TX bandwidth: %fM...") % (s->usrp->get_tx_bandwidth(i)/1e6) << std::endl; + std::cout << boost::format("Actual TX antenna: %s...") % (s->usrp->get_tx_antenna(i)) << std::endl; + } + } + */ + + + device->priv = s; + device->trx_start_func = trx_sodera_start; + device->trx_write_func = trx_sodera_write; + device->trx_read_func = trx_sodera_read; + device->trx_get_stats_func = trx_sodera_get_stats; + device->trx_reset_stats_func = trx_sodera_reset_stats; + device->trx_end_func = trx_sodera_end; + device->trx_stop_func = trx_sodera_stop; + device->trx_set_freq_func = trx_sodera_set_freq; + device->trx_set_gains_func = trx_sodera_set_gains; + + s->sample_rate = openair0_cfg[0].sample_rate; + // TODO: + + return 0; +}