This commit provides the IQ record-playback feature know under issue #272
This commit is contained in:
@@ -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_TIMING_TRACE False "Activate UE timing trace")
|
||||
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")
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ UE_AUTOTEST_TRACE="False"
|
||||
UE_DEBUG_TRACE="False"
|
||||
UE_TIMING_TRACE="False"
|
||||
DISABLE_LOG_X="False"
|
||||
USRP_REC_PLAY="False"
|
||||
BUILD_ECLIPSE=0
|
||||
trap handle_ctrl_c INT
|
||||
|
||||
@@ -158,6 +159,8 @@ Options
|
||||
Disable all LOG_* macros
|
||||
--build-eclipse
|
||||
Build eclipse project files. Paths are auto corrected by fixprj.sh
|
||||
--usrp-recplay
|
||||
Build for I/Q record-playback modes
|
||||
Usage (first build):
|
||||
oaisim (eNB + UE): ./build_oai -I --oaisim -x --install-system-files
|
||||
Eurecom EXMIMO + COTS UE : ./build_oai -I --eNB -x --install-system-files
|
||||
@@ -350,6 +353,10 @@ function main() {
|
||||
BUILD_TELNETSRV=1
|
||||
echo_info "Build embedded telnet server"
|
||||
shift ;;
|
||||
--usrp-recplay)
|
||||
USRP_REC_PLAY="True"
|
||||
echo_info "Enabling USRP record playback mode"
|
||||
shift 1;;
|
||||
-h | --help)
|
||||
print_help
|
||||
exit 1;;
|
||||
@@ -540,6 +547,7 @@ function main() {
|
||||
echo "set (UE_DEBUG_TRACE $UE_DEBUG_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 (USRP_REC_PLAY $USRP_REC_PLAY)" >> $cmake_file
|
||||
if [ "$UE" = 1 -a "$NOS1" = "0" ] ; then
|
||||
echo_info "Compiling UE S1 build : enabling Linux and NETLINK"
|
||||
echo "set (LINUX True )" >> $cmake_file
|
||||
|
||||
@@ -1871,6 +1871,23 @@ uint32_t rx_pucch(PHY_VARS_eNB *eNB,
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -2289,8 +2306,12 @@ uint32_t rx_pucch(PHY_VARS_eNB *eNB,
|
||||
stat_im=0;
|
||||
|
||||
// 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)) {//
|
||||
|
||||
#endif
|
||||
chL = (nsymb>>1)-4;
|
||||
chest_mag=0;
|
||||
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,
|
||||
if (fmt==pucch_format1b)
|
||||
*(1+payload) = (stat_im<0) ? 1 : 2;
|
||||
} 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);
|
||||
#endif
|
||||
*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])])[1] = (int16_t)(stat_im);
|
||||
|
||||
@@ -128,7 +128,11 @@
|
||||
/*!\brief Maximum number od control elemenets */
|
||||
#define MAX_NUM_CE 5
|
||||
/*!\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
|
||||
#endif
|
||||
/*!\brief size of buffer status report table */
|
||||
#define BSR_TABLE_SIZE 64
|
||||
/*!\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,
|
||||
RA_template[i].Msg2_subframe = (subframeP+4)%10;
|
||||
/* TODO: find better procedure to allocate RNTI */
|
||||
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();
|
||||
#endif
|
||||
loop++;
|
||||
} while (loop != 100 &&
|
||||
/* 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
|
||||
UE_list->ordered_ULCCids[0][UE_id] = cc_idP;
|
||||
UE_list->num_UEs++;
|
||||
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
|
||||
UE_list->UE_template[cc_idP][UE_id].rach_resource_type = rach_resource_type ;
|
||||
|
||||
@@ -220,7 +220,7 @@ pdcp_validate_security(
|
||||
stream_decrypt(pdcp_pP->cipheringAlgorithm,
|
||||
&decrypt_params,
|
||||
&buffer_decrypted);
|
||||
|
||||
#if !defined(USRP_REC_PLAY)
|
||||
if (srb_flagP) {
|
||||
/* Now check the integrity of the complete PDU */
|
||||
decrypt_params.message = pdcp_pdu_buffer;
|
||||
@@ -241,7 +241,7 @@ pdcp_validate_security(
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_VALIDATE_SECURITY, VCD_FUNCTION_OUT);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -242,7 +242,11 @@ typedef enum HO_STATE_e {
|
||||
// #define NUM_MAX_CBA_GROUP 4 // in the platform_constants
|
||||
|
||||
/* 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
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
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(
|
||||
ue_context_pP->ue_context.kenb,
|
||||
&kRRCint);
|
||||
|
||||
#if !defined(USRP_REC_PLAY)
|
||||
#define DEBUG_SECURITY 1
|
||||
|
||||
#endif
|
||||
|
||||
#if defined (DEBUG_SECURITY)
|
||||
#undef msg
|
||||
#define msg printf
|
||||
|
||||
@@ -207,6 +207,15 @@ typedef struct {
|
||||
int iq_rxrescale;
|
||||
//! Configuration file for LMS7002M
|
||||
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;
|
||||
|
||||
/*! \brief RF mapping */
|
||||
|
||||
@@ -270,11 +270,53 @@ static int sync_to_gps(openair0_device *device)
|
||||
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
|
||||
@param device pointer to the device structure specific to the RF hardware target
|
||||
*/
|
||||
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;
|
||||
|
||||
|
||||
@@ -313,12 +355,21 @@ static int trx_usrp_start(openair0_device *device) {
|
||||
s->rx_count = 0;
|
||||
s->tx_count = 0;
|
||||
s->rx_timestamp = 0;
|
||||
#if defined(USRP_REC_PLAY)
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
/*! \brief Terminate operation of the USRP transceiver -- free all associated resources
|
||||
* \param device the hardware to use
|
||||
*/
|
||||
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;
|
||||
|
||||
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) {
|
||||
s->tx_md.end_of_burst = true;
|
||||
s->tx_stream->send("", 0, s->tx_md);
|
||||
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
|
||||
@@ -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) {
|
||||
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;
|
||||
|
||||
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,
|
||||
|
||||
if (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;
|
||||
}
|
||||
@@ -421,9 +522,12 @@ static int trx_usrp_write(openair0_device *device, openair0_timestamp timestamp,
|
||||
* \returns the number of sample read
|
||||
*/
|
||||
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;
|
||||
int samples_received=0,i,j;
|
||||
int nsamps2; // aligned to upper 32 or 16 byte boundary
|
||||
usrp_state_t *s = (usrp_state_t*)device->priv;
|
||||
int samples_received=0,i,j;
|
||||
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__)
|
||||
#ifdef __AVX2__
|
||||
nsamps2 = (nsamps+7)>>3;
|
||||
@@ -490,7 +594,45 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp
|
||||
s->rx_count += nsamps;
|
||||
s->rx_timestamp = s->rx_md.time_spec.to_ticks(s->sample_rate);
|
||||
*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
|
||||
@@ -684,12 +826,135 @@ int trx_usrp_reset_stats(openair0_device* device) {
|
||||
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" {
|
||||
/*! \brief Initialize Openair USRP target. It returns 0 if OK
|
||||
* \param device the hardware to use
|
||||
* \param openair0_cfg RF frontend parameters set by application
|
||||
*/
|
||||
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);
|
||||
usrp_state_t *s = (usrp_state_t*)calloc(sizeof(usrp_state_t),1);
|
||||
|
||||
@@ -705,6 +970,11 @@ extern "C" {
|
||||
int vers=0,subvers=0,subsubvers=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);
|
||||
LOG_I(PHY,"Checking for USRPs : UHD %s (%d.%d.%d)\n",
|
||||
uhd::get_version_string().c_str(),vers,subvers,subsubvers);
|
||||
@@ -742,7 +1012,9 @@ extern "C" {
|
||||
//s->usrp->set_master_clock_rate(usrp_master_clock);
|
||||
|
||||
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) {
|
||||
case 30720000:
|
||||
// from usrp_time_offset
|
||||
@@ -801,9 +1073,15 @@ extern "C" {
|
||||
if ((vers == 3) && (subvers == 9) && (subsubvers>=2)) {
|
||||
openair0_cfg[0].rx_gain_calib_table = calib_table_b210;
|
||||
bw_gain_adjust=0;
|
||||
#if defined(USRP_REC_PLAY)
|
||||
std::cerr << "-- Using calibration table: calib_table_b210" << std::endl; // Bell Labs info
|
||||
#endif
|
||||
} else {
|
||||
openair0_cfg[0].rx_gain_calib_table = calib_table_b210_38;
|
||||
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) {
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
#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
|
||||
|
||||
Reference in New Issue
Block a user