Commit b4ef9fe6 authored by Robert Schmidt's avatar Robert Schmidt

Merge remote-tracking branch 'origin/iqfixes_nrue' into integration_2023_w10

parents db192857 bd42f37a
......@@ -56,7 +56,7 @@ CMAKE_CMD="$CMAKE"
MAKE_CMD=make
BUILD_ECLIPSE=0
NR="False"
OPTIONAL_LIBRARIES="telnetsrv enbscope uescope nrscope nrqtscope ldpc_cuda ldpc_t1 websrv"
OPTIONAL_LIBRARIES="telnetsrv enbscope uescope nrscope nrqtscope ldpc_cuda ldpc_t1 websrv oai_iqplayer"
RU=0
CMAKE_C_FLAGS=()
CMAKE_CXX_FLAGS=()
......@@ -576,7 +576,7 @@ function main() {
echo_info "Compiling UE specific part"
if [ $UE_ip -eq 1 ]
if [ "$UE_ip" = 1 ]
then
echo_info "Building ue_ip module"
compilations $BUILD_DIR ue_ip
......
......@@ -19,7 +19,19 @@
#define ENABLE_USE_CPU_EXECUTION_TIME
#include "../LOG/vcd_signal_dumper.c"
void err(char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
/*
* Dummy needed by assertions.h
*/
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
{
if (assert) {
abort();
} else {
exit(EXIT_SUCCESS);
}
}
void err(char *fmt, ...) __attribute__((format(printf, 1, 2)));
void err(char *fmt, ...)
{
va_list ap;
......
......@@ -29,6 +29,9 @@
#include <unistd.h>
#include <platform_types.h>
#define OAI_EXIT_NORMAL 0
#define OAI_EXIT_ASSERT 1
#define _Assert_Exit_ \
if (getenv("gdbStacks")) { \
char tmp [1000]; \
......@@ -38,7 +41,8 @@
fprintf(stderr, "\nExiting execution\n"); \
fflush(stdout); \
fflush(stderr); \
abort();
exit_function(__FILE__, __FUNCTION__, __LINE__, "_Assert_Exit_", OAI_EXIT_ASSERT); \
abort(); // to avoid gcc warnings - never executed unless app-specific exit_function() does not exit() nor abort()
#define _Assert_(cOND, aCTION, fORMAT, aRGS...) \
do { \
......
......@@ -2,5 +2,11 @@
int T_stdout;
#endif
void exit_function(const char *file, const char *function, const int line, const char *s) {
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
{
if (assert) {
abort();
} else {
exit(EXIT_SUCCESS);
}
}
......@@ -176,7 +176,13 @@ void initFloatingCoresTpool(int nbThreads,tpool_t *pool, bool performanceMeas, c
#ifdef TEST_THREAD_POOL
volatile int oai_exit=0;
void exit_function(const char *file, const char *function, const int line, const char *s) {
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
{
if (assert) {
abort();
} else {
exit(EXIT_SUCCESS);
}
}
struct testData {
......
......@@ -241,8 +241,8 @@ unsigned int build_rfdc(int dcoff_i_rxfe, int dcoff_q_rxfe) {
return (dcoff_i_rxfe + (dcoff_q_rxfe<<8));
}
void exit_function(const char *file, const char *function, const int line, const char *s) {
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
{
int ru_id;
if (s != NULL) {
......@@ -266,8 +266,12 @@ void exit_function(const char *file, const char *function, const int line, const
}
}
sleep(1); //allow lte-softmodem threads to exit first
exit(1);
if (assert) {
abort();
} else {
sleep(1); // allow lte-softmodem threads to exit first
exit(EXIT_SUCCESS);
}
}
......
......@@ -244,7 +244,7 @@ unsigned int build_rfdc(int dcoff_i_rxfe, int dcoff_q_rxfe) {
}
void exit_function(const char *file, const char *function, const int line, const char *s) {
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert) {
int CC_id;
logClean();
printf("%s:%d %s() Exiting OAI softmodem: %s\n",file,line, function, ((s==NULL)?"":s));
......@@ -258,12 +258,15 @@ void exit_function(const char *file, const char *function, const int line, const
PHY_vars_UE_g[0][CC_id]->rfdevice.trx_end_func(&PHY_vars_UE_g[0][CC_id]->rfdevice);
}
sleep(1); //allow lte-softmodem threads to exit first
if(PHY_vars_UE_g != NULL )
itti_terminate_tasks (TASK_UNKNOWN);
exit(1);
if (assert) {
abort();
} else {
sleep(1); // allow lte-softmodem threads to exit first
exit(EXIT_SUCCESS);
}
}
extern int16_t dlsch_demod_shift;
......
......@@ -85,7 +85,7 @@ int32_t uplink_frequency_offset[MAX_NUM_CCs][4];
void nfapi_setmode(nfapi_mode_t nfapi_mode) { return; }
void exit_function(const char *file, const char *function, const int line, const char *s) {
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert) {
if (s != NULL) {
printf("%s:%d %s() Exiting OAI softmodem: %s\n",file,line, function, s);
......@@ -102,11 +102,15 @@ void exit_function(const char *file, const char *function, const int line, const
ru_m.ifdevice.trx_end_func(&ru_m.ifdevice);
ru_m.ifdevice.trx_end_func = NULL;
}
pthread_mutex_destroy(ru_m.ru_mutex);
pthread_cond_destroy(ru_m.ru_cond);
sleep(1); //allow lte-softmodem threads to exit first
exit(1);
pthread_cond_destroy(ru_m.ru_cond);
if (assert) {
abort();
} else {
sleep(1); // allow lte-softmodem threads to exit first
exit(EXIT_SUCCESS);
}
}
......
......@@ -38,8 +38,14 @@ int oai_exit = 0;
instance_t CUuniqInstance = 0;
RRC_release_list_t rrc_release_info;
void exit_function(const char *file, const char *function, const int line, const char *s)
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
{
if (assert) {
abort();
} else {
sleep(1); // allow other threads to exit first
exit(EXIT_SUCCESS);
}
}
nfapi_mode_t nfapi_mod = -1;
......
......@@ -249,8 +249,8 @@ unsigned int build_rfdc(int dcoff_i_rxfe, int dcoff_q_rxfe) {
#define KBLU "\x1B[34m"
#define RESET "\033[0m"
void exit_function(const char *file, const char *function, const int line, const char *s) {
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
{
int ru_id;
if (s != NULL) {
......@@ -274,8 +274,12 @@ void exit_function(const char *file, const char *function, const int line, const
}
}
sleep(1); //allow lte-softmodem threads to exit first
exit(1);
if (assert) {
abort();
} else {
sleep(1); // allow nr-softmodem threads to exit first
exit(EXIT_SUCCESS);
}
}
......
......@@ -687,21 +687,33 @@ void syncInFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp) {
LOG_I(PHY,"Resynchronizing RX by %d samples (mode = %d)\n",UE->rx_offset,UE->mode);
*timestamp += UE->frame_parms.get_samples_per_slot(1,&UE->frame_parms);
for ( int size=UE->rx_offset ; size > 0 ; size -= UE->frame_parms.samples_per_subframe ) {
int unitTransfer=size>UE->frame_parms.samples_per_subframe ? UE->frame_parms.samples_per_subframe : size ;
// we write before read because gNB waits for UE to write and both executions halt
// this happens here as the read size is samples_per_subframe which is very much larger than samp_per_slot
if (IS_SOFTMODEM_RFSIM) dummyWrite(UE,*timestamp, unitTransfer);
AssertFatal(unitTransfer ==
UE->rfdevice.trx_read_func(&UE->rfdevice,
timestamp,
(void **)UE->common_vars.rxdata,
unitTransfer,
UE->frame_parms.nb_antennas_rx),"");
*timestamp += unitTransfer; // this does not affect the read but needed for RFSIM write
if (IS_SOFTMODEM_IQPLAYER || IS_SOFTMODEM_IQRECORDER) {
// Resynchonize by slot (will work with numerology 1 only)
for ( int size=UE->rx_offset ; size > 0 ; size -= UE->frame_parms.samples_per_subframe/2 ) {
int unitTransfer=size>UE->frame_parms.samples_per_subframe/2 ? UE->frame_parms.samples_per_subframe/2 : size ;
AssertFatal(unitTransfer ==
UE->rfdevice.trx_read_func(&UE->rfdevice,
timestamp,
(void **)UE->common_vars.rxdata,
unitTransfer,
UE->frame_parms.nb_antennas_rx),"");
}
} else {
*timestamp += UE->frame_parms.get_samples_per_slot(1,&UE->frame_parms);
for ( int size=UE->rx_offset ; size > 0 ; size -= UE->frame_parms.samples_per_subframe ) {
int unitTransfer=size>UE->frame_parms.samples_per_subframe ? UE->frame_parms.samples_per_subframe : size ;
// we write before read because gNB waits for UE to write and both executions halt
// this happens here as the read size is samples_per_subframe which is very much larger than samp_per_slot
if (IS_SOFTMODEM_RFSIM) dummyWrite(UE,*timestamp, unitTransfer);
AssertFatal(unitTransfer ==
UE->rfdevice.trx_read_func(&UE->rfdevice,
timestamp,
(void **)UE->common_vars.rxdata,
unitTransfer,
UE->frame_parms.nb_antennas_rx),"");
*timestamp += unitTransfer; // this does not affect the read but needed for RFSIM write
}
}
}
int computeSamplesShift(PHY_VARS_NR_UE *UE) {
......@@ -773,6 +785,11 @@ void *UE_thread(void *arg) {
syncRunning=false;
syncData_t *tmp=(syncData_t *)NotifiedFifoData(res);
if (UE->is_synchronized) {
LOG_I(PHY,"UE synchronized decoded_frame_rx=%d UE->init_sync_frame=%d trashed_frames=%d\n",
decoded_frame_rx,
UE->init_sync_frame,
trashed_frames);
decoded_frame_rx=(((mac->mib->systemFrameNumber.buf[0] >> mac->mib->systemFrameNumber.bits_unused)<<4) | tmp->proc.decoded_frame_rx);
// shift the frame index with all the frames we trashed meanwhile we perform the synch search
decoded_frame_rx=(decoded_frame_rx + UE->init_sync_frame + trashed_frames) % MAX_FRAME_NUMBER;
......@@ -780,8 +797,16 @@ void *UE_thread(void *arg) {
delNotifiedFIFO_elt(res);
start_rx_stream=0;
} else {
readFrame(UE, &timestamp, true);
trashed_frames+=2;
if (IS_SOFTMODEM_IQPLAYER || IS_SOFTMODEM_IQRECORDER) {
// For IQ recorder/player we force synchronization to happen in 280 ms
while (trashed_frames != 28) {
readFrame(UE, &timestamp, true);
trashed_frames+=2;
}
} else {
readFrame(UE, &timestamp, true);
trashed_frames+=2;
}
continue;
}
}
......
......@@ -213,7 +213,8 @@ int create_tasks_nrue(uint32_t ue_nb) {
return 0;
}
void exit_function(const char *file, const char *function, const int line, const char *s) {
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
{
int CC_id;
if (s != NULL) {
......@@ -229,8 +230,12 @@ void exit_function(const char *file, const char *function, const int line, const
}
}
sleep(1); //allow lte-softmodem threads to exit first
exit(1);
if (assert) {
abort();
} else {
sleep(1); // allow lte-softmodem threads to exit first
exit(EXIT_SUCCESS);
}
}
uint64_t get_nrUE_optmask(void) {
......
......@@ -219,7 +219,7 @@ void signal_handler(int sig) {
softmodem_printresources(sig,(telnet_printfunc_t)printf);
if (sig != SOFTMODEM_RTSIGNAL) {
printf("Linux signal %s...\n",strsignal(sig));
exit_function(__FILE__, __FUNCTION__, __LINE__,"softmodem starting exit procedure\n");
exit_function(__FILE__, __FUNCTION__, __LINE__, "softmodem starting exit procedure\n", OAI_EXIT_NORMAL);
}
}
}
......
......@@ -258,6 +258,7 @@ extern int usrp_tx_thread;
#define SOFTMODEM_DOSCOPE_BIT (1<<15)
#define SOFTMODEM_RECPLAY_BIT (1<<16)
#define SOFTMODEM_TELNETCLT_BIT (1<<17)
#define SOFTMODEM_RECRECORD_BIT (1<<18)
#define SOFTMODEM_ENB_BIT (1<<20)
#define SOFTMODEM_GNB_BIT (1<<21)
#define SOFTMODEM_4GUE_BIT (1<<22)
......@@ -278,6 +279,7 @@ extern int usrp_tx_thread;
#define IS_SOFTMODEM_DOSCOPE ( get_softmodem_optmask() & SOFTMODEM_DOSCOPE_BIT)
#define IS_SOFTMODEM_DOSCOPE_QT ( get_softmodem_optmask() & SOFTMODEM_DOSCOPE_QT_BIT)
#define IS_SOFTMODEM_IQPLAYER ( get_softmodem_optmask() & SOFTMODEM_RECPLAY_BIT)
#define IS_SOFTMODEM_IQRECORDER ( get_softmodem_optmask() & SOFTMODEM_RECRECORD_BIT)
#define IS_SOFTMODEM_TELNETCLT_BIT ( get_softmodem_optmask() & SOFTMODEM_TELNETCLT_BIT)
#define IS_SOFTMODEM_ENB_BIT ( get_softmodem_optmask() & SOFTMODEM_ENB_BIT)
#define IS_SOFTMODEM_GNB_BIT ( get_softmodem_optmask() & SOFTMODEM_GNB_BIT)
......
......@@ -28,7 +28,7 @@ PHY_VARS_UE ***PHY_vars_UE_g;
#include "common/ran_context.h"
RAN_CONTEXT_t RC;
void exit_function(const char* file, const char* function, const int line, const char *s) {
void exit_function(const char* file, const char* function, const int line, const char* s, const int assert) {
const char * msg= s==NULL ? "no comment": s;
printf("Exiting at: %s:%d %s(), %s\n", file, line, function, msg);
exit(-1);
......
......@@ -572,7 +572,7 @@ int pss_synchro_nr(PHY_VARS_NR_UE *PHY_vars_UE, int is, int rate_change)
#ifndef NR_UNIT_TEST
printf("PSS execution duration %4d microseconds \n", duration_ms);
LOG_I(PHY,"PSS execution duration %4d microseconds \n", duration_ms);
#endif
......
......@@ -541,7 +541,7 @@ int rx_sss_nr(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, int32_t *tot_metric,
#ifdef DEBUG_SSS_NR
printf("(phase,Nid1) (%d,%d), metric_phase %d tot_metric %d, phase_max %d \n",phase, Nid1, metric, *tot_metric, *phase_max);
LOG_D(PHY,"(phase,Nid1) (%d,%d), metric_phase %d tot_metric %d, phase_max %d \n",phase, Nid1, metric, *tot_metric, *phase_max);
#endif
}
......@@ -554,7 +554,7 @@ int rx_sss_nr(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, int32_t *tot_metric,
if (*tot_metric > SSS_METRIC_FLOOR_NR) {
Nid2 = GET_NID2(frame_parms->Nid_cell);
Nid1 = GET_NID1(frame_parms->Nid_cell);
printf("Nid2 %d Nid1 %d tot_metric %d, phase_max %d \n", Nid2, Nid1, *tot_metric, *phase_max);
LOG_D(PHY,"Nid2 %d Nid1 %d tot_metric %d, phase_max %d \n", Nid2, Nid1, *tot_metric, *phase_max);
}
//#endif
......@@ -564,7 +564,7 @@ int rx_sss_nr(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, int32_t *tot_metric,
int re = 0;
int im = 0;
if (Nid1 == N_ID_1_NUMBER) {
LOG_I(PHY,"Failled to detect SSS after PSS\n");
LOG_I(PHY,"Failed to detect SSS after PSS\n");
return -1;
}
d = (int16_t *)&d_sss[Nid2][Nid1];
......
......@@ -22,7 +22,7 @@
openair0_device openair0;
int oai_exit=0;
void exit_function(const char* file, const char* function, const int line,const char *s) {
void exit_function(const char* file, const char* function, const int line,const char* s, const int assert) {
const char * msg= s==NULL ? "no comment": s;
printf("Exiting at: %s:%d %s(), %s\n", file, line, function, msg);
exit(-1);
......
......@@ -35,7 +35,7 @@
int oai_exit=0;
void exit_function(const char* file, const char* function, const int line, const char *s) {
void exit_function(const char* file, const char* function, const int line, const char *s, const int assert) {
const char * msg= s==NULL ? "no comment": s;
printf("Exiting at: %s:%d %s(), %s\n", file, line, function, msg);
exit(-1);
......
......@@ -281,12 +281,12 @@ typedef struct protocol_ctxt_s {
#define CHECK_CTXT_ARGS(CTXT_Pp)
#define exit_fun(msg) exit_function(__FILE__,__FUNCTION__,__LINE__,msg)
#define exit_fun(msg) exit_function(__FILE__, __FUNCTION__, __LINE__, "exit_fun", OAI_EXIT_NORMAL)
#ifdef __cplusplus
extern "C"
{
#endif
void exit_function(const char *file, const char *function, const int line, const char *s);
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert);
#ifdef __cplusplus
}
#endif
......
......@@ -482,8 +482,14 @@ void ra_preambles_config(NR_PRACH_RESOURCES_t *prach_resources, NR_UE_MAC_INST_t
long deltaPreamble_Msg3 = 0;
uint8_t noGroupB = 0;
// Random seed generation
long long tmp = rdtsc_oai();
unsigned short int *seed = (unsigned short int*)&tmp;
unsigned int seed;
if (IS_SOFTMODEM_IQPLAYER || IS_SOFTMODEM_IQRECORDER) {
// Overwrite seed with non-random seed for IQ player/recorder
seed = 1;
} else {
seed=(unsigned int) (rdtsc_oai() && ~0);
}
RA_config_t *ra = &mac->ra;
NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP.rach_ConfigCommon;
......@@ -580,28 +586,28 @@ void ra_preambles_config(NR_PRACH_RESOURCES_t *prach_resources, NR_UE_MAC_INST_t
if(ra->ra_PreambleIndex < 0 || ra->ra_PreambleIndex > 63) {
if (noGroupB) {
// use Group A preamble
ra->ra_PreambleIndex = ra->starting_preamble_nb + (rand_r((unsigned int *)seed) % ra->cb_preambles_per_ssb);
ra->ra_PreambleIndex = ra->starting_preamble_nb + (rand_r(&seed) % ra->cb_preambles_per_ssb);
ra->RA_usedGroupA = 1;
} else if ((ra->Msg3_size < messageSizeGroupA) && (dl_pathloss > PLThreshold)) {
// Group B is configured and RA preamble Group A is used
// - todo add condition on CCCH_sdu_size for initiation by CCCH
ra->ra_PreambleIndex = ra->starting_preamble_nb + (rand_r((unsigned int *)seed) % sizeOfRA_PreamblesGroupA);
ra->ra_PreambleIndex = ra->starting_preamble_nb + (rand_r(&seed) % sizeOfRA_PreamblesGroupA);
ra->RA_usedGroupA = 1;
} else {
// Group B preamble is configured and used
// the first sizeOfRA_PreamblesGroupA RA preambles belong to RA Preambles Group A
// the remaining belong to RA Preambles Group B
ra->ra_PreambleIndex = ra->starting_preamble_nb + sizeOfRA_PreamblesGroupA + (rand_r((unsigned int *)seed) % (ra->cb_preambles_per_ssb - sizeOfRA_PreamblesGroupA));
ra->ra_PreambleIndex = ra->starting_preamble_nb + sizeOfRA_PreamblesGroupA + (rand_r(&seed) % (ra->cb_preambles_per_ssb - sizeOfRA_PreamblesGroupA));
ra->RA_usedGroupA = 0;
}
}
} else { // Msg3 is being retransmitted
if (ra->RA_usedGroupA && noGroupB) {
ra->ra_PreambleIndex = ra->starting_preamble_nb + (rand_r((unsigned int *)seed) % ra->cb_preambles_per_ssb);
ra->ra_PreambleIndex = ra->starting_preamble_nb + (rand_r(&seed) % ra->cb_preambles_per_ssb);
} else if (ra->RA_usedGroupA && !noGroupB){
ra->ra_PreambleIndex = ra->starting_preamble_nb + (rand_r((unsigned int *)seed) % sizeOfRA_PreamblesGroupA);
ra->ra_PreambleIndex = ra->starting_preamble_nb + (rand_r(&seed) % sizeOfRA_PreamblesGroupA);
} else {
ra->ra_PreambleIndex = ra->starting_preamble_nb + sizeOfRA_PreamblesGroupA + (rand_r((unsigned int *)seed) % (ra->cb_preambles_per_ssb - sizeOfRA_PreamblesGroupA));
ra->ra_PreambleIndex = ra->starting_preamble_nb + sizeOfRA_PreamblesGroupA + (rand_r(&seed) % (ra->cb_preambles_per_ssb - sizeOfRA_PreamblesGroupA));
}
}
}
......@@ -1033,9 +1039,15 @@ void nr_ra_failed(uint8_t mod_id, uint8_t CC_id, NR_PRACH_RESOURCES_t *prach_res
NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id);
RA_config_t *ra = &mac->ra;
// Random seed generation
long long tmp = rdtsc_oai();
unsigned short int *seed = (unsigned short int*)&tmp;
unsigned int seed;
if (IS_SOFTMODEM_IQPLAYER || IS_SOFTMODEM_IQRECORDER) {
// Overwrite seed with non-random seed for IQ player/recorder
seed = 1;
} else {
seed=(unsigned int) (rdtsc_oai() && ~0);
}
ra->first_Msg3 = 1;
ra->ra_PreambleIndex = -1;
ra->ra_state = RA_UE_IDLE;
......@@ -1047,7 +1059,7 @@ void nr_ra_failed(uint8_t mod_id, uint8_t CC_id, NR_PRACH_RESOURCES_t *prach_res
LOG_D(MAC, "In %s: [UE %d][%d.%d] Maximum number of RACH attempts (%d) reached, selecting backoff time...\n",
__FUNCTION__, mod_id, frame, slot, ra->preambleTransMax);
ra->RA_backoff_cnt = rand_r((unsigned int *)seed) % (prach_resources->RA_PREAMBLE_BACKOFF + 1);
ra->RA_backoff_cnt = rand_r(&seed) % (prach_resources->RA_PREAMBLE_BACKOFF + 1);
prach_resources->RA_PREAMBLE_TRANSMISSION_COUNTER = 1;
prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP += 2; // 2 dB increment
prach_resources->ra_PREAMBLE_RECEIVED_TARGET_POWER = nr_get_Po_NOMINAL_PUSCH(prach_resources, mod_id, CC_id);
......
......@@ -3236,12 +3236,14 @@ void nr_ue_process_mac_pdu(nr_downlink_indication_t *dl_info,
module_idP, frameP, pduP[1], pduP[2], pduP[3], pduP[4], pduP[5], pduP[6]);
bool ra_success = true;
for(int i = 0; i<mac_len; i++) {
if(ra->cont_res_id[i] != pduP[i+1]) {
ra_success = false;
break;
}
}
if (!IS_SOFTMODEM_IQPLAYER) { // Control is bypassed when replaying IQs (BMC)
for(int i = 0; i<mac_len; i++) {
if(ra->cont_res_id[i] != pduP[i+1]) {
ra_success = false;
break;
}
}
}
if ( (ra->RA_active == 1) && ra_success) {
nr_ra_succeeded(module_idP, frameP, slot);
......
......@@ -194,10 +194,10 @@ int8_t nr_rrc_ue_decode_secondary_cellgroup_config(const module_id_t module_id,
size, 0, 0);
if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) {
printf("NR_CellGroupConfig decode error\n");
LOG_E(NR_RRC, "NR_CellGroupConfig decode error\n");
for (i=0; i<size; i++)
printf("%02x ",buffer[i]);
printf("\n");
LOG_E(NR_RRC, "%02x ",buffer[i]);
LOG_E(NR_RRC, "\n");
// free the memory
SEQUENCE_free( &asn_DEF_NR_CellGroupConfig, (void *)cell_group_config, 1 );
return -1;
......@@ -1025,15 +1025,15 @@ static int8_t check_requested_SI_List(module_id_t module_id, BIT_STRING_t reques
LOG_D(RRC, "SIBs broadcasting: ");
for(int i = 0; i < sib1.si_SchedulingInfo->schedulingInfoList.list.array[0]->sib_MappingInfo.list.count; i++) {
printf("SIB%li ", sib1.si_SchedulingInfo->schedulingInfoList.list.array[0]->sib_MappingInfo.list.array[i]->type + 2);
LOG_D(RRC, "SIB%li ", sib1.si_SchedulingInfo->schedulingInfoList.list.array[0]->sib_MappingInfo.list.array[i]->type + 2);
}
printf("\n");
LOG_D(RRC, "\n");
LOG_D(RRC, "SIBs needed by UE: ");
for(int j = 0; j < 8*requested_SI_List.size; j++) {
if( ((requested_SI_List.buf[j/8]>>(j%8))&1) == 1) {
printf("SIB%i ", j + 2);
LOG_D(RRC, "SIB%i ", j + 2);
SIB_to_request[j] = true;
for(int i = 0; i < sib1.si_SchedulingInfo->schedulingInfoList.list.array[0]->sib_MappingInfo.list.count; i++) {
......@@ -1045,17 +1045,17 @@ static int8_t check_requested_SI_List(module_id_t module_id, BIT_STRING_t reques
}
}
printf("\n");
LOG_D(RRC, "\n");
LOG_D(RRC, "SIBs to request by UE: ");
bool do_ra = false;
for(int j = 0; j < 8*requested_SI_List.size; j++) {
if(SIB_to_request[j]) {
printf("SIB%i ", j + 2);
LOG_D(RRC, "SIB%i ", j + 2);
do_ra = true;
}
}
printf("\n");
LOG_D(RRC, "\n");
if(do_ra) {
......@@ -1458,8 +1458,8 @@ int8_t nr_rrc_ue_decode_ccch( const protocol_ctxt_t *const ctxt_pP, const NR_SRB
if ((dec_rval.code != RC_OK) || (dec_rval.consumed == 0)) {
for (i=0; i<buffer_len; i++)
printf("%02x ",bufferP[i]);
printf("\n");
LOG_D(NR_RRC, "%02x ",bufferP[i]);
LOG_D(NR_RRC, "\n");
// free the memory
SEQUENCE_free( &asn_DEF_NR_DL_DCCH_Message, (void *)nr_dl_dcch_msg, 1 );
return -1;
......
......@@ -110,7 +110,10 @@ int load_lib(openair0_device *device,
openair0_cfg->recplay_mode = read_recplayconfig(&(openair0_cfg->recplay_conf),&(device->recplay_state));
if ( openair0_cfg->recplay_mode == RECPLAY_REPLAYMODE ) {
if (openair0_cfg->recplay_mode == RECPLAY_RECORDMODE) {
set_softmodem_optmask(SOFTMODEM_RECRECORD_BIT); // softmodem has to know we use the iqrecorder to workaround randomized algorithms
}
if (openair0_cfg->recplay_mode == RECPLAY_REPLAYMODE) {
deflibname=OAI_IQPLAYER_LIBNAME;
shlib_fdesc[0].fname="device_init";
set_softmodem_optmask(SOFTMODEM_RECPLAY_BIT); // softmodem has to know we use the iqplayer to workaround randomized algorithms
......
......@@ -40,13 +40,11 @@
* recplay_state: store recorder or player data while the device runs
*/
int read_recplayconfig(recplay_conf_t **recplay_conf, recplay_state_t **recplay_state) {
unsigned int u_sf_record = 0; // record mode
unsigned int u_sf_replay = 0; // replay mode
*recplay_conf = calloc(sizeof(recplay_conf_t),1);
paramdef_t device_recplay_params[]=DEVICE_RECPLAY_PARAMS_DESC ;
config_get(device_recplay_params,sizeof(device_recplay_params)/sizeof(paramdef_t),DEVICE_RECPLAY_SECTION);
if (u_sf_record || u_sf_replay ) {
if ((*recplay_conf)->u_sf_record || (*recplay_conf)->u_sf_replay ) {
struct sysinfo systeminfo;
*recplay_state = calloc(sizeof(recplay_state_t),1);
......@@ -62,17 +60,18 @@ int read_recplayconfig(recplay_conf_t **recplay_conf, recplay_state_t **recplay_
LOG_W(HW,"System with %f GB of mem (<6GB), mmap usage disabled\n",systeminfo.totalram/10E9);
(*recplay_conf)->use_mmap = 0;
}
} else { /* record player enabled */
} else { /* player-recorder disable */
free(*recplay_conf);
*recplay_conf=NULL;
return RECPLAY_DISABLED;
}
if (u_sf_replay == 1)
if ((*recplay_conf)->u_sf_replay == 1)
return RECPLAY_REPLAYMODE;
else if (u_sf_record == 1)
else if ((*recplay_conf)->u_sf_record == 1)
return RECPLAY_RECORDMODE;
return 0;
return RECPLAY_DISABLED;
}
/*! \brief Terminate operation of the oai iq recorder. to be called by any device
......@@ -81,21 +80,15 @@ int read_recplayconfig(recplay_conf_t **recplay_conf, recplay_state_t **recplay_
*/
void iqrecorder_end(openair0_device *device) {
if (device->recplay_state != NULL) { // subframes store
iqfile_header_t fh = {device->type,device->openair0_cfg->tx_sample_advance, device->openair0_cfg->rx_bw,0,OAIIQFILE_ID};
iqfile_header_t fh = {device->type,device->openair0_cfg->tx_sample_advance, device->openair0_cfg->rx_bw,0,OAIIQFILE_ID};
recplay_state_t *rs = device->recplay_state;
recplay_conf_t *rc = device->openair0_cfg[0].recplay_conf;
recplay_conf_t *rc = device->openair0_cfg[0].recplay_conf;
rs->pFile = fopen (rc->u_sf_filename,"wb+");
if (rs->pFile == NULL) {
LOG_E(HW,"Cannot open %s\n", rc->u_sf_filename);
} else {
unsigned int i = 0;
unsigned int modu = 0;
if ((modu = rs->nbSamplesBlocks % 10) != 0) {
rs->nbSamplesBlocks -= modu; // store entire number of frames
}
fh.nbSamplesBlocks=rs->nbSamplesBlocks;
LOG_I(HW,"Writing file header to %s \n", rc->u_sf_filename );
fwrite(&fh, sizeof(fh), 1, rs->pFile);
......@@ -103,7 +96,7 @@ void iqrecorder_end(openair0_device *device) {
uint8_t *ptr=(uint8_t *)rs->ms_sample;
for (i = 0; i < rs->nbSamplesBlocks; i++) {
int blockBytes=sizeof(iqrec_t)+((iqrec_t *)ptr)->nbBytes;
int blockBytes=sizeof(iqrec_t)+BELL_LABS_IQ_BYTES_PER_SF;
fwrite(ptr, sizeof(unsigned char), blockBytes, rs->pFile);
ptr+=blockBytes;
}
......
......@@ -44,9 +44,8 @@ extern "C"
#define RECPLAY_REPLAYMODE 2
#define BELL_LABS_IQ_HEADER 0xabababababababab
#define BELL_LABS_IQ_PER_SF 46080 // 7680 => 5MHz bw for now; 46080 => 3/4 40MHz (106 PRBs)
#define BELL_LABS_IQ_PER_SF 23040 // 23040 => 46080/2 slots => 3/4 40MHz (106 PRBs)
#define BELL_LABS_IQ_BYTES_PER_SF (BELL_LABS_IQ_PER_SF * 4)
#define MAX_BELL_LABS_IQ_BYTES_PER_SF BELL_LABS_IQ_BYTES_PER_SF*10
#define OAIIQFILE_ID {'O', 'I','Q','F'}
typedef struct {
......@@ -61,7 +60,9 @@ typedef struct {
int64_t header;
int64_t ts;
int64_t nbBytes;
int64_t rfu2; // pad for 256 bits alignement required by AVX2
int64_t tv_sec; // nb of secs since EPOCH
int64_t tv_usec; // nb of µsecs since EPOCH
int64_t rfu2; // pad for 256 bits alignement required by AVX2
} iqrec_t;
#define DEF_NB_SF 120000 // default nb of sf or ms to capture (2 minutes at 5MHz)
#define DEF_SF_FILE "/tmp/iqfile" // default subframes file name
......@@ -95,29 +96,31 @@ typedef struct {
/* optname helpstr paramflags XXXptr defXXXval type numelt */
/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
#define DEVICE_RECPLAY_PARAMS_DESC { \
{CONFIG_OPT_SF_FILE, CONFIG_HLP_SF_FILE, 0, strptr:&((*recplay_conf)->u_sf_filename), defstrval:DEF_SF_FILE, TYPE_STRING, 0}, \
{CONFIG_OPT_SF_REC, CONFIG_HLP_SF_REC, PARAMFLAG_BOOL, uptr:&(u_sf_record), defuintval:0, TYPE_UINT, 0}, \
{CONFIG_OPT_SF_REP, CONFIG_HLP_SF_REP, PARAMFLAG_BOOL, uptr:&(u_sf_replay), defuintval:0, TYPE_UINT, 0}, \
{CONFIG_OPT_SF_MAX, CONFIG_HLP_SF_MAX, 0, uptr:&((*recplay_conf)->u_sf_max), defintval:DEF_NB_SF, TYPE_UINT, 0}, \
{CONFIG_OPT_SF_LOOPS, CONFIG_HLP_SF_LOOPS, 0, uptr:&((*recplay_conf)->u_sf_loops), defintval:DEF_SF_NB_LOOP, TYPE_UINT, 0}, \
{CONFIG_OPT_SF_RDELAY, CONFIG_HLP_SF_RDELAY, 0, uptr:&((*recplay_conf)->u_sf_read_delay), defintval:DEF_SF_DELAY_READ, TYPE_UINT, 0}, \
{CONFIG_OPT_SF_WDELAY, CONFIG_HLP_SF_WDELAY, 0, uptr:&((*recplay_conf)->u_sf_write_delay), defintval:DEF_SF_DELAY_WRITE, TYPE_UINT, 0}, \
{CONFIG_OPT_USE_MMAP, CONFIG_HLP_USE_MMAP, PARAMFLAG_BOOL, uptr:&((*recplay_conf)->use_mmap), defuintval:1, TYPE_UINT, 0}, \
{CONFIG_OPT_SF_FILE, CONFIG_HLP_SF_FILE, 0, strptr:&((*recplay_conf)->u_sf_filename), defstrval:DEF_SF_FILE, TYPE_STRING, 0}, \
{CONFIG_OPT_SF_REC, CONFIG_HLP_SF_REC, PARAMFLAG_BOOL, uptr:&((*recplay_conf)->u_sf_record), defuintval:0, TYPE_UINT, 0}, \
{CONFIG_OPT_SF_REP, CONFIG_HLP_SF_REP, PARAMFLAG_BOOL, uptr:&((*recplay_conf)->u_sf_replay), defuintval:0, TYPE_UINT, 0}, \
{CONFIG_OPT_SF_MAX, CONFIG_HLP_SF_MAX, 0, uptr:&((*recplay_conf)->u_sf_max), defintval:DEF_NB_SF, TYPE_UINT, 0}, \
{CONFIG_OPT_SF_LOOPS, CONFIG_HLP_SF_LOOPS, 0, uptr:&((*recplay_conf)->u_sf_loops), defintval:DEF_SF_NB_LOOP, TYPE_UINT, 0}, \
{CONFIG_OPT_SF_RDELAY, CONFIG_HLP_SF_RDELAY, 0, uptr:&((*recplay_conf)->u_sf_read_delay), defintval:DEF_SF_DELAY_READ, TYPE_UINT, 0}, \
{CONFIG_OPT_SF_WDELAY, CONFIG_HLP_SF_WDELAY, 0, uptr:&((*recplay_conf)->u_sf_write_delay), defintval:DEF_SF_DELAY_WRITE, TYPE_UINT, 0}, \
{CONFIG_OPT_USE_MMAP, CONFIG_HLP_USE_MMAP, PARAMFLAG_BOOL, uptr:&((*recplay_conf)->use_mmap), defuintval:1, TYPE_UINT, 0}, \
}/*! \brief Record Player Configuration and state */
typedef struct {
char *u_sf_filename; // subframes file path
unsigned int u_sf_max ; // max number of recorded subframes
unsigned int u_sf_loops ; // number of loops in replay mode
char *u_sf_filename; // subframes file path
unsigned int u_sf_max ; // max number of recorded subframes
unsigned int u_sf_loops ; // number of loops in replay mode
unsigned int u_sf_read_delay; // read delay in replay mode
unsigned int u_sf_write_delay ; // write delay in replay mode
unsigned int use_mmap; // default is to use mmap
unsigned int use_mmap; // default is to use mmap
unsigned int u_sf_replay; // replay mode (if 1)
unsigned int u_sf_record; // record mode (if 1)
} recplay_conf_t;
typedef struct {
size_t mapsize;
FILE *pFile;
int fd;
iqrec_t *ms_sample; // memory for all subframes
iqrec_t *ms_sample; // memory for all subframes
unsigned int nbSamplesBlocks;
uint8_t *currentPtr;
uint64_t currentTs;
......
......@@ -698,7 +698,7 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp
nsamps2 = (nsamps+3)>>2;
int16x8_t buff_tmp[cc<2 ? 2 : cc][nsamps2];
#endif
static int read_count = 0;
int rxshift;
switch (device->type) {
case USRP_B200_DEV:
......@@ -769,25 +769,30 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp
recplay_state_t *recPlay=device->recplay_state;
if ( recPlay != NULL) { // record mode
if (device->openair0_cfg->recplay_mode == RECPLAY_RECORDMODE) { // record mode
// Copy subframes to memory (later dump on a file)
if (recPlay->nbSamplesBlocks < device->openair0_cfg->recplay_conf->u_sf_max &&
recPlay->maxSizeBytes > (recPlay->currentPtr-(uint8_t *)recPlay->ms_sample) +
sizeof(iqrec_t) + nsamps*4 ) {
// The number of read samples might differ from BELL_LABS_IQ_BYTES_PER_SF
// The number of read samples is always stored in nbBytes but the record is always of BELL_LABS_IQ_BYTES_PER_SF size
if (recPlay->nbSamplesBlocks <= device->openair0_cfg->recplay_conf->u_sf_max &&
recPlay->maxSizeBytes >= (recPlay->currentPtr-(uint8_t *)recPlay->ms_sample) +
sizeof(iqrec_t) + BELL_LABS_IQ_BYTES_PER_SF) {
iqrec_t *hdr=(iqrec_t *)recPlay->currentPtr;
struct timespec trec;
(void) clock_gettime(CLOCK_REALTIME, &trec);
hdr->header = BELL_LABS_IQ_HEADER;
hdr->ts = *ptimestamp;
hdr->nbBytes=nsamps*4;
hdr->nbBytes=nsamps*4; // real number of samples bytes
hdr->tv_sec = trec.tv_sec; // record secs
hdr->tv_usec = trec.tv_nsec/1000; // record µsecs
memcpy(hdr+1, buff[0], nsamps*4);
recPlay->currentPtr+=sizeof(iqrec_t)+nsamps*4;
recPlay->currentPtr+=sizeof(iqrec_t)+BELL_LABS_IQ_BYTES_PER_SF; // record size is constant (BELL_LABS_IQ_BYTES_PER_SF)
recPlay->nbSamplesBlocks++;
#if 0 // BMC: this is too verbose
LOG_D(HW,"recorded %d samples, for TS %lu, shift in buffer %ld\n", nsamps, hdr->ts, recPlay->currentPtr-(uint8_t *)recPlay->ms_sample);
#endif
LOG_D(HW,"recorded %d samples, for TS %lu, shift in buffer %ld nbBytes %d nbSamplesBlocks %d\n", nsamps, hdr->ts, recPlay->currentPtr-(uint8_t *)recPlay->ms_sample, (int)hdr->nbBytes, (int)recPlay->nbSamplesBlocks);
} else
exit_function(__FILE__, __FUNCTION__, __LINE__,"Recording reaches max iq limit\n");
exit_function(__FILE__, __FUNCTION__, __LINE__, "Recording reaches max iq limit\n", OAI_EXIT_NORMAL);
}
read_count++;
LOG_D(HW,"usrp_lib: returning %d samples at ts %lu read_count %d\n", samples_received, *ptimestamp, read_count);
return samples_received;
}
......
......@@ -35,10 +35,33 @@
#include <time.h>
#include <sys/resource.h>
#include <errno.h>
#include <math.h>
#include <sys/time.h>
#include "common_lib.h"
#include "assertions.h"
#include "common/utils/LOG/log.h"
static void busy_wait(uint32_t usecs) {
uint32_t elapsed_usecs;
double temp;
int j;
struct timespec requestStart, requestEnd;
// Active wait
clock_gettime(CLOCK_REALTIME, &requestStart);
temp = 0;
while (1) {
for (j=0; j < 40; j++)
temp += sin(j);
clock_gettime(CLOCK_REALTIME, &requestEnd);
elapsed_usecs = ( requestEnd.tv_sec - requestStart.tv_sec ) / 1e-6
+ ( requestEnd.tv_nsec - requestStart.tv_nsec ) / 1e3;
if (elapsed_usecs >= usecs)
break;
}
//LOG_I(HW, "Expected: %d Elapsed: %d us\n", usecs, elapsed_usecs);
}
static void parse_iqfile_header(openair0_device *device, iqfile_header_t *iq_fh) {
char tmp[4]=OAIIQFILE_ID;
AssertFatal((memcmp(iq_fh->oaiid,tmp,sizeof(iq_fh->oaiid)) == 0),
......@@ -92,8 +115,8 @@ static int iqplayer_loadfile(openair0_device *device, openair0_config_t *openair
fstat(s->fd, &sb);
s->mapsize=sb.st_size;
LOG_I(HW, "Loading %u subframes from %s,size=%lu bytes ...\n",s->nbSamplesBlocks, c->u_sf_filename,(uint64_t)sb.st_size);
// allocate buffer for 1 sample at a time
s->ms_sample = (iqrec_t *) malloc(sizeof(iqrec_t)+MAX_BELL_LABS_IQ_BYTES_PER_SF*4);
// allocate buffer for 1 subframe at a time
s->ms_sample = (iqrec_t *) malloc(sizeof(iqrec_t)+BELL_LABS_IQ_BYTES_PER_SF);
if (s->ms_sample == NULL) {
LOG_E(HW,"Memory allocation failed for individual subframe replay mode.\n" );
......@@ -120,6 +143,56 @@ static int iqplayer_loadfile(openair0_device *device, openair0_config_t *openair
return 0;
}
/*! \brief print the device statistics
* \param device the hardware to use
* \returns 0 on success
*/
static int trx_iqplayer_get_stats(openair0_device *device)
{
LOG_I(HW, "trx_iqplayer_get_stats() called, not implemented\n");
return 0;
}
/*! \brief Reset device statistics
* \param device the hardware to use
* \returns 0 in success
*/
static int trx_iqplayer_reset_stats(openair0_device *device)
{
LOG_I(HW, "trx_iqplayer_reset_stats() called, not implemented\n");
return 0;
}
/*! \brief Stop operation of the transceiver
*/
static int trx_iqplayer_stop(openair0_device *device)
{
LOG_I(HW, "trx_iqplayer_stop() called, not implemented\n");
return 0;
}
/*! \brief Set RX frequencies
* \param device the hardware to use
* \param openair0_cfg RF frontend parameters set by application
* \returns 0 in success
*/
static int trx_iqplayer_set_freq(openair0_device *device, openair0_config_t *openair0_cfg)
{
LOG_I(HW, "trx_iqplayer_set_freq() called, not implemented\n");
return 0;
}
/*! \brief Set gains
* \param device the hardware to use
* \param openair0_cfg RF frontend parameters set by application
* \returns 0 in success
*/
static int trx_iqplayer_set_gains(openair0_device *device, openair0_config_t *openair0_cfg)
{
LOG_I(HW, "trx_iqplayer_set_gains() called, not implemented\n");
return 0;
}
/*! \brief start the oai iq player
* \param device, the hardware used
*/
......@@ -181,24 +254,28 @@ static int trx_iqplayer_write(openair0_device *device, openair0_timestamp timest
*/
static int trx_iqplayer_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int cc) {
recplay_state_t *s = device->recplay_state;
static struct timeval tprev;
static int read_count = 0;
if (s->curSamplesBlock==0 && s->wrap_count==0) {
s->currentTs=s->ms_sample->ts;
tprev.tv_sec = s->ms_sample->tv_sec;
tprev.tv_usec = s->ms_sample->tv_usec;
LOG_I(HW, "First timestamp=%lu s->nbSamplesBlocks=%u\n", s->currentTs, s->nbSamplesBlocks);
}
if (s->curSamplesBlock == s->nbSamplesBlocks) {
LOG_I(HW, "wrapping on iq file (%ld)\n", s->wrap_count);
s->curSamplesBlock = 0;
s->wrap_count++;
if (s->wrap_count == device->openair0_cfg->recplay_conf->u_sf_loops) {
LOG_W(HW, "iqplayer device terminating subframes replay after %u iteration\n",
device->openair0_cfg->recplay_conf->u_sf_loops);
exit_function(__FILE__, __FUNCTION__, __LINE__,"replay ended, triggering process termination\n");
exit_function(__FILE__, __FUNCTION__, __LINE__,"replay ended, triggering process termination\n", OAI_EXIT_NORMAL);
}
LOG_I(HW,"go back at the beginning of IQ file");
if (s->wrap_count > 0) {
LOG_I(HW, "wrapping on iq file (%ld)\n", s->wrap_count);
}
s->curSamplesBlock = 0;
s->wrap_count++;
device->recplay_state->currentPtr=(uint8_t *)device->recplay_state->ms_sample;
if (!(device->openair0_cfg->recplay_conf->use_mmap) ) {
......@@ -210,20 +287,23 @@ static int trx_iqplayer_read(openair0_device *device, openair0_timestamp *ptimes
if (!(device->openair0_cfg->recplay_conf->use_mmap)) {
// read sample from file
if (read(s->fd, s->ms_sample, sizeof(iqrec_t)) != sizeof(iqrec_t)) {
LOG_E(HW,"pb reading iqfile at index %lu %s\n",sizeof(iqrec_t)*s->curSamplesBlock, strerror(errno) );
LOG_E(HW,"pb reading iq record header at index %lu %s\n",sizeof(iqrec_t)*s->curSamplesBlock, strerror(errno) );
exit(-1);
} else {
if (read(s->fd, s->ms_sample+1, s->ms_sample->nbBytes) != s->ms_sample->nbBytes) {
LOG_E(HW,"pb reading iqfile at index %lu %s\n",sizeof(iqrec_t)*s->curSamplesBlock, strerror(errno) );
if (read(s->fd, s->ms_sample+1, BELL_LABS_IQ_BYTES_PER_SF) != BELL_LABS_IQ_BYTES_PER_SF) {
LOG_E(HW,"pb reading iq record data at index %lu %s\n",sizeof(iqrec_t)*s->curSamplesBlock, strerror(errno) );
exit(-1);
}
}
}
iqrec_t *curHeader=(iqrec_t *)s->currentPtr;
AssertFatal(curHeader->header==BELL_LABS_IQ_HEADER,"" );
if (curHeader->header != BELL_LABS_IQ_HEADER) {
LOG_I(HW,"Problem iq header nsamps %d\n", nsamps);
AssertFatal(curHeader->header==BELL_LABS_IQ_HEADER,"" );
}
// the current timestamp is the stored timestamp until we wrap on input
AssertFatal(nsamps*4==curHeader->nbBytes,"");
AssertFatal(nsamps*4==curHeader->nbBytes,"nsamps=%d curHeader->nbBytes=%d", (int)nsamps, (int)curHeader->nbBytes);
*ptimestamp = s->currentTs;
memcpy(buff[0], curHeader+1, nsamps*4);
s->curSamplesBlock++;
......@@ -231,33 +311,40 @@ static int trx_iqplayer_read(openair0_device *device, openair0_timestamp *ptimes
s->currentTs+=nsamps;
if (device->openair0_cfg->recplay_conf->use_mmap)
s->currentPtr+=sizeof(iqrec_t)+s->ms_sample->nbBytes;
s->currentPtr+=sizeof(iqrec_t)+BELL_LABS_IQ_BYTES_PER_SF;
// BMC TODO: support 1 second or more subframe read delay
struct timespec req;
req.tv_sec = 0;
req.tv_nsec = (device->openair0_cfg[0].recplay_conf->u_sf_read_delay) * 1000;
nanosleep(&req, NULL);
LOG_D(HW, "returning %d samples at ts %lu\n", nsamps, *ptimestamp);
// subframe read delay is not taken into account
// Real time interval is handle to mimic RF board latcency
struct timeval tcur, tdiff;
tcur.tv_sec = curHeader->tv_sec;
tcur.tv_usec = curHeader->tv_usec;
timersub(&tcur, &tprev, &tdiff);
if (tdiff.tv_usec > 0) {
busy_wait(tdiff.tv_usec);
}
tprev = tcur;
read_count++;
LOG_D(HW, "returning %d samples at ts %lu read_count %d\n", nsamps, *ptimestamp, read_count);
return nsamps;
}
int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
device->openair0_cfg = openair0_cfg;
device->trx_start_func = trx_iqplayer_start;
device->trx_get_stats_func = NULL;
device->trx_reset_stats_func = NULL;
device->trx_end_func = trx_iqplayer_end;
device->trx_stop_func = NULL;
device->trx_set_freq_func = NULL;
device->trx_set_gains_func = NULL;
device->trx_get_stats_func = trx_iqplayer_get_stats;
device->trx_reset_stats_func = trx_iqplayer_reset_stats;
device->trx_end_func = trx_iqplayer_end;
device->trx_stop_func = trx_iqplayer_stop;
device->trx_set_freq_func = trx_iqplayer_set_freq;
device->trx_set_gains_func = trx_iqplayer_set_gains;
// Replay subframes from from file
// openair0_cfg[0].rx_gain_calib_table = calib_table_b210_38;
// bw_gain_adjust=1;
device->trx_write_func = trx_iqplayer_write;
device->trx_read_func = trx_iqplayer_read;
iqplayer_loadfile(device, openair0_cfg);
LOG_UI(HW,"iqplayer device initialized, replay %s for %i iterations",openair0_cfg->recplay_conf->u_sf_filename,openair0_cfg->recplay_conf->u_sf_loops);
LOG_UI(HW,"iqplayer device initialized, replay %s for %i iteration(s)\n",openair0_cfg->recplay_conf->u_sf_filename,openair0_cfg->recplay_conf->u_sf_loops);
return 0;
}
/*@}*/
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