Commit 90731761 authored by bruno mongazon's avatar bruno mongazon

This commit provides the IQ record-playback feature know under issue #272

parent d915c208
Branches unavailable
2024.w06 2024.w05 2024.w04 2024.w03 2024.w02 2024.w01 2023.w51 2023.w50 2023.w49 2023.w48 2023.w47 2023.w45 2023.w43 2023.w42 2023.w41 2023.w40 2023.w39 2023.w38 2023.w37 2023.w36 2023.w34 2023.w33 2023.w32 2023.w31 2023.w30 2023.w29 2023.w28 2023.w27 2023.w26 2023.w25 2023.w24 2023.w23 2023.w22 2023.w21 2023.w20 2023.w19 2023.w18 2023.w18b 2023.w16 2023.w15 2023.w14 2023.w13 2023.w12 2023.w11 2023.w11b 2023.w10 2023.w10b 2023.w09 2023.w08 2023.w08b 2023.w07 2023.w06 2023.w05 2023.w03 2023.w02 2022.42 2022.41 2022.w51 2022.w50 2022.w49 2022.w48 2022.w47 2022.w46 2022.w45 2022.w43 2022.w42 2022.w42b 2022.w41 2022.w40 2022.w39 2022.w38 2022.w37 2022.w37b 2022.w36 2022.w35 2022.w33 2022.w32 2022.w31 2022.w31b 2022.w30 2022.w29 2022.w26 2022.w25 2022.w24 2022.w24b 2022.w23 2022.w22 2022.w21 2022.w20 2022.w19 2022.w18 2022.w17 2022.w15 2022.w15b 2022.w14a 2022.w13 2022.w13b 2022.w13a 2022.w12 2022.w10 2022.w09 2022.w09b 2022.w08 2022.w08b 2022.w07 2022.w07b 2022.w06 2022.w06a 2022.w05 2022.w05b 2022.w03_hotfix 2022.w03_b 2022.w02 2022.w01 2021.wk46 2021.wk14_a 2021.wk13_d 2021.wk13_c 2021.w51_c 2021.w51_a 2021.w50_a 2021.w49_b 2021.w49_a 2021.w48 2021.w47 2021.w46 2021.w46-powder 2021.w45 2021.w45_b 2021.w44 2021.w43 2021.w42 2021.w37 2021.w36 2021.w35 2021.w34 2021.w33 2021.w32 2021.w31 2021.w30 2021.w29 2021.w28 2021.w27 2021.w26 2021.w25 2021.w24 2021.w23 2021.w22 2021.w20 2021.w19 2021.w18_b 2021.w18_a 2021.w17_b 2021.w16 2021.w15 2021.w14 2021.w13_a 2021.w12 2021.w11 2021.w10 2021.w09 2021.w08 2021.w06 2021.w05 2021.w04 2021.w02 2020.w51_2 2020.w51 2020.w50 2020.w49 2020.w48_2 2020.w48 2020.w47 2020.w46_2 2020.w46 2020.w45_2 2020.w45 2020.w44 2020.w42_2 2020.w42 2020.w41 2020.w39 2020.w38 2020.w37 2020.w36 2020.w34 2020.w33 2020.w31 2020.w30 2020.w29 2020.w28 2020.w26 2020.w25 2020.w24 2020.w23 2020.w22 2020.w19 2020.w17 2020.w16 2020.w15 2020.w11 2020.w09 2020.w06 2020.w05 2020.w04 2020.w03 2019.w51 2019.w44 2019.w41 2019.w36 2019.w30 2019.w28 2019.w27 2019.w25 2019.w23 2019.w21 2019.w17 2019.w15 2019.w13 2019.w11 2019.w10 2019.w09 2019.w08 2019.w07 2019.w06 2019.w04 2019.w03 2018.w51 2018.w48 2018.w47 2018.w46 2018.w44 2018.w41 2018.w40 2018.w39 2018.w36 2018.w33 2018.w31 2018.w29 2018.w25 2018.w19 2018.w15 2018.w12 2018.w11 2018.w10 2018.w09 2018.w08 2018.w07 2018.w06 2018.w05 2018.w04 2018.w03 2018.w02 2017.w48 v2.1.0 v2.0.0 v1.2.2 v1.2.1 v1.2.0 v1.1.1 v1.1.0 v1.0.3 v1.0.2 v1.0.1 v1.0.0 setparam osa-etsi-ws-ue osa-etsi-ws-try2 osa-etsi-ws-try1 osa-etsi-ws-gNB oai_nr_sync nr-ip-over-lte nr-ip-over-lte-v.1.5 nr-ip-over-lte-v.1.4 nr-ip-over-lte-v.1.3 nr-ip-over-lte-v.1.2 nr-ip-over-lte-v.1.1 nr-ip-over-lte-v.1.0 flexran-eol develop-nr-pdcch develop-nr-2020w03 develop-nr-2020w02 develop-nr-2019w51 develop-nr-2019w50 develop-nr-2019w48 develop-nr-2019w47 develop-nr-2019w45 develop-nr-2019w43 develop-nr-2019w42 develop-nr-2019w40 develop-nr-2019w28 develop-nr-2019w23 benetel_phase_rotation benetel_gnb_rel_2.0 benetel_gnb_rel_1.0 benetel_enb_rel_2.0 benetel_enb_rel_1.0
No related merge requests found
...@@ -241,6 +241,7 @@ add_boolean_option(UE_AUTOTEST_TRACE False "Activate UE autotest specific logs ...@@ -241,6 +241,7 @@ add_boolean_option(UE_AUTOTEST_TRACE False "Activate UE autotest specific logs
add_boolean_option(UE_DEBUG_TRACE False "Activate UE debug trace") add_boolean_option(UE_DEBUG_TRACE False "Activate UE debug trace")
add_boolean_option(UE_TIMING_TRACE False "Activate UE timing trace") add_boolean_option(UE_TIMING_TRACE False "Activate UE timing trace")
add_boolean_option(DISABLE_LOG_X False "Deactivate all LOG_* macros") add_boolean_option(DISABLE_LOG_X False "Deactivate all LOG_* macros")
add_boolean_option(USRP_REC_PLAY False "Enable USRP record playback mode")
add_boolean_option(DEBUG_CONSOLE False "makes debugging easier, disables stdout/stderr buffering") add_boolean_option(DEBUG_CONSOLE False "makes debugging easier, disables stdout/stderr buffering")
......
...@@ -66,6 +66,7 @@ UE_AUTOTEST_TRACE="False" ...@@ -66,6 +66,7 @@ UE_AUTOTEST_TRACE="False"
UE_DEBUG_TRACE="False" UE_DEBUG_TRACE="False"
UE_TIMING_TRACE="False" UE_TIMING_TRACE="False"
DISABLE_LOG_X="False" DISABLE_LOG_X="False"
USRP_REC_PLAY="False"
BUILD_ECLIPSE=0 BUILD_ECLIPSE=0
trap handle_ctrl_c INT trap handle_ctrl_c INT
...@@ -158,6 +159,8 @@ Options ...@@ -158,6 +159,8 @@ Options
Disable all LOG_* macros Disable all LOG_* macros
--build-eclipse --build-eclipse
Build eclipse project files. Paths are auto corrected by fixprj.sh Build eclipse project files. Paths are auto corrected by fixprj.sh
--usrp-recplay
Build for I/Q record-playback modes
Usage (first build): Usage (first build):
oaisim (eNB + UE): ./build_oai -I --oaisim -x --install-system-files oaisim (eNB + UE): ./build_oai -I --oaisim -x --install-system-files
Eurecom EXMIMO + COTS UE : ./build_oai -I --eNB -x --install-system-files Eurecom EXMIMO + COTS UE : ./build_oai -I --eNB -x --install-system-files
...@@ -350,6 +353,10 @@ function main() { ...@@ -350,6 +353,10 @@ function main() {
BUILD_TELNETSRV=1 BUILD_TELNETSRV=1
echo_info "Build embedded telnet server" echo_info "Build embedded telnet server"
shift ;; shift ;;
--usrp-recplay)
USRP_REC_PLAY="True"
echo_info "Enabling USRP record playback mode"
shift 1;;
-h | --help) -h | --help)
print_help print_help
exit 1;; exit 1;;
...@@ -540,6 +547,7 @@ function main() { ...@@ -540,6 +547,7 @@ function main() {
echo "set (UE_DEBUG_TRACE $UE_DEBUG_TRACE)" >> $cmake_file echo "set (UE_DEBUG_TRACE $UE_DEBUG_TRACE)" >> $cmake_file
echo "set (UE_TIMING_TRACE $UE_TIMING_TRACE)" >> $cmake_file echo "set (UE_TIMING_TRACE $UE_TIMING_TRACE)" >> $cmake_file
echo "set (DISABLE_LOG_X $DISABLE_LOG_X)" >> $cmake_file echo "set (DISABLE_LOG_X $DISABLE_LOG_X)" >> $cmake_file
echo "set (USRP_REC_PLAY $USRP_REC_PLAY)" >> $cmake_file
if [ "$UE" = 1 -a "$NOS1" = "0" ] ; then if [ "$UE" = 1 -a "$NOS1" = "0" ] ; then
echo_info "Compiling UE S1 build : enabling Linux and NETLINK" echo_info "Compiling UE S1 build : enabling Linux and NETLINK"
echo "set (LINUX True )" >> $cmake_file echo "set (LINUX True )" >> $cmake_file
......
...@@ -1871,6 +1871,23 @@ uint32_t rx_pucch(PHY_VARS_eNB *eNB, ...@@ -1871,6 +1871,23 @@ uint32_t rx_pucch(PHY_VARS_eNB *eNB,
eNB->pucch1ab_stats_cnt[j][i]=0; eNB->pucch1ab_stats_cnt[j][i]=0;
} }
} }
#if defined(USRP_REC_PLAY)
// It's probably bad to do this statically only once.
// Looks like the above is incomplete.
// Such reset needs to be done once a UE PHY structure is being used/re-used
// Don't know if this is ever possible in current architecture
for (i=0;i<10240;i++) {
for (j=0;j<NUMBER_OF_UE_MAX;j++) {
eNB->pucch1_stats[j][i]=0;
eNB->pucch1_stats_thres[j][i]=0;
}
}
for (i=0;i<20480;i++) {
for (j=0;j<NUMBER_OF_UE_MAX;j++) {
eNB->pucch1ab_stats[j][i]=0;
}
}
#endif
first_call=0; first_call=0;
} }
...@@ -2289,8 +2306,12 @@ uint32_t rx_pucch(PHY_VARS_eNB *eNB, ...@@ -2289,8 +2306,12 @@ uint32_t rx_pucch(PHY_VARS_eNB *eNB,
stat_im=0; stat_im=0;
// Do detection now // Do detection now
#if defined(USRP_REC_PLAY)
// It looks like the value is a bit messy when RF is replayed.
if (sigma2_dB<=(dB_fixed(stat_max)-pucch1_thres+2)) {//
#else
if (sigma2_dB<(dB_fixed(stat_max)-pucch1_thres)) {// if (sigma2_dB<(dB_fixed(stat_max)-pucch1_thres)) {//
#endif
chL = (nsymb>>1)-4; chL = (nsymb>>1)-4;
chest_mag=0; chest_mag=0;
cfo = (frame_parms->Ncp==0) ? &cfo_pucch_np[14*phase_max] : &cfo_pucch_ep[12*phase_max]; cfo = (frame_parms->Ncp==0) ? &cfo_pucch_np[14*phase_max] : &cfo_pucch_ep[12*phase_max];
...@@ -2431,7 +2452,11 @@ uint32_t rx_pucch(PHY_VARS_eNB *eNB, ...@@ -2431,7 +2452,11 @@ uint32_t rx_pucch(PHY_VARS_eNB *eNB,
if (fmt==pucch_format1b) if (fmt==pucch_format1b)
*(1+payload) = (stat_im<0) ? 1 : 2; *(1+payload) = (stat_im<0) ? 1 : 2;
} else { // insufficient energy on PUCCH so NAK } else { // insufficient energy on PUCCH so NAK
#if defined(USRP_REC_PLAY)
LOG_I(PHY,"PUCCH 1a/b: NAK subframe %d : sigma2_dB %d, stat_max %d, pucch1_thres %d\n",subframe,sigma2_dB,dB_fixed(stat_max),pucch1_thres);
#else
LOG_I(PHY,"PUCCH 1a/b: subframe %d : sigma2_dB %d, stat_max %d, pucch1_thres %d\n",subframe,sigma2_dB,dB_fixed(stat_max),pucch1_thres); LOG_I(PHY,"PUCCH 1a/b: subframe %d : sigma2_dB %d, stat_max %d, pucch1_thres %d\n",subframe,sigma2_dB,dB_fixed(stat_max),pucch1_thres);
#endif
*payload = 4; // DTX *payload = 4; // DTX
((int16_t*)&eNB->pucch1ab_stats[UE_id][(subframe<<10) + (eNB->pucch1ab_stats_cnt[UE_id][subframe])])[0] = (int16_t)(stat_re); ((int16_t*)&eNB->pucch1ab_stats[UE_id][(subframe<<10) + (eNB->pucch1ab_stats_cnt[UE_id][subframe])])[0] = (int16_t)(stat_re);
((int16_t*)&eNB->pucch1ab_stats[UE_id][(subframe<<10) + (eNB->pucch1ab_stats_cnt[UE_id][subframe])])[1] = (int16_t)(stat_im); ((int16_t*)&eNB->pucch1ab_stats[UE_id][(subframe<<10) + (eNB->pucch1ab_stats_cnt[UE_id][subframe])])[1] = (int16_t)(stat_im);
......
...@@ -128,7 +128,11 @@ ...@@ -128,7 +128,11 @@
/*!\brief Maximum number od control elemenets */ /*!\brief Maximum number od control elemenets */
#define MAX_NUM_CE 5 #define MAX_NUM_CE 5
/*!\brief Maximum number of random access process */ /*!\brief Maximum number of random access process */
#if defined(USRP_REC_PLAY)
#define NB_RA_PROC_MAX 1
#else
#define NB_RA_PROC_MAX 4 #define NB_RA_PROC_MAX 4
#endif
/*!\brief size of buffer status report table */ /*!\brief size of buffer status report table */
#define BSR_TABLE_SIZE 64 #define BSR_TABLE_SIZE 64
/*!\brief The power headroom reporting range is from -23 ...+40 dB and beyond, with step 1 */ /*!\brief The power headroom reporting range is from -23 ...+40 dB and beyond, with step 1 */
......
...@@ -1244,7 +1244,25 @@ void initiate_ra_proc(module_id_t module_idP, ...@@ -1244,7 +1244,25 @@ void initiate_ra_proc(module_id_t module_idP,
RA_template[i].Msg2_subframe = (subframeP+4)%10; RA_template[i].Msg2_subframe = (subframeP+4)%10;
/* TODO: find better procedure to allocate RNTI */ /* TODO: find better procedure to allocate RNTI */
do { do {
#if defined(USRP_REC_PLAY) // deterministic rnti in usrp record/playback mode
static int drnti[NUMBER_OF_UE_MAX] = { 0xbda7, 0x71da, 0x9c40, 0xc350, 0x2710, 0x4e20, 0x7530, 0x1388, 0x3a98, 0x61a8, 0x88b8, 0xafc8, 0xd6d8, 0x1b58, 0x4268, 0x6978 };
int j = 0;
int nb_ue = 0;
for (j = 0; j < NUMBER_OF_UE_MAX; j++) {
if (UE_RNTI(module_idP, j) > 0) {
nb_ue++;
} else {
break;
}
}
if (nb_ue >= NUMBER_OF_UE_MAX) {
printf("No more free RNTI available, increase NUMBER_OF_UE_MAX\n");
abort();
}
RA_template[i].rnti = drnti[nb_ue];
#else
RA_template[i].rnti = taus(); RA_template[i].rnti = taus();
#endif
loop++; loop++;
} while (loop != 100 && } while (loop != 100 &&
/* TODO: this is not correct, the rnti may be in use without /* TODO: this is not correct, the rnti may be in use without
......
...@@ -1717,6 +1717,9 @@ int add_new_ue(module_id_t mod_idP, int cc_idP, rnti_t rntiP,int harq_pidP ...@@ -1717,6 +1717,9 @@ int add_new_ue(module_id_t mod_idP, int cc_idP, rnti_t rntiP,int harq_pidP
UE_list->ordered_ULCCids[0][UE_id] = cc_idP; UE_list->ordered_ULCCids[0][UE_id] = cc_idP;
UE_list->num_UEs++; UE_list->num_UEs++;
UE_list->active[UE_id] = TRUE; UE_list->active[UE_id] = TRUE;
#if defined(USRP_REC_PLAY) // not specific to record/playback ?
UE_list->UE_template[cc_idP][UE_id].pre_assigned_mcs_ul = 0;
#endif
#ifdef Rel14 #ifdef Rel14
UE_list->UE_template[cc_idP][UE_id].rach_resource_type = rach_resource_type ; UE_list->UE_template[cc_idP][UE_id].rach_resource_type = rach_resource_type ;
......
...@@ -220,7 +220,7 @@ pdcp_validate_security( ...@@ -220,7 +220,7 @@ pdcp_validate_security(
stream_decrypt(pdcp_pP->cipheringAlgorithm, stream_decrypt(pdcp_pP->cipheringAlgorithm,
&decrypt_params, &decrypt_params,
&buffer_decrypted); &buffer_decrypted);
#if !defined(USRP_REC_PLAY)
if (srb_flagP) { if (srb_flagP) {
/* Now check the integrity of the complete PDU */ /* Now check the integrity of the complete PDU */
decrypt_params.message = pdcp_pdu_buffer; decrypt_params.message = pdcp_pdu_buffer;
...@@ -241,7 +241,7 @@ pdcp_validate_security( ...@@ -241,7 +241,7 @@ pdcp_validate_security(
return -1; return -1;
} }
} }
#endif
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_VALIDATE_SECURITY, VCD_FUNCTION_OUT); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_VALIDATE_SECURITY, VCD_FUNCTION_OUT);
return 0; return 0;
......
...@@ -242,7 +242,11 @@ typedef enum HO_STATE_e { ...@@ -242,7 +242,11 @@ typedef enum HO_STATE_e {
// #define NUM_MAX_CBA_GROUP 4 // in the platform_constants // #define NUM_MAX_CBA_GROUP 4 // in the platform_constants
/* TS 36.331: RRC-TransactionIdentifier ::= INTEGER (0..3) */ /* TS 36.331: RRC-TransactionIdentifier ::= INTEGER (0..3) */
#if defined(USRP_REC_PLAY)
#define RRC_TRANSACTION_IDENTIFIER_NUMBER 1
#else
#define RRC_TRANSACTION_IDENTIFIER_NUMBER 3 #define RRC_TRANSACTION_IDENTIFIER_NUMBER 3
#endif
typedef struct { typedef struct {
unsigned short transport_block_size; /*!< \brief Minimum PDU size in bytes provided by RLC to MAC layer interface */ unsigned short transport_block_size; /*!< \brief Minimum PDU size in bytes provided by RLC to MAC layer interface */
......
...@@ -390,8 +390,10 @@ rrc_pdcp_config_security( ...@@ -390,8 +390,10 @@ rrc_pdcp_config_security(
ue_context_pP->ue_context.kenb, ue_context_pP->ue_context.kenb,
&kRRCint); &kRRCint);
#if !defined(USRP_REC_PLAY)
#define DEBUG_SECURITY 1 #define DEBUG_SECURITY 1
#endif
#if defined (DEBUG_SECURITY) #if defined (DEBUG_SECURITY)
#undef msg #undef msg
#define msg printf #define msg printf
......
...@@ -207,6 +207,15 @@ typedef struct { ...@@ -207,6 +207,15 @@ typedef struct {
int iq_rxrescale; int iq_rxrescale;
//! Configuration file for LMS7002M //! Configuration file for LMS7002M
char *configFilename; char *configFilename;
#if defined(USRP_REC_PLAY)
unsigned short sf_mode; // 1=record, 2=replay
char sf_filename[1024]; // subframes file path
unsigned int sf_max; // max number of recorded subframes
unsigned int sf_loops; // number of loops in replay mode
unsigned int sf_read_delay; // read delay in replay mode
unsigned int sf_write_delay; // write delay in replay mode
unsigned int eth_mtu; // ethernet MTU
#endif
} openair0_config_t; } openair0_config_t;
/*! \brief RF mapping */ /*! \brief RF mapping */
......
...@@ -270,11 +270,53 @@ static int sync_to_gps(openair0_device *device) ...@@ -270,11 +270,53 @@ static int sync_to_gps(openair0_device *device)
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
#if defined(USRP_REC_PLAY)
#include "usrp_lib.h"
static FILE *pFile = NULL;
int mmapfd = 0;
struct stat sb;
iqrec_t *ms_sample = NULL; // memory for all subframes
unsigned int nb_samples = 0;
unsigned int cur_samples = 0;
int64_t wrap_count = 0;
int64_t wrap_ts = 0;
unsigned int u_sf_mode = 0; // 1=record, 2=replay
unsigned int u_sf_record = 0; // record mode
unsigned int u_sf_replay = 0; // replay mode
char u_sf_filename[1024]; // subframes file path
unsigned int u_sf_max = DEF_NB_SF; // max number of recorded subframes
unsigned int u_sf_loops = DEF_SF_NB_LOOP; // number of loops in replay mode
unsigned int u_sf_read_delay = DEF_SF_DELAY_READ; // read delay in replay mode
unsigned int u_sf_write_delay = DEF_SF_DELAY_WRITE; // write delay in replay mode
char *tmp_filename[1]; // use an array of pointer (libconfig does not seems to work with char array yet)
char config_opt_sf_file[] = CONFIG_OPT_SF_FILE;
char config_def_sf_file[] = DEF_SF_FILE;
char config_hlp_sf_file[] = CONFIG_HLP_SF_FILE;
char config_opt_sf_rec[] = CONFIG_OPT_SF_REC;
char config_hlp_sf_rec[] = CONFIG_HLP_SF_REC;
char config_opt_sf_rep[] = CONFIG_OPT_SF_REP;
char config_hlp_sf_rep[] = CONFIG_HLP_SF_REP;
char config_opt_sf_max[] = CONFIG_OPT_SF_MAX;
char config_hlp_sf_max[] = CONFIG_HLP_SF_MAX;
char config_opt_sf_loops[] = CONFIG_OPT_SF_LOOPS;
char config_hlp_sf_loops[] = CONFIG_HLP_SF_LOOPS;
char config_opt_sf_rdelay[] = CONFIG_OPT_SF_RDELAY;
char config_hlp_sf_rdelay[] = CONFIG_HLP_SF_RDELAY;
char config_opt_sf_wdelay[] = CONFIG_OPT_SF_WDELAY;
char config_hlp_sf_wdelay[] = CONFIG_HLP_SF_WDELAY;
#endif
/*! \brief Called to start the USRP transceiver. Return 0 if OK, < 0 if error /*! \brief Called to start the USRP transceiver. Return 0 if OK, < 0 if error
@param device pointer to the device structure specific to the RF hardware target @param device pointer to the device structure specific to the RF hardware target
*/ */
static int trx_usrp_start(openair0_device *device) { static int trx_usrp_start(openair0_device *device) {
#if defined(USRP_REC_PLAY)
if (u_sf_mode != 2) { // not replay mode
#endif
usrp_state_t *s = (usrp_state_t*)device->priv; usrp_state_t *s = (usrp_state_t*)device->priv;
...@@ -313,12 +355,21 @@ static int trx_usrp_start(openair0_device *device) { ...@@ -313,12 +355,21 @@ static int trx_usrp_start(openair0_device *device) {
s->rx_count = 0; s->rx_count = 0;
s->tx_count = 0; s->tx_count = 0;
s->rx_timestamp = 0; s->rx_timestamp = 0;
#if defined(USRP_REC_PLAY)
}
#endif
return 0; return 0;
} }
/*! \brief Terminate operation of the USRP transceiver -- free all associated resources /*! \brief Terminate operation of the USRP transceiver -- free all associated resources
* \param device the hardware to use * \param device the hardware to use
*/ */
static void trx_usrp_end(openair0_device *device) { static void trx_usrp_end(openair0_device *device) {
#if defined(USRP_REC_PLAY) // For some ugly reason, this can be called several times...
static int done = 0;
if (done == 1) return;
done = 1;
if (u_sf_mode != 2) { // not subframes replay
#endif
usrp_state_t *s = (usrp_state_t*)device->priv; usrp_state_t *s = (usrp_state_t*)device->priv;
s->rx_stream->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); s->rx_stream->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
...@@ -326,7 +377,45 @@ static void trx_usrp_end(openair0_device *device) { ...@@ -326,7 +377,45 @@ static void trx_usrp_end(openair0_device *device) {
s->tx_md.end_of_burst = true; s->tx_md.end_of_burst = true;
s->tx_stream->send("", 0, s->tx_md); s->tx_stream->send("", 0, s->tx_md);
s->tx_md.end_of_burst = false; s->tx_md.end_of_burst = false;
#if defined(USRP_REC_PLAY)
}
#endif
#if defined(USRP_REC_PLAY)
if (u_sf_mode == 1) { // subframes store
pFile = fopen (u_sf_filename,"wb+");
if (pFile == NULL) {
std::cerr << "Cannot open " << u_sf_filename << std::endl;
} else {
unsigned int i = 0;
unsigned int modu = 0;
if ((modu = nb_samples % 10) != 0) {
nb_samples -= modu; // store entire number of frames
}
std::cerr << "Writing " << nb_samples << " subframes to " << u_sf_filename << " ..." << std::endl;
for (i = 0; i < nb_samples; i++) {
fwrite(ms_sample+i, sizeof(unsigned char), sizeof(iqrec_t), pFile);
}
fclose (pFile);
std::cerr << "File " << u_sf_filename << " closed." << std::endl;
}
}
if (u_sf_mode == 1) { // record
if (ms_sample != NULL) {
free((void*)ms_sample);
ms_sample = NULL;
}
}
if (u_sf_mode == 2) { // replay
if (ms_sample != MAP_FAILED) {
munmap(ms_sample, sb.st_size);
ms_sample = NULL;
}
if (mmapfd != 0) {
close(mmapfd);
mmapfd = 0;
}
}
#endif
} }
/*! \brief Called to send samples to the USRP RF target /*! \brief Called to send samples to the USRP RF target
...@@ -339,6 +428,9 @@ static void trx_usrp_end(openair0_device *device) { ...@@ -339,6 +428,9 @@ static void trx_usrp_end(openair0_device *device) {
*/ */
static int trx_usrp_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags) { static int trx_usrp_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags) {
int ret=0; int ret=0;
#if defined(USRP_REC_PLAY)
if (u_sf_mode != 2) { // not replay mode
#endif
usrp_state_t *s = (usrp_state_t*)device->priv; usrp_state_t *s = (usrp_state_t*)device->priv;
int nsamps2; // aligned to upper 32 or 16 byte boundary int nsamps2; // aligned to upper 32 or 16 byte boundary
...@@ -405,6 +497,15 @@ static int trx_usrp_write(openair0_device *device, openair0_timestamp timestamp, ...@@ -405,6 +497,15 @@ static int trx_usrp_write(openair0_device *device, openair0_timestamp timestamp,
if (ret != nsamps) if (ret != nsamps)
LOG_E(PHY,"[xmit] tx samples %d != %d\n",ret,nsamps); LOG_E(PHY,"[xmit] tx samples %d != %d\n",ret,nsamps);
#if defined(USRP_REC_PLAY)
} else {
struct timespec req;
req.tv_sec = 0;
req.tv_nsec = u_sf_write_delay * 1000;
nanosleep(&req, NULL);
ret = nsamps;
}
#endif
return ret; return ret;
} }
...@@ -421,9 +522,12 @@ static int trx_usrp_write(openair0_device *device, openair0_timestamp timestamp, ...@@ -421,9 +522,12 @@ static int trx_usrp_write(openair0_device *device, openair0_timestamp timestamp,
* \returns the number of sample read * \returns the number of sample read
*/ */
static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int cc) { static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int cc) {
usrp_state_t *s = (usrp_state_t*)device->priv; usrp_state_t *s = (usrp_state_t*)device->priv;
int samples_received=0,i,j; int samples_received=0,i,j;
int nsamps2; // aligned to upper 32 or 16 byte boundary int nsamps2; // aligned to upper 32 or 16 byte boundary
#if defined(USRP_REC_PLAY)
if (u_sf_mode != 2) { // not replay mode
#endif
#if defined(__x86_64) || defined(__i386__) #if defined(__x86_64) || defined(__i386__)
#ifdef __AVX2__ #ifdef __AVX2__
nsamps2 = (nsamps+7)>>3; nsamps2 = (nsamps+7)>>3;
...@@ -490,7 +594,45 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp ...@@ -490,7 +594,45 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp
s->rx_count += nsamps; s->rx_count += nsamps;
s->rx_timestamp = s->rx_md.time_spec.to_ticks(s->sample_rate); s->rx_timestamp = s->rx_md.time_spec.to_ticks(s->sample_rate);
*ptimestamp = s->rx_timestamp; *ptimestamp = s->rx_timestamp;
return samples_received; #if defined (USRP_REC_PLAY)
}
#endif
#if defined(USRP_REC_PLAY)
if (u_sf_mode == 1) { // record mode
// Copy subframes to memory (later dump on a file)
if (nb_samples < u_sf_max) {
(ms_sample+nb_samples)->header = BELL_LABS_IQ_HEADER;
(ms_sample+nb_samples)->ts = *ptimestamp;
memcpy((ms_sample+nb_samples)->samples, buff[0], nsamps*4);
nb_samples++;
}
} else if (u_sf_mode == 2) { // replay mode
if (cur_samples == nb_samples) {
cur_samples = 0;
wrap_count++;
if (wrap_count == u_sf_loops) {
std::cerr << "USRP device terminating subframes replay mode after " << u_sf_loops << " loops." << std::endl;
return 0; // should make calling process exit
}
wrap_ts = wrap_count * (nb_samples * (((int)(device->openair0_cfg[0].sample_rate)) / 1000));
}
if (cur_samples < nb_samples) {
*ptimestamp = (ms_sample[0].ts + (cur_samples * (((int)(device->openair0_cfg[0].sample_rate)) / 1000))) + wrap_ts;
if (cur_samples == 0) {
std::cerr << "starting subframes file with wrap_count=" << wrap_count << " wrap_ts=" << wrap_ts
<< " ts=" << *ptimestamp << std::endl;
}
memcpy(buff[0], &ms_sample[cur_samples].samples[0], nsamps*4);
cur_samples++;
}
struct timespec req;
req.tv_sec = 0;
req.tv_nsec = u_sf_read_delay * 1000;
nanosleep(&req, NULL);
return nsamps;
}
#endif
return samples_received;
} }
/*! \brief Compares two variables within precision /*! \brief Compares two variables within precision
...@@ -684,12 +826,135 @@ int trx_usrp_reset_stats(openair0_device* device) { ...@@ -684,12 +826,135 @@ int trx_usrp_reset_stats(openair0_device* device) {
return(0); return(0);
} }
#if defined(USRP_REC_PLAY)
extern "C" {
/*! \brief Initializer for USRP record/playback config
* \param parameter array description
* \returns 0 on success
*/
int trx_usrp_recplay_config_init(paramdef_t *usrp_recplay_params) {
// --subframes-file
memcpy(usrp_recplay_params[0].optname, config_opt_sf_file, strlen(config_opt_sf_file));
usrp_recplay_params[0].helpstr = config_hlp_sf_file;
usrp_recplay_params[0].paramflags=PARAMFLAG_NOFREE;
usrp_recplay_params[0].strptr=(char **)&tmp_filename[0];
usrp_recplay_params[0].defstrval = NULL;
usrp_recplay_params[0].type=TYPE_STRING;
usrp_recplay_params[0].numelt=sizeof(u_sf_filename);
// --subframes-record
memcpy(usrp_recplay_params[1].optname, config_opt_sf_rec, strlen(config_opt_sf_rec));
usrp_recplay_params[1].helpstr = config_hlp_sf_rec;
usrp_recplay_params[1].paramflags=PARAMFLAG_BOOL;
usrp_recplay_params[1].uptr=&u_sf_record;
usrp_recplay_params[1].defuintval=0;
usrp_recplay_params[1].type=TYPE_UINT;
usrp_recplay_params[1].numelt=0;
// --subframes-replay
memcpy(usrp_recplay_params[2].optname, config_opt_sf_rep, strlen(config_opt_sf_rep));
usrp_recplay_params[2].helpstr = config_hlp_sf_rep;
usrp_recplay_params[2].paramflags=PARAMFLAG_BOOL;
usrp_recplay_params[2].uptr=&u_sf_replay;
usrp_recplay_params[2].defuintval=0;
usrp_recplay_params[2].type=TYPE_UINT;
usrp_recplay_params[2].numelt=0;
// --subframes-max
memcpy(usrp_recplay_params[3].optname, config_opt_sf_max, strlen(config_opt_sf_max));
usrp_recplay_params[3].helpstr = config_hlp_sf_max;
usrp_recplay_params[3].paramflags=0;
usrp_recplay_params[3].uptr=&u_sf_max;
usrp_recplay_params[3].defuintval=DEF_NB_SF;
usrp_recplay_params[3].type=TYPE_UINT;
usrp_recplay_params[3].numelt=0;
// --subframes-loops
memcpy(usrp_recplay_params[4].optname, config_opt_sf_loops, strlen(config_opt_sf_loops));
usrp_recplay_params[4].helpstr = config_hlp_sf_loops;
usrp_recplay_params[4].paramflags=0;
usrp_recplay_params[4].uptr=&u_sf_loops;
usrp_recplay_params[4].defuintval=DEF_SF_NB_LOOP;
usrp_recplay_params[4].type=TYPE_UINT;
usrp_recplay_params[4].numelt=0;
// --subframes-read-delay
memcpy(usrp_recplay_params[5].optname, config_opt_sf_rdelay, strlen(config_opt_sf_rdelay));
usrp_recplay_params[5].helpstr = config_hlp_sf_rdelay;
usrp_recplay_params[5].paramflags=0;
usrp_recplay_params[5].uptr=&u_sf_read_delay;
usrp_recplay_params[5].defuintval=DEF_SF_DELAY_READ;
usrp_recplay_params[5].type=TYPE_UINT;
usrp_recplay_params[5].numelt=0;
// --subframes-write-delay
memcpy(usrp_recplay_params[6].optname, config_opt_sf_wdelay, strlen(config_opt_sf_wdelay));
usrp_recplay_params[6].helpstr = config_hlp_sf_wdelay;
usrp_recplay_params[6].paramflags=0;
usrp_recplay_params[6].uptr=&u_sf_write_delay;
usrp_recplay_params[6].defuintval=DEF_SF_DELAY_WRITE;
usrp_recplay_params[6].type=TYPE_UINT;
usrp_recplay_params[6].numelt=0;
return 0; // always ok
}
}
#endif
extern "C" { extern "C" {
/*! \brief Initialize Openair USRP target. It returns 0 if OK /*! \brief Initialize Openair USRP target. It returns 0 if OK
* \param device the hardware to use * \param device the hardware to use
* \param openair0_cfg RF frontend parameters set by application * \param openair0_cfg RF frontend parameters set by application
*/ */
int device_init(openair0_device* device, openair0_config_t *openair0_cfg) { int device_init(openair0_device* device, openair0_config_t *openair0_cfg) {
#if defined(USRP_REC_PLAY)
paramdef_t usrp_recplay_params[7];
// to check
static int done = 0;
if (done == 1) {
return 0;
} // prevent from multiple init
done = 1;
// end to check
memset(usrp_recplay_params, 0, 7*sizeof(paramdef_t));
memset(&u_sf_filename[0], 0, 1024);
tmp_filename[0] = u_sf_filename;
if (trx_usrp_recplay_config_init(usrp_recplay_params) != 0) {
std::cerr << "USRP device record/replay mode configuration error exiting" << std::endl;
return -1;
}
config_process_cmdline(usrp_recplay_params,sizeof(usrp_recplay_params)/sizeof(paramdef_t),NULL);
if (strlen(tmp_filename[0]) != 0) {
(void) strcpy(u_sf_filename, tmp_filename[0]);
} else {
(void) strcpy(u_sf_filename, DEF_SF_FILE);
}
if (u_sf_replay == 1) u_sf_mode = 2;
if (u_sf_record == 1) u_sf_mode = 1;
if (u_sf_mode == 2) {
// Replay subframes from from file
int bw_gain_adjust=0;
device->openair0_cfg = openair0_cfg;
device->type = USRP_B200_DEV;
openair0_cfg[0].rx_gain_calib_table = calib_table_b210_38;
bw_gain_adjust=1;
openair0_cfg[0].tx_sample_advance = 80;
openair0_cfg[0].tx_bw = 20e6;
openair0_cfg[0].rx_bw = 20e6;
openair0_cfg[0].iq_txshift = 4;//shift
openair0_cfg[0].iq_rxrescale = 15;//rescale iqs
set_rx_gain_offset(&openair0_cfg[0],0,bw_gain_adjust);
device->priv = NULL;
device->trx_start_func = trx_usrp_start;
device->trx_write_func = trx_usrp_write;
device->trx_read_func = trx_usrp_read;
device->trx_get_stats_func = trx_usrp_get_stats;
device->trx_reset_stats_func = trx_usrp_reset_stats;
device->trx_end_func = trx_usrp_end;
device->trx_stop_func = trx_usrp_stop;
device->trx_set_freq_func = trx_usrp_set_freq;
device->trx_set_gains_func = trx_usrp_set_gains;
device->openair0_cfg = openair0_cfg;
std::cerr << "USRP device initialized in subframes replay mode for " << u_sf_loops << " loops." << std::endl;
} else {
#endif
uhd::set_thread_priority_safe(1.0); uhd::set_thread_priority_safe(1.0);
usrp_state_t *s = (usrp_state_t*)calloc(sizeof(usrp_state_t),1); usrp_state_t *s = (usrp_state_t*)calloc(sizeof(usrp_state_t),1);
...@@ -705,6 +970,11 @@ extern "C" { ...@@ -705,6 +970,11 @@ extern "C" {
int vers=0,subvers=0,subsubvers=0; int vers=0,subvers=0,subsubvers=0;
int bw_gain_adjust=0; int bw_gain_adjust=0;
#if defined(USRP_REC_PLAY)
if (u_sf_mode == 1) {
std::cerr << "USRP device initialized in subframes record mode" << std::endl;
}
#endif
sscanf(uhd::get_version_string().c_str(),"%d.%d.%d",&vers,&subvers,&subsubvers); sscanf(uhd::get_version_string().c_str(),"%d.%d.%d",&vers,&subvers,&subsubvers);
LOG_I(PHY,"Checking for USRPs : UHD %s (%d.%d.%d)\n", LOG_I(PHY,"Checking for USRPs : UHD %s (%d.%d.%d)\n",
uhd::get_version_string().c_str(),vers,subvers,subsubvers); uhd::get_version_string().c_str(),vers,subvers,subsubvers);
...@@ -742,7 +1012,9 @@ extern "C" { ...@@ -742,7 +1012,9 @@ extern "C" {
//s->usrp->set_master_clock_rate(usrp_master_clock); //s->usrp->set_master_clock_rate(usrp_master_clock);
openair0_cfg[0].rx_gain_calib_table = calib_table_x310; openair0_cfg[0].rx_gain_calib_table = calib_table_x310;
#if defined(USRP_REC_PLAY)
std::cerr << "-- Using calibration table: calib_table_x310" << std::endl; // Bell Labs info
#endif
switch ((int)openair0_cfg[0].sample_rate) { switch ((int)openair0_cfg[0].sample_rate) {
case 30720000: case 30720000:
// from usrp_time_offset // from usrp_time_offset
...@@ -801,9 +1073,15 @@ extern "C" { ...@@ -801,9 +1073,15 @@ extern "C" {
if ((vers == 3) && (subvers == 9) && (subsubvers>=2)) { if ((vers == 3) && (subvers == 9) && (subsubvers>=2)) {
openair0_cfg[0].rx_gain_calib_table = calib_table_b210; openair0_cfg[0].rx_gain_calib_table = calib_table_b210;
bw_gain_adjust=0; bw_gain_adjust=0;
#if defined(USRP_REC_PLAY)
std::cerr << "-- Using calibration table: calib_table_b210" << std::endl; // Bell Labs info
#endif
} else { } else {
openair0_cfg[0].rx_gain_calib_table = calib_table_b210_38; openair0_cfg[0].rx_gain_calib_table = calib_table_b210_38;
bw_gain_adjust=1; bw_gain_adjust=1;
#if defined(USRP_REC_PLAY)
std::cerr << "-- Using calibration table: calib_table_b210_38" << std::endl; // Bell Labs info
#endif
} }
switch ((int)openair0_cfg[0].sample_rate) { switch ((int)openair0_cfg[0].sample_rate) {
...@@ -965,6 +1243,45 @@ extern "C" { ...@@ -965,6 +1243,45 @@ extern "C" {
} }
} }
#if defined(USRP_REC_PLAY)
}
#endif
#if defined(USRP_REC_PLAY)
if (u_sf_mode == 1) { // record mode
ms_sample = (iqrec_t*) malloc(u_sf_max * sizeof(iqrec_t));
if (ms_sample == NULL) {
std::cerr<< "Memory allocation failed for subframe record or replay mode." << std::endl;
exit(-1);
}
memset(ms_sample, 0, u_sf_max * BELL_LABS_IQ_BYTES_PER_SF);
}
if (u_sf_mode == 2) {
// use mmap
mmapfd = open(u_sf_filename, O_RDONLY | O_LARGEFILE);
if (mmapfd != 0) {
fstat(mmapfd, &sb);
std::cerr << "Loading subframes using mmap() from " << u_sf_filename << " size=" << (uint64_t)sb.st_size << " bytes ..." << std::endl;
ms_sample = (iqrec_t*) mmap(NULL, sb.st_size, PROT_WRITE, MAP_PRIVATE, mmapfd, 0);
if (ms_sample != MAP_FAILED) {
nb_samples = (sb.st_size / sizeof(iqrec_t));
int aligned = (((unsigned long)ms_sample & 31) == 0)? 1:0;
std::cerr<< "Loaded "<< nb_samples << " subframes." << std::endl;
if (aligned == 0) {
std::cerr<< "mmap address is not 32 bytes aligned, exiting." << std::endl;
close(mmapfd);
exit(-1);
}
} else {
std::cerr << "Cannot mmap file, exiting." << std::endl;
close(mmapfd);
exit(-1);
}
} else {
std::cerr << "Cannot open " << u_sf_filename << " , exiting." << std::endl;
exit(-1);
}
}
#endif
return 0; return 0;
} }
} }
......
#ifndef __USRP_LIB_H
#define __USRP_LIB_H
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/** usrp_lib.h
*
* \author: bruno.mongazon-cazavet@nokia-bell-labs.com
*/
#if defined (USRP_REC_PLAY)
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "common/config/config_paramdesc.h"
#include "common/config/config_userapi.h"
#define BELL_LABS_IQ_HEADER 0xabababababababab
#define BELL_LABS_IQ_PER_SF 7680 // Up to 5MHz bw for now
#define BELL_LABS_IQ_BYTES_PER_SF (BELL_LABS_IQ_PER_SF * 4)
typedef struct {
int64_t header;
int64_t ts;
int64_t rfu1;
int64_t rfu2; // pad for 256 bits alignement required by AVX2
unsigned char samples[BELL_LABS_IQ_BYTES_PER_SF]; // iq's for one subframe
} iqrec_t;
#define DEF_NB_SF 120000 // default nb of sf or ms to capture (2 minutes at 5MHz)
#define DEF_SF_FILE "/home/nokia/iqfile" // default subframes file name
#define DEF_SF_DELAY_READ 860 // default read delay µs (860=real)
#define DEF_SF_DELAY_WRITE 15 // default write delay µs (15=real)
#define DEF_SF_NB_LOOP 5 // default nb loops
/* help strings definition for command line options, used in CMDLINE_XXX_DESC macros and printed when -h option is used */
#define CONFIG_HLP_SF_FILE "Path of the file used for subframes record or replay"
#define CONFIG_HLP_SF_REC "Record subframes from USRP driver into a file for later replay"
#define CONFIG_HLP_SF_REP "Replay subframes into USRP driver from a file"
#define CONFIG_HLP_SF_MAX "Maximum count of subframes to be recorded in subframe file"
#define CONFIG_HLP_SF_LOOPS "Number of loops to replay of the entire subframes file"
#define CONFIG_HLP_SF_RDELAY "Delay in microseconds to read a subframe in replay mode"
#define CONFIG_HLP_SF_WDELAY "Delay in microseconds to write a subframe in replay mode"
/* keyword strings for command line options, used in CMDLINE_XXX_DESC macros and printed when -h option is used */
#define CONFIG_OPT_SF_FILE "subframes-file"
#define CONFIG_OPT_SF_REC "subframes-record"
#define CONFIG_OPT_SF_REP "subframes-replay"
#define CONFIG_OPT_SF_MAX "subframes-max"
#define CONFIG_OPT_SF_LOOPS "subframes-loops"
#define CONFIG_OPT_SF_RDELAY "subframes-read-delay"
#define CONFIG_OPT_SF_WDELAY "subframes-write-delay"
/* For information only - the macro is not usable in C++ */
/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
/* command line parameters for USRP record/playback */
/* optname helpstr paramflags XXXptr defXXXval type numelt */
/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
#define USRP_RECPLAY_PARAMS_DESC { \
{"subframes-file", CONFIG_HLP_SF_FILE, 0, strptr:(char **)&u_sf_filename, defstrval:DEF_SF_FILE, TYPE_STRING, sizeof(u_sf_filename)}, \
{"subframes-record", CONFIG_HLP_SF_REC, PARAMFLAG_BOOL, uptr:&u_sf_record, defuintval:0, TYPE_UINT, 0}, \
{"subframes-replay", CONFIG_HLP_SF_REP, PARAMFLAG_BOOL, uptr:&u_sf_replay, defuintval:0, TYPE_UINT, 0}, \
{"subframes-max", CONFIG_HLP_SF_MAX, 0, uptr:&u_sf_max, defintval:DEF_NB_SF, TYPE_UINT, 0}, \
{"subframes-loops", CONFIG_HLP_SF_LOOPS, 0, uptr:&u_sf_loops, defintval:DEF_SF_NB_LOOP, TYPE_UINT, 0}, \
{"subframes-read-delay", CONFIG_HLP_SF_RDELAY, 0, uptr:&u_sf_read_delay, defintval:DEF_SF_DELAY_READ, TYPE_UINT, 0}, \
{"subframes-write-delay", CONFIG_HLP_SF_WDELAY, 0, uptr:&u_sf_write_delay, defintval:DEF_SF_DELAY_WRITE, TYPE_UINT, 0}, \
}
#endif // BELL_LABS_MUST
#endif // __USRP_LIB_H
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment