mirror of https://github.com/PentHertz/srsLTE.git
Merge pull request #1 from softwareradiosystems/next_lime
adding native lime, soapy, decimation filtering and neon optimizations
This commit is contained in:
commit
a723b79ab8
|
@ -0,0 +1,28 @@
|
|||
if(NOT LIMESDR_FOUND)
|
||||
pkg_check_modules (LIMESDR_PKG LimeSuite)
|
||||
|
||||
find_path(LIMESDR_INCLUDE_DIRS
|
||||
NAMES LimeSuite.h
|
||||
PATHS ${LIMESDR_PKG_INCLUDE_DIRS}
|
||||
/usr/include/lime
|
||||
/usr/local/include/lime
|
||||
)
|
||||
|
||||
find_library(LIMESDR_LIBRARIES
|
||||
NAMES LimeSuite
|
||||
PATHS ${LIMESDR_PKG_LIBRARY_DIRS}
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
)
|
||||
|
||||
if(LIMESDR_INCLUDE_DIRS AND LIMESDR_LIBRARIES)
|
||||
set(LIMESDR_FOUND TRUE CACHE INTERNAL "libLimeSuite found")
|
||||
message(STATUS "Found libLimeSuite: ${LIMESDR_INCLUDE_DIRS}, ${LIMESDR_LIBRARIES}")
|
||||
else(LIMESDR_INCLUDE_DIRS AND LIMESDR_LIBRARIES)
|
||||
set(LIMESDR_FOUND FALSE CACHE INTERNAL "libLimeSuite found")
|
||||
message(STATUS "libLimeSuite not found.")
|
||||
endif(LIMESDR_INCLUDE_DIRS AND LIMESDR_LIBRARIES)
|
||||
|
||||
mark_as_advanced(LIMESDR_LIBRARIES LIMESDR_INCLUDE_DIRS)
|
||||
|
||||
endif(NOT LIMESDR_FOUND)
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
message(STATUS "FINDING SOAPY.")
|
||||
if(NOT SOAPYSDR_FOUND)
|
||||
pkg_check_modules (SOAPYSDR_PKG SoapySDR)
|
||||
|
||||
find_path(SOAPYSDR_INCLUDE_DIRS
|
||||
NAMES Device.h
|
||||
PATHS ${SOAPYSDR_PKG_INCLUDE_DIRS}
|
||||
/usr/include/SoapySDR
|
||||
/usr/include/local/SoapySDR
|
||||
)
|
||||
|
||||
find_library(SOAPYSDR_LIBRARIES
|
||||
NAMES SoapySDR
|
||||
PATHS ${LIMESDR_PKG_LIBRARY_DIRS}
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
|
||||
)
|
||||
|
||||
if(SOAPYSDR_INCLUDE_DIRS AND SOAPYSDR_LIBRARIES)
|
||||
set(SOAPYSDR_FOUND TRUE CACHE INTERNAL "libSOAPYSDR found")
|
||||
message(STATUS "Found libSOAPYSDR: ${SOAPYSDR_INCLUDE_DIRS}, ${SOAPYSDR_LIBRARIES}")
|
||||
else(SOAPYSDR_INCLUDE_DIRS AND SOAPYSDR_LIBRARIES)
|
||||
set(SOAPYSDR_FOUND FALSE CACHE INTERNAL "libSOAPYSDR found")
|
||||
message(STATUS "libSOAPYSDR not found.")
|
||||
endif(SOAPYSDR_INCLUDE_DIRS AND SOAPYSDR_LIBRARIES)
|
||||
|
||||
mark_as_advanced(SOAPYSDR_LIBRARIES SOAPYSDR_INCLUDE_DIRS)
|
||||
|
||||
endif(NOT SOAPYSDR_FOUND)
|
|
@ -69,12 +69,27 @@ if(NOT DisableBladeRF)
|
|||
endif(BLADERF_FOUND)
|
||||
endif(NOT DisableBladeRF)
|
||||
|
||||
if(BLADERF_FOUND OR UHD_FOUND)
|
||||
find_package(SoapySDR)
|
||||
if(SOAPYSDR_FOUND)
|
||||
include_directories(${SOAPYSDR_INCLUDE_DIRS})
|
||||
link_directories(${SOAPYSDR_LIBRARY_DIRS})
|
||||
endif(SOAPYSDR_FOUND)
|
||||
|
||||
|
||||
find_package(LimeSDR)
|
||||
if(LIMESDR_FOUND)
|
||||
include_directories(${LIMESDR_INCLUDE_DIRS})
|
||||
link_directories(${LIMESDR_LIBRARY_DIRS})
|
||||
endif(LIMESDR_FOUND)
|
||||
|
||||
|
||||
|
||||
if(BLADERF_FOUND OR UHD_FOUND OR SOAPYSDR_FOUND OR LIMESDR_FOUND)
|
||||
set(RF_FOUND TRUE CACHE INTERNAL "RF frontend found")
|
||||
else(BLADERF_FOUND OR UHD_FOUND)
|
||||
else(BLADERF_FOUND OR UHD_FOUND OR SOAPYSDR_FOUND OR LIMESDR_FOUND)
|
||||
set(RF_FOUND FALSE CACHE INTERNAL "RF frontend found")
|
||||
add_definitions(-DDISABLE_RF)
|
||||
endif(BLADERF_FOUND OR UHD_FOUND)
|
||||
endif(BLADERF_FOUND OR UHD_FOUND OR SOAPYSDR_FOUND OR LIMESDR_FOUND)
|
||||
|
||||
include(CheckFunctionExistsMath)
|
||||
if(${DISABLE_VOLK})
|
||||
|
|
|
@ -96,6 +96,7 @@ typedef struct {
|
|||
char *net_address;
|
||||
int net_port_signal;
|
||||
char *net_address_signal;
|
||||
int decimate;
|
||||
}prog_args_t;
|
||||
|
||||
void args_default(prog_args_t *args) {
|
||||
|
@ -124,6 +125,7 @@ void args_default(prog_args_t *args) {
|
|||
args->net_address = "127.0.0.1";
|
||||
args->net_port_signal = -1;
|
||||
args->net_address_signal = "127.0.0.1";
|
||||
args->decimate = 0;
|
||||
}
|
||||
|
||||
void usage(prog_args_t *args, char *prog) {
|
||||
|
@ -166,7 +168,7 @@ void usage(prog_args_t *args, char *prog) {
|
|||
void parse_args(prog_args_t *args, int argc, char **argv) {
|
||||
int opt;
|
||||
args_default(args);
|
||||
while ((opt = getopt(argc, argv, "aAoglipPcOCtdDnvrfuUsS")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "aAoglipPcOCtdDnvrfuUsSZ")) != -1) {
|
||||
switch (opt) {
|
||||
case 'i':
|
||||
args->input_file_name = argv[optind];
|
||||
|
@ -234,6 +236,9 @@ void parse_args(prog_args_t *args, int argc, char **argv) {
|
|||
case 'v':
|
||||
srslte_verbose++;
|
||||
break;
|
||||
case 'Z':
|
||||
args->decimate = atoi(argv[optind]);
|
||||
break;
|
||||
default:
|
||||
usage(args, argv[0]);
|
||||
exit(-1);
|
||||
|
@ -289,6 +294,7 @@ srslte_netsink_t net_sink, net_sink_signal;
|
|||
|
||||
int main(int argc, char **argv) {
|
||||
int ret;
|
||||
int decimate = 1;
|
||||
srslte_cell_t cell;
|
||||
int64_t sf_cnt;
|
||||
srslte_ue_mib_t ue_mib;
|
||||
|
@ -412,7 +418,19 @@ int main(int argc, char **argv) {
|
|||
|
||||
} else {
|
||||
#ifndef DISABLE_RF
|
||||
if (srslte_ue_sync_init_multi(&ue_sync, cell, srslte_rf_recv_wrapper, prog_args.rf_nof_rx_ant, (void*) &rf)) {
|
||||
if(prog_args.decimate)
|
||||
{
|
||||
if(prog_args.decimate > 4 || prog_args.decimate < 0)
|
||||
{
|
||||
printf("Invalid decimation factor, setting to 1 \n");
|
||||
}
|
||||
else
|
||||
{
|
||||
decimate = prog_args.decimate;
|
||||
//ue_sync.decimate = prog_args.decimate;
|
||||
}
|
||||
}
|
||||
if (srslte_ue_sync_init_multi_decim(&ue_sync, cell, srslte_rf_recv_wrapper, prog_args.rf_nof_rx_ant, (void*) &rf,decimate)) {
|
||||
fprintf(stderr, "Error initiating ue_sync\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
|
|
@ -100,6 +100,12 @@ SRSLTE_API int srslte_viterbi_init_sse(srslte_viterbi_t *q,
|
|||
uint32_t max_frame_length,
|
||||
bool tail_bitting);
|
||||
|
||||
SRSLTE_API int srslte_viterbi_init_neon(srslte_viterbi_t *q,
|
||||
srslte_viterbi_type_t type,
|
||||
int poly[3],
|
||||
uint32_t max_frame_length,
|
||||
bool tail_bitting);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include "srslte/config.h"
|
||||
#include "srslte/common/phy_common.h"
|
||||
#include "srslte/utils/convolution.h"
|
||||
#include "srslte/utils/filter.h"
|
||||
|
||||
#define CONVOLUTION_FFT
|
||||
|
||||
|
@ -74,13 +75,17 @@ typedef struct SRSLTE_API {
|
|||
|
||||
#ifdef CONVOLUTION_FFT
|
||||
srslte_conv_fft_cc_t conv_fft;
|
||||
#endif
|
||||
srslte_filt_cc_t filter;
|
||||
|
||||
#endif
|
||||
int decimate;
|
||||
uint32_t frame_size;
|
||||
uint32_t N_id_2;
|
||||
uint32_t fft_size;
|
||||
cf_t *pss_signal_freq_full[3];
|
||||
|
||||
cf_t *pss_signal_time[3];
|
||||
|
||||
cf_t pss_signal_freq[3][SRSLTE_PSS_LEN]; // One sequence for each N_id_2
|
||||
cf_t *tmp_input;
|
||||
cf_t *conv_output;
|
||||
|
@ -102,6 +107,12 @@ SRSLTE_API int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q,
|
|||
uint32_t fft_size,
|
||||
int cfo_i);
|
||||
|
||||
SRSLTE_API int srslte_pps_synch_init_fft_offset_decim(srslte_pss_synch_t *q,
|
||||
uint32_t frame_size,
|
||||
uint32_t fft_size,
|
||||
int cfo_i,
|
||||
int decimate);
|
||||
|
||||
SRSLTE_API int srslte_pss_synch_init(srslte_pss_synch_t *q,
|
||||
uint32_t frame_size);
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ typedef struct SRSLTE_API {
|
|||
srslte_sss_synch_t sss;
|
||||
srslte_cp_synch_t cp_synch;
|
||||
cf_t *cfo_i_corr[2];
|
||||
|
||||
int decimate;
|
||||
float threshold;
|
||||
float peak_value;
|
||||
uint32_t N_id_2;
|
||||
|
@ -112,6 +112,13 @@ SRSLTE_API int srslte_sync_init(srslte_sync_t *q,
|
|||
uint32_t max_offset,
|
||||
uint32_t fft_size);
|
||||
|
||||
SRSLTE_API int srslte_sync_init_decim(srslte_sync_t *q,
|
||||
uint32_t frame_size,
|
||||
uint32_t max_offset,
|
||||
uint32_t fft_size,
|
||||
int decimate);
|
||||
|
||||
|
||||
SRSLTE_API void srslte_sync_free(srslte_sync_t *q);
|
||||
|
||||
SRSLTE_API void srslte_sync_reset(srslte_sync_t *q);
|
||||
|
|
|
@ -73,7 +73,7 @@ typedef struct SRSLTE_API {
|
|||
srslte_agc_t agc;
|
||||
bool do_agc;
|
||||
uint32_t agc_period;
|
||||
|
||||
int decimate;
|
||||
void *stream;
|
||||
void *stream_single;
|
||||
int (*recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*);
|
||||
|
@ -135,6 +135,13 @@ SRSLTE_API int srslte_ue_sync_init_multi(srslte_ue_sync_t *q,
|
|||
uint32_t nof_rx_antennas,
|
||||
void *stream_handler);
|
||||
|
||||
SRSLTE_API int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q,
|
||||
srslte_cell_t cell,
|
||||
int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*),
|
||||
uint32_t nof_rx_antennas,
|
||||
void *stream_handler,
|
||||
int decimate);
|
||||
|
||||
SRSLTE_API int srslte_ue_sync_init_file(srslte_ue_sync_t *q,
|
||||
uint32_t nof_prb,
|
||||
char *file_name,
|
||||
|
|
|
@ -49,12 +49,16 @@ typedef struct SRSLTE_API {
|
|||
srslte_dft_plan_t input_plan;
|
||||
srslte_dft_plan_t filter_plan;
|
||||
srslte_dft_plan_t output_plan;
|
||||
//cf_t *pss_signal_time_fft[3]; // One sequence for each N_id_2
|
||||
//cf_t *pss_signal_time[3];
|
||||
|
||||
}srslte_conv_fft_cc_t;
|
||||
|
||||
SRSLTE_API int srslte_conv_fft_cc_init(srslte_conv_fft_cc_t *q,
|
||||
uint32_t input_len,
|
||||
uint32_t filter_len);
|
||||
|
||||
|
||||
SRSLTE_API void srslte_conv_fft_cc_free(srslte_conv_fft_cc_t *q);
|
||||
|
||||
SRSLTE_API uint32_t srslte_conv_fft_cc_run(srslte_conv_fft_cc_t *q,
|
||||
|
@ -62,6 +66,11 @@ SRSLTE_API uint32_t srslte_conv_fft_cc_run(srslte_conv_fft_cc_t *q,
|
|||
cf_t *filter,
|
||||
cf_t *output);
|
||||
|
||||
SRSLTE_API uint32_t srslte_conv_fft_cc_run_opt(srslte_conv_fft_cc_t *q,
|
||||
cf_t *input,
|
||||
cf_t *filter_freq,
|
||||
cf_t *output);
|
||||
|
||||
SRSLTE_API uint32_t srslte_conv_cc(cf_t *input,
|
||||
cf_t *filter,
|
||||
cf_t *output,
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
*
|
||||
* \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/.
|
||||
*
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
* File: debug.h
|
||||
*
|
||||
* Description: Debug output utilities.
|
||||
*
|
||||
* Reference:
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef FILTER_H
|
||||
#define FILTER_H
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "srslte/config.h"
|
||||
#include <stdbool.h>
|
||||
#include "srslte/utils/vector.h"
|
||||
typedef struct SRSLTE_API{
|
||||
cf_t *filter_input;
|
||||
cf_t *downsampled_input;
|
||||
cf_t *filter_output;
|
||||
bool is_decimator;
|
||||
int factor;
|
||||
int num_taps;
|
||||
float *taps;
|
||||
|
||||
}srslte_filt_cc_t;
|
||||
|
||||
void srslte_filt_decim_cc_init(srslte_filt_cc_t *q, int factor, int order);
|
||||
|
||||
void srslte_filt_decim_cc_free(srslte_filt_cc_t *q);
|
||||
|
||||
void srslte_filt_decim_cc_execute(srslte_filt_cc_t *q, cf_t *input, cf_t *downsampled_input, cf_t *output, int size);
|
||||
|
||||
void srslte_downsample_cc(cf_t *input, cf_t *output, int M, int size) ;
|
||||
#endif // FILTER_H
|
|
@ -95,6 +95,15 @@ if(RF_FOUND)
|
|||
if(BLADERF_FOUND)
|
||||
target_link_libraries(srslte ${BLADERF_LIBRARIES})
|
||||
endif(BLADERF_FOUND)
|
||||
|
||||
if(LIMESDR_FOUND)
|
||||
target_link_libraries(srslte ${LIMESDR_LIBRARIES})
|
||||
endif(LIMESDR_FOUND)
|
||||
|
||||
if(SOAPYSDR_FOUND)
|
||||
target_link_libraries(srslte ${SOAPYSDR_LIBRARIES})
|
||||
endif(SOAPYSDR_FOUND)
|
||||
|
||||
endif(RF_FOUND)
|
||||
|
||||
if(VOLK_FOUND)
|
||||
|
|
|
@ -119,6 +119,51 @@ void free37_sse(void *o) {
|
|||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_NEON
|
||||
int decode37_neon(void *o, uint8_t *symbols, uint8_t *data, uint32_t frame_length) {
|
||||
srslte_viterbi_t *q = o;
|
||||
|
||||
uint32_t best_state;
|
||||
|
||||
if (frame_length > q->framebits) {
|
||||
fprintf(stderr, "Initialized decoder for max frame length %d bits\n",
|
||||
q->framebits);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize Viterbi decoder */
|
||||
init_viterbi37_neon(q->ptr, q->tail_biting?-1:0);
|
||||
|
||||
/* Decode block */
|
||||
if (q->tail_biting) {
|
||||
for (int i=0;i<TB_ITER;i++) {
|
||||
memcpy(&q->tmp[i*3*frame_length], symbols, 3*frame_length*sizeof(uint8_t));
|
||||
}
|
||||
update_viterbi37_blk_neon(q->ptr, q->tmp, TB_ITER*frame_length, &best_state);
|
||||
chainback_viterbi37_neon(q->ptr, q->tmp, TB_ITER*frame_length, best_state);
|
||||
memcpy(data, &q->tmp[((int) (TB_ITER/2))*frame_length], frame_length*sizeof(uint8_t));
|
||||
} else {
|
||||
update_viterbi37_blk_neon(q->ptr, symbols, frame_length+q->K-1, NULL);
|
||||
chainback_viterbi37_neon(q->ptr, data, frame_length, 0);
|
||||
}
|
||||
|
||||
return q->framebits;
|
||||
}
|
||||
|
||||
void free37_neon(void *o) {
|
||||
srslte_viterbi_t *q = o;
|
||||
if (q->symbols_uc) {
|
||||
free(q->symbols_uc);
|
||||
}
|
||||
if (q->tmp) {
|
||||
free(q->tmp);
|
||||
}
|
||||
delete_viterbi37_neon(q->ptr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void free37(void *o) {
|
||||
srslte_viterbi_t *q = o;
|
||||
if (q->symbols_uc) {
|
||||
|
@ -203,6 +248,44 @@ int init37_sse(srslte_viterbi_t *q, int poly[3], uint32_t framebits, bool tail_b
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NEON
|
||||
int init37_neon(srslte_viterbi_t *q, int poly[3], uint32_t framebits, bool tail_biting) {
|
||||
q->K = 7;
|
||||
q->R = 3;
|
||||
q->framebits = framebits;
|
||||
q->gain_quant_s = 4;
|
||||
q->gain_quant = DEFAULT_GAIN;
|
||||
q->tail_biting = tail_biting;
|
||||
q->decode = decode37_neon;
|
||||
q->free = free37_neon;
|
||||
q->decode_f = NULL;
|
||||
printf("USING NEON VITERBI***************\n");
|
||||
q->symbols_uc = srslte_vec_malloc(3 * (q->framebits + q->K - 1) * sizeof(uint8_t));
|
||||
if (!q->symbols_uc) {
|
||||
perror("malloc");
|
||||
return -1;
|
||||
}
|
||||
if (q->tail_biting) {
|
||||
q->tmp = srslte_vec_malloc(TB_ITER*3*(q->framebits + q->K - 1) * sizeof(uint8_t));
|
||||
if (!q->tmp) {
|
||||
perror("malloc");
|
||||
free37(q);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
q->tmp = NULL;
|
||||
}
|
||||
|
||||
if ((q->ptr = create_viterbi37_neon(poly, TB_ITER*framebits)) == NULL) {
|
||||
fprintf(stderr, "create_viterbi37 failed\n");
|
||||
free37(q);
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void srslte_viterbi_set_gain_quant(srslte_viterbi_t *q, float gain_quant) {
|
||||
q->gain_quant = gain_quant;
|
||||
}
|
||||
|
@ -217,9 +300,13 @@ int srslte_viterbi_init(srslte_viterbi_t *q, srslte_viterbi_type_t type, int pol
|
|||
case SRSLTE_VITERBI_37:
|
||||
#ifdef LV_HAVE_SSE
|
||||
return init37_sse(q, poly, max_frame_length, tail_bitting);
|
||||
#else
|
||||
#ifdef HAVE_NEON
|
||||
return init37_neon(q, poly, max_frame_length, tail_bitting);
|
||||
#else
|
||||
return init37(q, poly, max_frame_length, tail_bitting);
|
||||
#endif
|
||||
#endif
|
||||
default:
|
||||
fprintf(stderr, "Decoder not implemented\n");
|
||||
return -1;
|
||||
|
|
|
@ -65,3 +65,26 @@ int update_viterbi37_blk_sse(void *p,
|
|||
uint8_t *syms,
|
||||
uint32_t nbits,
|
||||
uint32_t *best_state);
|
||||
|
||||
void *create_viterbi37_neon(int polys[3],
|
||||
uint32_t len);
|
||||
|
||||
int init_viterbi37_neon(void *p,
|
||||
int starting_state);
|
||||
|
||||
|
||||
void reset_blk_neon(void *p, int nbits);
|
||||
|
||||
int chainback_viterbi37_neon(void *p,
|
||||
uint8_t *data,
|
||||
uint32_t nbits,
|
||||
uint32_t endstate);
|
||||
|
||||
void delete_viterbi37_neon(void *p);
|
||||
|
||||
int update_viterbi37_blk_neon(void *p,
|
||||
uint8_t *syms,
|
||||
uint32_t nbits,
|
||||
uint32_t *best_state);
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,354 @@
|
|||
/* Adapted Phil Karn's r=1/3 k=9 viterbi decoder to r=1/3 k=7
|
||||
*
|
||||
* K=15 r=1/6 Viterbi decoder for ARM NEON
|
||||
* Copyright Mar 2004, Phil Karn, KA9Q
|
||||
* May be used under the terms of the GNU Lesser General Public License (LGPL)
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include <limits.h>
|
||||
#include "parity.h"
|
||||
|
||||
//#define DEBUG
|
||||
//#define HAVE_NEON
|
||||
#ifdef HAVE_NEON
|
||||
|
||||
#include <arm_neon.h>
|
||||
|
||||
typedef union {
|
||||
unsigned char c[64];
|
||||
uint8x16_t v[4];
|
||||
} metric_t;
|
||||
|
||||
|
||||
typedef union {
|
||||
unsigned long w[2];
|
||||
unsigned char c[8];
|
||||
unsigned short s[4];
|
||||
uint8x8_t v[1];
|
||||
} decision_t;
|
||||
|
||||
|
||||
union branchtab27{
|
||||
unsigned char c[32];
|
||||
uint8x16_t v[2];
|
||||
} Branchtab37_neon[3];
|
||||
|
||||
int8_t __attribute__((aligned(16))) xr[8];
|
||||
uint8x8_t mask_and;
|
||||
int8x8_t mask_shift;
|
||||
|
||||
|
||||
int firstGo;
|
||||
/* State info for instance of Viterbi decoder */
|
||||
struct v37 {
|
||||
metric_t metrics1; /* path metric buffer 1 */
|
||||
metric_t metrics2; /* path metric buffer 2 */
|
||||
decision_t *dp; /* Pointer to current decision */
|
||||
metric_t *old_metrics,*new_metrics; /* Pointers to path metrics, swapped on every bit */
|
||||
decision_t *decisions; /* Beginning of decisions for block */
|
||||
uint32_t len;
|
||||
};
|
||||
|
||||
void set_viterbi37_polynomial_neon(int polys[3]) {
|
||||
int state;
|
||||
|
||||
for(state=0;state < 32;state++){
|
||||
Branchtab37_neon[0].c[state] = (polys[0] < 0) ^ parity((2*state) & polys[0]) ? 255:0;
|
||||
Branchtab37_neon[1].c[state] = (polys[1] < 0) ^ parity((2*state) & polys[1]) ? 255:0;
|
||||
Branchtab37_neon[2].c[state] = (polys[2] < 0) ^ parity((2*state) & polys[2]) ? 255:0;
|
||||
}
|
||||
}
|
||||
|
||||
void clear_v37_neon(struct v37 *vp) {
|
||||
bzero(vp->decisions, sizeof(decision_t)*vp->len);
|
||||
vp->dp = NULL;
|
||||
bzero(&vp->metrics1, sizeof(metric_t));
|
||||
bzero(&vp->metrics2, sizeof(metric_t));
|
||||
vp->old_metrics = NULL;
|
||||
vp->new_metrics = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Initialize Viterbi decoder for start of new frame */
|
||||
int init_viterbi37_neon(void *p, int starting_state) {
|
||||
struct v37 *vp = p;
|
||||
uint32_t i;
|
||||
firstGo = 1;
|
||||
for(i=0;i<64;i++)
|
||||
vp->metrics1.c[i] = 63;
|
||||
|
||||
clear_v37_neon(vp);
|
||||
for(int i = 0; i <8;i++)
|
||||
xr[i] = i-7;
|
||||
|
||||
mask_and = vdup_n_u8(0x80);
|
||||
mask_shift = vld1_s8(xr);
|
||||
|
||||
|
||||
vp->old_metrics = &vp->metrics1;
|
||||
vp->new_metrics = &vp->metrics2;
|
||||
vp->dp = vp->decisions;
|
||||
if (starting_state != -1) {
|
||||
vp->old_metrics->c[starting_state & 63] = 0; /* Bias known start state */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Create a new instance of a Viterbi decoder */
|
||||
void *create_viterbi37_neon(int polys[3], uint32_t len) {
|
||||
void *p;
|
||||
struct v37 *vp;
|
||||
|
||||
set_viterbi37_polynomial_neon(polys);
|
||||
|
||||
/* Ordinary malloc() only returns 8-byte alignment, we need 16 */
|
||||
if(posix_memalign(&p, sizeof(uint8x16_t),sizeof(struct v37)))
|
||||
return NULL;
|
||||
|
||||
vp = (struct v37 *)p;
|
||||
if(posix_memalign(&p, sizeof(uint8x16_t),(len+6)*sizeof(decision_t))) {
|
||||
free(vp);
|
||||
return NULL;
|
||||
}
|
||||
vp->decisions = (decision_t *)p;
|
||||
vp->len = len+6;
|
||||
return vp;
|
||||
}
|
||||
|
||||
|
||||
/* Viterbi chainback */
|
||||
int chainback_viterbi37_neon(
|
||||
void *p,
|
||||
uint8_t *data, /* Decoded output data */
|
||||
uint32_t nbits, /* Number of data bits */
|
||||
uint32_t endstate) { /* Terminal encoder state */
|
||||
struct v37 *vp = p;
|
||||
|
||||
if (p == NULL)
|
||||
return -1;
|
||||
|
||||
decision_t *d = (decision_t *)vp->decisions;
|
||||
|
||||
/* Make room beyond the end of the encoder register so we can
|
||||
* accumulate a full byte of decoded data
|
||||
*/
|
||||
endstate %= 64;
|
||||
endstate <<= 2;
|
||||
|
||||
/* The store into data[] only needs to be done every 8 bits.
|
||||
* But this avoids a conditional branch, and the writes will
|
||||
* combine in the cache anyway
|
||||
*/
|
||||
d += 6; /* Look past tail */
|
||||
while(nbits--) {
|
||||
int k;
|
||||
|
||||
k = (d[nbits].c[(endstate>>2)/8] >> ((endstate>>2)%8)) & 1;
|
||||
endstate = (endstate >> 1) | (k << 7);
|
||||
data[nbits] = k;
|
||||
//printf("nbits=%d, endstate=%3d, k=%d, w[0]=%d, w[1]=%d, c=%d\n", nbits, endstate, k, d[nbits].s[1]&1, d[nbits].s[2]&1, d[nbits].c[(endstate>>2)/8]&1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Delete instance of a Viterbi decoder */
|
||||
void delete_viterbi37_neon(void *p){
|
||||
struct v37 *vp = p;
|
||||
|
||||
if(vp != NULL){
|
||||
free(vp->decisions);
|
||||
free(vp);
|
||||
}
|
||||
}
|
||||
|
||||
void print_uint8x16_t(char *s, uint8x16_t val) {
|
||||
|
||||
printf("%s: ", s);
|
||||
|
||||
uint8_t *x = (uint8_t*) &val;
|
||||
for (int i=0;i<16;i++) {
|
||||
printf("%3d, ", x[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int movemask_neon(uint8x16_t movemask_low_in)
|
||||
{
|
||||
uint8x8_t lo = vget_low_u8(movemask_low_in);
|
||||
uint8x8_t hi = vget_high_u8(movemask_low_in);
|
||||
lo = vand_u8(lo, mask_and);
|
||||
lo = vshl_u8(lo, mask_shift);
|
||||
hi = vand_u8(hi, mask_and);
|
||||
hi = vshl_u8(hi, mask_shift);
|
||||
|
||||
lo = vpadd_u8(lo, lo);
|
||||
lo = vpadd_u8(lo, lo);
|
||||
lo = vpadd_u8(lo, lo);
|
||||
|
||||
hi = vpadd_u8(hi, hi);
|
||||
hi = vpadd_u8(hi, hi);
|
||||
hi = vpadd_u8(hi, hi);
|
||||
|
||||
return ((hi[0] << 8) | (lo[0] & 0xFF));
|
||||
}
|
||||
|
||||
void update_viterbi37_blk_neon(void *p,unsigned char *syms,int nbits, uint32_t *best_state) {
|
||||
struct v37 *vp = p;
|
||||
decision_t *d;
|
||||
|
||||
uint8_t thirtyone;
|
||||
thirtyone = 31;
|
||||
if(p == NULL)
|
||||
return;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[");
|
||||
#endif
|
||||
|
||||
d = (decision_t *) vp->dp;
|
||||
|
||||
for (int s=0;s<nbits;s++) {
|
||||
memset(d+s,0,sizeof(decision_t));
|
||||
}
|
||||
|
||||
while(nbits--) {
|
||||
uint8x16_t sym0v,sym1v,sym2v;
|
||||
|
||||
void *tmp;
|
||||
int i;
|
||||
|
||||
// printf("nbits=%d, syms=%d,%d,%d\n", nbits, syms[0], syms[1], syms[2]);fflush(stdout);
|
||||
|
||||
/* Splat the 0th symbol across sym0v, the 1st symbol across sym1v, etc */
|
||||
sym0v = vld1q_dup_u8(syms); // passing a char as opposed to a pointer to a char
|
||||
sym1v = vld1q_dup_u8(syms+1);
|
||||
sym2v = vld1q_dup_u8(syms+2);
|
||||
syms += 3;
|
||||
|
||||
for(i=0;i<2;i++){
|
||||
uint8x16_t decision0, decision1, metric, m_metric, m0, m1, m2, m3, survivor0, survivor1;
|
||||
|
||||
/* Form branch metrics */
|
||||
m0 = vrhaddq_u8(veorq_u8(Branchtab37_neon[0].v[i],sym0v),veorq_u8(Branchtab37_neon[1].v[i],sym1v));
|
||||
metric = vrhaddq_u8(veorq_u8(Branchtab37_neon[2].v[i],sym2v),m0);
|
||||
|
||||
metric = vshrq_n_u8(metric,3);
|
||||
m_metric = vsubq_u8(vld1q_dup_u8(&thirtyone),metric);
|
||||
|
||||
/* Add branch metrics to path metrics */
|
||||
m0 = vaddq_u8(vp->old_metrics->v[i],metric);
|
||||
m3 = vaddq_u8(vp->old_metrics->v[2+i],metric);
|
||||
m1 = vaddq_u8(vp->old_metrics->v[2+i],m_metric);
|
||||
m2 = vaddq_u8(vp->old_metrics->v[i],m_metric);
|
||||
|
||||
/* Compare and select, using modulo arithmetic */
|
||||
|
||||
|
||||
decision0 = (uint8x16_t)vcgtq_s8(vsubq_s8((int8x16_t)m0,(int8x16_t)m1),vdupq_n_s8(0));
|
||||
decision1 = (uint8x16_t)vcgtq_s8(vsubq_s8((int8x16_t)m2,(int8x16_t)m3),vdupq_n_s8(0));
|
||||
survivor0 = vorrq_u8(vandq_u8(decision0,m1),vandq_u8(vmvnq_u8(decision0),m0));
|
||||
survivor1 = vorrq_u8 (vandq_u8(decision1,m3),vandq_u8(vmvnq_u8(decision1),m2) );
|
||||
|
||||
////// equal to _mm_unpacklo_epi8 //////////
|
||||
uint8x8_t a1 = vget_low_u8(decision0);
|
||||
uint8x8_t b1 = vget_low_u8(decision1);
|
||||
uint8x8x2_t result = vzip_u8(a1, b1);
|
||||
uint8x16_t movemask_low_in = vcombine_u8(result.val[0], result.val[1]);
|
||||
/////////////////////////////////////////
|
||||
|
||||
|
||||
////////equal to _mm_movemask_epi8 ////////
|
||||
d->s[2*i] = movemask_neon(movemask_low_in);
|
||||
|
||||
///////equal to _mm_unpackhi_epi8////////////
|
||||
a1 = vget_high_u8(decision0);
|
||||
b1 = vget_high_u8(decision1);
|
||||
result = vzip_u8(a1, b1);
|
||||
uint8x16_t movemask_hi_in = vcombine_u8(result.val[0], result.val[1]);
|
||||
|
||||
|
||||
|
||||
////////equal to _mm_movemask//////////////
|
||||
d->s[2*i+1] = movemask_neon(movemask_hi_in);
|
||||
|
||||
|
||||
a1 = vget_low_u8(survivor0);
|
||||
b1 = vget_low_u8(survivor1);
|
||||
result = vzip_u8(a1, b1);
|
||||
vp->new_metrics->v[2*i] = vcombine_u8(result.val[0], result.val[1]);
|
||||
|
||||
|
||||
a1 = vget_high_u8(survivor0);
|
||||
b1 = vget_high_u8(survivor1);
|
||||
result = vzip_u8(a1, b1);
|
||||
vp->new_metrics->v[2*i+1] = vcombine_u8(result.val[0], result.val[1]);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
// See if we need to normalize
|
||||
if (vp->new_metrics->c[0] > 100) {
|
||||
int i;
|
||||
uint8_t adjust;
|
||||
uint8x16_t adjustv;
|
||||
|
||||
union { uint8x16_t v; signed short w[8]; } t;
|
||||
|
||||
adjustv = vp->new_metrics->v[0];
|
||||
for(i=1;i<4;i++)
|
||||
{
|
||||
adjustv = vminq_u8(vp->new_metrics->v[i],adjustv);
|
||||
}
|
||||
|
||||
adjustv = vminq_u8(adjustv,vextq_u8(adjustv, vdupq_n_u8(0), (8)));
|
||||
adjustv = vminq_u8(adjustv,vextq_u8(adjustv, vdupq_n_u8(0), (4)));
|
||||
adjustv = vminq_u8(adjustv,vextq_u8(adjustv, vdupq_n_u8(0), (2)));
|
||||
t.v = adjustv;
|
||||
adjust = t.w[0];
|
||||
adjustv = vld1q_dup_u8(&adjust);
|
||||
|
||||
/* We cannot use a saturated subtract, because we often have to adjust by more than SHRT_MAX
|
||||
* This is okay since it can't overflow anyway
|
||||
*/
|
||||
for(i=0;i<4;i++)
|
||||
{
|
||||
vp->new_metrics->v[i] = vsubq_u8(vp->new_metrics->v[i],adjustv);
|
||||
}
|
||||
|
||||
}
|
||||
d++;
|
||||
/* Swap pointers to old and new metrics */
|
||||
tmp = vp->old_metrics;
|
||||
vp->old_metrics = vp->new_metrics;
|
||||
vp->new_metrics = tmp;
|
||||
//firstGo = 0;
|
||||
}
|
||||
|
||||
if (best_state) {
|
||||
uint32_t i, bst=0;
|
||||
uint8_t minmetric=UINT8_MAX;
|
||||
for (i=0;i<64;i++) {
|
||||
if (vp->old_metrics->c[i] <= minmetric) {
|
||||
bst = i;
|
||||
minmetric = vp->old_metrics->c[i];
|
||||
}
|
||||
}
|
||||
*best_state = bst;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("];\n===========================================\n");
|
||||
#endif
|
||||
|
||||
vp->dp = d;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -33,6 +33,17 @@ if(RF_FOUND)
|
|||
list(APPEND SOURCES_RF rf_blade_imp.c)
|
||||
endif (BLADERF_FOUND)
|
||||
|
||||
if (LIMESDR_FOUND)
|
||||
add_definitions(-DENABLE_LIMESDR)
|
||||
list(APPEND SOURCES_RF rf_limesdr_imp.c)
|
||||
endif (LIMESDR_FOUND)
|
||||
|
||||
if (SOAPYSDR_FOUND)
|
||||
add_definitions(-DENABLE_SOAPYSDR)
|
||||
list(APPEND SOURCES_RF rf_soapy_imp.c)
|
||||
endif (SOAPYSDR_FOUND)
|
||||
|
||||
|
||||
add_library(srslte_rf SHARED ${SOURCES_RF})
|
||||
|
||||
|
||||
|
@ -44,6 +55,15 @@ if(RF_FOUND)
|
|||
target_link_libraries(srslte_rf ${BLADERF_LIBRARIES})
|
||||
endif (BLADERF_FOUND)
|
||||
|
||||
if (LIMESDR_FOUND)
|
||||
target_link_libraries(srslte_rf ${LIMESDR_LIBRARIES})
|
||||
endif (LIMESDR_FOUND)
|
||||
|
||||
if (SOAPYSDR_FOUND)
|
||||
target_link_libraries(srslte_rf ${SOAPYSDR_LIBRARIES})
|
||||
endif (SOAPYSDR_FOUND)
|
||||
|
||||
|
||||
INSTALL(TARGETS srslte_rf DESTINATION ${LIBRARY_DIR})
|
||||
SRSLTE_SET_PIC(srslte_rf)
|
||||
endif(RF_FOUND)
|
||||
|
|
|
@ -140,6 +140,83 @@ static rf_dev_t dev_blade = {
|
|||
};
|
||||
#endif
|
||||
|
||||
/* Define implementation for LimeSDR */
|
||||
#ifdef ENABLE_LIMESDR
|
||||
|
||||
#include "rf_limesdr_imp.h"
|
||||
|
||||
static rf_dev_t dev_limesdr = {
|
||||
"limesdr",
|
||||
rf_limesdr_devname,
|
||||
rf_limesdr_rx_wait_lo_locked,
|
||||
rf_limesdr_start_rx_stream,
|
||||
rf_limesdr_stop_rx_stream,
|
||||
rf_limesdr_flush_buffer,
|
||||
rf_limesdr_has_rssi,
|
||||
rf_limesdr_get_rssi,
|
||||
rf_limesdr_suppress_stdout,
|
||||
rf_limesdr_register_error_handler,
|
||||
rf_limesdr_open,
|
||||
rf_limesdr_open_multi,
|
||||
rf_limesdr_close,
|
||||
rf_limesdr_set_master_clock_rate,
|
||||
rf_limesdr_is_master_clock_dynamic,
|
||||
rf_limesdr_set_rx_srate,
|
||||
rf_limesdr_set_rx_gain,
|
||||
rf_limesdr_set_tx_gain,
|
||||
rf_limesdr_get_rx_gain,
|
||||
rf_limesdr_get_tx_gain,
|
||||
rf_limesdr_set_rx_freq,
|
||||
rf_limesdr_set_tx_srate,
|
||||
rf_limesdr_set_tx_freq,
|
||||
rf_limesdr_get_time,
|
||||
rf_limesdr_recv_with_time,
|
||||
rf_limesdr_recv_with_time_multi,
|
||||
rf_limesdr_send_timed,
|
||||
rf_limesdr_set_tx_cal,
|
||||
rf_limesdr_set_rx_cal
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SOAPYSDR
|
||||
|
||||
#include "rf_soapy_imp.h"
|
||||
|
||||
static rf_dev_t dev_soapy = {
|
||||
"soapy",
|
||||
rf_soapy_devname,
|
||||
rf_soapy_rx_wait_lo_locked,
|
||||
rf_soapy_start_rx_stream,
|
||||
rf_soapy_stop_rx_stream,
|
||||
rf_soapy_flush_buffer,
|
||||
rf_soapy_has_rssi,
|
||||
rf_soapy_get_rssi,
|
||||
rf_soapy_suppress_stdout,
|
||||
rf_soapy_register_error_handler,
|
||||
rf_soapy_open,
|
||||
rf_soapy_open_multi,
|
||||
rf_soapy_close,
|
||||
rf_soapy_set_master_clock_rate,
|
||||
rf_soapy_is_master_clock_dynamic,
|
||||
rf_soapy_set_rx_srate,
|
||||
rf_soapy_set_rx_gain,
|
||||
rf_soapy_set_tx_gain,
|
||||
rf_soapy_get_rx_gain,
|
||||
rf_soapy_get_tx_gain,
|
||||
rf_soapy_set_rx_freq,
|
||||
rf_soapy_set_tx_srate,
|
||||
rf_soapy_set_tx_freq,
|
||||
rf_soapy_get_time,
|
||||
rf_soapy_recv_with_time,
|
||||
rf_soapy_recv_with_time_multi,
|
||||
rf_soapy_send_timed,
|
||||
rf_soapy_set_tx_cal,
|
||||
rf_soapy_set_rx_cal
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
//#define ENABLE_DUMMY_DEV
|
||||
|
||||
#ifdef ENABLE_DUMMY_DEV
|
||||
|
@ -183,12 +260,19 @@ static rf_dev_t dev_dummy = {
|
|||
#endif
|
||||
|
||||
static rf_dev_t *available_devices[] = {
|
||||
|
||||
#ifdef ENABLE_UHD
|
||||
&dev_uhd,
|
||||
#endif
|
||||
#ifdef ENABLE_SOAPYSDR
|
||||
&dev_soapy,
|
||||
#endif
|
||||
#ifdef ENABLE_BLADERF
|
||||
&dev_blade,
|
||||
#endif
|
||||
#ifdef ENABLE_LIMESDR
|
||||
&dev_limesdr,
|
||||
#endif
|
||||
#ifdef ENABLE_DUMMY_DEV
|
||||
&dev_dummy,
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,475 @@
|
|||
/**
|
||||
*
|
||||
* \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 <sys/time.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "srslte/srslte.h"
|
||||
#include "rf_limesdr_imp.h"
|
||||
#include "srslte/rf/rf.h"
|
||||
#include "lime/LimeSuite.h"
|
||||
|
||||
typedef struct {
|
||||
char *devname;
|
||||
lms_dev_info_t *dev_info;
|
||||
lms_device_t *device;
|
||||
lms_info_str_t list[8];
|
||||
lms_stream_t rx_stream;
|
||||
lms_stream_t tx_stream;
|
||||
int sampling_rate;
|
||||
bool rx_is_streaming;
|
||||
bool tx_is_streaming;
|
||||
int channel;
|
||||
|
||||
int buffer_size;
|
||||
int num_buffers;
|
||||
|
||||
lms_stream_meta_t tx_metadata; //Use metadata for additional control over sample receive function behaviour
|
||||
lms_stream_meta_t rx_metadata; //Use metadata for additional control over sample receive function behaviour
|
||||
|
||||
lms_range_t rx_range;
|
||||
lms_range_t tx_range;
|
||||
|
||||
} rf_limesdr_handler_t;
|
||||
|
||||
int lime_error(void *h)
|
||||
{
|
||||
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
|
||||
|
||||
//print last error message
|
||||
fprintf(stderr, "Error: %s\n", LMS_GetLastErrorMessage());
|
||||
if(handler->device != NULL)
|
||||
LMS_Close(handler->device);
|
||||
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
void rf_limesdr_get_freq_range(void *h)
|
||||
{
|
||||
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
|
||||
LMS_GetLOFrequencyRange(handler->device, LMS_CH_RX, &(handler->rx_range));
|
||||
LMS_GetLOFrequencyRange(handler->device, LMS_CH_TX, &(handler->tx_range));
|
||||
}
|
||||
|
||||
void rf_limesdr_suppress_handler(const char *x)
|
||||
{
|
||||
// not supported
|
||||
}
|
||||
|
||||
void rf_limesdr_msg_handler(const char *msg)
|
||||
{
|
||||
// not supported
|
||||
}
|
||||
|
||||
void rf_limesdr_suppress_stdout(void *h)
|
||||
{
|
||||
// not supported
|
||||
}
|
||||
|
||||
void rf_limesdr_register_error_handler(void *notused, srslte_rf_error_handler_t new_handler)
|
||||
{
|
||||
// not supported
|
||||
}
|
||||
|
||||
static bool isLocked(rf_limesdr_handler_t *handler, char *sensor_name, void *value_h)
|
||||
{
|
||||
// not supported
|
||||
return true;
|
||||
}
|
||||
|
||||
char* rf_limesdr_devname(void* h)
|
||||
{
|
||||
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
|
||||
handler->dev_info = LMS_GetDeviceInfo(handler);
|
||||
|
||||
return handler->dev_info->deviceName;
|
||||
}
|
||||
|
||||
bool rf_limesdr_rx_wait_lo_locked(void *h)
|
||||
{
|
||||
// not supported
|
||||
return true;
|
||||
}
|
||||
|
||||
void rf_limesdr_set_tx_cal(void *h, srslte_rf_cal_t *cal)
|
||||
{
|
||||
// not supported
|
||||
}
|
||||
|
||||
void rf_limesdr_set_rx_cal(void *h, srslte_rf_cal_t *cal)
|
||||
{
|
||||
// not supported
|
||||
}
|
||||
|
||||
int rf_limesdr_start_rx_stream(void *h)
|
||||
{
|
||||
printf("Starting rx stream\n");
|
||||
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
|
||||
if(LMS_StartStream(&(handler->rx_stream)) != 0){
|
||||
return lime_error(h);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int rf_limesdr_start_tx_stream(void *h)
|
||||
{
|
||||
printf("Starting tx stream\n");
|
||||
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
|
||||
if(LMS_StartStream(&(handler->tx_stream)) != 0){
|
||||
return lime_error(h);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rf_limesdr_stop_rx_stream(void *h)
|
||||
{
|
||||
printf("Stopping rx stream\n");
|
||||
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
|
||||
//stream is stopped but can be started again with LMS_StartStream()
|
||||
if(LMS_StopStream(&(handler->rx_stream)) != 0){
|
||||
return lime_error(h);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int rf_limesdr_stop_tx_stream(void *h)
|
||||
{
|
||||
printf("Stopping tx stream\n");
|
||||
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
|
||||
//stream is stopped but can be started again with LMS_StartStream()
|
||||
if(LMS_StopStream(&(handler->tx_stream)) != 0){
|
||||
return lime_error(h);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rf_limesdr_flush_buffer(void *h)
|
||||
{
|
||||
int n;
|
||||
cf_t tmp1[1024];
|
||||
cf_t tmp2[1024];
|
||||
void *data[2] = {tmp1, tmp2};
|
||||
do {
|
||||
n = rf_limesdr_recv_with_time_multi(h, data, 1024, 0, NULL, NULL);
|
||||
} while (n > 0);
|
||||
}
|
||||
|
||||
bool rf_limesdr_has_rssi(void *h)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
float rf_limesdr_get_rssi(void *h)
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
//TODO: add multi-channel support
|
||||
int rf_limesdr_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
|
||||
{
|
||||
return rf_limesdr_open(args, h);
|
||||
}
|
||||
|
||||
int rf_limesdr_open(char *args, void **h)
|
||||
{
|
||||
printf("Opening device\n");
|
||||
*h = NULL;
|
||||
|
||||
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) malloc(sizeof(rf_limesdr_handler_t));
|
||||
if (!handler) {
|
||||
perror("malloc");
|
||||
return -1;
|
||||
}
|
||||
*h = handler;
|
||||
|
||||
handler->device = NULL;
|
||||
|
||||
handler->buffer_size = 1024;
|
||||
handler->num_buffers = 8;
|
||||
handler->channel = 0;
|
||||
|
||||
|
||||
int n;
|
||||
if ((n = LMS_GetDeviceList(handler->list)) < 0) //NULL can be passed to only get number of devices
|
||||
return SRSLTE_ERROR;
|
||||
|
||||
if (LMS_Open(&(handler->device), handler->list[0], NULL))
|
||||
return SRSLTE_ERROR;
|
||||
|
||||
if (LMS_Init(handler->device) != 0)
|
||||
return SRSLTE_ERROR;
|
||||
|
||||
if (LMS_EnableChannel(handler->device, LMS_CH_RX, handler->channel, true) != 0)
|
||||
return lime_error(handler);
|
||||
|
||||
if (LMS_EnableChannel(handler->device, LMS_CH_TX, handler->channel, true) != 0)
|
||||
return lime_error(handler);
|
||||
|
||||
rf_limesdr_get_freq_range(handler);
|
||||
|
||||
handler->rx_is_streaming = false;
|
||||
handler->rx_stream.channel = handler->channel; //channel number
|
||||
handler->rx_stream.fifoSize = 1024 * 1024; //fifo size in samples
|
||||
handler->rx_stream.throughputVsLatency = 1.0; //optimize for max throughput
|
||||
handler->rx_stream.isTx = false; //RX channel
|
||||
handler->rx_stream.dataFmt = LMS_FMT_F32;
|
||||
handler->rx_metadata.flushPartialPacket = false; //Do not discard data remainder when read size differs from packet size
|
||||
handler->rx_metadata.waitForTimestamp = false; //Do not wait for specific timestamps
|
||||
|
||||
if (LMS_SetupStream(handler->device, &(handler->rx_stream)) != 0)
|
||||
return lime_error(handler);
|
||||
|
||||
handler->tx_is_streaming = false;
|
||||
handler->tx_stream.channel = handler->channel; //channel number
|
||||
handler->tx_stream.fifoSize = 1024 * 1024; //fifo size in samples
|
||||
handler->tx_stream.throughputVsLatency = 1.0; //optimize for max throughput
|
||||
handler->tx_stream.isTx = true; //TX channel
|
||||
handler->rx_stream.dataFmt = LMS_FMT_F32;
|
||||
handler->tx_metadata.flushPartialPacket = false; //Do not discard data remainder when read size differs from packet size
|
||||
handler->tx_metadata.waitForTimestamp = false; //Do not wait for specific timestamps
|
||||
|
||||
if (LMS_SetupStream(handler->device, &(handler->tx_stream)) != 0)
|
||||
return lime_error(handler);
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int rf_limesdr_close(void *h)
|
||||
{
|
||||
printf("Closing device\n");
|
||||
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
|
||||
if(handler->rx_is_streaming) {
|
||||
LMS_StopStream(&(handler->rx_stream));
|
||||
}
|
||||
LMS_DestroyStream(handler->device, &(handler->rx_stream)); //stream is deallocated and can no longer be used
|
||||
|
||||
if(handler->tx_is_streaming) {
|
||||
LMS_StopStream(&(handler->tx_stream));
|
||||
}
|
||||
LMS_DestroyStream(handler->device, &(handler->tx_stream)); //stream is deallocated and can no longer be used
|
||||
|
||||
LMS_Close(handler->device);
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
void rf_limesdr_set_master_clock_rate(void *h, double rate)
|
||||
{
|
||||
// Allow the limesdr to automatically set the appropriate clock rate
|
||||
}
|
||||
|
||||
bool rf_limesdr_is_master_clock_dynamic(void *h)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
double rf_limesdr_set_rx_srate(void *h, double rate)
|
||||
{
|
||||
fprintf(stdout, "Setting rx rate: %f\n", rate);
|
||||
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
|
||||
if (LMS_SetSampleRate(handler->device, rate, 0) != 0)
|
||||
return lime_error(handler);
|
||||
|
||||
handler->sampling_rate = rate;
|
||||
return rate;
|
||||
}
|
||||
|
||||
double rf_limesdr_set_tx_srate(void *h, double rate)
|
||||
{
|
||||
fprintf(stdout, "Setting tx rate: %f\n", rate);
|
||||
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
|
||||
if (LMS_SetSampleRate(handler->device, rate, 0) != 0)
|
||||
return lime_error(handler);
|
||||
|
||||
handler->sampling_rate = rate;
|
||||
return rate;
|
||||
}
|
||||
|
||||
double rf_limesdr_set_rx_gain(void *h, double gain)
|
||||
{
|
||||
fprintf(stdout, "Setting rx gain: %f\n", gain);
|
||||
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
|
||||
if (LMS_SetNormalizedGain(handler->device, LMS_CH_RX, handler->channel, gain) != 0)
|
||||
return lime_error(handler);
|
||||
|
||||
return gain;
|
||||
}
|
||||
|
||||
double rf_limesdr_set_tx_gain(void *h, double gain)
|
||||
{
|
||||
fprintf(stdout, "Setting tx gain: %f\n", gain);
|
||||
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
|
||||
if (LMS_SetNormalizedGain(handler->device, LMS_CH_TX, handler->channel, gain) != 0)
|
||||
return lime_error(handler);
|
||||
|
||||
return gain;
|
||||
}
|
||||
|
||||
double rf_limesdr_get_rx_gain(void *h)
|
||||
{
|
||||
double gain;
|
||||
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
|
||||
if(LMS_GetNormalizedGain(handler->device, LMS_CH_RX,handler->channel,&gain) != 0)
|
||||
return lime_error(handler);
|
||||
|
||||
return gain;
|
||||
}
|
||||
|
||||
double rf_limesdr_get_tx_gain(void *h)
|
||||
{
|
||||
double gain;
|
||||
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
|
||||
if(LMS_GetNormalizedGain(handler->device, LMS_CH_TX, handler->channel, &gain) != 0)
|
||||
return lime_error(handler);
|
||||
|
||||
return gain;
|
||||
}
|
||||
|
||||
double rf_limesdr_set_rx_freq(void *h, double freq)
|
||||
{
|
||||
fprintf(stdout, "Setting rx freq: %f\n", freq);
|
||||
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
|
||||
|
||||
if(freq > handler->rx_range.max || freq < handler->rx_range.min) {
|
||||
fprintf(stderr, "Requested freq outside supported range. freq: %f, min: %f, max: %f\n", freq, handler->rx_range.min, handler->rx_range.max);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
if(LMS_SetLOFrequency(handler->device, LMS_CH_RX, handler->channel, freq) != 0)
|
||||
return lime_error(handler);
|
||||
|
||||
// Automatic antenna port selection doesn't work - so set manually
|
||||
int ant_port = 1; // manually select antenna index 1 (LNA_H)
|
||||
if(freq < 1.5e9) {
|
||||
ant_port = 2; // manually select antenna index 2 (LNA_L)
|
||||
}
|
||||
if (LMS_SetAntenna(handler->device, LMS_CH_RX, handler->channel, ant_port) != 0)
|
||||
return lime_error(handler);
|
||||
|
||||
lms_name_t antenna_list[10]; //large enough list for antenna names.
|
||||
//Alternatively, NULL can be passed to LMS_GetAntennaList() to find out number of available antennae
|
||||
int n = 0;
|
||||
if ((n = LMS_GetAntennaList(handler->device, LMS_CH_RX, 0, antenna_list)) < 0)
|
||||
return lime_error(handler);
|
||||
|
||||
fprintf(stdout, "Available antennae:\n"); //print available antennae names
|
||||
for(int i = 0; i < n; i++)
|
||||
fprintf(stdout, "%d : %s\n", i, antenna_list[i]);
|
||||
|
||||
if((n = LMS_GetAntenna(handler->device, LMS_CH_RX, handler->channel)) < 0) //get currently selected antenna index
|
||||
return lime_error(handler);
|
||||
fprintf(stdout, "Selected antenna: %d : %s\n", n, antenna_list[n]); //print antenna index and name
|
||||
|
||||
return freq;
|
||||
}
|
||||
|
||||
double rf_limesdr_set_tx_freq(void *h, double freq)
|
||||
{
|
||||
fprintf(stdout, "Setting tx freq: %f\n", freq);
|
||||
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
|
||||
if(freq > handler->tx_range.max || freq < handler->tx_range.min) {
|
||||
fprintf(stderr, "Requested freq outside supported range. freq: %f, min: %f, max: %f\n", freq, handler->rx_range.min, handler->rx_range.max);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
if(LMS_SetLOFrequency(handler->device, LMS_CH_TX, handler->channel, freq) != 0)
|
||||
return lime_error(handler);
|
||||
|
||||
return freq;
|
||||
}
|
||||
|
||||
|
||||
void rf_limesdr_get_time(void *h, time_t *secs, double *frac_secs) {
|
||||
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
|
||||
LMS_RecvStream(&(handler->rx_stream),NULL,0, &(handler->rx_metadata), 0);
|
||||
if (secs && frac_secs) {
|
||||
*secs = (handler->rx_metadata.timestamp) / (handler->sampling_rate);
|
||||
int remainder = handler->rx_metadata.timestamp % handler->sampling_rate;
|
||||
*frac_secs = remainder/(handler->sampling_rate);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: add multi-channel support
|
||||
int rf_limesdr_recv_with_time_multi(void *h,
|
||||
void **data,
|
||||
uint32_t nsamples,
|
||||
bool blocking,
|
||||
time_t *secs,
|
||||
double *frac_secs)
|
||||
{
|
||||
return rf_limesdr_recv_with_time(h, *data, nsamples, blocking, secs, frac_secs);
|
||||
}
|
||||
|
||||
int rf_limesdr_recv_with_time(void *h,
|
||||
void *data,
|
||||
uint32_t nsamples,
|
||||
bool blocking,
|
||||
time_t *secs,
|
||||
double *frac_secs)
|
||||
{
|
||||
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
|
||||
int samples = LMS_RecvStream(&(handler->rx_stream),data,nsamples, &(handler->rx_metadata), blocking ? 1000:0);
|
||||
if (secs && frac_secs) {
|
||||
*secs = (handler->rx_metadata.timestamp) / (handler->sampling_rate);
|
||||
int remainder = handler->rx_metadata.timestamp % handler->sampling_rate;
|
||||
*frac_secs = remainder/(handler->sampling_rate);
|
||||
}
|
||||
|
||||
return samples;
|
||||
}
|
||||
|
||||
|
||||
int rf_limesdr_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_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
|
||||
|
||||
//float *data_in = (float*) data;
|
||||
|
||||
if(!handler->tx_is_streaming)
|
||||
rf_limesdr_start_tx_stream(h);
|
||||
|
||||
handler->tx_metadata.timestamp = secs*handler->sampling_rate;
|
||||
handler->tx_metadata.timestamp += frac_secs*handler->sampling_rate;
|
||||
|
||||
LMS_SendStream(&(handler->rx_stream), data, nsamples, &(handler->tx_metadata), blocking ? 1000:0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
/**
|
||||
*
|
||||
* \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_limesdr_open( char *args,
|
||||
void **handler);
|
||||
|
||||
SRSLTE_API int rf_limesdr_open_multi( char *args,
|
||||
void **handler,
|
||||
uint32_t nof_rx_antennas);
|
||||
|
||||
SRSLTE_API char* rf_limesdr_devname(void *h);
|
||||
|
||||
SRSLTE_API int rf_limesdr_close(void *h);
|
||||
|
||||
SRSLTE_API void rf_limesdr_set_tx_cal(void *h, srslte_rf_cal_t *cal);
|
||||
|
||||
SRSLTE_API void rf_limesdr_set_rx_cal(void *h, srslte_rf_cal_t *cal);
|
||||
|
||||
SRSLTE_API int rf_limesdr_start_rx_stream(void *h);
|
||||
|
||||
SRSLTE_API int rf_limesdr_stop_rx_stream(void *h);
|
||||
|
||||
SRSLTE_API void rf_limesdr_flush_buffer(void *h);
|
||||
|
||||
SRSLTE_API bool rf_limesdr_has_rssi(void *h);
|
||||
|
||||
SRSLTE_API float rf_limesdr_get_rssi(void *h);
|
||||
|
||||
SRSLTE_API bool rf_limesdr_rx_wait_lo_locked(void *h);
|
||||
|
||||
SRSLTE_API void rf_limesdr_set_master_clock_rate(void *h,
|
||||
double rate);
|
||||
|
||||
SRSLTE_API bool rf_limesdr_is_master_clock_dynamic(void *h);
|
||||
|
||||
SRSLTE_API double rf_limesdr_set_rx_srate(void *h,
|
||||
double freq);
|
||||
|
||||
SRSLTE_API double rf_limesdr_set_rx_gain(void *h,
|
||||
double gain);
|
||||
|
||||
SRSLTE_API double rf_limesdr_get_rx_gain(void *h);
|
||||
|
||||
SRSLTE_API double rf_limesdr_set_tx_gain(void *h,
|
||||
double gain);
|
||||
|
||||
SRSLTE_API double rf_limesdr_get_tx_gain(void *h);
|
||||
|
||||
SRSLTE_API void rf_limesdr_suppress_stdout(void *h);
|
||||
|
||||
SRSLTE_API void rf_limesdr_register_error_handler(void *h, srslte_rf_error_handler_t error_handler);
|
||||
|
||||
SRSLTE_API double rf_limesdr_set_rx_freq(void *h,
|
||||
double freq);
|
||||
|
||||
SRSLTE_API int rf_limesdr_recv_with_time(void *h,
|
||||
void *data,
|
||||
uint32_t nsamples,
|
||||
bool blocking,
|
||||
time_t *secs,
|
||||
double *frac_secs);
|
||||
|
||||
SRSLTE_API int rf_limesdr_recv_with_time_multi(void *h,
|
||||
void **data,
|
||||
uint32_t nsamples,
|
||||
bool blocking,
|
||||
time_t *secs,
|
||||
double *frac_secs);
|
||||
|
||||
SRSLTE_API double rf_limesdr_set_tx_srate(void *h,
|
||||
double freq);
|
||||
|
||||
SRSLTE_API double rf_limesdr_set_tx_freq(void *h,
|
||||
double freq);
|
||||
|
||||
SRSLTE_API void rf_limesdr_get_time(void *h,
|
||||
time_t *secs,
|
||||
double *frac_secs);
|
||||
|
||||
SRSLTE_API int rf_limesdr_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,457 @@
|
|||
/**
|
||||
*
|
||||
* \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 <sys/time.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "srslte/srslte.h"
|
||||
#include "rf_soapy_imp.h"
|
||||
#include "srslte/rf/rf.h"
|
||||
|
||||
#include <SoapySDR/Device.h>
|
||||
#include <SoapySDR/Formats.h>
|
||||
//#include "lime/LimeSuite.h"
|
||||
|
||||
typedef struct {
|
||||
|
||||
SoapySDRKwargs args;
|
||||
SoapySDRDevice *device;
|
||||
SoapySDRRange *ranges;
|
||||
|
||||
SoapySDRStream *rxStream;
|
||||
SoapySDRStream *txStream;
|
||||
|
||||
|
||||
} rf_soapy_handler_t;
|
||||
|
||||
int soapy_error(void *h)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void rf_soapy_get_freq_range(void *h)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void rf_soapy_suppress_handler(const char *x)
|
||||
{
|
||||
// not supported
|
||||
}
|
||||
|
||||
void rf_soapy_msg_handler(const char *msg)
|
||||
{
|
||||
// not supported
|
||||
}
|
||||
|
||||
void rf_soapy_suppress_stdout(void *h)
|
||||
{
|
||||
// not supported
|
||||
}
|
||||
|
||||
void rf_soapy_register_error_handler(void *notused, srslte_rf_error_handler_t new_handler)
|
||||
{
|
||||
// not supported
|
||||
}
|
||||
|
||||
static bool isLocked(rf_soapy_handler_t *handler, char *sensor_name, void *value_h)
|
||||
{
|
||||
// not supported
|
||||
return true;
|
||||
}
|
||||
|
||||
char* rf_soapy_devname(void* h)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool rf_soapy_rx_wait_lo_locked(void *h)
|
||||
{
|
||||
// not supported
|
||||
return true;
|
||||
}
|
||||
|
||||
void rf_soapy_set_tx_cal(void *h, srslte_rf_cal_t *cal)
|
||||
{
|
||||
// not supported
|
||||
}
|
||||
|
||||
void rf_soapy_set_rx_cal(void *h, srslte_rf_cal_t *cal)
|
||||
{
|
||||
// not supported
|
||||
}
|
||||
|
||||
int rf_soapy_start_rx_stream(void *h)
|
||||
{
|
||||
//printf("starting SOAPY rx stream \n");
|
||||
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
|
||||
//SoapySDRStream *rxStream;
|
||||
|
||||
if(SoapySDRDevice_activateStream(handler->device, handler->rxStream, 0, 0, 0)!=0)//start streaming
|
||||
return SRSLTE_ERROR;
|
||||
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int rf_soapy_start_tx_stream(void *h)
|
||||
{
|
||||
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
|
||||
//SoapySDRStream *rxStream;
|
||||
if (SoapySDRDevice_setupStream(handler->device, &(handler->txStream), SOAPY_SDR_TX, SOAPY_SDR_CF32, NULL, 0, NULL) != 0)
|
||||
{
|
||||
printf("setupStream fail: %s\n", SoapySDRDevice_lastError());
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
if(SoapySDRDevice_activateStream(handler->device, handler->txStream, 0, 0, 0) != 0)
|
||||
return SRSLTE_ERROR;
|
||||
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int rf_soapy_stop_rx_stream(void *h)
|
||||
{
|
||||
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
|
||||
if(SoapySDRDevice_deactivateStream(handler->device, handler->rxStream, 0, 0) != 0)
|
||||
return SRSLTE_ERROR;
|
||||
|
||||
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
int rf_soapy_stop_tx_stream(void *h)
|
||||
{
|
||||
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
|
||||
|
||||
if(SoapySDRDevice_deactivateStream(handler->device, handler->txStream, 0, 0) != 0)
|
||||
return SRSLTE_ERROR;
|
||||
|
||||
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
void rf_soapy_flush_buffer(void *h)
|
||||
{
|
||||
int n;
|
||||
cf_t tmp1[1024];
|
||||
cf_t tmp2[1024];
|
||||
void *data[2] = {tmp1, tmp2};
|
||||
do {
|
||||
n = rf_soapy_recv_with_time_multi(h, data, 1024, 0, NULL, NULL);
|
||||
} while (n > 0);
|
||||
}
|
||||
|
||||
bool rf_soapy_has_rssi(void *h)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
float rf_soapy_get_rssi(void *h)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//TODO: add multi-channel support
|
||||
int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
|
||||
{//SoapySDRKwargs soapy_args = {};
|
||||
size_t length;
|
||||
const SoapySDRKwargs *soapy_args = SoapySDRDevice_enumerate(NULL, &length);
|
||||
|
||||
if(length == 0)
|
||||
{
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < length; i++)
|
||||
{
|
||||
printf("Soapy Has Found device #%d: ", (int)i);
|
||||
for (size_t j = 0; j < soapy_args[i].size; j++)
|
||||
{
|
||||
printf("%s=%s, ", soapy_args[i].keys[j], soapy_args[i].vals[j]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// SoapySDRrgs_set(&soapy_args, "driver", "rtlsdr");
|
||||
SoapySDRDevice *sdr = SoapySDRDevice_make(&(soapy_args[0]));
|
||||
|
||||
if(sdr == NULL)
|
||||
{
|
||||
printf("failed to create SOAPY object\n");
|
||||
return SRSLTE_ERROR;
|
||||
|
||||
}
|
||||
|
||||
//SoapySDRKwargs_clear(&soapy_args);
|
||||
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) malloc(sizeof(rf_soapy_handler_t));
|
||||
*h = handler;
|
||||
handler->device = sdr;
|
||||
|
||||
|
||||
|
||||
//size_t channels[1];
|
||||
//channels[0] = 0;
|
||||
|
||||
if (SoapySDRDevice_setupStream(handler->device, &(handler->rxStream), SOAPY_SDR_RX, SOAPY_SDR_CF32, NULL, 0, NULL) != 0)
|
||||
{
|
||||
printf("setupStream fail: %s\n", SoapySDRDevice_lastError());
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
int rf_soapy_open(char *args, void **h)
|
||||
{
|
||||
return rf_soapy_open_multi(args, h, 1);
|
||||
}
|
||||
|
||||
|
||||
int rf_soapy_close(void *h)
|
||||
{
|
||||
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
|
||||
SoapySDRDevice_closeStream(handler->device, handler->txStream);
|
||||
SoapySDRDevice_closeStream(handler->device, handler->rxStream);
|
||||
SoapySDRDevice_unmake(handler->device);
|
||||
}
|
||||
|
||||
void rf_soapy_set_master_clock_rate(void *h, double rate)
|
||||
{
|
||||
// Allow the soapy to automatically set the appropriate clock rate
|
||||
|
||||
printf("SET MASTER CLOCK RATE\n");
|
||||
}
|
||||
|
||||
bool rf_soapy_is_master_clock_dynamic(void *h)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
double rf_soapy_set_rx_srate(void *h, double rate)
|
||||
{
|
||||
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
|
||||
if (SoapySDRDevice_setSampleRate(handler->device, SOAPY_SDR_RX, 0, rate) != 0)
|
||||
{
|
||||
printf("setSampleRate fail: %s\n", SoapySDRDevice_lastError());
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
double ret = SoapySDRDevice_getSampleRate(handler->device, SOAPY_SDR_RX,0);
|
||||
printf("Sampling rate is set to %f.3 : \n",ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
double rf_soapy_set_tx_srate(void *h, double rate)
|
||||
{
|
||||
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
|
||||
if (SoapySDRDevice_setSampleRate(handler->device, SOAPY_SDR_TX, 0, rate) != 0)
|
||||
{
|
||||
printf("setSampleRate fail: %s\n", SoapySDRDevice_lastError());
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
double ret = SoapySDRDevice_getSampleRate(handler->device, SOAPY_SDR_TX,0);
|
||||
printf("Sampling rate is set to %f.3 : \n",ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
double rf_soapy_set_rx_gain(void *h, double gain)
|
||||
{
|
||||
|
||||
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
|
||||
if (SoapySDRDevice_setGain(handler->device, SOAPY_SDR_RX, 0, gain) != 0)
|
||||
{
|
||||
printf("setGain fail: %s\n", SoapySDRDevice_lastError());
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
double ret = rf_soapy_get_rx_gain(h);
|
||||
printf("gain has been set to %f.2 \n",ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
double rf_soapy_set_tx_gain(void *h, double gain)
|
||||
{
|
||||
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
|
||||
if (SoapySDRDevice_setGain(handler->device, SOAPY_SDR_TX, 0, gain) != 0)
|
||||
{
|
||||
printf("setGain fail: %s\n", SoapySDRDevice_lastError());
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
double ret = rf_soapy_get_rx_gain(h);
|
||||
printf("gain has been set to %f.2 \n",ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
double rf_soapy_get_rx_gain(void *h)
|
||||
{
|
||||
|
||||
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
|
||||
return SoapySDRDevice_getGain(handler->device,SOAPY_SDR_RX,0);
|
||||
|
||||
}
|
||||
|
||||
double rf_soapy_get_tx_gain(void *h)
|
||||
{
|
||||
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
|
||||
return SoapySDRDevice_getGain(handler->device,SOAPY_SDR_TX,0);
|
||||
}
|
||||
|
||||
double rf_soapy_set_rx_freq(void *h, double freq)
|
||||
{
|
||||
|
||||
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
|
||||
if (SoapySDRDevice_setFrequency(handler->device, SOAPY_SDR_RX, 0, freq, NULL) != 0)
|
||||
{
|
||||
printf("setFrequency fail: %s\n", SoapySDRDevice_lastError());
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
double ret = SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_RX, 0);
|
||||
printf("Frequency has been set to %f : \n",ret);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
double rf_soapy_set_tx_freq(void *h, double freq)
|
||||
{
|
||||
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
|
||||
if (SoapySDRDevice_setFrequency(handler->device, SOAPY_SDR_TX, 0, freq, NULL) != 0)
|
||||
{
|
||||
printf("setFrequency fail: %s\n", SoapySDRDevice_lastError());
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
double ret = SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_RX, 0);
|
||||
printf("Frequency has been set to %f : \n",ret);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void rf_soapy_get_time(void *h, time_t *secs, double *frac_secs) {
|
||||
|
||||
}
|
||||
|
||||
//TODO: add multi-channel support
|
||||
int rf_soapy_recv_with_time_multi(void *h,
|
||||
void **data,
|
||||
uint32_t nsamples,
|
||||
bool blocking,
|
||||
time_t *secs,
|
||||
double *frac_secs)
|
||||
{
|
||||
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
|
||||
//void *buffs[] = {buff}; //array of buffers
|
||||
|
||||
int flags; //flags set by receive operation
|
||||
|
||||
int num_channels = 1; // temp
|
||||
|
||||
int trials = 0;
|
||||
int ret = 0;
|
||||
long long timeNs; //timestamp for receive buffer
|
||||
int n = 0;
|
||||
do{
|
||||
|
||||
size_t rx_samples = nsamples;
|
||||
|
||||
if (rx_samples > nsamples - n)
|
||||
{
|
||||
rx_samples = nsamples - n;
|
||||
}
|
||||
void *buffs_ptr[4];
|
||||
for (int i=0;i<num_channels;i++)
|
||||
{
|
||||
cf_t *data_c = (cf_t*) data[i];
|
||||
buffs_ptr[i] = &data_c[n];
|
||||
} //(void*)(&data)
|
||||
ret = SoapySDRDevice_readStream(handler->device, handler->rxStream,buffs_ptr , rx_samples, &flags, &timeNs, 1000000);
|
||||
|
||||
if(ret < 0)
|
||||
return SRSLTE_ERROR;
|
||||
n += ret;
|
||||
trials++;
|
||||
}while (n < nsamples && trials < 100);
|
||||
|
||||
|
||||
//*secs = timeNs / 1000000000;
|
||||
//*frac_secs = (timeNs % 1000000000)/1000000000;
|
||||
// printf("ret=%d, flags=%d, timeNs=%lld\n", ret, flags, timeNs);
|
||||
return n;
|
||||
|
||||
|
||||
}
|
||||
|
||||
int rf_soapy_recv_with_time(void *h,
|
||||
void *data,
|
||||
uint32_t nsamples,
|
||||
bool blocking,
|
||||
time_t *secs,
|
||||
double *frac_secs)
|
||||
{
|
||||
return rf_soapy_recv_with_time_multi(h, &data, nsamples, blocking, secs, frac_secs);
|
||||
}
|
||||
|
||||
|
||||
int rf_soapy_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)
|
||||
{
|
||||
|
||||
int flags;
|
||||
long long timeNs;
|
||||
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
|
||||
timeNs = secs * 1000000000;
|
||||
timeNs = timeNs + (frac_secs * 1000000000);
|
||||
int ret = SoapySDRDevice_writeStream(handler->device, handler->txStream, &data, nsamples, &flags, timeNs, 100000);
|
||||
|
||||
|
||||
|
||||
if(ret != nsamples)
|
||||
return SRSLTE_ERROR;
|
||||
|
||||
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
/**
|
||||
*
|
||||
* \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_soapy_open( char *args,
|
||||
void **handler);
|
||||
|
||||
SRSLTE_API int rf_soapy_open_multi( char *args,
|
||||
void **handler,
|
||||
uint32_t nof_rx_antennas);
|
||||
|
||||
SRSLTE_API char* rf_soapy_devname(void *h);
|
||||
|
||||
SRSLTE_API int rf_soapy_close(void *h);
|
||||
|
||||
SRSLTE_API void rf_soapy_set_tx_cal(void *h, srslte_rf_cal_t *cal);
|
||||
|
||||
SRSLTE_API void rf_soapy_set_rx_cal(void *h, srslte_rf_cal_t *cal);
|
||||
|
||||
SRSLTE_API int rf_soapy_start_rx_stream(void *h);
|
||||
|
||||
SRSLTE_API int rf_soapy_stop_rx_stream(void *h);
|
||||
|
||||
SRSLTE_API void rf_soapy_flush_buffer(void *h);
|
||||
|
||||
SRSLTE_API bool rf_soapy_has_rssi(void *h);
|
||||
|
||||
SRSLTE_API float rf_soapy_get_rssi(void *h);
|
||||
|
||||
SRSLTE_API bool rf_soapy_rx_wait_lo_locked(void *h);
|
||||
|
||||
SRSLTE_API void rf_soapy_set_master_clock_rate(void *h,
|
||||
double rate);
|
||||
|
||||
SRSLTE_API bool rf_soapy_is_master_clock_dynamic(void *h);
|
||||
|
||||
SRSLTE_API double rf_soapy_set_rx_srate(void *h,
|
||||
double freq);
|
||||
|
||||
SRSLTE_API double rf_soapy_set_rx_gain(void *h,
|
||||
double gain);
|
||||
|
||||
SRSLTE_API double rf_soapy_get_rx_gain(void *h);
|
||||
|
||||
SRSLTE_API double rf_soapy_set_tx_gain(void *h,
|
||||
double gain);
|
||||
|
||||
SRSLTE_API double rf_soapy_get_tx_gain(void *h);
|
||||
|
||||
SRSLTE_API void rf_soapy_suppress_stdout(void *h);
|
||||
|
||||
SRSLTE_API void rf_soapy_register_error_handler(void *h, srslte_rf_error_handler_t error_handler);
|
||||
|
||||
SRSLTE_API double rf_soapy_set_rx_freq(void *h,
|
||||
double freq);
|
||||
|
||||
SRSLTE_API int rf_soapy_recv_with_time(void *h,
|
||||
void *data,
|
||||
uint32_t nsamples,
|
||||
bool blocking,
|
||||
time_t *secs,
|
||||
double *frac_secs);
|
||||
|
||||
SRSLTE_API int rf_soapy_recv_with_time_multi(void *h,
|
||||
void **data,
|
||||
uint32_t nsamples,
|
||||
bool blocking,
|
||||
time_t *secs,
|
||||
double *frac_secs);
|
||||
|
||||
SRSLTE_API double rf_soapy_set_tx_srate(void *h,
|
||||
double freq);
|
||||
|
||||
SRSLTE_API double rf_soapy_set_tx_freq(void *h,
|
||||
double freq);
|
||||
|
||||
SRSLTE_API void rf_soapy_get_time(void *h,
|
||||
time_t *secs,
|
||||
double *frac_secs);
|
||||
|
||||
SRSLTE_API int rf_soapy_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);
|
||||
|
|
@ -84,14 +84,19 @@ int srslte_pss_synch_init_fft(srslte_pss_synch_t *q, uint32_t frame_size, uint32
|
|||
return srslte_pss_synch_init_fft_offset(q, frame_size, fft_size, 0);
|
||||
}
|
||||
|
||||
int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t fft_size, int offset) {
|
||||
return srslte_pss_synch_init_fft_offset_decim(q, frame_size, fft_size, offset, 1);
|
||||
}
|
||||
|
||||
/* Initializes the PSS synchronization object.
|
||||
*
|
||||
* It correlates a signal of frame_size samples with the PSS sequence in the frequency
|
||||
* domain. The PSS sequence is transformed using fft_size samples.
|
||||
*/
|
||||
int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t fft_size, int offset) {
|
||||
int ret = SRSLTE_ERROR_INVALID_INPUTS;
|
||||
int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t fft_size, int offset, int decimate) {
|
||||
|
||||
|
||||
int ret = SRSLTE_ERROR_INVALID_INPUTS;
|
||||
if (q != NULL) {
|
||||
|
||||
ret = SRSLTE_ERROR;
|
||||
|
@ -101,12 +106,26 @@ int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, uint32_t frame_size,
|
|||
bzero(q, sizeof(srslte_pss_synch_t));
|
||||
|
||||
q->N_id_2 = 10;
|
||||
q->fft_size = fft_size;
|
||||
q->frame_size = frame_size;
|
||||
q->ema_alpha = 0.2;
|
||||
|
||||
q->decimate = decimate;
|
||||
fft_size = fft_size/q->decimate;
|
||||
frame_size = frame_size/q->decimate;
|
||||
|
||||
q->fft_size = fft_size;
|
||||
q->frame_size = frame_size;
|
||||
|
||||
buffer_size = fft_size + frame_size + 1;
|
||||
|
||||
if(q->decimate > 1)
|
||||
{
|
||||
int filter_order = 3;
|
||||
srslte_filt_decim_cc_init(&q->filter,q->decimate,filter_order);
|
||||
q->filter.filter_output = srslte_vec_malloc((buffer_size) * sizeof(cf_t));
|
||||
q->filter.downsampled_input = srslte_vec_malloc((buffer_size + filter_order) * sizeof(cf_t));
|
||||
printf("decimation for the PSS search is %d \n",q->decimate);
|
||||
}
|
||||
|
||||
if (srslte_dft_plan(&q->dftp_input, fft_size, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)) {
|
||||
fprintf(stderr, "Error creating DFT plan \n");
|
||||
goto clean_and_exit;
|
||||
|
@ -115,7 +134,7 @@ int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, uint32_t frame_size,
|
|||
srslte_dft_plan_set_dc(&q->dftp_input, true);
|
||||
srslte_dft_plan_set_norm(&q->dftp_input, true);
|
||||
|
||||
q->tmp_input = srslte_vec_malloc(buffer_size * sizeof(cf_t));
|
||||
q->tmp_input = srslte_vec_malloc((buffer_size + frame_size*(q->decimate - 1)) * sizeof(cf_t));
|
||||
if (!q->tmp_input) {
|
||||
fprintf(stderr, "Error allocating memory\n");
|
||||
goto clean_and_exit;
|
||||
|
@ -159,10 +178,20 @@ int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, uint32_t frame_size,
|
|||
|
||||
}
|
||||
#ifdef CONVOLUTION_FFT
|
||||
|
||||
|
||||
for(N_id_2 = 0; N_id_2<3; N_id_2++)
|
||||
q->pss_signal_freq_full[N_id_2] = srslte_vec_malloc(buffer_size * sizeof(cf_t));
|
||||
|
||||
if (srslte_conv_fft_cc_init(&q->conv_fft, frame_size, fft_size)) {
|
||||
fprintf(stderr, "Error initiating convolution FFT\n");
|
||||
goto clean_and_exit;
|
||||
}
|
||||
for(int i =0; i< 3; i++)
|
||||
{
|
||||
srslte_dft_run_c(&q->conv_fft.filter_plan, q->pss_signal_time[i], q->pss_signal_freq_full[i]);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
srslte_pss_synch_reset(q);
|
||||
|
@ -175,8 +204,10 @@ clean_and_exit:
|
|||
srslte_pss_synch_free(q);
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void srslte_pss_synch_free(srslte_pss_synch_t *q) {
|
||||
uint32_t i;
|
||||
|
||||
|
@ -185,6 +216,9 @@ void srslte_pss_synch_free(srslte_pss_synch_t *q) {
|
|||
if (q->pss_signal_time[i]) {
|
||||
free(q->pss_signal_time[i]);
|
||||
}
|
||||
if(q->pss_signal_freq_full[i]){
|
||||
free(q->pss_signal_freq_full[i]);
|
||||
}
|
||||
}
|
||||
#ifdef CONVOLUTION_FFT
|
||||
srslte_conv_fft_cc_free(&q->conv_fft);
|
||||
|
@ -205,6 +239,14 @@ void srslte_pss_synch_free(srslte_pss_synch_t *q) {
|
|||
|
||||
srslte_dft_plan_free(&q->dftp_input);
|
||||
|
||||
if(q->decimate > 1)
|
||||
{
|
||||
srslte_filt_decim_cc_free(&q->filter);
|
||||
free(q->filter.filter_output);
|
||||
free(q->filter.downsampled_input);
|
||||
}
|
||||
|
||||
|
||||
bzero(q, sizeof(srslte_pss_synch_t));
|
||||
}
|
||||
}
|
||||
|
@ -314,8 +356,17 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe
|
|||
*/
|
||||
if (q->frame_size >= q->fft_size) {
|
||||
#ifdef CONVOLUTION_FFT
|
||||
memcpy(q->tmp_input, input, q->frame_size * sizeof(cf_t));
|
||||
conv_output_len = srslte_conv_fft_cc_run(&q->conv_fft, q->tmp_input, q->pss_signal_time[q->N_id_2], q->conv_output);
|
||||
memcpy(q->tmp_input, input, (q->frame_size * q->decimate) * sizeof(cf_t));
|
||||
if(q->decimate > 1)
|
||||
{
|
||||
srslte_filt_decim_cc_execute(&(q->filter), q->tmp_input, q->filter.downsampled_input, q->filter.filter_output , (q->frame_size * q->decimate));
|
||||
conv_output_len = srslte_conv_fft_cc_run_opt(&q->conv_fft, q->filter.filter_output,q->pss_signal_freq_full[q->N_id_2], q->conv_output);
|
||||
}
|
||||
else
|
||||
{
|
||||
conv_output_len = srslte_conv_fft_cc_run_opt(&q->conv_fft, q->tmp_input, q->pss_signal_freq_full[q->N_id_2], q->conv_output);
|
||||
}
|
||||
|
||||
#else
|
||||
conv_output_len = srslte_conv_cc(input, q->pss_signal_time[q->N_id_2], q->conv_output, q->frame_size, q->fft_size);
|
||||
#endif
|
||||
|
@ -388,6 +439,14 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe
|
|||
}
|
||||
#endif
|
||||
|
||||
if(q->decimate >1)
|
||||
{
|
||||
int decimation_correction = (q->filter.num_taps - 2);
|
||||
corr_peak_pos = corr_peak_pos - decimation_correction;
|
||||
corr_peak_pos = corr_peak_pos*q->decimate;
|
||||
}
|
||||
|
||||
|
||||
if (q->frame_size >= q->fft_size) {
|
||||
ret = (int) corr_peak_pos;
|
||||
} else {
|
||||
|
|
|
@ -47,7 +47,13 @@ static bool fft_size_isvalid(uint32_t fft_size) {
|
|||
}
|
||||
}
|
||||
|
||||
int srslte_sync_init(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offset, uint32_t fft_size) {
|
||||
|
||||
|
||||
int srslte_sync_init(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offset, uint32_t fft_size)
|
||||
{
|
||||
return srslte_sync_init_decim(q, frame_size, max_offset, fft_size, 1);
|
||||
}
|
||||
int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offset, uint32_t fft_size, int decimate) {
|
||||
|
||||
int ret = SRSLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
|
@ -56,7 +62,6 @@ int srslte_sync_init(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offset,
|
|||
fft_size_isvalid(fft_size))
|
||||
{
|
||||
ret = SRSLTE_ERROR;
|
||||
|
||||
bzero(q, sizeof(srslte_sync_t));
|
||||
q->detect_cp = true;
|
||||
q->sss_en = true;
|
||||
|
@ -105,8 +110,12 @@ int srslte_sync_init(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offset,
|
|||
}
|
||||
|
||||
srslte_sync_set_cp(q, SRSLTE_CP_NORM);
|
||||
q->decimate = decimate;
|
||||
if(!decimate)
|
||||
decimate = 1;
|
||||
|
||||
if (srslte_pss_synch_init_fft(&q->pss, max_offset, fft_size)) {
|
||||
|
||||
if (srslte_pss_synch_init_fft_offset_decim(&q->pss, max_offset, fft_size,0,decimate)) {
|
||||
fprintf(stderr, "Error initializing PSS object\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
@ -457,8 +466,13 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t
|
|||
} else {
|
||||
srslte_pss_synch_set_N_id_2(&q->pss, q->N_id_2);
|
||||
peak_pos = srslte_pss_synch_find_pss(&q->pss, &input_cfo[find_offset], &q->peak_value);
|
||||
// this compensates for the constant time shift caused by the low pass filter
|
||||
if(q->decimate && peak_pos < 0)
|
||||
{
|
||||
peak_pos = 0 ;//peak_pos + q->decimate*(2);// replace 2 with q->filter_size -2;
|
||||
}
|
||||
if (peak_pos < 0) {
|
||||
fprintf(stderr, "Error calling finding PSS sequence\n");
|
||||
fprintf(stderr, "Error calling finding PSS sequence at : %d \n", peak_pos);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,6 +128,18 @@ int srslte_ue_sync_init_multi(srslte_ue_sync_t *q,
|
|||
int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t,srslte_timestamp_t*),
|
||||
uint32_t nof_rx_antennas,
|
||||
void *stream_handler)
|
||||
|
||||
{
|
||||
|
||||
return srslte_ue_sync_init_multi_decim(q, cell,recv_callback ,nof_rx_antennas,stream_handler,1);
|
||||
}
|
||||
|
||||
int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q,
|
||||
srslte_cell_t cell,
|
||||
int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t,srslte_timestamp_t*),
|
||||
uint32_t nof_rx_antennas,
|
||||
void *stream_handler,
|
||||
int decimate)
|
||||
{
|
||||
int ret = SRSLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
|
@ -138,9 +150,9 @@ int srslte_ue_sync_init_multi(srslte_ue_sync_t *q,
|
|||
recv_callback != NULL)
|
||||
{
|
||||
ret = SRSLTE_ERROR;
|
||||
|
||||
//int decimate = q->decimate;
|
||||
bzero(q, sizeof(srslte_ue_sync_t));
|
||||
|
||||
q->decimate = decimate;
|
||||
q->stream = stream_handler;
|
||||
q->recv_callback = recv_callback;
|
||||
q->nof_rx_antennas = nof_rx_antennas;
|
||||
|
@ -170,7 +182,13 @@ int srslte_ue_sync_init_multi(srslte_ue_sync_t *q,
|
|||
|
||||
q->frame_len = q->nof_recv_sf*q->sf_len;
|
||||
|
||||
if(srslte_sync_init(&q->sfind, q->frame_len, q->frame_len, q->fft_size)) {
|
||||
if(q->fft_size < 700 && q->decimate)
|
||||
{
|
||||
q->decimate = 1;
|
||||
}
|
||||
|
||||
|
||||
if(srslte_sync_init_decim(&q->sfind, q->frame_len, q->frame_len, q->fft_size,q->decimate)) {
|
||||
fprintf(stderr, "Error initiating sync find\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
|
|
@ -40,6 +40,8 @@ int srslte_conv_fft_cc_init(srslte_conv_fft_cc_t *q, uint32_t input_len, uint32_
|
|||
q->input_fft = srslte_vec_malloc(sizeof(cf_t)*q->output_len);
|
||||
q->filter_fft = srslte_vec_malloc(sizeof(cf_t)*q->output_len);
|
||||
q->output_fft = srslte_vec_malloc(sizeof(cf_t)*q->output_len);
|
||||
|
||||
|
||||
if (!q->input_fft || !q->filter_fft || !q->output_fft) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
@ -58,6 +60,7 @@ int srslte_conv_fft_cc_init(srslte_conv_fft_cc_t *q, uint32_t input_len, uint32_
|
|||
srslte_dft_plan_set_norm(&q->input_plan, true);
|
||||
srslte_dft_plan_set_norm(&q->filter_plan, true);
|
||||
srslte_dft_plan_set_norm(&q->output_plan, false);
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -71,6 +74,7 @@ void srslte_conv_fft_cc_free(srslte_conv_fft_cc_t *q) {
|
|||
if (q->output_fft) {
|
||||
free(q->output_fft);
|
||||
}
|
||||
|
||||
srslte_dft_plan_free(&q->input_plan);
|
||||
srslte_dft_plan_free(&q->filter_plan);
|
||||
srslte_dft_plan_free(&q->output_plan);
|
||||
|
@ -79,16 +83,21 @@ void srslte_conv_fft_cc_free(srslte_conv_fft_cc_t *q) {
|
|||
|
||||
}
|
||||
|
||||
uint32_t srslte_conv_fft_cc_run(srslte_conv_fft_cc_t *q, cf_t *input, cf_t *filter, cf_t *output) {
|
||||
|
||||
uint32_t srslte_conv_fft_cc_run_opt(srslte_conv_fft_cc_t *q, cf_t *input, cf_t *filter_freq, cf_t *output)
|
||||
{
|
||||
srslte_dft_run_c(&q->input_plan, input, q->input_fft);
|
||||
srslte_dft_run_c(&q->filter_plan, filter, q->filter_fft);
|
||||
|
||||
srslte_vec_prod_ccc(q->input_fft,q->filter_fft,q->output_fft,q->output_len);
|
||||
|
||||
srslte_vec_prod_ccc(q->input_fft, filter_freq, q->output_fft, q->output_len);
|
||||
srslte_dft_run_c(&q->output_plan, q->output_fft, output);
|
||||
|
||||
return q->output_len-1;
|
||||
return (q->output_len-1); // divide output length by dec factor
|
||||
|
||||
}
|
||||
|
||||
uint32_t srslte_conv_fft_cc_run(srslte_conv_fft_cc_t *q, cf_t *input, cf_t *filter, cf_t *output) {
|
||||
|
||||
srslte_dft_run_c(&q->filter_plan, filter, q->filter_fft);
|
||||
|
||||
return srslte_conv_fft_cc_run_opt(q, input, q->filter_fft, output);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
/**
|
||||
*
|
||||
* \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/utils/filter.h"
|
||||
#define SRSLTE_NUM_FILTERS 8
|
||||
#define SRSLTE_MAX_FILTER_SIZE 11
|
||||
|
||||
float srslte_filt_decim2[SRSLTE_NUM_FILTERS][SRSLTE_MAX_FILTER_SIZE] =
|
||||
{
|
||||
{0.0167364016736, 0.48326359832636, 0.48326359832636, 0.01673640167364,0,0,0,0,0,0,0},
|
||||
{0.000000000000000, 0.203712369200737, 0.592575261598526, 0.203712369200737, 0.000000000000000,0,0,0,0,0,0},
|
||||
{-0.007776312719103, 0.064454645578710, 0.443321667140393, 0.443321667140393, 0.064454645578710, -0.007776312719103,0,0,0,0,0},
|
||||
{-0.008721828105097, 0.000000000000000, 0.251842786534672, 0.513758083140849, 0.251842786534672, 0.000000000000000, -0.008721828105097,0,0,0,0},
|
||||
{-0.005164298061200, -0.022882524920256, 0.096755650536968, 0.431291172444487, 0.431291172444487, 0.096755650536968, -0.022882524920256, -0.005164298061200,0,0,0},
|
||||
{-0.000000000000000, -0.022663985459553, 0.000000000000000, 0.273977082565524, 0.497373805788057, 0.273977082565524, 0.000000000000000, -0.022663985459553, -0.000000000000000,0,0},
|
||||
{ 0.003971846362414, -0.011976365116169, -0.041119498116286, 0.114687063714704, 0.434436953155337, 0.434436953155337, 0.114687063714704, -0.041119498116286, -0.011976365116169, 0.003971846362414,0},
|
||||
{0.005060317124845, -0.000000000000000, -0.041942879431345, 0.000000000000000, 0.288484826302638, 0.496795472007725, 0.288484826302638, 0.000000000000000, -0.041942879431345, -0.000000000000000, 0.005060317124845}
|
||||
};
|
||||
|
||||
float srslte_filt_decim3[SRSLTE_NUM_FILTERS][SRSLTE_MAX_FILTER_SIZE] =
|
||||
{
|
||||
{0.032388663967611, 0.467611336032389, 0.467611336032389, 0.032388663967611,0,0,0,0,0,0,0},
|
||||
{0.016883339167609, 0.227925078762723, 0.510383164139335, 0.227925078762723, 0.016883339167609,0,0,0,0,0,0},
|
||||
{0.006703633822959, 0.111127306155495, 0.382169060021546, 0.382169060021546, 0.111127306155495, 0.006703633822959,0,0,0,0,0},
|
||||
{0.000000000000000, 0.050666848023938, 0.251699825667307, 0.395266652617510, 0.251699825667307, 0.050666848023938, 0.000000000000000,0,0,0,0},
|
||||
{-0.004018779518049, 0.017806838679915, 0.150587600493065, 0.335624340345069, 0.335624340345069, 0.150587600493065, 0.017806838679915, -0.004018779518049,0,0,0},
|
||||
{-0.005814396641997, 0.000000000000000, 0.078494354666956, 0.251550893097387, 0.351538297755307, 0.251550893097387, 0.078494354666956, 0.000000000000000, -0.005814396641997,0,0},
|
||||
{ -0.005798226803038, -0.008741738083915, 0.030013771222565, 0.167423798937736, 0.317102394726653, 0.317102394726653, 0.167423798937736, 0.030013771222565, -0.008741738083915, -0.005798226803038,0},
|
||||
{-0.004444793932295, -0.011657318166992, 0.000000000000000, 0.094750202492597, 0.253394317761931, 0.335915183689516, 0.253394317761931, 0.094750202492597, 0.000000000000000, -0.011657318166992, -0.004444793932295},
|
||||
|
||||
};
|
||||
|
||||
|
||||
float srslte_filt_decim4[SRSLTE_NUM_FILTERS][SRSLTE_MAX_FILTER_SIZE] =
|
||||
{
|
||||
{ 0.038579006748772, 0.461420993251228, 0.461420993251228, 0.038579006748772,0,0,0,0,0,0,0},
|
||||
{0.024553834015017, 0.234389464237986, 0.482113403493995, 0.234389464237986, 0.024553834015017,0,0,0,0,0,0},
|
||||
{0.015196373491712, 0.125956465856097, 0.358847160652191, 0.358847160652191, 0.125956465856097, 0.015196373491712,0,0,0,0,0},
|
||||
{0.008485920061584, 0.069755250084282, 0.245030941778248, 0.353455776151771, 0.245030941778248, 0.069755250084282, 0.008485920061584,0,0,0,0},
|
||||
{0.003560172702629, 0.038083722795699, 0.161031852333115, 0.297324252168557, 0.297324252168557, 0.161031852333115, 0.038083722795699, 0.003560172702629,0,0,0},
|
||||
{0.000000000000000, 0.019096925170212, 0.101875313412667, 0.230856124287772, 0.296343274258697, 0.230856124287772, 0.101875313412667, 0.019096925170212, 0.000000000000000,0,0},
|
||||
{-0.002426023829880, 0.007315224335493, 0.060635381185575, 0.169119131895270, 0.265356286413542, 0.265356286413542, 0.169119131895270, 0.060635381185575 , 0.007315224335493, -0.002426023829880,0},
|
||||
{-0.003871323167475, 0.000000000000000, 0.032087799410030, 0.116708621643743, 0.220701186106900, 0.268747432013603, 0.220701186106900, 0.116708621643743 , 0.032087799410030, 0.000000000000000,-0.003871323167475}
|
||||
};
|
||||
|
||||
|
||||
void srslte_filt_decim_cc_init(srslte_filt_cc_t *q, int factor, int order)
|
||||
{
|
||||
q->factor = factor;
|
||||
q->num_taps = order + 1;
|
||||
q->is_decimator = true;
|
||||
q->taps = malloc(q->num_taps * sizeof(float));
|
||||
|
||||
switch(q->factor)
|
||||
{
|
||||
case 2:
|
||||
for(int i = 0; i <(q->num_taps); i++)
|
||||
q->taps[i] = srslte_filt_decim2[(q->num_taps) - 4][i];
|
||||
break;
|
||||
case 3:
|
||||
for(int i = 0; i <(q->num_taps); i++)
|
||||
q->taps[i] = srslte_filt_decim3[(q->num_taps) - 4][i];
|
||||
case 4:
|
||||
for(int i = 0; i <(q->num_taps); i++)
|
||||
q->taps[i] = srslte_filt_decim4[(q->num_taps) - 4][i];
|
||||
|
||||
break;
|
||||
default:
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
for(int x = 0; x<(q->num_taps);x++)
|
||||
{
|
||||
printf("tap : %f.9\n" ,q->taps[x]);
|
||||
}
|
||||
}
|
||||
|
||||
void srslte_filt_decim_cc_free(srslte_filt_cc_t *q)
|
||||
{
|
||||
free(q->taps);
|
||||
}
|
||||
|
||||
void srslte_filt_decim_cc_execute(srslte_filt_cc_t *q, cf_t *input, cf_t *downsampled_input, cf_t *output, int size)
|
||||
{
|
||||
// we assume that "downsampled_input" made size (input/2 + order) so as to have prepended zeros //
|
||||
srslte_downsample_cc(input, downsampled_input + (q->num_taps - 1), q->factor, size);
|
||||
|
||||
for(int i = 0;i < size/q->factor;i++)
|
||||
{
|
||||
output[i] = srslte_vec_dot_prod_cfc(&(downsampled_input[i]), q->taps, q->num_taps);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* Performs integer linear downsamling by a factor of M */
|
||||
void srslte_downsample_cc(cf_t *input, cf_t *output, int M, int size) {
|
||||
int i;
|
||||
for (i=0;i<size/M;i++) {
|
||||
output[i] = input[i*M];
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue