add config options for rfsimulator, set a common lib for l1sim and rfsimulator, avoid simulation sources to be added twice in some execs (tau.c)

This commit is contained in:
frtabu
2019-07-31 18:31:02 +02:00
parent 4d073a75bb
commit 7995f413ef
7 changed files with 1125 additions and 1039 deletions
+14 -4
View File
@@ -172,7 +172,7 @@ int config_get_processedint(paramdef_t *cfgoption) {
return ret;
}
void config_printhelp(paramdef_t *params,int numparams, char *prefix) {
printf("\n-----Help for section %-26s: %03i entries------\n",(prefix==NULL)?"(root section)":prefix ,numparams);
printf("\n-----Help for section %-26s: %03i entries------\n",(prefix==NULL)?"(root section)":prefix,numparams);
for (int i=0 ; i<numparams ; i++) {
printf(" %s%s: %s",
@@ -204,6 +204,16 @@ int config_execcheck(paramdef_t *params,int numparams, char *prefix) {
return st;
}
int config_paramidx_fromname(paramdef_t *params,int numparams, char *name) {
for (int i=0; i<numparams ; i++) {
if (strcmp(name,params[i].optname) == 0)
return i;
}
fprintf(stderr,"[CONFIG]config_paramidx_fromname , %s is not a valid parameter name\n",name);
return -1;
}
int config_get(paramdef_t *params,int numparams, char *prefix) {
int ret= -1;
@@ -438,7 +448,7 @@ int config_setdefault_intlist(paramdef_t *cfgoptions, char *prefix) {
status=1;
for (int j=0; j<cfgoptions->numelt ; j++) {
printf_params("[CONFIG] %s[%i] set to default value %i\n",cfgoptions->optname ,j,(int)cfgoptions->iptr[j]);
printf_params("[CONFIG] %s[%i] set to default value %i\n",cfgoptions->optname,j,(int)cfgoptions->iptr[j]);
}
}
@@ -452,7 +462,7 @@ int config_setdefault_double(paramdef_t *cfgoptions, char *prefix) {
if( ((cfgoptions->paramflags & PARAMFLAG_MANDATORY) == 0)) {
*(cfgoptions->dblptr)=cfgoptions->defdblval;
status=1;
printf_params("[CONFIG] %s set to default value %lf\n",cfgoptions->optname , *(cfgoptions->dblptr));
printf_params("[CONFIG] %s set to default value %lf\n",cfgoptions->optname, *(cfgoptions->dblptr));
}
return status;
@@ -460,7 +470,7 @@ int config_setdefault_double(paramdef_t *cfgoptions, char *prefix) {
int config_assign_ipv4addr(paramdef_t *cfgoptions, char *ipv4addr) {
config_check_valptr(cfgoptions,(char **)&(cfgoptions->uptr), sizeof(int));
int rst=inet_pton(AF_INET, ipv4addr ,cfgoptions->uptr );
int rst=inet_pton(AF_INET, ipv4addr,cfgoptions->uptr );
if (rst == 1 && *(cfgoptions->uptr) > 0) {
printf_params("[CONFIG] %s: %s\n",cfgoptions->optname, ipv4addr);
+3
View File
@@ -39,6 +39,7 @@ extern "C"
{
#endif
/* utility functions to ease usage of config module structures */
#define CONFIG_GETSOURCE ( (config_get_if()==NULL) ? NULL : config_get_if()->cfgmode )
#define CONFIG_GETNUMP ( (config_get_if()==NULL) ? 0 : config_get_if()->num_cfgP )
#define CONFIG_GETP(P) ( (config_get_if()==NULL) ? NULL : config_get_if()->cfgP[P] )
@@ -46,6 +47,8 @@ extern "C"
#define CONFIG_SETRTFLAG(P) if (config_get_if()) { config_get_if()->rtflags |= P; }
#define CONFIG_CLEARRTFLAG(P) if (config_get_if()) { config_get_if()->rtflags &= (~P); }
#define CONFIG_ISPARAMFLAGSET(P,F) ( !!(P.paramflags & F))
extern int config_paramidx_fromname(paramdef_t *params,int numparams, char *name);
/* utility functions, to be used by configuration module and/or configuration libraries */
extern configmodule_interface_t *config_get_if(void);
extern char *config_check_valptr(paramdef_t *cfgoptions, char **ptr, int length) ;
+4 -4
View File
@@ -123,7 +123,7 @@ void client_printf(const char *message, ...) {
if (telnetparams.new_socket > 0) {
vsnprintf(telnetparams.msgbuff,sizeof(telnetparams.msgbuff)-1,message, va_args);
send(telnetparams.new_socket,telnetparams.msgbuff , strlen(telnetparams.msgbuff), MSG_NOSIGNAL);
send(telnetparams.new_socket,telnetparams.msgbuff, strlen(telnetparams.msgbuff), MSG_NOSIGNAL);
} else {
vprintf(message, va_args);
}
@@ -475,7 +475,7 @@ int process_command(char *buf) {
memset(cmdb,0,sizeof(cmdb));
bufbck=strdup(buf);
rt=CMDSTATUS_NOTFOUND;
j = sscanf(buf,"%9s %9s %9[^\t\n]",modulename,cmd,cmdb);
j = sscanf(buf,"%19s %19s %19[^\t\n]",modulename,cmd,cmdb);
if (telnetparams.telnetdbg > 0)
printf("process_command: %i words, module=%s cmd=%s, parameters= %s\n",j,modulename,cmd,cmdb);
@@ -543,7 +543,7 @@ void run_telnetsrv(void) {
char buf[TELNET_MAX_MSGLENGTH];
struct sockaddr cli_addr;
unsigned int cli_len = sizeof(cli_addr);
int readc , filled;
int readc, filled;
int status;
int optval = 1;
pthread_setname_np(pthread_self(), "telnet");
@@ -604,7 +604,7 @@ void run_telnetsrv(void) {
}
if (telnetparams.telnetdbg > 0)
printf("[TELNETSRV] Command received: readc %i filled %i \"%s\"\n", readc, filled ,buf);
printf("[TELNETSRV] Command received: readc %i filled %i \"%s\"\n", readc, filled,buf);
if (buf[0] == '!') {
if (buf[1] == '!') {
+34 -32
View File
@@ -122,7 +122,6 @@ void handle_nfapi_hi_dci0_hi_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxt
phich->config[phich->num_hi].n_DMRS = hi_dci0_config_pdu->hi_pdu.hi_pdu_rel8.cyclic_shift_2_for_drms;
phich->num_hi++;
AssertFatal(phich->num_hi<32,"Maximum number of phich reached in subframe\n");
}
void handle_nfapi_bch_pdu(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc,
@@ -186,6 +185,7 @@ void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_pro
#endif
harq_pid = dlsch0->harq_ids[proc->frame_tx%2][proc->subframe_tx];
if((harq_pid < 0) || (harq_pid >= dlsch0->Mdlharq)) {
LOG_E(PHY,"illegal harq_pid %d %s:%d\n", harq_pid, __FILE__, __LINE__);
return;
@@ -260,9 +260,7 @@ void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_pro
dlsch0->harq_mask = 1;
dlsch0_harq = dlsch0->harq_processes[0];
dlsch0_harq->pdu = sdu;
LOG_D(PHY,"NFAPI: frame %d, subframe %d (TX %d.%d): Programming SI-BR (%d) => %d\n",frame,subframe,proc->frame_tx,proc->subframe_tx,rel13->pdsch_payload_type,UE_id);
dlsch0->rnti = 0xFFFF;
dlsch0->Kmimo = 1;
dlsch0->Mdlharq = 4;
@@ -569,8 +567,7 @@ void handle_uci_sr_pdu(PHY_VARS_eNB *eNB,
nfapi_ul_config_request_pdu_t *ul_config_pdu,
uint16_t frame,
uint8_t subframe,
uint8_t srs_active)
{
uint8_t srs_active) {
LTE_eNB_UCI *uci = &eNB->uci_vars[UE_id];
if (NFAPI_MODE==NFAPI_MODE_VNF) return;
@@ -803,13 +800,13 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) {
// clear DCI allocation maps for new subframe
if (NFAPI_MODE!=NFAPI_MODE_VNF)
for (i=0; i<NUMBER_OF_UE_MAX; i++) {
if (eNB->ulsch[i]) {
ulsch_harq = eNB->ulsch[i]->harq_processes[harq_pid];
ulsch_harq->dci_alloc=0;
ulsch_harq->rar_alloc=0;
for (i=0; i<NUMBER_OF_UE_MAX; i++) {
if (eNB->ulsch[i]) {
ulsch_harq = eNB->ulsch[i]->harq_processes[harq_pid];
ulsch_harq->dci_alloc=0;
ulsch_harq->rar_alloc=0;
}
}
}
}
for (i=0; i<number_dl_pdu; i++) {
@@ -820,6 +817,7 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) {
case NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE:
if (NFAPI_MODE!=NFAPI_MODE_VNF)
handle_nfapi_dci_dl_pdu(eNB,NFAPI_SFNSF2SFN(DL_req->sfn_sf),NFAPI_SFNSF2SF(DL_req->sfn_sf),proc,dl_config_pdu);
eNB->pdcch_vars[NFAPI_SFNSF2SF(DL_req->sfn_sf)&1].num_dci++;
//LOG_E(PHY,"Incremented num_dci:%d but already set??? dl_config:num_dci:%d\n", eNB->pdcch_vars[subframe&1].num_dci, number_dci);
do_oai=1;
@@ -832,11 +830,13 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) {
TX_req->tx_request_body.number_of_pdus);
eNB->pbch_configured=1;
do_oai=1;
//LOG_D(PHY,"%s() NFAPI_DL_CONFIG_BCH_PDU_TYPE TX:%d/%d RX:%d/%d TXREQ:%d/%d\n",
//__FUNCTION__, proc->frame_tx, proc->subframe_tx, proc->frame_rx, proc->subframe_rx, NFAPI_SFNSF2SFN(TX_req->sfn_sf), NFAPI_SFNSF2SF(TX_req->sfn_sf));
if (NFAPI_MODE!=NFAPI_MODE_VNF)
handle_nfapi_bch_pdu(eNB,proc,dl_config_pdu,
TX_req->tx_request_body.tx_pdu_list[dl_config_pdu->bch_pdu.bch_pdu_rel8.pdu_index].segments[0].segment_data);
TX_req->tx_request_body.tx_pdu_list[dl_config_pdu->bch_pdu.bch_pdu_rel8.pdu_index].segments[0].segment_data);
break;
case NFAPI_DL_CONFIG_MCH_PDU_TYPE:
@@ -867,8 +867,8 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) {
dlsch_pdu_rel8->transport_blocks);
if (1) { //sdu != NULL)
if (NFAPI_MODE!=NFAPI_MODE_VNF)
handle_nfapi_dlsch_pdu(eNB,NFAPI_SFNSF2SFN(DL_req->sfn_sf),NFAPI_SFNSF2SF(DL_req->sfn_sf),proc,dl_config_pdu, dlsch_pdu_rel8->transport_blocks-1, sdu);
if (NFAPI_MODE!=NFAPI_MODE_VNF)
handle_nfapi_dlsch_pdu(eNB,NFAPI_SFNSF2SFN(DL_req->sfn_sf),NFAPI_SFNSF2SF(DL_req->sfn_sf),proc,dl_config_pdu, dlsch_pdu_rel8->transport_blocks-1, sdu);
} else {
dont_send=1;
LOG_E(MAC,"%s() NFAPI_DL_CONFIG_DLSCH_PDU_TYPE sdu is NULL DL_CFG:SFN/SF:%d:pdu_index:%d TX_REQ:SFN/SF:%d:pdus:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(DL_req->sfn_sf), pdu_index,
@@ -911,6 +911,7 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) {
case NFAPI_DL_CONFIG_MPDCCH_PDU_TYPE:
if (NFAPI_MODE!=NFAPI_MODE_VNF)
handle_nfapi_mpdcch_pdu(eNB,proc,dl_config_pdu);
eNB->mpdcch_vars[subframe&1].num_dci++;
break;
#endif
@@ -918,10 +919,11 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) {
}
if ((NFAPI_MODE!=NFAPI_MONOLITHIC) && do_oai && !dont_send) {
if(Sched_INFO->TX_req->tx_request_body.number_of_pdus > 0){
if(Sched_INFO->TX_req->tx_request_body.number_of_pdus > 0) {
Sched_INFO->TX_req->sfn_sf = frame << 4 | subframe;
oai_nfapi_tx_req(Sched_INFO->TX_req);
}
Sched_INFO->DL_req->sfn_sf = frame << 4 | subframe;
oai_nfapi_dl_config_req(Sched_INFO->DL_req); // DJP - .dl_config_request_body.dl_config_pdu_list[0]); // DJP - FIXME TODO - yuk - only copes with 1 pdu
Sched_INFO->UE_release_req->sfn_sf = frame << 4 | subframe;
@@ -935,27 +937,27 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) {
eNB->pdcch_vars[NFAPI_SFNSF2SF(HI_DCI0_req->sfn_sf)&1].num_pdcch_symbols=0;
}
if (NFAPI_MODE!=NFAPI_MODE_VNF)
for (i=0; i<number_hi_dci0_pdu; i++) {
hi_dci0_req_pdu = &HI_DCI0_req->hi_dci0_request_body.hi_dci0_pdu_list[i];
LOG_D(PHY,"NFAPI: hi_dci0_pdu %d : type %d\n",i,hi_dci0_req_pdu->pdu_type);
if (NFAPI_MODE!=NFAPI_MODE_VNF)
for (i=0; i<number_hi_dci0_pdu; i++) {
hi_dci0_req_pdu = &HI_DCI0_req->hi_dci0_request_body.hi_dci0_pdu_list[i];
LOG_D(PHY,"NFAPI: hi_dci0_pdu %d : type %d\n",i,hi_dci0_req_pdu->pdu_type);
switch (hi_dci0_req_pdu->pdu_type) {
case NFAPI_HI_DCI0_DCI_PDU_TYPE:
handle_nfapi_hi_dci0_dci_pdu(eNB,NFAPI_SFNSF2SFN(HI_DCI0_req->sfn_sf),NFAPI_SFNSF2SF(HI_DCI0_req->sfn_sf),proc,hi_dci0_req_pdu);
eNB->pdcch_vars[NFAPI_SFNSF2SF(HI_DCI0_req->sfn_sf)&1].num_dci++;
break;
switch (hi_dci0_req_pdu->pdu_type) {
case NFAPI_HI_DCI0_DCI_PDU_TYPE:
handle_nfapi_hi_dci0_dci_pdu(eNB,NFAPI_SFNSF2SFN(HI_DCI0_req->sfn_sf),NFAPI_SFNSF2SF(HI_DCI0_req->sfn_sf),proc,hi_dci0_req_pdu);
eNB->pdcch_vars[NFAPI_SFNSF2SF(HI_DCI0_req->sfn_sf)&1].num_dci++;
break;
case NFAPI_HI_DCI0_MPDCCH_DCI_PDU_TYPE:
handle_nfapi_hi_dci0_mpdcch_dci_pdu(eNB,proc,hi_dci0_req_pdu);
eNB->mpdcch_vars[subframe&1].num_dci++;
break;
case NFAPI_HI_DCI0_MPDCCH_DCI_PDU_TYPE:
handle_nfapi_hi_dci0_mpdcch_dci_pdu(eNB,proc,hi_dci0_req_pdu);
eNB->mpdcch_vars[subframe&1].num_dci++;
break;
case NFAPI_HI_DCI0_HI_PDU_TYPE:
handle_nfapi_hi_dci0_hi_pdu(eNB,NFAPI_SFNSF2SFN(HI_DCI0_req->sfn_sf),NFAPI_SFNSF2SF(HI_DCI0_req->sfn_sf),proc,hi_dci0_req_pdu);
break;
case NFAPI_HI_DCI0_HI_PDU_TYPE:
handle_nfapi_hi_dci0_hi_pdu(eNB,NFAPI_SFNSF2SFN(HI_DCI0_req->sfn_sf),NFAPI_SFNSF2SF(HI_DCI0_req->sfn_sf),proc,hi_dci0_req_pdu);
break;
}
}
}
if (NFAPI_MODE!=NFAPI_MONOLITHIC) {
if (number_ul_pdu>0) {
File diff suppressed because it is too large Load Diff
+63 -22
View File
@@ -147,7 +147,7 @@ typedef struct {
/// Rice factor???
/// Walls (penetration loss)
/// Nodes in the scenario
node_desc_t* nodes;
node_desc_t *nodes;
} scenario_desc_t;
typedef enum {
@@ -180,29 +180,59 @@ typedef enum {
EPA_medium,
EPA_high,
} SCM_t;
#define CHANNELMOD_MAP_INIT \
{"custom",custom},\
{"SCM_A",SCM_A},\
{"SCM_B",SCM_B},\
{"SCM_C",SCM_C},\
{"SCM_D",SCM_D},\
{"EPA",EPA},\
{"EVA",EVA},\
{"ETU",ETU},\
{"MBSFN",MBSFN},\
{"Rayleigh8",Rayleigh8},\
{"Rayleigh1",Rayleigh1},\
{"Rayleigh1_800",Rayleigh1_800},\
{"Rayleigh1_corr",Rayleigh1_corr},\
{"Rayleigh1_anticorr",Rayleigh1_anticorr},\
{"Rice8",Rice8},\
{"Rice1",Rice1},\
{"Rice1_corr",Rice1_corr},\
{"Rice1_anticorr",Rice1_anticorr},\
{"AWGN",AWGN},\
{"Rayleigh1_orthogonal",Rayleigh1_orthogonal},\
{"Rayleigh1_orth_eff_ch_TM4_prec_real",Rayleigh1_orth_eff_ch_TM4_prec_real},\
{"Rayleigh1_orth_eff_ch_TM4_prec_imag",Rayleigh1_orth_eff_ch_TM4_prec_imag},\
{"Rayleigh8_orth_eff_ch_TM4_prec_real",Rayleigh8_orth_eff_ch_TM4_prec_real},\
{"Rayleigh8_orth_eff_ch_TM4_prec_imag",Rayleigh8_orth_eff_ch_TM4_prec_imag},\
{"TS_SHIFT",TS_SHIFT},\
{"EPA_low",EPA_low},\
{"EPA_medium",EPA_medium},\
{"EPA_high",EPA_high},\
{NULL, -1}
#include "platform_constants.h"
typedef struct {
channel_desc_t *RU2UE[NUMBER_OF_RU_MAX][NUMBER_OF_UE_MAX][MAX_NUM_CCs];
channel_desc_t *UE2RU[NUMBER_OF_UE_MAX][NUMBER_OF_RU_MAX][MAX_NUM_CCs];
double r_re_DL[NUMBER_OF_UE_MAX][2][30720];
double r_im_DL[NUMBER_OF_UE_MAX][2][30720];
double r_re_UL[NUMBER_OF_eNB_MAX][2][30720];
double r_im_UL[NUMBER_OF_eNB_MAX][2][30720];
int RU_output_mask[NUMBER_OF_UE_MAX];
int UE_output_mask[NUMBER_OF_RU_MAX];
pthread_mutex_t RU_output_mutex[NUMBER_OF_UE_MAX];
pthread_mutex_t UE_output_mutex[NUMBER_OF_RU_MAX];
pthread_mutex_t subframe_mutex;
int subframe_ru_mask;
int subframe_UE_mask;
openair0_timestamp current_ru_rx_timestamp[NUMBER_OF_RU_MAX][MAX_NUM_CCs];
openair0_timestamp current_UE_rx_timestamp[MAX_MOBILES_PER_ENB][MAX_NUM_CCs];
openair0_timestamp last_ru_rx_timestamp[NUMBER_OF_RU_MAX][MAX_NUM_CCs];
openair0_timestamp last_UE_rx_timestamp[MAX_MOBILES_PER_ENB][MAX_NUM_CCs];
double ru_amp[NUMBER_OF_RU_MAX];
pthread_t rfsim_thread;
channel_desc_t *RU2UE[NUMBER_OF_RU_MAX][NUMBER_OF_UE_MAX][MAX_NUM_CCs];
channel_desc_t *UE2RU[NUMBER_OF_UE_MAX][NUMBER_OF_RU_MAX][MAX_NUM_CCs];
double r_re_DL[NUMBER_OF_UE_MAX][2][30720];
double r_im_DL[NUMBER_OF_UE_MAX][2][30720];
double r_re_UL[NUMBER_OF_eNB_MAX][2][30720];
double r_im_UL[NUMBER_OF_eNB_MAX][2][30720];
int RU_output_mask[NUMBER_OF_UE_MAX];
int UE_output_mask[NUMBER_OF_RU_MAX];
pthread_mutex_t RU_output_mutex[NUMBER_OF_UE_MAX];
pthread_mutex_t UE_output_mutex[NUMBER_OF_RU_MAX];
pthread_mutex_t subframe_mutex;
int subframe_ru_mask;
int subframe_UE_mask;
openair0_timestamp current_ru_rx_timestamp[NUMBER_OF_RU_MAX][MAX_NUM_CCs];
openair0_timestamp current_UE_rx_timestamp[MAX_MOBILES_PER_ENB][MAX_NUM_CCs];
openair0_timestamp last_ru_rx_timestamp[NUMBER_OF_RU_MAX][MAX_NUM_CCs];
openair0_timestamp last_UE_rx_timestamp[MAX_MOBILES_PER_ENB][MAX_NUM_CCs];
double ru_amp[NUMBER_OF_RU_MAX];
pthread_t rfsim_thread;
} sim_t;
@@ -231,7 +261,7 @@ typedef struct {
channel_desc_t *new_channel_desc_scm(uint8_t nb_tx,
uint8_t nb_rx,
SCM_t channel_model,
double sampling_rate,
double sampling_rate,
double channel_bandwidth,
double forgetting_factor,
int32_t channel_offset,
@@ -395,9 +425,19 @@ void multipath_tv_channel(channel_desc_t *desc,
/**@} */
/**@} */
void rxAddInput( struct complex16 *input_sig, struct complex16 *after_channel_sig,
int rxAnt,
channel_desc_t *channelDesc,
int nbSamples,
uint64_t TS,
uint32_t CirSize
);
void init_channelmod(void) ;
double N_RB2sampling_rate(uint16_t N_RB);
double N_RB2channel_bandwidth(uint16_t N_RB);
#include "targets/RT/USER/rfsim.h"
void do_DL_sig(sim_t *sim,
@@ -409,9 +449,10 @@ void do_DL_sig(sim_t *sim,
int CC_id);
void do_UL_sig(sim_t *sim,
uint16_t subframe,uint8_t abstraction_flag,LTE_DL_FRAME_PARMS *frame_parms,
uint16_t subframe,uint8_t abstraction_flag,LTE_DL_FRAME_PARMS *frame_parms,
uint32_t frame,int ru_id,uint8_t CC_id);
#endif
+87 -151
View File
@@ -29,6 +29,7 @@
#include "common_lib.h"
#include <openair1/PHY/defs_eNB.h>
#include "openair1/PHY/defs_UE.h"
#define CHANNELMOD_DYNAMICLOAD
#include <openair1/SIMULATION/TOOLS/sim.h>
#define PORT 4043 //default TCP port for this simulator
@@ -44,25 +45,26 @@
extern double snr_dB;
extern RAN_CONTEXT_t RC;
//
#define MAX_RFSIMU_OPT 2
#define RFSIMU_SECTION "rfsimulator"
#define RFSIMU_OPTIONS_PARAMNAME "options"
# define RFSIM_CONFIG_HELP_OPTIONS " list of comma separated options to enable rf simulator functionalities. Available options: \n"\
" chanmod: enable channel modelisation\n"\
" saviq: enable saving written iqs to a file\n"
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
/* configuration parameters for the rfsimulator device */
/* optname helpstr paramflags XXXptr defXXXval type numelt */
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
/* configuration parameters for the rfsimulator device */
/* optname helpstr paramflags XXXptr defXXXval type numelt */
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
#define RFSIMULATOR_PARAMS_DESC {\
{"serveraddr", "<ip address to connect to>\n", 0, strptr:&(rfsimulator->ip), defstrval:"127.0.0.1", TYPE_STRING, 0 },\
{"serverport", "<port to connect to>\n", 0, u16ptr:&(rfsimulator->port), defuintval:PORT, TYPE_UINT16, 0 },\
{RFSIMU_OPTIONS_PARAMNAME, RFSIM_CONFIG_HELP_OPTIONS, 0, strlistptr:NULL, defstrlistval:NULL, TYPE_STRINGLIST,0}, \
{"IQfile", "<file path to use when saving IQs>\n", 0, strptr:&(saveF), defstrval:"/tmp/rfsimulator.iqs",TYPE_STRING, 0 }\
};
{"serveraddr", "<ip address to connect to>\n", 0, strptr:&(rfsimulator->ip), defstrval:"127.0.0.1", TYPE_STRING, 0 },\
{"serverport", "<port to connect to>\n", 0, u16ptr:&(rfsimulator->port), defuintval:PORT, TYPE_UINT16, 0 },\
{RFSIMU_OPTIONS_PARAMNAME, RFSIM_CONFIG_HELP_OPTIONS, 0, strlistptr:NULL, defstrlistval:NULL, TYPE_STRINGLIST,0}, \
{"IQfile", "<file path to use when saving IQs>\n", 0, strptr:&(saveF), defstrval:"/tmp/rfsimulator.iqs",TYPE_STRING, 0 }\
};
pthread_mutex_t Sockmutex;
typedef struct buffer_s {
int conn_sock;
openair0_timestamp lastReceivedTS;
@@ -88,84 +90,9 @@ typedef struct {
int tx_num_channels;
double sample_rate;
double tx_bw;
bool enable_channelmod;
} rfsimulator_state_t;
/*
Legacy study:
The parameters are:
gain&loss (decay, signal power, ...)
either a fixed gain in dB, a target power in dBm or ACG (automatic control gain) to a target average
=> don't redo the AGC, as it was used in UE case, that must have a AGC inside the UE
will be better to handle the "set_gain()" called by UE to apply it's gain (enable test of UE power loop)
lin_amp = pow(10.0,.05*txpwr_dBm)/sqrt(nb_tx_antennas);
a lot of operations in legacy, grouped in one simulation signal decay: txgain*decay*rxgain
multi_path (auto convolution, ISI, ...)
either we regenerate the channel (call again random_channel(desc,0)), or we keep it over subframes
legacy: we regenerate each sub frame in UL, and each frame only in DL
*/
void rxAddInput( struct complex16 *input_sig, struct complex16 *after_channel_sig,
int rxAnt,
channel_desc_t *channelDesc,
int nbSamples,
uint64_t TS
) {
// channelDesc->path_loss_dB should contain the total path gain
// so, in actual RF: tx gain + path loss + rx gain (+antenna gain, ...)
// UE and NB gain control to be added
// Fixme: not sure when it is "volts" so dB is 20*log10(...) or "power", so dB is 10*log10(...)
const double pathLossLinear = pow(10,channelDesc->path_loss_dB/20.0);
// Energy in one sample to calibrate input noise
//Fixme: modified the N0W computation, not understand the origin value
const double KT=1.38e-23*290; //Boltzman*temperature
// sampling rate is linked to acquisition band (the input pass band filter)
const double noise_figure_watt = KT*channelDesc->sampling_rate;
// Fixme: how to convert a noise in Watt into a 12 bits value out of the RF ADC ?
// the parameter "-s" is declared as SNR, but the input power is not well defined
// −132.24 dBm is a LTE subcarrier noise, that was used in origin code (15KHz BW thermal noise)
const double rxGain= 132.24 - snr_dB;
// sqrt(4*noise_figure_watt) is the thermal noise factor (volts)
// fixme: the last constant is pure trial results to make decent noise
const double noise_per_sample = sqrt(4*noise_figure_watt) * pow(10,rxGain/20) *10;
// Fixme: we don't fill the offset length samples at begining ?
// anyway, in today code, channel_offset=0
const int dd = abs(channelDesc->channel_offset);
const int nbTx=channelDesc->nb_tx;
for (int i=0; i<((int)nbSamples-dd); i++) {
struct complex16 *out_ptr=after_channel_sig+dd+i;
struct complex rx_tmp= {0};
for (int txAnt=0; txAnt < nbTx; txAnt++) {
const struct complex *channelModel= channelDesc->ch[rxAnt+(txAnt*channelDesc->nb_rx)];
//const struct complex *channelModelEnd=channelModel+channelDesc->channel_length;
for (int l = 0; l<(int)channelDesc->channel_length; l++) {
// let's assume TS+i >= l
// fixme: the rfsimulator current structure is interleaved antennas
// this has been designed to not have to wait a full block transmission
// but it is not very usefull
// it would be better to split out each antenna in a separate flow
// that will allow to mix ru antennas freely
struct complex16 tx16=input_sig[((TS+i-l)*nbTx+txAnt)%CirSize];
rx_tmp.x += tx16.r * channelModel[l].x - tx16.i * channelModel[l].y;
rx_tmp.y += tx16.i * channelModel[l].x + tx16.r * channelModel[l].y;
} //l
}
out_ptr->r += round(rx_tmp.x*pathLossLinear + noise_per_sample*gaussdouble(0.0,1.0));
out_ptr->i += round(rx_tmp.y*pathLossLinear + noise_per_sample*gaussdouble(0.0,1.0));
out_ptr++;
}
if ( (TS*nbTx)%CirSize+nbSamples <= CirSize )
// Cast to a wrong type for compatibility !
LOG_D(HW,"Input power %f, output power: %f, channel path loss %f, noise coeff: %f \n",
10*log10((double)signal_energy((int32_t *)&input_sig[(TS*nbTx)%CirSize], nbSamples)),
10*log10((double)signal_energy((int32_t *)after_channel_sig, nbSamples)),
channelDesc->path_loss_dB,
10*log10(noise_per_sample));
}
void allocCirBuf(rfsimulator_state_t *bridge, int sock) {
buffer_t *ptr=&bridge->buf[sock];
@@ -183,26 +110,29 @@ void allocCirBuf(rfsimulator_state_t *bridge, int sock) {
ev.events = EPOLLIN | EPOLLRDHUP;
ev.data.fd = sock;
AssertFatal(epoll_ctl(bridge->epollfd, EPOLL_CTL_ADD, sock, &ev) != -1, "");
// create channel simulation model for this mode reception
// snr_dB is pure global, coming from configuration paramter "-s"
// Fixme: referenceSignalPower should come from the right place
// but the datamodel is inconsistant
// legacy: RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower
// (must not come from ru[]->frame_parms as it doesn't belong to ru !!!)
// Legacy sets it as:
// ptr->channel_model->path_loss_dB = -132.24 + snr_dB - RC.ru[0]->frame_parms->pdsch_config_common.referenceSignalPower;
// we use directly the paramter passed on the command line ("-s")
// the value channel_model->path_loss_dB seems only a storage place (new_channel_desc_scm() only copy the passed value)
// Legacy changes directlty the variable channel_model->path_loss_dB place to place
// while calling new_channel_desc_scm() with path losses = 0
ptr->channel_model=new_channel_desc_scm(bridge->tx_num_channels,bridge->rx_num_channels,
AWGN,
bridge->sample_rate,
bridge->tx_bw,
0.0, // forgetting_factor
0, // maybe used for TA
0); // path_loss in dB
random_channel(ptr->channel_model,false);
if ( bridge->enable_channelmod==true) {
// create channel simulation model for this mode reception
// snr_dB is pure global, coming from configuration paramter "-s"
// Fixme: referenceSignalPower should come from the right place
// but the datamodel is inconsistant
// legacy: RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower
// (must not come from ru[]->frame_parms as it doesn't belong to ru !!!)
// Legacy sets it as:
// ptr->channel_model->path_loss_dB = -132.24 + snr_dB - RC.ru[0]->frame_parms->pdsch_config_common.referenceSignalPower;
// we use directly the paramter passed on the command line ("-s")
// the value channel_model->path_loss_dB seems only a storage place (new_channel_desc_scm() only copy the passed value)
// Legacy changes directlty the variable channel_model->path_loss_dB place to place
// while calling new_channel_desc_scm() with path losses = 0
ptr->channel_model=new_channel_desc_scm(bridge->tx_num_channels,bridge->rx_num_channels,
AWGN,
bridge->sample_rate,
bridge->tx_bw,
0.0, // forgetting_factor
0, // maybe used for TA
0); // path_loss in dB
random_channel(ptr->channel_model,false);
}
}
void removeCirBuf(rfsimulator_state_t *bridge, int sock) {
@@ -231,6 +161,7 @@ void socketError(rfsimulator_state_t *bridge, int sock) {
rfsimulator: error: you have to run one UE and one eNB\n\
For this, export RFSIMULATOR=enb (eNB case) or \n\
RFSIMULATOR=<an ip address> (UE case)\n\
or use rfsimulator.serveraddr configuration option\n\
\x1b[m"
enum blocking_t {
@@ -284,43 +215,46 @@ void fullwrite(int fd, void *_buf, ssize_t count, rfsimulator_state_t *t) {
buf += l;
}
}
void rfsimulator_readconfig(rfsimulator_state_t *rfsimulator) {
char *saveF=NULL;
paramdef_t rfsimu_params[] = RFSIMULATOR_PARAMS_DESC;
char *saveF=NULL;
paramdef_t rfsimu_params[] = RFSIMULATOR_PARAMS_DESC;
int p = config_paramidx_fromname(rfsimu_params,sizeof(rfsimu_params)/sizeof(paramdef_t), RFSIMU_OPTIONS_PARAMNAME) ;
int ret = config_get( rfsimu_params,sizeof(rfsimu_params)/sizeof(paramdef_t),RFSIMU_SECTION);
AssertFatal(ret >= 0, "configuration couldn't be performed");
rfsimulator->saveIQfile = -1;
rfsimulator->saveIQfile = -1;
for(int i=0; i<rfsimu_params[p].numelt ; i++) {
if (strcmp(rfsimu_params[p].strlistptr[i],"saviq") == 0) {
rfsimulator->saveIQfile=open(saveF,O_APPEND| O_CREAT|O_TRUNC | O_WRONLY, 0666);
if ( rfsimulator->saveIQfile != -1 )
LOG_I(HW,"rfsimulator: will save written IQ samples in %s\n", saveF);
else
LOG_E(HW, "can't open %s for IQ saving (%s)\n", saveF, strerror(errno));
break;
} else if (strcmp(rfsimu_params[p].strlistptr[i],"chanmod") == 0) {
load_module_shlib("chanmod",NULL,0,NULL);
} else {
fprintf(stderr,"Unknown rfsimulator option: %s\n",rfsimu_params[p].strlistptr[i]);
exit(-1);
}
if (strcmp(rfsimu_params[p].strlistptr[i],"saviq") == 0) {
rfsimulator->saveIQfile=open(saveF,O_APPEND| O_CREAT|O_TRUNC | O_WRONLY, 0666);
if ( rfsimulator->saveIQfile != -1 )
LOG_I(HW,"rfsimulator: will save written IQ samples in %s\n", saveF);
else
LOG_E(HW, "can't open %s for IQ saving (%s)\n", saveF, strerror(errno));
break;
} else if (strcmp(rfsimu_params[p].strlistptr[i],"chanmod") == 0) {
init_channelmod();
rfsimulator->enable_channelmod=true;
} else {
fprintf(stderr,"Unknown rfsimulator option: %s\n",rfsimu_params[p].strlistptr[i]);
exit(-1);
}
}
/* for compatibility keep environment variable usage */
if ( getenv("RFSIMULATOR") != NULL ) {
rfsimulator->ip=getenv("RFSIMULATOR");
rfsimulator->ip=getenv("RFSIMULATOR");
}
if ( strncasecmp(rfsimulator->ip,"enb",3) == 0 ||
strncasecmp(rfsimulator->ip,"server",3) == 0 )
strncasecmp(rfsimulator->ip,"server",3) == 0 )
rfsimulator->typeStamp = ENB_MAGICDL_FDD;
else
rfsimulator->typeStamp = UE_MAGICDL_FDD;
}
int server_start(openair0_device *device) {
@@ -383,13 +317,13 @@ int rfsimulator_write(openair0_device *device, openair0_timestamp timestamp, voi
rfsimulator_state_t *t = device->priv;
LOG_D(HW,"sending %d samples at time: %ld\n", nsamps, timestamp);
for (int i=0; i<FD_SETSIZE; i++) {
buffer_t *b=&t->buf[i];
if (b->conn_sock >= 0 ) {
if ( abs((double)b->lastWroteTS-timestamp) > (double)CirSize)
LOG_E(HW,"Tx/Rx shift too large Tx:%lu, Rx:%lu\n", b->lastWroteTS, b->lastReceivedTS);
LOG_E(HW,"Tx/Rx shift too large Tx:%lu, Rx:%lu\n", b->lastWroteTS, b->lastReceivedTS);
samplesBlockHeader_t header= {t->typeStamp, nsamps, nbAnt, timestamp};
fullwrite(b->conn_sock,&header, sizeof(header), t);
sample_t tmpSamples[nsamps][nbAnt];
@@ -546,42 +480,48 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo
// no connected device (we are eNB, no UE is connected)
if ( t->nextTimestamp == 0)
LOG_W(HW,"No connected device, generating void samples...\n");
if (!flushInput(t, 10)) {
for (int x=0; x < nbAnt; x++)
memset(samplesVoid[x],0,sampleToByte(nsamps,1));
t->nextTimestamp+=nsamps;
if ( ((t->nextTimestamp/nsamps)%100) == 0)
LOG_W(HW,"Generated void samples for Rx: %ld\n", t->nextTimestamp);
*ptimestamp = t->nextTimestamp-nsamps;
pthread_mutex_unlock(&Sockmutex);
return nsamps;
}
} else {
bool have_to_wait;
do {
have_to_wait=false;
for ( int sock=0; sock<FD_SETSIZE; sock++) {
buffer_t *b=&t->buf[sock];
buffer_t *b=&t->buf[sock];
if ( b->circularBuf) {
LOG_D(HW,"sock: %d, lastWroteTS: %lu, lastRecvTS: %lu, TS must be avail: %lu\n",
sock, b->lastWroteTS,
b->lastReceivedTS,
t->nextTimestamp+nsamps);
if ( b->lastReceivedTS > b->lastWroteTS ) {
// The caller momdem (NB, UE, ...) must send Tx in advance, so we fill TX if Rx is in advance
// This occurs for example when UE is in sync mode: it doesn't transmit
// with USRP, it seems ok: if "tx stream" is off, we may consider it actually cuts the Tx power
struct complex16 v={0};
void *samplesVoid[b->th.nbAnt];
for ( int i=0; i <b->th.nbAnt; i++)
samplesVoid[i]=(void*)&v;
rfsimulator_write(device, b->lastReceivedTS, samplesVoid, 1, b->th.nbAnt, 0);
}
}
if ( b->lastReceivedTS > b->lastWroteTS ) {
// The caller momdem (NB, UE, ...) must send Tx in advance, so we fill TX if Rx is in advance
// This occurs for example when UE is in sync mode: it doesn't transmit
// with USRP, it seems ok: if "tx stream" is off, we may consider it actually cuts the Tx power
struct complex16 v= {0};
void *samplesVoid[b->th.nbAnt];
for ( int i=0; i <b->th.nbAnt; i++)
samplesVoid[i]=(void *)&v;
rfsimulator_write(device, b->lastReceivedTS, samplesVoid, 1, b->th.nbAnt, 0);
}
}
if ( b->circularBuf )
if ( t->nextTimestamp+nsamps > b->lastReceivedTS ) {
@@ -616,15 +556,17 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo
random_channel(ptr->channel_model,0);
for (int a=0; a<nbAnt; a++) {
if ( ptr->channel_model != NULL ) // apply a channel model
if ( ptr->channel_model != NULL ) // apply a channel model
rxAddInput( ptr->circularBuf, (struct complex16 *) samplesVoid[a],
a,
ptr->channel_model,
nsamps,
t->nextTimestamp
t->nextTimestamp,
CirSize
);
else { // no channel modeling
sample_t *out=(sample_t *)samplesVoid[a];
for ( int i=0; i < nsamps; i++ ) {
out[i].r+=ptr->circularBuf[((t->nextTimestamp+i)*nbAnt+a)%CirSize].r;
out[i].i+=ptr->circularBuf[((t->nextTimestamp+i)*nbAnt+a)%CirSize].i;
@@ -672,15 +614,9 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
// to change the log level, use this on command line
// --log_config.hw_log_level debug
rfsimulator_state_t *rfsimulator = (rfsimulator_state_t *)calloc(sizeof(rfsimulator_state_t),1);
rfsimulator_readconfig(rfsimulator);
pthread_mutex_init(&Sockmutex, NULL);
LOG_I(HW,"rfsimulator: running as %s\n", rfsimulator-> typeStamp == ENB_MAGICDL_FDD ? "(eg)NB" : "UE");
device->trx_start_func = rfsimulator->typeStamp == ENB_MAGICDL_FDD ?
server_start :
start_ue;