Merge remote-tracking branch 'origin/develop' into issue_345_l2_fapi_simulator_new
Signed-off-by: Raphael Defosseux <raphael.defosseux@eurecom.fr>
This commit is contained in:
+397
-476
File diff suppressed because it is too large
Load Diff
+62
-37
@@ -90,6 +90,7 @@
|
||||
#include "common/utils/LOG/vcd_signal_dumper.h"
|
||||
#include "UTIL/OPT/opt.h"
|
||||
#include "enb_config.h"
|
||||
#include "targets/RT/USER/lte-softmodem.h"
|
||||
//#include "PHY/TOOLS/time_meas.h"
|
||||
|
||||
/* these variables have to be defined before including ENB_APP/enb_paramdef.h */
|
||||
@@ -122,12 +123,13 @@ extern int numerology;
|
||||
extern clock_source_t clock_source;
|
||||
extern uint8_t dlsch_ue_select_tbl_in_use;
|
||||
extern uint8_t nfapi_mode;
|
||||
|
||||
extern PARALLEL_CONF_t get_thread_parallel_conf(void);
|
||||
extern WORKER_CONF_t get_thread_worker_conf(void);
|
||||
extern void phy_init_RU(RU_t*);
|
||||
extern void phy_free_RU(RU_t*);
|
||||
|
||||
void init_RU(char*);
|
||||
|
||||
void stop_RU(int nb_ru);
|
||||
void do_ru_sync(RU_t *ru);
|
||||
|
||||
@@ -705,6 +707,7 @@ static void* emulatedRF_thread(void* param) {
|
||||
RU_proc_t *proc = (RU_proc_t *) param;
|
||||
int microsec = 500; // length of time to sleep, in miliseconds
|
||||
struct timespec req = {0};
|
||||
int numerology = get_softmodem_params()->numerology;
|
||||
req.tv_sec = 0;
|
||||
req.tv_nsec = (numerology>0)? ((microsec * 1000L)/numerology):(microsec * 1000L)*2;
|
||||
cpu_set_t cpuset;
|
||||
@@ -749,7 +752,7 @@ void rx_rf(RU_t *ru,int *frame,int *subframe) {
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 );
|
||||
|
||||
old_ts = proc->timestamp_rx;
|
||||
if(emulate_rf){
|
||||
if(get_softmodem_params()->emulate_rf){
|
||||
wait_on_condition(&proc->mutex_emulateRF,&proc->cond_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread");
|
||||
release_thread(&proc->mutex_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread");
|
||||
rxs = fp->samples_per_tti;
|
||||
@@ -767,9 +770,9 @@ void rx_rf(RU_t *ru,int *frame,int *subframe) {
|
||||
proc->timestamp_rx = ts-ru->ts_offset;
|
||||
|
||||
// AssertFatal(rxs == fp->samples_per_tti,
|
||||
// "rx_rf: Asked for %d samples, got %d from USRP\n",fp->samples_per_tti,rxs);
|
||||
// "rx_rf: Asked for %d samples, got %d from SDR\n",fp->samples_per_tti,rxs);
|
||||
if(rxs != fp->samples_per_tti){
|
||||
LOG_E(PHY,"rx_rf: Asked for %d samples, got %d from USRP\n",fp->samples_per_tti,rxs);
|
||||
LOG_E(PHY,"rx_rf: Asked for %d samples, got %d from SDR\n",fp->samples_per_tti,rxs);
|
||||
late_control=STATE_BURST_TERMINATE;
|
||||
}
|
||||
|
||||
@@ -962,7 +965,7 @@ void tx_rf(RU_t *ru) {
|
||||
/*!
|
||||
* \brief The Asynchronous RX/TX FH thread of RAU/RCC/eNB/RRU.
|
||||
* This handles the RX FH for an asynchronous RRU/UE
|
||||
* \param param is a \ref eNB_proc_t structure which contains the info what to process.
|
||||
* \param param is a \ref L1_proc_t structure which contains the info what to process.
|
||||
* \returns a pointer to an int. The storage is not on the heap and must not be freed.
|
||||
*/
|
||||
static void* ru_thread_asynch_rxtx( void* param ) {
|
||||
@@ -1255,12 +1258,12 @@ void do_ru_synch(RU_t *ru) {
|
||||
|
||||
|
||||
|
||||
void wakeup_eNBs(RU_t *ru) {
|
||||
void wakeup_L1s(RU_t *ru) {
|
||||
|
||||
int i;
|
||||
PHY_VARS_eNB **eNB_list = ru->eNB_list;
|
||||
|
||||
LOG_D(PHY,"wakeup_eNBs (num %d) for RU %d ru->eNB_top:%p\n",ru->num_eNB,ru->idx, ru->eNB_top);
|
||||
LOG_D(PHY,"wakeup_L1s (num %d) for RU %d ru->eNB_top:%p\n",ru->num_eNB,ru->idx, ru->eNB_top);
|
||||
|
||||
|
||||
if (ru->num_eNB==1 && ru->eNB_top!=0 && get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD) {
|
||||
@@ -1279,7 +1282,6 @@ void wakeup_eNBs(RU_t *ru) {
|
||||
for (i=0;i<ru->num_eNB;i++)
|
||||
{
|
||||
LOG_D(PHY,"ru->wakeup_rxtx:%p\n", ru->wakeup_rxtx);
|
||||
eNB_list[i]->proc.ru_proc = &ru->proc;
|
||||
if (ru->wakeup_rxtx!=0 && ru->wakeup_rxtx(eNB_list[i],ru) < 0)
|
||||
{
|
||||
LOG_E(PHY,"could not wakeup eNB rxtx process for subframe %d\n", ru->proc.subframe_rx);
|
||||
@@ -1358,7 +1360,7 @@ void fill_rf_config(RU_t *ru, char *rf_config_file) {
|
||||
LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
|
||||
openair0_config_t *cfg = &ru->openair0_cfg;
|
||||
//printf("////////////////numerology in config = %d\n",numerology);
|
||||
|
||||
int numerology = get_softmodem_params()->numerology;
|
||||
if(fp->N_RB_DL == 100) {
|
||||
if(numerology == 0){
|
||||
if (fp->threequarter_fs) {
|
||||
@@ -1417,7 +1419,7 @@ void fill_rf_config(RU_t *ru, char *rf_config_file) {
|
||||
cfg->num_rb_dl=fp->N_RB_DL;
|
||||
cfg->tx_num_channels=ru->nb_tx;
|
||||
cfg->rx_num_channels=ru->nb_rx;
|
||||
cfg->clock_source=clock_source;
|
||||
cfg->clock_source=get_softmodem_params()->clock_source;
|
||||
|
||||
for (i=0; i<ru->nb_tx; i++) {
|
||||
|
||||
@@ -1535,8 +1537,12 @@ volatile int16_t phy_tx_end;
|
||||
#endif
|
||||
|
||||
static void* ru_thread_tx( void* param ) {
|
||||
RU_t *ru = (RU_t*)param;
|
||||
RU_proc_t *proc = &ru->proc;
|
||||
RU_t *ru = (RU_t*)param;
|
||||
RU_proc_t *proc = &ru->proc;
|
||||
PHY_VARS_eNB *eNB;
|
||||
L1_proc_t *eNB_proc;
|
||||
L1_rxtx_proc_t *L1_proc;
|
||||
|
||||
cpu_set_t cpuset;
|
||||
CPU_ZERO(&cpuset);
|
||||
|
||||
@@ -1557,8 +1563,8 @@ static void* ru_thread_tx( void* param ) {
|
||||
if (oai_exit) break;
|
||||
|
||||
|
||||
LOG_D(PHY,"ru_thread_tx: Waiting for TX processing\n");
|
||||
// wait until eNBs are finished subframe RX n and TX n+4
|
||||
LOG_D(PHY,"ru_thread_tx: Waiting for TX processing\n");
|
||||
// wait until eNBs are finished subframe RX n and TX n+4
|
||||
wait_on_condition(&proc->mutex_eNBs,&proc->cond_eNBs,&proc->instance_cnt_eNBs,"ru_thread_tx");
|
||||
if (oai_exit) break;
|
||||
|
||||
@@ -1567,22 +1573,44 @@ static void* ru_thread_tx( void* param ) {
|
||||
|
||||
// do OFDM if needed
|
||||
if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru);
|
||||
if(!emulate_rf){
|
||||
if(!(get_softmodem_params()->emulate_rf)){
|
||||
// do outgoing fronthaul (south) if needed
|
||||
if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru);
|
||||
|
||||
if (ru->fh_north_out) ru->fh_north_out(ru);
|
||||
}
|
||||
release_thread(&proc->mutex_eNBs,&proc->instance_cnt_eNBs,"ru_thread_tx");
|
||||
|
||||
pthread_mutex_lock( &proc->mutex_eNBs );
|
||||
proc->ru_tx_ready++;
|
||||
// the thread can now be woken up
|
||||
if (pthread_cond_signal(&proc->cond_eNBs) != 0) {
|
||||
LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB TXnp4 thread\n");
|
||||
exit_fun( "ERROR pthread_cond_signal" );
|
||||
for(int i = 0; i<ru->num_eNB; i++)
|
||||
{
|
||||
eNB = ru->eNB_list[i];
|
||||
eNB_proc = &eNB->proc;
|
||||
L1_proc = (get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT)? &eNB_proc->L1_proc_tx : &eNB_proc->L1_proc;
|
||||
pthread_mutex_lock(&eNB_proc->mutex_RU_tx);
|
||||
for (int j=0;j<eNB->num_RU;j++) {
|
||||
if (ru == eNB->RU_list[j]) {
|
||||
if ((eNB_proc->RU_mask_tx&(1<<j)) > 0)
|
||||
LOG_E(PHY,"eNB %d frame %d, subframe %d : previous information from RU tx %d (num_RU %d,mask %x) has not been served yet!\n",
|
||||
eNB->Mod_id,eNB_proc->frame_rx,eNB_proc->subframe_rx,ru->idx,eNB->num_RU,eNB_proc->RU_mask_tx);
|
||||
eNB_proc->RU_mask_tx |= (1<<j);
|
||||
}
|
||||
}
|
||||
if (eNB_proc->RU_mask_tx != (1<<eNB->num_RU)-1) { // not all RUs have provided their information so return
|
||||
pthread_mutex_unlock(&eNB_proc->mutex_RU_tx);
|
||||
}
|
||||
else { // all RUs TX are finished so send the ready signal to eNB processing
|
||||
eNB_proc->RU_mask_tx = 0;
|
||||
pthread_mutex_unlock(&eNB_proc->mutex_RU_tx);
|
||||
|
||||
pthread_mutex_lock( &L1_proc->mutex_RUs);
|
||||
L1_proc->instance_cnt_RUs = 0;
|
||||
// the thread can now be woken up
|
||||
if (pthread_cond_signal(&L1_proc->cond_RUs) != 0) {
|
||||
LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB TXnp4 thread\n");
|
||||
exit_fun( "ERROR pthread_cond_signal" );
|
||||
}
|
||||
pthread_mutex_unlock( &L1_proc->mutex_RUs );
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock( &proc->mutex_eNBs );
|
||||
}
|
||||
release_thread(&proc->mutex_FH1,&proc->instance_cnt_FH1,"ru_thread_tx");
|
||||
return 0;
|
||||
@@ -1619,7 +1647,7 @@ static void* ru_thread( void* param ) {
|
||||
|
||||
LOG_I(PHY,"Starting RU %d (%s,%s),\n",ru->idx,eNB_functions[ru->function],eNB_timing[ru->if_timing]);
|
||||
|
||||
if(emulate_rf){
|
||||
if(get_softmodem_params()->emulate_rf){
|
||||
fill_rf_config(ru,ru->rf_config_file);
|
||||
init_frame_parms(&ru->frame_parms,1);
|
||||
phy_init_RU(ru);
|
||||
@@ -1665,7 +1693,7 @@ static void* ru_thread( void* param ) {
|
||||
|
||||
wait_sync("ru_thread");
|
||||
|
||||
if(!emulate_rf){
|
||||
if(!(get_softmodem_params()->emulate_rf)){
|
||||
// Start RF device if any
|
||||
if (ru->start_rf) {
|
||||
if (ru->start_rf(ru) != 0)
|
||||
@@ -1791,7 +1819,7 @@ static void* ru_thread( void* param ) {
|
||||
#endif
|
||||
|
||||
// wakeup all eNB processes waiting for this RU
|
||||
if (ru->num_eNB>0) wakeup_eNBs(ru);
|
||||
if (ru->num_eNB>0) wakeup_L1s(ru);
|
||||
|
||||
#ifndef PHY_TX_THREAD
|
||||
if(get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD || ru->num_eNB==0){
|
||||
@@ -1800,7 +1828,7 @@ static void* ru_thread( void* param ) {
|
||||
|
||||
// do OFDM if needed
|
||||
if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru);
|
||||
if(!emulate_rf){
|
||||
if(!(get_softmodem_params()->emulate_rf)){
|
||||
// do outgoing fronthaul (south) if needed
|
||||
if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru);
|
||||
|
||||
@@ -1823,7 +1851,7 @@ static void* ru_thread( void* param ) {
|
||||
|
||||
printf( "Exiting ru_thread \n");
|
||||
|
||||
if (!emulate_rf){
|
||||
if (!(get_softmodem_params()->emulate_rf)){
|
||||
if (ru->stop_rf != NULL) {
|
||||
if (ru->stop_rf(ru) != 0)
|
||||
LOG_E(HW,"Could not stop the RF device\n");
|
||||
@@ -1974,7 +2002,7 @@ void* pre_scd_thread( void* param ){
|
||||
#ifdef PHY_TX_THREAD
|
||||
/*!
|
||||
* \brief The phy tx thread of eNB.
|
||||
* \param param is a \ref eNB_proc_t structure which contains the info what to process.
|
||||
* \param param is a \ref L1_proc_t structure which contains the info what to process.
|
||||
* \returns a pointer to an int. The storage is not on the heap and must not be freed.
|
||||
*/
|
||||
static void* eNB_thread_phy_tx( void* param ) {
|
||||
@@ -1985,7 +2013,7 @@ static void* eNB_thread_phy_tx( void* param ) {
|
||||
RU_proc_t *proc = &ru->proc;
|
||||
PHY_VARS_eNB **eNB_list = ru->eNB_list;
|
||||
|
||||
eNB_rxtx_proc_t proc_rxtx;
|
||||
L1_rxtx_proc_t L1_proc;
|
||||
|
||||
// set default return value
|
||||
eNB_thread_phy_tx_status = 0;
|
||||
@@ -2002,9 +2030,9 @@ static void* eNB_thread_phy_tx( void* param ) {
|
||||
|
||||
LOG_D(PHY,"Running eNB phy tx procedures\n");
|
||||
if(ru->num_eNB == 1){
|
||||
proc_rxtx.subframe_tx = proc->subframe_phy_tx;
|
||||
proc_rxtx.frame_tx = proc->frame_phy_tx;
|
||||
phy_procedures_eNB_TX(eNB_list[0], &proc_rxtx, 1);
|
||||
L1_proc.subframe_tx = proc->subframe_phy_tx;
|
||||
L1_proc.frame_tx = proc->frame_phy_tx;
|
||||
phy_procedures_eNB_TX(eNB_list[0], &L1_proc, 1);
|
||||
phy_tx_txdataF_end = 1;
|
||||
if(pthread_mutex_lock(&ru->proc.mutex_rf_tx) != 0){
|
||||
LOG_E( PHY, "[RU] ERROR pthread_mutex_lock for rf tx thread (IC %d)\n", ru->proc.instance_cnt_rf_tx);
|
||||
@@ -2136,8 +2164,6 @@ void init_RU_proc(RU_t *ru) {
|
||||
proc->frame_offset = 0;
|
||||
proc->num_slaves = 0;
|
||||
proc->frame_tx_unwrap = 0;
|
||||
proc->ru_rx_ready = 0;
|
||||
proc->ru_tx_ready = 0;
|
||||
|
||||
for (i=0;i<10;i++) proc->symbol_mask[i]=0;
|
||||
|
||||
@@ -2209,7 +2235,7 @@ void init_RU_proc(RU_t *ru) {
|
||||
pthread_create( &proc->pthread_rf_tx, NULL, rf_tx, (void*)ru );
|
||||
#endif
|
||||
|
||||
if(emulate_rf)
|
||||
if(get_softmodem_params()->emulate_rf)
|
||||
pthread_create( &proc->pthread_emulateRF, attr_emulateRF, emulatedRF_thread, (void*)proc );
|
||||
|
||||
if (get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT)
|
||||
@@ -2312,7 +2338,6 @@ void kill_RU_proc(RU_t *ru)
|
||||
pthread_mutex_unlock(&proc->mutex_synch);
|
||||
|
||||
pthread_mutex_lock(&proc->mutex_eNBs);
|
||||
proc->ru_tx_ready = 0;
|
||||
proc->instance_cnt_eNBs = 1;
|
||||
// cond_eNBs is used by both ru_thread and ru_thread_tx, so we need to send
|
||||
// a broadcast to wake up both threads
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*! \file lte-softmodem-common.c
|
||||
* \brief Top-level threads for eNodeB
|
||||
* \author Nokia BellLabs France, francois Taburet
|
||||
* \date 2012
|
||||
* \version 0.1
|
||||
* \company Eurecom
|
||||
* \email: francois.taburet@nokia-bell-labs.com
|
||||
* \note
|
||||
* \warning
|
||||
*/
|
||||
|
||||
#include "lte-softmodem.h"
|
||||
#include "UTIL/OPT/opt.h"
|
||||
#include "common/config/config_userapi.h"
|
||||
#include "common/utils/load_module_shlib.h"
|
||||
static softmodem_params_t softmodem_params;
|
||||
char *parallel_config=NULL;
|
||||
char *worker_config=NULL;
|
||||
|
||||
uint64_t get_softmodem_optmask(void) {
|
||||
return softmodem_params.optmask;
|
||||
}
|
||||
|
||||
uint64_t set_softmodem_optmask(uint64_t bitmask) {
|
||||
softmodem_params.optmask = softmodem_params.optmask | bitmask;
|
||||
return softmodem_params.optmask;
|
||||
}
|
||||
|
||||
softmodem_params_t* get_softmodem_params(void) {
|
||||
return &softmodem_params;
|
||||
}
|
||||
|
||||
void get_common_options(void)
|
||||
{
|
||||
|
||||
|
||||
uint32_t online_log_messages;
|
||||
uint32_t glog_level ;
|
||||
uint32_t start_telnetsrv;
|
||||
uint32_t noS1;
|
||||
uint32_t nokrnmod;
|
||||
uint32_t nonbiot;
|
||||
paramdef_t cmdline_params[] =CMDLINE_PARAMS_DESC ;
|
||||
paramdef_t cmdline_logparams[] =CMDLINE_LOGPARAMS_DESC ;
|
||||
|
||||
|
||||
|
||||
config_process_cmdline( cmdline_params,sizeof(cmdline_params)/sizeof(paramdef_t),NULL);
|
||||
|
||||
if (strlen(in_path) > 0) {
|
||||
opt_type = OPT_PCAP;
|
||||
opt_enabled=1;
|
||||
printf("Enabling OPT for PCAP with the following file %s \n",in_path);
|
||||
}
|
||||
if (strlen(in_ip) > 0) {
|
||||
opt_enabled=1;
|
||||
opt_type = OPT_WIRESHARK;
|
||||
printf("Enabling OPT for wireshark for local interface");
|
||||
}
|
||||
|
||||
config_process_cmdline( cmdline_logparams,sizeof(cmdline_logparams)/sizeof(paramdef_t),NULL);
|
||||
|
||||
if(config_isparamset(cmdline_logparams,CMDLINE_ONLINELOG_IDX)) {
|
||||
set_glog_onlinelog(online_log_messages);
|
||||
}
|
||||
if(config_isparamset(cmdline_logparams,CMDLINE_GLOGLEVEL_IDX)) {
|
||||
set_glog(glog_level);
|
||||
}
|
||||
if (start_telnetsrv) {
|
||||
load_module_shlib("telnetsrv",NULL,0,NULL);
|
||||
}
|
||||
|
||||
if (noS1) {
|
||||
set_softmodem_optmask(SOFTMODEM_NOS1_BIT);
|
||||
}
|
||||
if (nokrnmod) {
|
||||
set_softmodem_optmask(SOFTMODEM_NOKRNMOD_BIT);
|
||||
}
|
||||
if (nonbiot) {
|
||||
set_softmodem_optmask(SOFTMODEM_NONBIOT_BIT);
|
||||
}
|
||||
if(parallel_config != NULL) set_parallel_conf(parallel_config);
|
||||
if(worker_config != NULL) set_worker_conf(worker_config);
|
||||
}
|
||||
+277
-443
File diff suppressed because it is too large
Load Diff
+104
-53
@@ -95,7 +95,8 @@
|
||||
#define CONFIG_HLP_EMULATE_RF "Emulated RF enabled(disable by defult)\n"
|
||||
#define CONFIG_HLP_PARALLEL_CMD "three config for level of parallelism 'PARALLEL_SINGLE_THREAD', 'PARALLEL_RU_L1_SPLIT', or 'PARALLEL_RU_L1_TRX_SPLIT'\n"
|
||||
#define CONFIG_HLP_WORKER_CMD "two option for worker 'WORKER_DISABLE' or 'WORKER_ENABLE'\n"
|
||||
|
||||
#define CONFIG_HLP_NOS1 "Disable s1 interface\n"
|
||||
#define CONFIG_HLP_NOKRNMOD "(noS1 only): Use tun instead of namesh module \n"
|
||||
#define CONFIG_HLP_DISABLNBIOT "disable nb-iot, even if defined in config\n"
|
||||
|
||||
#define CONFIG_HLP_USRP_ARGS "set the arguments to identify USRP (same syntax as in UHD)\n"
|
||||
@@ -130,30 +131,49 @@
|
||||
#define CMDLINE_DUMPMEMORY_IDX 7
|
||||
/*------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
#define START_MSC softmodem_params.start_msc
|
||||
/*-------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
/* command line parameters specific to UE */
|
||||
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
||||
/*-------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
/*--------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
/* command line parameters specific to UE */
|
||||
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
||||
/*--------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
#define CMDLINE_UEPARAMS_DESC { \
|
||||
{"siml1", CONFIG_HLP_SIML1, PARAMFLAG_BOOL, iptr:&simL1flag, defintval:0, TYPE_INT, 0}, \
|
||||
{"U", CONFIG_HLP_NUMUE, 0, u8ptr:&NB_UE_INST, defuintval:1, TYPE_UINT, 0}, \
|
||||
{"ue-rxgain", CONFIG_HLP_UERXG, 0, dblptr:&(rx_gain[0][0]), defdblval:130, TYPE_DOUBLE, 0}, \
|
||||
{"ue-rxgain-off", CONFIG_HLP_UERXGOFF, 0, dblptr:&rx_gain_off, defdblval:0, TYPE_DOUBLE, 0}, \
|
||||
{"ue-txgain", CONFIG_HLP_UETXG, 0, dblptr:&(tx_gain[0][0]), defdblval:0, TYPE_DOUBLE, 0}, \
|
||||
{"ue-nb-ant-rx", CONFIG_HLP_UENANTR, 0, u8ptr:&nb_antenna_rx, defuintval:1, TYPE_UINT8, 0}, \
|
||||
{"ue-nb-ant-tx", CONFIG_HLP_UENANTT, 0, u8ptr:&nb_antenna_tx, defuintval:1, TYPE_UINT8, 0}, \
|
||||
{"ue-scan-carrier", CONFIG_HLP_UESCAN, PARAMFLAG_BOOL, iptr:&UE_scan_carrier, defintval:0, TYPE_INT, 0}, \
|
||||
{"ue-max-power", NULL, 0, iptr:&(tx_max_power[0]), defintval:23, TYPE_INT, 0}, \
|
||||
{"emul-iface", CONFIG_HLP_EMULIFACE, 0, strptr:&emul_iface, defstrval:"lo", TYPE_STRING, 100}, \
|
||||
{"L2-emul", NULL, 0, u8ptr:&nfapi_mode, defuintval:3, TYPE_UINT8, 0}, \
|
||||
{"num-ues", NULL, 0, u16ptr:&(NB_UE_INST), defuintval:1, TYPE_UINT16, 0}, \
|
||||
{"nums_ue_thread" , NULL, 0, u16ptr:&(NB_THREAD_INST), defuintval:1, TYPE_UINT16, 0}, \
|
||||
{"r" , CONFIG_HLP_PRB, 0, u8ptr:&(frame_parms[0]->N_RB_DL), defintval:25, TYPE_UINT8, 0}, \
|
||||
{"dlsch-demod-shift", CONFIG_HLP_DLSHIFT, 0, iptr:(int32_t *)&dlsch_demod_shift, defintval:0, TYPE_INT, 0}, \
|
||||
{"usrp-args", CONFIG_HLP_USRP_ARGS, 0, strptr:(char **)&usrp_args, defstrval:"type=b200", TYPE_STRING, 0}, \
|
||||
{"usrp-clksrc", CONFIG_HLP_USRP_CLK_SRC,0, strptr:(char **)&usrp_clksrc, defstrval:"internal", TYPE_STRING, 0} \
|
||||
}
|
||||
{"siml1", CONFIG_HLP_SIML1, PARAMFLAG_BOOL, iptr:&simL1flag, defintval:0, TYPE_INT, 0}, \
|
||||
{"U", CONFIG_HLP_NUMUE, 0, u8ptr:&NB_UE_INST, defuintval:1, TYPE_UINT, 0}, \
|
||||
{"ue-rxgain", CONFIG_HLP_UERXG, 0, dblptr:&(rx_gain[0][0]), defdblval:130, TYPE_DOUBLE, 0}, \
|
||||
{"ue-rxgain-off", CONFIG_HLP_UERXGOFF, 0, dblptr:&rx_gain_off, defdblval:0, TYPE_DOUBLE, 0}, \
|
||||
{"ue-txgain", CONFIG_HLP_UETXG, 0, dblptr:&(tx_gain[0][0]), defdblval:0, TYPE_DOUBLE, 0}, \
|
||||
{"ue-nb-ant-rx", CONFIG_HLP_UENANTR, 0, u8ptr:&nb_antenna_rx, defuintval:1, TYPE_UINT8, 0}, \
|
||||
{"ue-nb-ant-tx", CONFIG_HLP_UENANTT, 0, u8ptr:&nb_antenna_tx, defuintval:1, TYPE_UINT8, 0}, \
|
||||
{"ue-scan-carrier", CONFIG_HLP_UESCAN, PARAMFLAG_BOOL, iptr:&UE_scan_carrier, defintval:0, TYPE_INT, 0}, \
|
||||
{"ue-max-power", NULL, 0, iptr:&(tx_max_power[0]), defintval:23, TYPE_INT, 0}, \
|
||||
{"emul-iface", CONFIG_HLP_EMULIFACE, 0, strptr:&emul_iface, defstrval:"lo", TYPE_STRING, 100}, \
|
||||
{"L2-emul", NULL, 0, u8ptr:&nfapi_mode, defuintval:3, TYPE_UINT8, 0}, \
|
||||
{"num-ues", NULL, 0, u8ptr:&(NB_UE_INST), defuintval:1, TYPE_UINT8, 0}, \
|
||||
{"nums_ue_thread", NULL, 0, u16ptr:&(NB_THREAD_INST), defuintval:1, TYPE_UINT16, 0}, \
|
||||
{"r" , CONFIG_HLP_PRB, 0, u8ptr:&(frame_parms[0]->N_RB_DL), defintval:25, TYPE_UINT8, 0}, \
|
||||
{"dlsch-demod-shift", CONFIG_HLP_DLSHIFT, 0, iptr:(int32_t *)&dlsch_demod_shift, defintval:0, TYPE_INT, 0}, \
|
||||
{"usrp-args", CONFIG_HLP_USRP_ARGS, 0, strptr:(char **)&usrp_args, defstrval:"type=b200",TYPE_STRING, 0}, \
|
||||
{"usrp-clksrc", CONFIG_HLP_USRP_CLK_SRC,0, strptr:(char **)&usrp_clksrc, defstrval:"internal", TYPE_STRING, 0}, \
|
||||
{"mmapped-dma", CONFIG_HLP_DMAMAP, PARAMFLAG_BOOL, uptr:&mmapped_dma, defintval:0, TYPE_INT, 0}, \
|
||||
{"clock", CONFIG_HLP_CLK, 0, uptr:&clock_source, defintval:0, TYPE_UINT, 0}, \
|
||||
{"s" , CONFIG_HLP_SNR, 0, iptr:&snr_dB, defintval:25, TYPE_INT, 0}, \
|
||||
{"T" , CONFIG_HLP_TDD, PARAMFLAG_BOOL, iptr:&tddflag, defintval:0, TYPE_INT, 0}, \
|
||||
{"A", CONFIG_HLP_TADV, 0, iptr:&(timingadv), defintval:0, TYPE_INT, 0} \
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
/* command line parameters specific to UE threads */
|
||||
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
||||
/*-------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
#define CMDLINE_UETHREADSPARAMS_DESC { \
|
||||
{"threadIQ", NULL, 0, iptr:&(threads.iq), defintval:1, TYPE_INT, 0}, \
|
||||
{"threadOneSubframe", NULL, 0, iptr:&(threads.one), defintval:1, TYPE_INT, 0}, \
|
||||
{"threadTwoSubframe", NULL, 0, iptr:&(threads.two), defintval:1, TYPE_INT, 0}, \
|
||||
{"threadThreeSubframe", NULL, 0, iptr:&(threads.three), defintval:1, TYPE_INT, 0}, \
|
||||
{"threadSlot1ProcOne", NULL, 0, iptr:&(threads.slot1_proc_one), defintval:1, TYPE_INT, 0}, \
|
||||
{"threadSlot1ProcTwo", NULL, 0, iptr:&(threads.slot1_proc_two), defintval:1, TYPE_INT, 0}, \
|
||||
}
|
||||
|
||||
#define DEFAULT_DLF 2680000000
|
||||
|
||||
@@ -161,40 +181,38 @@
|
||||
/* command line parameters common to eNodeB and UE */
|
||||
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
||||
/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
#define RF_CONFIG_FILE softmodem_params.rf_config_file
|
||||
#define PHY_TEST softmodem_params.phy_test
|
||||
#define WAIT_FOR_SYNC softmodem_params.wait_for_sync
|
||||
#define SINGLE_THREAD_FLAG softmodem_params.single_thread_flag
|
||||
#define CHAIN_OFFSET softmodem_params.chain_offset
|
||||
#define DO_FORMS softmodem_params.do_forms
|
||||
#define NUMEROLOGY softmodem_params.numerology
|
||||
#define EMULATE_RF softmodem_params.emulate_rf
|
||||
#define CLOCK_SOURCE softmodem_params.clock_source
|
||||
#define USIM_TEST softmodem_params.usim_test
|
||||
#define CMDLINE_PARAMS_DESC { \
|
||||
{"rf-config-file", CONFIG_HLP_RFCFGF, 0, strptr:(char **)&rf_config_file, defstrval:NULL, TYPE_STRING, sizeof(rf_config_file)}, \
|
||||
{"rf-config-file", CONFIG_HLP_RFCFGF, 0, strptr:(char **)&RF_CONFIG_FILE, defstrval:NULL, TYPE_STRING, sizeof(RF_CONFIG_FILE)}, \
|
||||
{"ulsch-max-errors", CONFIG_HLP_ULMAXE, 0, uptr:&ULSCH_max_consecutive_errors, defuintval:0, TYPE_UINT, 0}, \
|
||||
{"phy-test", CONFIG_HLP_PHYTST, PARAMFLAG_BOOL, iptr:&phy_test, defintval:0, TYPE_INT, 0}, \
|
||||
{"usim-test", CONFIG_HLP_USIM, PARAMFLAG_BOOL, u8ptr:&usim_test, defintval:0, TYPE_UINT8, 0}, \
|
||||
{"mmapped-dma", CONFIG_HLP_DMAMAP, PARAMFLAG_BOOL, uptr:&mmapped_dma, defintval:0, TYPE_INT, 0}, \
|
||||
{"clock", CONFIG_HLP_CLK, 0, uptr:&clock_source, defintval:0, TYPE_UINT, 0}, \
|
||||
{"wait-for-sync", NULL, PARAMFLAG_BOOL, iptr:&wait_for_sync, defintval:0, TYPE_INT, 0}, \
|
||||
{"single-thread-enable", CONFIG_HLP_NOSNGLT, PARAMFLAG_BOOL, iptr:&single_thread_flag, defintval:0, TYPE_INT, 0}, \
|
||||
{"threadIQ", NULL, 0, iptr:&(threads.iq), defintval:1, TYPE_INT, 0}, \
|
||||
{"threadOneSubframe", NULL, 0, iptr:&(threads.one), defintval:1, TYPE_INT, 0}, \
|
||||
{"threadTwoSubframe", NULL, 0, iptr:&(threads.two), defintval:1, TYPE_INT, 0}, \
|
||||
{"threadThreeSubframe", NULL, 0, iptr:&(threads.three), defintval:1, TYPE_INT, 0}, \
|
||||
{"threadSlot1ProcOne", NULL, 0, iptr:&(threads.slot1_proc_one), defintval:1, TYPE_INT, 0}, \
|
||||
{"threadSlot1ProcTwo", NULL, 0, iptr:&(threads.slot1_proc_two), defintval:1, TYPE_INT, 0}, \
|
||||
{"dlsch-demod-shift", CONFIG_HLP_DLSHIFT, 0, iptr:(int32_t *)&dlsch_demod_shift, defintval:0, TYPE_INT, 0}, \
|
||||
{"A" , CONFIG_HLP_TADV, 0, uptr:&timing_advance, defintval:0, TYPE_UINT, 0}, \
|
||||
{"phy-test", CONFIG_HLP_PHYTST, PARAMFLAG_BOOL, iptr:&PHY_TEST, defintval:0, TYPE_INT, 0}, \
|
||||
{"usim-test", CONFIG_HLP_USIM, PARAMFLAG_BOOL, u8ptr:&USIM_TEST, defintval:0, TYPE_UINT8, 0}, \
|
||||
{"emulate-rf" , CONFIG_HLP_EMULATE_RF, PARAMFLAG_BOOL, iptr:&EMULATE_RF, defintval:0, TYPE_INT, 0}, \
|
||||
{"clock", CONFIG_HLP_CLK, 0, uptr:&CLOCK_SOURCE, defintval:0, TYPE_UINT, 0}, \
|
||||
{"wait-for-sync", NULL, PARAMFLAG_BOOL, iptr:&WAIT_FOR_SYNC, defintval:0, TYPE_INT, 0}, \
|
||||
{"single-thread-enable", CONFIG_HLP_NOSNGLT, PARAMFLAG_BOOL, iptr:&SINGLE_THREAD_FLAG, defintval:0, TYPE_INT, 0}, \
|
||||
{"C" , CONFIG_HLP_DLF, 0, uptr:&(downlink_frequency[0][0]), defuintval:2680000000, TYPE_UINT, 0}, \
|
||||
{"a" , CONFIG_HLP_CHOFF, 0, iptr:&chain_offset, defintval:0, TYPE_INT, 0}, \
|
||||
{"d" , CONFIG_HLP_SOFTS, PARAMFLAG_BOOL, uptr:(uint32_t *)&do_forms, defintval:0, TYPE_INT8, 0}, \
|
||||
{"E" , CONFIG_HLP_TQFS, PARAMFLAG_BOOL, i8ptr:&threequarter_fs, defintval:0, TYPE_INT8, 0}, \
|
||||
{"m" , CONFIG_HLP_DLMCS, 0, uptr:&target_dl_mcs, defintval:0, TYPE_UINT, 0}, \
|
||||
{"t" , CONFIG_HLP_ULMCS, 0, uptr:&target_ul_mcs, defintval:0, TYPE_UINT, 0}, \
|
||||
{"a" , CONFIG_HLP_CHOFF, 0, iptr:&CHAIN_OFFSET, defintval:0, TYPE_INT, 0}, \
|
||||
{"d" , CONFIG_HLP_SOFTS, PARAMFLAG_BOOL, uptr:(uint32_t *)&DO_FORMS, defintval:0, TYPE_INT8, 0}, \
|
||||
{"W" , CONFIG_HLP_L2MONW, 0, strptr:(char **)&in_ip, defstrval:"127.0.0.1", TYPE_STRING, sizeof(in_ip)}, \
|
||||
{"P" , CONFIG_HLP_L2MONP, 0, strptr:(char **)&in_path, defstrval:"/tmp/oai_opt.pcap", TYPE_STRING, sizeof(in_path)}, \
|
||||
{"q" , CONFIG_HLP_STMON, PARAMFLAG_BOOL, iptr:&opp_enabled, defintval:0, TYPE_INT, 0}, \
|
||||
{"S" , CONFIG_HLP_MSLOTS, PARAMFLAG_BOOL, u8ptr:&exit_missed_slots, defintval:1, TYPE_UINT8, 0}, \
|
||||
{"T" , CONFIG_HLP_TDD, PARAMFLAG_BOOL, iptr:&tddflag, defintval:0, TYPE_INT, 0}, \
|
||||
{"s" , CONFIG_HLP_SNR, 0, iptr:&snr_dB, defintval:25, TYPE_INT, 0}, \
|
||||
{"numerology" , CONFIG_HLP_NUMEROLOGY, PARAMFLAG_BOOL, iptr:&numerology, defintval:0, TYPE_INT, 0}, \
|
||||
{"emulate-rf" , CONFIG_HLP_EMULATE_RF, PARAMFLAG_BOOL, iptr:&emulate_rf, defintval:0, TYPE_INT, 0}, \
|
||||
{"numerology" , CONFIG_HLP_NUMEROLOGY, PARAMFLAG_BOOL, iptr:&NUMEROLOGY, defintval:0, TYPE_INT, 0}, \
|
||||
{"parallel-config", CONFIG_HLP_PARALLEL_CMD,0, strptr:(char **)¶llel_config, defstrval:NULL, TYPE_STRING, 0}, \
|
||||
{"worker-config", CONFIG_HLP_WORKER_CMD, 0, strptr:(char **)&worker_config, defstrval:NULL, TYPE_STRING, 0}, \
|
||||
{"nbiot-disable", CONFIG_HLP_DISABLNBIOT, PARAMFLAG_BOOL, iptr:&nonbiotflag, defintval:0, TYPE_INT, 0} \
|
||||
{"noS1", CONFIG_HLP_NOS1, PARAMFLAG_BOOL, uptr:&noS1, defintval:0, TYPE_INT, 0}, \
|
||||
{"nokrnmod", CONFIG_HLP_NOKRNMOD, PARAMFLAG_BOOL, uptr:&nokrnmod, defintval:0, TYPE_INT, 0}, \
|
||||
{"nbiot-disable", CONFIG_HLP_DISABLNBIOT, PARAMFLAG_BOOL, uptr:&nonbiot, defuintval:0, TYPE_INT, 0}, \
|
||||
}
|
||||
|
||||
#define CONFIG_HLP_FLOG "Enable online log \n"
|
||||
@@ -205,11 +223,12 @@
|
||||
/* command line parameters for LOG utility */
|
||||
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
||||
/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
#define START_MSC softmodem_params.start_msc
|
||||
#define CMDLINE_LOGPARAMS_DESC { \
|
||||
{"R" , CONFIG_HLP_FLOG, 0, uptr:&online_log_messages, defintval:1, TYPE_INT, 0}, \
|
||||
{"g" , CONFIG_HLP_LOGL, 0, uptr:&glog_level, defintval:0, TYPE_UINT, 0}, \
|
||||
{"telnetsrv", CONFIG_HLP_TELN, PARAMFLAG_BOOL, uptr:&start_telnetsrv, defintval:0, TYPE_UINT, 0}, \
|
||||
{"msc", CONFIG_HLP_MSC, PARAMFLAG_BOOL, uptr:start_msc, defintval:0, TYPE_UINT, 0}, \
|
||||
{"msc", CONFIG_HLP_MSC, PARAMFLAG_BOOL, uptr:&START_MSC, defintval:0, TYPE_UINT, 0}, \
|
||||
}
|
||||
#define CMDLINE_ONLINELOG_IDX 0
|
||||
#define CMDLINE_GLOGLEVEL_IDX 1
|
||||
@@ -218,6 +237,38 @@
|
||||
|
||||
/***************************************************************************************************************************************/
|
||||
/* */
|
||||
#include "threads_t.h"
|
||||
|
||||
#define SOFTMODEM_NOS1_BIT (1<<0)
|
||||
#define SOFTMODEM_NOKRNMOD_BIT (1<<1)
|
||||
#define SOFTMODEM_NONBIOT_BIT (1<<2)
|
||||
typedef struct {
|
||||
uint64_t optmask;
|
||||
THREAD_STRUCT thread_struct;
|
||||
char rf_config_file[1024];
|
||||
int phy_test;
|
||||
uint8_t usim_test;
|
||||
int emulate_rf;
|
||||
int wait_for_sync; //eNodeB only
|
||||
int single_thread_flag; //eNodeB only
|
||||
int chain_offset;
|
||||
uint32_t do_forms;
|
||||
int numerology;
|
||||
unsigned int start_msc;
|
||||
int nonbiotflag;
|
||||
uint32_t clock_source;
|
||||
int hw_timing_advance;
|
||||
} softmodem_params_t;
|
||||
|
||||
#define SOFTMODEM_NOS1 ( get_softmodem_optmask() & SOFTMODEM_NOS1_BIT)
|
||||
#define SOFTMODEM_NOKRNMOD ( get_softmodem_optmask() & SOFTMODEM_NOKRNMOD_BIT)
|
||||
#define SOFTMODEM_NONBIOT ( get_softmodem_optmask() & SOFTMODEM_NONBIOT_BIT)
|
||||
extern uint64_t get_softmodem_optmask(void);
|
||||
extern uint64_t set_softmodem_optmask(uint64_t bitmask);
|
||||
extern void get_common_options(void);
|
||||
extern softmodem_params_t* get_softmodem_params(void);
|
||||
|
||||
uint64_t get_pdcp_optmask(void);
|
||||
extern pthread_cond_t sync_cond;
|
||||
extern pthread_mutex_t sync_mutex;
|
||||
extern int sync_var;
|
||||
@@ -245,8 +296,8 @@ extern volatile int start_eNB;
|
||||
extern volatile int start_UE;
|
||||
#endif
|
||||
|
||||
#include "threads_t.h"
|
||||
extern threads_t threads;
|
||||
|
||||
|
||||
|
||||
// In lte-enb.c
|
||||
extern void init_eNB(int single_thread_flag,int wait_for_sync);
|
||||
@@ -254,7 +305,7 @@ extern void stop_eNB(int);
|
||||
extern void kill_eNB_proc(int inst);
|
||||
|
||||
// In lte-ru.c
|
||||
extern void init_RU(const char*);
|
||||
extern void init_RU(char*);
|
||||
extern void stop_ru(RU_t *ru);
|
||||
extern void init_ru_vnf(void);
|
||||
extern void init_RU_proc(RU_t *ru);
|
||||
@@ -272,7 +323,7 @@ extern void init_thread(int sched_runtime, int sched_deadline, int sched_fifo, c
|
||||
extern void reset_opp_meas(void);
|
||||
extern void print_opp_meas(void);
|
||||
|
||||
extern void init_fep_thread(PHY_VARS_eNB *, pthread_attr_t *);
|
||||
|
||||
extern void init_td_thread(PHY_VARS_eNB *);
|
||||
extern void init_te_thread(PHY_VARS_eNB *);
|
||||
extern void kill_td_thread(PHY_VARS_eNB *);
|
||||
|
||||
@@ -58,8 +58,8 @@
|
||||
#include "UTIL/MATH/oml.h"
|
||||
#include "common/utils/LOG/vcd_signal_dumper.h"
|
||||
#include "UTIL/OPT/opt.h"
|
||||
|
||||
|
||||
#include "lte-softmodem.h"
|
||||
#include "common/config/config_userapi.h"
|
||||
#include "T.h"
|
||||
|
||||
extern double cpuf;
|
||||
@@ -160,12 +160,21 @@ static const eutra_band_t eutra_bands[] = {
|
||||
};
|
||||
|
||||
|
||||
|
||||
threads_t threads= {-1,-1,-1,-1,-1,-1,-1};
|
||||
|
||||
pthread_t main_ue_thread;
|
||||
pthread_attr_t attr_UE_thread;
|
||||
struct sched_param sched_param_UE_thread;
|
||||
|
||||
|
||||
void get_uethreads_params(void) {
|
||||
paramdef_t cmdline_threadsparams[] =CMDLINE_UETHREADSPARAMS_DESC;
|
||||
|
||||
|
||||
config_process_cmdline( cmdline_threadsparams,sizeof(cmdline_threadsparams)/sizeof(paramdef_t),NULL);
|
||||
}
|
||||
|
||||
|
||||
void phy_init_lte_ue_transport(PHY_VARS_UE *ue,int absraction_flag);
|
||||
|
||||
PHY_VARS_UE* init_ue_vars(LTE_DL_FRAME_PARMS *frame_parms,
|
||||
@@ -181,7 +190,7 @@ PHY_VARS_UE* init_ue_vars(LTE_DL_FRAME_PARMS *frame_parms,
|
||||
memcpy(&(ue->frame_parms), frame_parms, sizeof(LTE_DL_FRAME_PARMS));
|
||||
}
|
||||
|
||||
|
||||
ue->hw_timing_advance=get_softmodem_params()->hw_timing_advance;
|
||||
ue->Mod_id = UE_id;
|
||||
ue->mac_enabled = 1;
|
||||
|
||||
|
||||
+340
-474
File diff suppressed because it is too large
Load Diff
@@ -62,7 +62,6 @@ sim_t sim;
|
||||
|
||||
|
||||
void init_ru_devices(void);
|
||||
void init_RU(const char*);
|
||||
void *rfsim_top(void *n_frames);
|
||||
|
||||
void wait_RUs(void)
|
||||
|
||||
Reference in New Issue
Block a user