Commit 3cfbb768 authored by Raymond Knopp's avatar Raymond Knopp

Merge branch 'enhancement-10-harmony' of...

Merge branch 'enhancement-10-harmony' of https://gitlab.eurecom.fr/oai/openairinterface5g into enhancement-10-harmony

Conflicts:
	openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c
	openair1/SCHED/phy_procedures_lte_eNb.c
parents d9761e7a d3d423f5
......@@ -138,7 +138,7 @@ else (CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l")
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -mavx2")
endif()
if (CPUINFO MATCHES "sse4_1")
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -msse4.1")
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -msse4.1 -mavx2")
endif()
if (CPUINFO MATCHES "ssse3")
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -mssse3")
......@@ -259,15 +259,6 @@ if (${ENABLE_ITTI})
endif (${ENABLE_ITTI})
add_boolean_option(RTAI False "Use RTAI")
if (${RTAI})
set(LOWLATENCY False)
set(CPU_AFFINITY False)
add_definitions("-DENABLE_RTAI_CLOCK")
add_definitions("-DCONFIG_RTAI_LXRT_INLINE")
include_directories ("/usr/realtime/include")
include_directories ("/usr/realtime/include/asm")
set(RTAI_SOURCE sched_dlsch.c sched_rx_pdsch.c rt_wrapper.c vcd_signal_dumper.c log.c)
endif (${RTAI})
#############################
# ASN.1 grammar C code generation & dependancies
......@@ -1574,11 +1565,10 @@ add_executable(lte-softmodem
${rrc_h}
${s1ap_h}
${OPENAIR_BIN_DIR}/messages_xml.h
${OPENAIR_TARGETS}/RT/USER/sched_dlsch.c
${OPENAIR_TARGETS}/RT/USER/sched_rx_pdsch.c
${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c
${OPENAIR_TARGETS}/RT/USER/lte-ue.c
${OPENAIR_TARGETS}/RT/USER/lte-softmodem.c
${OPENAIR_TARGETS}/RT/USER/lte-enb.c
${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c
${OPENAIR_TARGETS}/SIMU/USER/init_lte.c
${OPENAIR_TARGETS}/COMMON/create_tasks.c
......@@ -1610,8 +1600,6 @@ add_executable(lte-softmodem-nos1
${rrc_h}
${s1ap_h}
${OPENAIR_BIN_DIR}/messages_xml.h
${OPENAIR_TARGETS}/RT/USER/sched_dlsch.c
${OPENAIR_TARGETS}/RT/USER/sched_rx_pdsch.c
${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c
${OPENAIR_TARGETS}/RT/USER/lte-ue.c
${OPENAIR_TARGETS}/RT/USER/lte-softmodem.c
......
......@@ -726,7 +726,9 @@ typedef enum {format0,
format2B,
format2C,
format2D,
format3
format3,
format3A,
format4
} DCI_format_t;
typedef enum {
......
......@@ -140,7 +140,7 @@ uint32_t FOUR[2]={0,4};
uint32_t TWO[2]={0,2};
int allocate_REs_in_RB_no_pilots_16QAM_siso(LTE_DL_FRAME_PARMS *frame_parms,
int32_t * **txdataF,
int **txdataF,
uint32_t *jj,
uint32_t *jj2,
uint16_t re_offset,
......@@ -213,7 +213,7 @@ int allocate_REs_in_RB_no_pilots_16QAM_siso(LTE_DL_FRAME_PARMS *frame_parms,
}
int allocate_REs_in_RB_pilots_16QAM_siso(LTE_DL_FRAME_PARMS *frame_parms,
int32_t * **txdataF,
int **txdataF,
uint32_t *jj,
uint32_t *jj2,
uint16_t re_offset,
......@@ -295,7 +295,7 @@ int allocate_REs_in_RB_pilots_16QAM_siso(LTE_DL_FRAME_PARMS *frame_parms,
}
int allocate_REs_in_RB_no_pilots_64QAM_siso(LTE_DL_FRAME_PARMS *frame_parms,
int32_t * **txdataF,
int **txdataF,
uint32_t *jj,
uint32_t *jj2,
uint16_t re_offset,
......@@ -377,7 +377,7 @@ int allocate_REs_in_RB_no_pilots_64QAM_siso(LTE_DL_FRAME_PARMS *frame_parms,
}
int allocate_REs_in_RB_pilots_64QAM_siso(LTE_DL_FRAME_PARMS *frame_parms,
int32_t * **txdataF,
int **txdataF,
uint32_t *jj,
uint32_t *jj2,
uint16_t re_offset,
......@@ -1514,7 +1514,7 @@ int dlsch_modulation(int32_t **txdataF,
int16_t qam16_table_a1[4],qam64_table_a1[8],qam16_table_b1[4],qam64_table_b1[8];
int16_t *qam_table_s0=NULL,*qam_table_s1=NULL;
int (*allocate_REs)(LTE_DL_FRAME_PARMS *,
int32_t * **,
int **,
uint32_t*,
uint32_t*,
uint16_t,
......
......@@ -638,7 +638,7 @@ int32_t generate_prach( PHY_VARS_UE *phy_vars_ue, uint8_t eNB_id, uint8_t subfra
prach_start = ((subframe*phy_vars_ue->lte_frame_parms.samples_per_tti)<<1)-phy_vars_ue->N_TA_offset;
#else
#if defined(EXMIMO) || defined(OAI_USRP)
prach_start = (phy_vars_ue->rx_offset+subframe*phy_vars_ue->lte_frame_parms.samples_per_tti-openair_daq_vars.timing_advance-phy_vars_ue->N_TA_offset);
prach_start = (phy_vars_ue->rx_offset+subframe*phy_vars_ue->lte_frame_parms.samples_per_tti-phy_vars_ue->hw_timing_advance-phy_vars_ue->N_TA_offset);
if (prach_start<0)
prach_start+=(phy_vars_ue->lte_frame_parms.samples_per_tti*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME);
......
......@@ -102,7 +102,7 @@ int dump_ue_stats(PHY_VARS_UE *phy_vars_ue, char* buffer, int length, runmode_t
len += sprintf(&buffer[len], "[UE PROC] RX Gain %d dB\n",phy_vars_ue->rx_total_gain_dB);
#endif
#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
len += sprintf(&buffer[len], "[UE_PROC] Frequency offset %d Hz (%d), estimated carrier frequency %f Hz\n",phy_vars_ue->lte_ue_common_vars.freq_offset,openair_daq_vars.freq_offset,openair0_cfg[0].rx_freq[0]-phy_vars_ue->lte_ue_common_vars.freq_offset);
len += sprintf(&buffer[len], "[UE_PROC] Frequency offset %d Hz, estimated carrier frequency %f Hz\n",phy_vars_ue->lte_ue_common_vars.freq_offset,openair0_cfg[0].rx_freq[0]-phy_vars_ue->lte_ue_common_vars.freq_offset);
#endif
len += sprintf(&buffer[len], "[UE PROC] UE mode = %s (%d)\n",mode_string[phy_vars_ue->UE_mode[0]],phy_vars_ue->UE_mode[0]);
len += sprintf(&buffer[len], "[UE PROC] timing_advance = %d\n",phy_vars_ue->timing_advance);
......@@ -529,7 +529,7 @@ int dump_ue_stats(PHY_VARS_UE *phy_vars_ue, char* buffer, int length, runmode_t
#endif
len += sprintf(&buffer[len], "[UE PROC] DLSCH Bitrate %dkbps\n",(phy_vars_ue->bitrate[0]/1000));
len += sprintf(&buffer[len], "[UE PROC] Total Received Bits %dkbits\n",(phy_vars_ue->total_received_bits[0]/1000));
len += sprintf(&buffer[len], "[UE PROC] IA receiver %d\n",openair_daq_vars.use_ia_receiver);
len += sprintf(&buffer[len], "[UE PROC] IA receiver %d\n",phy_vars_ue->use_ia_receiver);
}
......
......@@ -47,11 +47,11 @@ static void ia_receiver_on_off( FL_OBJECT *button, long arg)
if (fl_get_button(button)) {
fl_set_object_label(button, "IA Receiver ON");
openair_daq_vars.use_ia_receiver = 1;
// PHY_vars_UE_g[0][0]->use_ia_receiver = 1;
fl_set_object_color(button, FL_GREEN, FL_GREEN);
} else {
fl_set_object_label(button, "IA Receiver OFF");
openair_daq_vars.use_ia_receiver = 0;
// PHY_vars_UE_g[0][0]->use_ia_receiver = 0;
fl_set_object_color(button, FL_RED, FL_RED);
}
}
......
......@@ -37,7 +37,6 @@
#include "../defs.h"
#include "../../SCHED/defs.h" // for OPENAIR_DAQ_VARS
extern OPENAIR_DAQ_VARS openair_daq_vars;
/* Forms and Objects */
typedef struct {
......
......@@ -330,6 +330,15 @@ typedef struct PHY_VARS_eNB_s {
MU_MIMO_mode mu_mimo_mode[NUMBER_OF_UE_MAX];
/// target_ue_dl_mcs : only for debug purposes
uint32_t target_ue_dl_mcs;
/// target_ue_ul_mcs : only for debug purposes
uint32_t target_ue_ul_mcs;
/// target_ue_dl_rballoc : only for debug purposes
uint32_t ue_dl_rb_alloc;
/// target ul PRBs : only for debug
uint32_t ue_ul_nb_rb;
///check for Total Transmissions
uint32_t check_for_total_transmissions;
......@@ -347,6 +356,8 @@ typedef struct PHY_VARS_eNB_s {
uint32_t total_transmitted_bits;
uint32_t total_system_throughput;
int hw_timing_advance;
time_stats_t phy_proc;
time_stats_t phy_proc_tx;
time_stats_t phy_proc_rx;
......@@ -577,6 +588,7 @@ typedef struct {
// uint8_t prach_timer;
int rx_offset; /// Timing offset
int timing_advance; ///timing advance signalled from eNB
int hw_timing_advance;
int N_TA_offset; ///timing offset used in TDD
/// Flag to tell if UE is secondary user (cognitive mode)
unsigned char is_secondary_ue;
......@@ -645,6 +657,8 @@ typedef struct {
time_stats_t phy_proc_tx;
time_stats_t phy_proc_rx;
uint32_t use_ia_receiver;
time_stats_t ofdm_mod_stats;
time_stats_t ulsch_encoding_stats;
time_stats_t ulsch_modulation_stats;
......
......@@ -86,7 +86,7 @@ enum openair_SYNCH_STATUS {
#define DAQ_AGC_OFF 0
/*
typedef struct {
boolean_t is_eNB;
uint8_t mode;
......@@ -133,6 +133,7 @@ typedef struct {
uint32_t get_frame_done;
uint32_t use_ia_receiver;
} OPENAIR_DAQ_VARS;
*/
#ifndef USER_MODE
int32_t openair_sched_init(void);
......
......@@ -75,7 +75,6 @@ extern int openair_sched_status;
extern int synch_wait_cnt;
extern OPENAIR_DAQ_VARS openair_daq_vars;
extern int16_t hundred_times_delta_TF[100];
extern uint16_t hundred_times_log10_NPRB[100];
......
......@@ -234,7 +234,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rballoc = rballoc;
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->TPC = 0;
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->harq_pid = DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist];
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs;
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = phy_vars_eNB->target_ue_dl_mcs;
//((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->frame%1024)%28);
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1;
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rv = 0;
......@@ -253,7 +253,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->dai = 0;
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->harq_pid = 1;
//((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->proc[subframe].frame%1024)%28);
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs;
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = phy_vars_eNB->target_ue_dl_mcs;
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->ndi = 1;
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rv = 0;
memcpy((void*)&DCI_pdu->dci_alloc[1].dci_pdu[0],(void *)&((DCI1_5MHz_FDD_t *)&dlsch_pdu)->,sizeof(DCI1_5MHz_TDD_t));
......@@ -265,7 +265,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e
((DCI1_5MHz_TDD_t *)&dlsch_pdu)->TPC = 0;
((DCI1_5MHz_TDD_t *)&dlsch_pdu)->dai = 0;
((DCI1_5MHz_TDD_t *)&dlsch_pdu)->harq_pid = DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist];
((DCI1_5MHz_TDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs;
((DCI1_5MHz_TDD_t *)&dlsch_pdu)->mcs = phy_vars_eNB->target_ue_dl_mcs;
//((DCI1_5MHz_TDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->frame%1024)%28);
((DCI1_5MHz_TDD_t *)&dlsch_pdu)->ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1;
((DCI1_5MHz_TDD_t *)&dlsch_pdu)->rv = 0;
......@@ -284,7 +284,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->dai = 0;
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->harq_pid = 1;
//((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->proc[subframe].frame%1024)%28);
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs;
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = phy_vars_eNB->target_ue_dl_mcs;
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->ndi = 1;
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rv = 0;
memcpy((void*)&DCI_pdu->dci_alloc[1].dci_pdu[0],(void *)&((DCI1_5MHz_FDD_t *)&dlsch_pdu)->,sizeof(DCI1_5MHz_TDD_t));
......@@ -301,7 +301,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e
((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rballoc = rballoc;
((DCI1_10MHz_FDD_t *)&dlsch_pdu)->TPC = 0;
((DCI1_10MHz_FDD_t *)&dlsch_pdu)->harq_pid = DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist];
((DCI1_10MHz_FDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs;
((DCI1_10MHz_FDD_t *)&dlsch_pdu)->mcs = phy_vars_eNB->target_ue_dl_mcs;
//((DCI1_10MHz_FDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->frame%1024)%28);
((DCI1_10MHz_FDD_t *)&dlsch_pdu)->ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1;
((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rv = 0;
......@@ -320,7 +320,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e
((DCI1_10MHz_FDD_t *)&dlsch_pdu)->dai = 0;
((DCI1_10MHz_FDD_t *)&dlsch_pdu)->harq_pid = 1;
//((DCI1_10MHz_FDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->proc[subframe].frame%1024)%28);
((DCI1_10MHz_FDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs;
((DCI1_10MHz_FDD_t *)&dlsch_pdu)->mcs = phy_vars_eNB->target_ue_dl_mcs;
((DCI1_10MHz_FDD_t *)&dlsch_pdu)->ndi = 1;
((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rv = 0;
memcpy((void*)&DCI_pdu->dci_alloc[1].dci_pdu[0],(void *)&((DCI1_10MHz_FDD_t *)&dlsch_pdu)->,sizeof(DCI1_10MHz_TDD_t));
......@@ -332,7 +332,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e
((DCI1_10MHz_TDD_t *)&dlsch_pdu)->TPC = 0;
((DCI1_10MHz_TDD_t *)&dlsch_pdu)->dai = 0;
((DCI1_10MHz_TDD_t *)&dlsch_pdu)->harq_pid = DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist];
((DCI1_10MHz_TDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs;
((DCI1_10MHz_TDD_t *)&dlsch_pdu)->mcs = phy_vars_eNB->target_ue_dl_mcs;
//((DCI1_10MHz_TDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->frame%1024)%28);
((DCI1_10MHz_TDD_t *)&dlsch_pdu)->ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1;
((DCI1_10MHz_TDD_t *)&dlsch_pdu)->rv = 0;
......@@ -351,7 +351,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e
((DCI1_10MHz_FDD_t *)&dlsch_pdu)->dai = 0;
((DCI1_10MHz_FDD_t *)&dlsch_pdu)->harq_pid = 1;
//((DCI1_10MHz_FDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->proc[subframe].frame%1024)%28);
((DCI1_10MHz_FDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs;
((DCI1_10MHz_FDD_t *)&dlsch_pdu)->mcs = phy_vars_eNB->target_ue_dl_mcs;
((DCI1_10MHz_FDD_t *)&dlsch_pdu)->ndi = 1;
((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rv = 0;
memcpy((void*)&DCI_pdu->dci_alloc[1].dci_pdu[0],(void *)&((DCI1_10MHz_FDD_t *)&dlsch_pdu)->,sizeof(DCI1_10MHz_TDD_t));
......@@ -367,7 +367,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rballoc = rballoc;
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->TPC = 0;
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->harq_pid = DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist];
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs;
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = phy_vars_eNB->target_ue_dl_mcs;
//((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->frame%1024)%28);
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1;
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rv = 0;
......@@ -386,7 +386,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->dai = 0;
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->harq_pid = 1;
//((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->proc[subframe].frame%1024)%28);
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs;
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = phy_vars_eNB->target_ue_dl_mcs;
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->ndi = 1;
((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rv = 0;
memcpy((void*)&DCI_pdu->dci_alloc[1].dci_pdu[0],(void *)&((DCI1_5MHz_FDD_t *)&dlsch_pdu)->,sizeof(DCI1_5MHz_TDD_t));
......@@ -398,7 +398,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e
((DCI1_20MHz_TDD_t *)&dlsch_pdu)->TPC = 0;
((DCI1_20MHz_TDD_t *)&dlsch_pdu)->dai = 0;
((DCI1_20MHz_TDD_t *)&dlsch_pdu)->harq_pid = DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist];
((DCI1_20MHz_TDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs;
((DCI1_20MHz_TDD_t *)&dlsch_pdu)->mcs = phy_vars_eNB->target_ue_dl_mcs;
//((DCI1_20MHz_TDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->frame%1024)%28);
((DCI1_20MHz_TDD_t *)&dlsch_pdu)->ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1;
((DCI1_20MHz_TDD_t *)&dlsch_pdu)->rv = 0;
......@@ -417,7 +417,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e
((DCI1_20MHz_FDD_t *)&dlsch_pdu)->dai = 0;
((DCI1_20MHz_FDD_t *)&dlsch_pdu)->harq_pid = 1;
//((DCI1_20MHz_FDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->proc[subframe].frame%1024)%28);
((DCI1_20MHz_FDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs;
((DCI1_20MHz_FDD_t *)&dlsch_pdu)->mcs = phy_vars_eNB->target_ue_dl_mcs;
((DCI1_20MHz_FDD_t *)&dlsch_pdu)->ndi = 1;
((DCI1_20MHz_FDD_t *)&dlsch_pdu)->rv = 0;
memcpy((void*)&DCI_pdu->dci_alloc[1].dci_pdu[0],(void *)&((DCI1_20MHz_FDD_t *)&dlsch_pdu)->,sizeof(DCI1_5MHz_TDD_t));
......@@ -438,14 +438,14 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e
((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->tpmi = 0;
((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->rv1 = 0;
((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->ndi1 = phy_vars_eNB->proc[sched_subframe].frame_tx&1;
((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->mcs1 = openair_daq_vars.target_ue_dl_mcs;
((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->mcs1 = phy_vars_eNB->target_ue_dl_mcs;
((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->rv2 = 0;
((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->ndi2 = phy_vars_eNB->proc[sched_subframe].frame_tx&1;
((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->mcs2 = openair_daq_vars.target_ue_dl_mcs;
((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->mcs2 = phy_vars_eNB->target_ue_dl_mcs;
((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->tb_swap = 0;
((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->harq_pid = DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist];
((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->TPC = 0;
((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->rballoc = openair_daq_vars.ue_dl_rb_alloc;
((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->rballoc = phy_vars_eNB->ue_dl_rb_alloc;
((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->rah = 0;
} else if (transmission_mode==5) {
......@@ -462,13 +462,13 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e
DLSCH_alloc_pdu1E.ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1;
//DLSCH_alloc_pdu1E.mcs = cqi_to_mcs[phy_vars_eNB->eNB_UE_stats->DL_cqi[0]];
//DLSCH_alloc_pdu1E.mcs = (unsigned char) (taus()%28);
DLSCH_alloc_pdu1E.mcs = openair_daq_vars.target_ue_dl_mcs;
DLSCH_alloc_pdu1E.mcs = phy_vars_eNB->target_ue_dl_mcs;
//DLSCH_alloc_pdu1E.mcs = (unsigned char) ((phy_vars_eNB->proc[subframe].frame%1024)%28);
phy_vars_eNB->eNB_UE_stats[0].dlsch_mcs1 = DLSCH_alloc_pdu1E.mcs;
DLSCH_alloc_pdu1E.harq_pid = DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist];
DLSCH_alloc_pdu1E.dai = 0;
DLSCH_alloc_pdu1E.TPC = 0;
DLSCH_alloc_pdu1E.rballoc = openair_daq_vars.ue_dl_rb_alloc;
DLSCH_alloc_pdu1E.rballoc = phy_vars_eNB->ue_dl_rb_alloc;
DLSCH_alloc_pdu1E.rah = 0;
DLSCH_alloc_pdu1E.dl_power_off = 0; //0=second user present
memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&DLSCH_alloc_pdu1E,sizeof(DCI1E_5MHz_2A_M10PRB_TDD_t));
......@@ -479,7 +479,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e
DCI_pdu->dci_alloc[1].rnti = 0x1236;
DCI_pdu->dci_alloc[1].format = format1E_2A_M10PRB;
DCI_pdu->dci_alloc[1].ra_flag = 0;
//DLSCH_alloc_pdu1E.mcs = openair_daq_vars.target_ue_dl_mcs;
//DLSCH_alloc_pdu1E.mcs = phy_vars_eNB->target_ue_dl_mcs;
//DLSCH_alloc_pdu1E.mcs = (unsigned char) (taus()%28);
//DLSCH_alloc_pdu1E.mcs = (unsigned char) ((phy_vars_eNB->frame%1024)%28);
DLSCH_alloc_pdu1E.mcs = (unsigned char) (((phy_vars_eNB->proc[sched_subframe].frame_tx%1024)/3)%28);
......@@ -531,8 +531,8 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e
UL_alloc_pdu.type = 0;
UL_alloc_pdu.hopping = 0;
UL_alloc_pdu.rballoc = computeRIV(25,2,openair_daq_vars.ue_ul_nb_rb);
UL_alloc_pdu.mcs = openair_daq_vars.target_ue_ul_mcs;
UL_alloc_pdu.rballoc = computeRIV(25,2,phy_vars_eNB->ue_ul_nb_rb);
UL_alloc_pdu.mcs = phy_vars_eNB->target_ue_ul_mcs;
UL_alloc_pdu.ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1;
UL_alloc_pdu.TPC = 0;
UL_alloc_pdu.cshift = 0;
......@@ -551,10 +551,10 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e
UL_alloc_pdu.type = 0;
UL_alloc_pdu.hopping = 0;
if (cooperation_flag==0)
UL_alloc_pdu.rballoc = computeRIV(25,2+openair_daq_vars.ue_ul_nb_rb,openair_daq_vars.ue_ul_nb_rb);
UL_alloc_pdu.rballoc = computeRIV(25,2+phy_vars_eNB->ue_ul_nb_rb,phy_vars_eNB->ue_ul_nb_rb);
else
UL_alloc_pdu.rballoc = computeRIV(25,0,openair_daq_vars.ue_ul_nb_rb);
UL_alloc_pdu.mcs = openair_daq_vars.target_ue_ul_mcs;
UL_alloc_pdu.rballoc = computeRIV(25,0,phy_vars_eNB->ue_ul_nb_rb);
UL_alloc_pdu.mcs = phy_vars_eNB->target_ue_ul_mcs;
UL_alloc_pdu.ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1;
UL_alloc_pdu.TPC = 0;
if ((cooperation_flag==0) || (cooperation_flag==1))
......@@ -612,11 +612,11 @@ void fill_dci_emos(DCI_PDU *DCI_pdu, uint8_t subframe, PHY_VARS_eNB *phy_vars_eN
DCI_pdu->dci_alloc[0].format = format1;
DCI_pdu->dci_alloc[0].ra_flag = 0;
DLSCH_alloc_pdu.rballoc = openair_daq_vars.ue_dl_rb_alloc;
DLSCH_alloc_pdu.rballoc = phy_vars_eNB->ue_dl_rb_alloc;
DLSCH_alloc_pdu.TPC = 0;
DLSCH_alloc_pdu.dai = 0;
DLSCH_alloc_pdu.harq_pid = 1;
DLSCH_alloc_pdu.mcs = openair_daq_vars.target_ue_dl_mcs;
DLSCH_alloc_pdu.mcs = phy_vars_eNB->target_ue_dl_mcs;
DLSCH_alloc_pdu.ndi = 1;
DLSCH_alloc_pdu.rv = 0;
memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&DLSCH_alloc_pdu,sizeof(DCI1_5MHz_TDD_t));
......@@ -633,7 +633,7 @@ void fill_dci_emos(DCI_PDU *DCI_pdu, uint8_t subframe, PHY_VARS_eNB *phy_vars_eN
DLSCH_alloc_pdu.TPC = 0;
DLSCH_alloc_pdu.dai = 0;
DLSCH_alloc_pdu.harq_pid = 1;
DLSCH_alloc_pdu.mcs = openair_daq_vars.target_ue_dl_mcs;
DLSCH_alloc_pdu.mcs = phy_vars_eNB->target_ue_dl_mcs;
DLSCH_alloc_pdu.ndi = 1;
DLSCH_alloc_pdu.rv = 0;
memcpy((void*)&DCI_pdu->dci_alloc[1].dci_pdu[0],(void *)&DLSCH_alloc_pdu,sizeof(DCI1_5MHz_TDD_t));
......@@ -650,11 +650,11 @@ void fill_dci_emos(DCI_PDU *DCI_pdu, uint8_t subframe, PHY_VARS_eNB *phy_vars_eN
DLSCH_alloc_pdu1E.tpmi = 5; //5=use feedback
DLSCH_alloc_pdu1E.rv = 0;
DLSCH_alloc_pdu1E.ndi = 1;
DLSCH_alloc_pdu1E.mcs = openair_daq_vars.target_ue_dl_mcs;
DLSCH_alloc_pdu1E.mcs = phy_vars_eNB->target_ue_dl_mcs;
DLSCH_alloc_pdu1E.harq_pid = 1;
DLSCH_alloc_pdu1E.dai = 0;
DLSCH_alloc_pdu1E.TPC = 0;
DLSCH_alloc_pdu1E.rballoc = openair_daq_vars.ue_dl_rb_alloc;
DLSCH_alloc_pdu1E.rballoc = phy_vars_eNB->ue_dl_rb_alloc;
DLSCH_alloc_pdu1E.rah = 0;
DLSCH_alloc_pdu1E.dl_power_off = 0; //0=second user present
memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&DLSCH_alloc_pdu1E,sizeof(DCI1E_5MHz_2A_M10PRB_TDD_t));
......@@ -706,8 +706,8 @@ void fill_dci_emos(DCI_PDU *DCI_pdu, uint8_t subframe, PHY_VARS_eNB *phy_vars_eN
UL_alloc_pdu.type = 0;
UL_alloc_pdu.hopping = 0;
UL_alloc_pdu.rballoc = computeRIV(25,0,openair_daq_vars.ue_ul_nb_rb);
UL_alloc_pdu.mcs = openair_daq_vars.target_ue_ul_mcs;
UL_alloc_pdu.rballoc = computeRIV(25,0,phy_vars_eNB->ue_ul_nb_rb);
UL_alloc_pdu.mcs = phy_vars_eNB->target_ue_ul_mcs;
UL_alloc_pdu.ndi = 1;
UL_alloc_pdu.TPC = 0;
UL_alloc_pdu.cshift = 0;
......@@ -726,10 +726,10 @@ void fill_dci_emos(DCI_PDU *DCI_pdu, uint8_t subframe, PHY_VARS_eNB *phy_vars_eN
UL_alloc_pdu.type = 0;
UL_alloc_pdu.hopping = 0;
if (cooperation_flag==0)
UL_alloc_pdu.rballoc = computeRIV(25,2+openair_daq_vars.ue_ul_nb_rb,openair_daq_vars.ue_ul_nb_rb);
UL_alloc_pdu.rballoc = computeRIV(25,2+phy_vars_eNB->ue_ul_nb_rb,phy_vars_eNB->ue_ul_nb_rb);
else
UL_alloc_pdu.rballoc = computeRIV(25,0,openair_daq_vars.ue_ul_nb_rb);
UL_alloc_pdu.mcs = openair_daq_vars.target_ue_ul_mcs;
UL_alloc_pdu.rballoc = computeRIV(25,0,phy_vars_eNB->ue_ul_nb_rb);
UL_alloc_pdu.mcs = phy_vars_eNB->target_ue_ul_mcs;
UL_alloc_pdu.ndi = 1;
UL_alloc_pdu.TPC = 0;
if ((cooperation_flag==0) || (cooperation_flag==1))
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -115,7 +115,7 @@ extern int rx_sig_fifo;
extern uint32_t downlink_frequency[MAX_NUM_CCs][4];
#endif
#ifdef USER_MODE
void dump_dlsch(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t subframe,uint8_t harq_pid)
{
......@@ -286,7 +286,7 @@ void dump_dlsch_ra(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t subframe)
write_output("dlsch_mag1.m","dlschmag1",phy_vars_ue->lte_ue_pdsch_vars_ra[0]->dl_ch_mag0,300*nsymb,1,1);
write_output("dlsch_mag2.m","dlschmag2",phy_vars_ue->lte_ue_pdsch_vars_ra[0]->dl_ch_magb0,300*nsymb,1,1);
}
#endif
void phy_reset_ue(uint8_t Mod_id,uint8_t CC_id,uint8_t eNB_index)
{
......@@ -367,13 +367,11 @@ void process_timing_advance_rar(PHY_VARS_UE *phy_vars_ue,uint16_t timing_advance
timing_advance = timing_advance - (1<<11);
*/
if (openair_daq_vars.manual_timing_advance == 0) {
phy_vars_ue->timing_advance = timing_advance*4;
phy_vars_ue->timing_advance = timing_advance*4;
}
#ifdef DEBUG_PHY_PROC
LOG_I(PHY,"[UE %d] Frame %d, received (rar) timing_advance %d, HW timing advance %d\n",phy_vars_ue->Mod_id,phy_vars_ue->frame_rx, phy_vars_ue->timing_advance,openair_daq_vars.timing_advance);
LOG_I(PHY,"[UE %d] Frame %d, received (rar) timing_advance %d, HW timing advance %d\n",phy_vars_ue->Mod_id,phy_vars_ue->frame_rx, phy_vars_ue->timing_advance);
#endif
}
......@@ -386,11 +384,8 @@ void process_timing_advance(uint8_t Mod_id,uint8_t CC_id,int16_t timing_advance)
// timing advance has Q1.5 format
timing_advance = timing_advance - 31;
if (openair_daq_vars.manual_timing_advance == 0) {
//if ( (frame % 100) == 0) {
//if ((timing_advance > 3) || (timing_advance < -3) )
PHY_vars_UE_g[Mod_id][CC_id]->timing_advance = PHY_vars_UE_g[Mod_id][CC_id]->timing_advance+timing_advance*4; //this is for 25RB only!!!
}
PHY_vars_UE_g[Mod_id][CC_id]->timing_advance = PHY_vars_UE_g[Mod_id][CC_id]->timing_advance+timing_advance*4; //this is for 25RB only!!!
LOG_I(PHY,"[UE %d] Got timing advance %d from MAC, new value %d\n",Mod_id, timing_advance, PHY_vars_UE_g[Mod_id][CC_id]->timing_advance);
......@@ -1223,7 +1218,7 @@ void phy_procedures_UE_TX(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstra
#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)//this is the EXPRESS MIMO case
ulsch_start = (phy_vars_ue->rx_offset+subframe_tx*frame_parms->samples_per_tti-
openair_daq_vars.timing_advance-
phy_vars_ue->hw_timing_advance-
phy_vars_ue->timing_advance-
phy_vars_ue->N_TA_offset+5)%(LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*frame_parms->samples_per_tti);
#else //this is the normal case
......@@ -1234,7 +1229,7 @@ void phy_procedures_UE_TX(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstra
Mod_id,frame_tx,subframe_tx,
ulsch_start,
phy_vars_ue->rx_offset,
openair_daq_vars.timing_advance,
phy_vars_ue->hw_timing_advance,
phy_vars_ue->timing_advance,
phy_vars_ue->N_TA_offset);
......@@ -1525,14 +1520,7 @@ void lte_ue_measurement_procedures(uint16_t l, PHY_VARS_UE *phy_vars_ue,uint8_t
// AGC
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GAIN_CONTROL, VCD_FUNCTION_IN);
#if defined EXMIMO
if ((openair_daq_vars.rx_gain_mode == DAQ_AGC_ON) &&
(mode != rx_calib_ue) && (mode != rx_calib_ue_med) && (mode != rx_calib_ue_byp) )
if (phy_vars_ue->frame_rx%100==0)
gain_control_all(dB_fixed(phy_vars_ue->PHY_measurements.rssi),0);
#else
#ifndef OAI_USRP
#ifndef OAI_BLADERF
#ifndef OAI_LMSSDR
......@@ -1540,7 +1528,7 @@ void lte_ue_measurement_procedures(uint16_t l, PHY_VARS_UE *phy_vars_ue,uint8_t
#endif
#endif
#endif
#endif
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GAIN_CONTROL, VCD_FUNCTION_OUT);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ADJUST_SYNCH, VCD_FUNCTION_IN);
eNB_id = 0;
......@@ -1554,29 +1542,6 @@ void lte_ue_measurement_procedures(uint16_t l, PHY_VARS_UE *phy_vars_ue,uint8_t
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ADJUST_SYNCH, VCD_FUNCTION_OUT);
/* if (openair_daq_vars.auto_freq_correction == 1) {
if (frame_rx % 100 == 0) {
if ((phy_vars_ue->lte_ue_common_vars.freq_offset>100) && (openair_daq_vars.freq_offset < 1000)) {
openair_daq_vars.freq_offset+=100;
#if defined(EXMIMO) && defined(DRIVER2013)
for (aa = 0; aa<4; aa++) {
p_exmimo_config->rf.rf_freq_rx[aa] = downlink_frequency[aa]+=openair_daq_vars.freq_offset;
p_exmimo_config->rf.rf_freq_tx[aa] = downlink_frequency[aa]+=openair_daq_vars.freq_offset;
}
#endif
}
else if ((phy_vars_ue->lte_ue_common_vars.freq_offset<-100) && (openair_daq_vars.freq_offset > -1000)) {
openair_daq_vars.freq_offset-=100;
#if defined(EXMIMO) && defined(DRIVER2013)
for (aa = 0; aa<4; aa++) {
p_exmimo_config->rf.rf_freq_rx[aa] = downlink_frequency[aa]+=openair_daq_vars.freq_offset;
p_exmimo_config->rf.rf_freq_tx[aa] = downlink_frequency[aa]+=openair_daq_vars.freq_offset;
}
#endif
}
}
}*/
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_MEASUREMENT_PROCEDURES, VCD_FUNCTION_OUT);
......@@ -1681,9 +1646,7 @@ void restart_phy(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstraction_fla
// first_run = 1;
if (abstraction_flag ==0 ) {
openair_daq_vars.mode = openair_NOT_SYNCHED;
phy_vars_ue->UE_mode[eNB_id] = NOT_SYNCHED;
openair_daq_vars.sync_state=0;
} else {
phy_vars_ue->UE_mode[eNB_id] = PRACH;
phy_vars_ue->prach_resources[eNB_id]=NULL;
......@@ -1691,8 +1654,8 @@ void restart_phy(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstraction_fla
phy_vars_ue->frame_rx = -1;
phy_vars_ue->frame_tx = -1;
openair_daq_vars.synch_wait_cnt=0;
openair_daq_vars.sched_cnt=-1;
// phy_vars_ue->synch_wait_cnt=0;
// phy_vars_ue->sched_cnt=-1;
phy_vars_ue->lte_ue_pbch_vars[eNB_id]->pdu_errors_conseq=0;
phy_vars_ue->lte_ue_pbch_vars[eNB_id]->pdu_errors=0;
......@@ -2564,7 +2527,7 @@ int phy_procedures_UE_RX(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstrac
if ((phy_vars_ue->transmission_mode[eNB_id] == 5) &&
(phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->dl_power_off==0) &&
(openair_daq_vars.use_ia_receiver ==1)) {
(phy_vars_ue->use_ia_receiver ==1)) {
dual_stream_UE = 1;
eNB_id_i = phy_vars_ue->n_connected_eNB;
i_mod = phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->Qm;
......@@ -2975,9 +2938,9 @@ int phy_procedures_UE_RX(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstrac
if (ret == (1+phy_vars_ue->dlsch_ue_ra[eNB_id]->max_turbo_iterations)) {
phy_vars_ue->dlsch_ra_errors[eNB_id]++;
LOG_D(PHY,"[UE %d] Frame %d, subframe %d, received RA in error\n",phy_vars_ue->Mod_id,frame_rx,subframe_prev);
#ifdef USER_MODE
//dump_dlsch_ra(phy_vars_ue,eNB_id,subframe_prev);
#endif
// dump_dlsch_ra(phy_vars_ue,eNB_id,subframe_prev); exit(-1);
// oai_exit=1;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX, VCD_FUNCTION_OUT);
stop_meas(&phy_vars_ue->phy_proc_rx);
......@@ -3107,7 +3070,7 @@ int phy_procedures_UE_RX(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstrac
if ((phy_vars_ue->transmission_mode[eNB_id] == 5) &&
(phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->dl_power_off==0) &&
(openair_daq_vars.use_ia_receiver ==1)) {
(phy_vars_ue->use_ia_receiver ==1)) {
dual_stream_UE = 1;
eNB_id_i = phy_vars_ue->n_connected_eNB;
i_mod = phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->Qm;
......@@ -3176,7 +3139,7 @@ int phy_procedures_UE_RX(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstrac
if ((phy_vars_ue->transmission_mode[eNB_id] == 5) &&
(phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->dl_power_off==0) &&
(openair_daq_vars.use_ia_receiver ==1)) {
(phy_vars_ue->use_ia_receiver ==1)) {
dual_stream_UE = 1;
eNB_id_i = phy_vars_ue->n_connected_eNB;
i_mod = phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->Qm;
......
......@@ -28,7 +28,6 @@
*******************************************************************************/
#include "defs.h"
OPENAIR_DAQ_VARS openair_daq_vars;
......@@ -569,17 +569,9 @@ schedule_ue_spec(
eNB_UE_stats->DL_cqi[0], MIN_CQI_VALUE, MAX_CQI_VALUE);
*/
eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[eNB_UE_stats->DL_cqi[0]];
eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs);
eNB_UE_stats->dlsch_mcs1 = eNB_UE_stats->dlsch_mcs1;//cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs);
#ifdef EXMIMO
if (mac_xface->get_transmission_mode(module_idP,CC_id, rnti)==5) {
eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1,16);
}
#endif
// store stats
UE_list->eNB_UE_stats[CC_id][UE_id].dl_cqi= eNB_UE_stats->DL_cqi[0];
......
......@@ -826,14 +826,14 @@ void schedule_ulsch_rnti(module_id_t module_idP,
UE_list->eNB_UE_stats[CC_id][UE_id].normalized_rx_power=normalized_rx_power;
UE_list->eNB_UE_stats[CC_id][UE_id].target_rx_power=target_rx_power;
UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1=UE_template->pre_assigned_mcs_ul;
mcs = cmin (UE_template->pre_assigned_mcs_ul, openair_daq_vars.target_ue_ul_mcs); // adjust, based on user-defined MCS
mcs = UE_template->pre_assigned_mcs_ul;//cmin (UE_template->pre_assigned_mcs_ul, openair_daq_vars.target_ue_ul_mcs); // adjust, based on user-defined MCS
if ((cqi_req==1) && (mcs>19)) {
mcs=19;
}
if (UE_template->pre_allocated_rb_table_index_ul >=0) {
rb_table_index=UE_template->pre_allocated_rb_table_index_ul;
} else {
mcs=cmin (10, openair_daq_vars.target_ue_ul_mcs);
mcs=10;//cmin (10, openair_daq_vars.target_ue_ul_mcs);
rb_table_index=5; // for PHR
}
......@@ -1171,7 +1171,7 @@ void schedule_ulsch_cba_rnti(module_id_t module_idP, unsigned char cooperation_f
required_rbs[cba_group] = 0;
num_cba_resources[cba_group]=0;
active_UEs[cba_group]=0;
mcs[cba_group]=openair_daq_vars.target_ue_ul_mcs;
mcs[cba_group]=10;//openair_daq_vars.target_ue_ul_mcs;
}
//LOG_D(MAC, "[eNB ] CBA granted ues are %d\n",granted_UEs );
......@@ -1219,7 +1219,7 @@ void schedule_ulsch_cba_rnti(module_id_t module_idP, unsigned char cooperation_f
}
}
mcs[cba_group]= cmin(mcs[cba_group],openair_daq_vars.target_ue_ul_mcs);
mcs[cba_group]= mcs[cba_group];//cmin(mcs[cba_group],openair_daq_vars.target_ue_ul_mcs);
if (available_rbs < min_rb_unit )
break;
......
......@@ -178,7 +178,7 @@ void assign_rbs_required (module_id_t Mod_id,
*/
eNB_UE_stats[CC_id]->dlsch_mcs1=cqi_to_mcs[eNB_UE_stats[CC_id]->DL_cqi[0]];
eNB_UE_stats[CC_id]->dlsch_mcs1 = cmin(eNB_UE_stats[CC_id]->dlsch_mcs1,openair_daq_vars.target_ue_dl_mcs);
eNB_UE_stats[CC_id]->dlsch_mcs1 = eNB_UE_stats[CC_id]->dlsch_mcs1;//cmin(eNB_UE_stats[CC_id]->dlsch_mcs1,openair_daq_vars.target_ue_dl_mcs);
}
......
/*******************************************************************************
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenAirInterface is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/*! \file lte-enb.c
* \brief Top-level threads for eNodeB
* \author R. Knopp, F. Kaltenberger, Navid Nikaein
* \date 2012
* \version 0.1
* \company Eurecom
* \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr, navid.nikaein@eurecom.fr
* \note
* \warning
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sched.h>
#include <linux/sched.h>
#include <signal.h>
#include <execinfo.h>
#include <getopt.h>
#include <sys/sysinfo.h>
#include "rt_wrapper.h"
#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all
#include "assertions.h"
#include "msc.h"
#include "PHY/types.h"
#include "PHY/defs.h"
#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all
//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all
#include "../../ARCH/COMMON/common_lib.h"
//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all
#include "PHY/extern.h"
#include "SCHED/extern.h"
#include "LAYER2/MAC/extern.h"
#include "../../SIMU/USER/init_lte.h"
#include "LAYER2/MAC/defs.h"
#include "LAYER2/MAC/extern.h"
#include "LAYER2/MAC/proto.h"
#include "RRC/LITE/extern.h"
#include "PHY_INTERFACE/extern.h"
#ifdef SMBV
#include "PHY/TOOLS/smbv.h"
unsigned short config_frames[4] = {2,9,11,13};
#endif
#include "UTIL/LOG/log_extern.h"
#include "UTIL/OTG/otg_tx.h"
#include "UTIL/OTG/otg_externs.h"
#include "UTIL/MATH/oml.h"
#include "UTIL/LOG/vcd_signal_dumper.h"
#include "UTIL/OPT/opt.h"
#include "enb_config.h"
//#include "PHY/TOOLS/time_meas.h"
#ifndef OPENAIR2
#include "UTIL/OTG/otg_extern.h"
#endif
#if defined(ENABLE_ITTI)
# if defined(ENABLE_USE_MME)
# include "s1ap_eNB.h"
#ifdef PDCP_USE_NETLINK
# include "SIMULATION/ETH_TRANSPORT/proto.h"
#endif
# endif
#endif
//#define DEBUG_THREADS 1
//#define USRP_DEBUG 1
struct timing_info_t {
//unsigned int frame, hw_slot, last_slot, next_slot;
RTIME time_min, time_max, time_avg, time_last, time_now;
//unsigned int mbox0, mbox1, mbox2, mbox_target;
unsigned int n_samples;
} timing_info;
extern openair0_device openair0;
#if defined(ENABLE_ITTI)
extern volatile int start_eNB;
extern volatile int start_UE;
#endif
extern volatile int oai_exit;
extern openair0_config_t openair0_cfg[MAX_CARDS];
extern pthread_cond_t sync_cond;
extern pthread_mutex_t sync_mutex;
extern int sync_var;
pthread_attr_t attr_eNB_proc_tx[MAX_NUM_CCs][NUM_ENB_THREADS];
pthread_attr_t attr_eNB_proc_rx[MAX_NUM_CCs][NUM_ENB_THREADS];
#ifndef LOWLATENCY
struct sched_param sched_param_eNB_proc_tx[MAX_NUM_CCs][NUM_ENB_THREADS];
struct sched_param sched_param_eNB_proc_rx[MAX_NUM_CCs][NUM_ENB_THREADS];
#endif
pthread_t main_eNB_thread;
pthread_attr_t attr_dlsch_threads;
#ifndef LOWLATENCY
struct sched_param sched_param_dlsch;
#endif
time_stats_t softmodem_stats_mt; // main thread
time_stats_t softmodem_stats_hw; // hw acquisition
time_stats_t softmodem_stats_tx_sf[10]; // total tx time
time_stats_t softmodem_stats_rx_sf[10]; // total rx time
int32_t **rxdata;
int32_t **txdata;
static int time_offset[4] = {0,0,0,0};
/* mutex, cond and variable to serialize phy proc TX calls
* (this mechanism may be relaxed in the future for better
* performances)
*/
static struct {
pthread_mutex_t mutex_phy_proc_tx;
pthread_cond_t cond_phy_proc_tx;
volatile uint8_t phy_proc_CC_id;
} sync_phy_proc[NUM_ENB_THREADS];
void exit_fun(const char* s);
void init_eNB(void);
void stop_eNB(void);
void do_OFDM_mod_rt(int subframe,PHY_VARS_eNB *phy_vars_eNB)
{
unsigned int aa,slot_offset, slot_offset_F;
int dummy_tx_b[7680*4] __attribute__((aligned(32)));
int i, tx_offset;
int slot_sizeF = (phy_vars_eNB->lte_frame_parms.ofdm_symbol_size)*
((phy_vars_eNB->lte_frame_parms.Ncp==1) ? 6 : 7);
int len;
slot_offset_F = (subframe<<1)*slot_sizeF;
slot_offset = subframe*phy_vars_eNB->lte_frame_parms.samples_per_tti;
if ((subframe_select(&phy_vars_eNB->lte_frame_parms,subframe)==SF_DL)||
((subframe_select(&phy_vars_eNB->lte_frame_parms,subframe)==SF_S))) {
// LOG_D(HW,"Frame %d: Generating slot %d\n",frame,next_slot);
for (aa=0; aa<phy_vars_eNB->lte_frame_parms.nb_antennas_tx; aa++) {
if (phy_vars_eNB->lte_frame_parms.Ncp == EXTENDED) {
PHY_ofdm_mod(&phy_vars_eNB->lte_eNB_common_vars.txdataF[0][aa][slot_offset_F],
dummy_tx_b,
phy_vars_eNB->lte_frame_parms.ofdm_symbol_size,
6,
phy_vars_eNB->lte_frame_parms.nb_prefix_samples,
CYCLIC_PREFIX);
PHY_ofdm_mod(&phy_vars_eNB->lte_eNB_common_vars.txdataF[0][aa][slot_offset_F+slot_sizeF],
dummy_tx_b+(phy_vars_eNB->lte_frame_parms.samples_per_tti>>1),
phy_vars_eNB->lte_frame_parms.ofdm_symbol_size,
6,
phy_vars_eNB->lte_frame_parms.nb_prefix_samples,
CYCLIC_PREFIX);
} else {
normal_prefix_mod(&phy_vars_eNB->lte_eNB_common_vars.txdataF[0][aa][slot_offset_F],
dummy_tx_b,
7,
&(phy_vars_eNB->lte_frame_parms));
// if S-subframe generate first slot only
if (subframe_select(&phy_vars_eNB->lte_frame_parms,subframe) == SF_DL)
normal_prefix_mod(&phy_vars_eNB->lte_eNB_common_vars.txdataF[0][aa][slot_offset_F+slot_sizeF],
dummy_tx_b+(phy_vars_eNB->lte_frame_parms.samples_per_tti>>1),
7,
&(phy_vars_eNB->lte_frame_parms));
}
// if S-subframe generate first slot only
if (subframe_select(&phy_vars_eNB->lte_frame_parms,subframe) == SF_S)
len = phy_vars_eNB->lte_frame_parms.samples_per_tti>>1;
else
len = phy_vars_eNB->lte_frame_parms.samples_per_tti;
/*
for (i=0;i<len;i+=4) {
dummy_tx_b[i] = 0x100;
dummy_tx_b[i+1] = 0x01000000;
dummy_tx_b[i+2] = 0xff00;
dummy_tx_b[i+3] = 0xff000000;
}*/
for (i=0; i<len; i++) {
tx_offset = (int)slot_offset+time_offset[aa]+i;
if (tx_offset<0)
tx_offset += LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->lte_frame_parms.samples_per_tti;
if (tx_offset>=(LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->lte_frame_parms.samples_per_tti))
tx_offset -= LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->lte_frame_parms.samples_per_tti;
((short*)&phy_vars_eNB->lte_eNB_common_vars.txdata[0][aa][tx_offset])[0] = ((short*)dummy_tx_b)[2*i]<<openair0_cfg[0].iq_txshift;
((short*)&phy_vars_eNB->lte_eNB_common_vars.txdata[0][aa][tx_offset])[1] = ((short*)dummy_tx_b)[2*i+1]<<openair0_cfg[0].iq_txshift;
}
// if S-subframe switch to RX in second subframe
if (subframe_select(&phy_vars_eNB->lte_frame_parms,subframe) == SF_S) {
for (i=0; i<len; i++) {
phy_vars_eNB->lte_eNB_common_vars.txdata[0][aa][tx_offset++] = 0x00010001;
}
}
if ((((phy_vars_eNB->lte_frame_parms.tdd_config==0) ||
(phy_vars_eNB->lte_frame_parms.tdd_config==1) ||
(phy_vars_eNB->lte_frame_parms.tdd_config==2) ||
(phy_vars_eNB->lte_frame_parms.tdd_config==6)) &&
(subframe==0)) || (subframe==5)) {
// turn on tx switch N_TA_offset before
//LOG_D(HW,"subframe %d, time to switch to tx (N_TA_offset %d, slot_offset %d) \n",subframe,phy_vars_eNB->N_TA_offset,slot_offset);
for (i=0; i<phy_vars_eNB->N_TA_offset; i++) {
tx_offset = (int)slot_offset+time_offset[aa]+i-phy_vars_eNB->N_TA_offset/2;
if (tx_offset<0)
tx_offset += LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->lte_frame_parms.samples_per_tti;
if (tx_offset>=(LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->lte_frame_parms.samples_per_tti))
tx_offset -= LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->lte_frame_parms.samples_per_tti;
phy_vars_eNB->lte_eNB_common_vars.txdata[0][aa][tx_offset] = 0x00000000;
}
}
}
}
}
/*!
* \brief The transmit thread of eNB.
* \ref NUM_ENB_THREADS threads of this type are active at the same time.
* \param param is a \ref eNB_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_tx( void* param )
{
static int eNB_thread_tx_status[NUM_ENB_THREADS];
eNB_proc_t *proc = (eNB_proc_t*)param;
FILE *tx_time_file = NULL;
char tx_time_name[101];
if (opp_enabled == 1) {
snprintf(tx_time_name, 100,"/tmp/%s_tx_time_thread_sf_%d", "eNB", proc->subframe);
tx_time_file = fopen(tx_time_name,"w");
}
// set default return value
eNB_thread_tx_status[proc->subframe] = 0;
MSC_START_USE();
#ifdef LOWLATENCY
struct sched_attr attr;
unsigned int flags = 0;
uint64_t runtime = 850000 ;
uint64_t deadline = 1 * 1000000 ; // each tx thread will finish within 1ms
uint64_t period = 1 * 10000000; // each tx thread has a period of 10ms from the starting point
attr.size = sizeof(attr);
attr.sched_flags = 0;
attr.sched_nice = 0;
attr.sched_priority = 0;
attr.sched_policy = SCHED_DEADLINE;
attr.sched_runtime = runtime;
attr.sched_deadline = deadline;
attr.sched_period = period;
if (sched_setattr(0, &attr, flags) < 0 ) {
perror("[SCHED] eNB tx thread: sched_setattr failed\n");
return &eNB_thread_tx_status[proc->subframe];
}
LOG_I( HW, "[SCHED] eNB TX deadline thread %d(TID %ld) started on CPU %d\n", proc->subframe, gettid(), sched_getcpu() );
#else //LOW_LATENCY
int policy, s, j;
struct sched_param sparam;
char cpu_affinity[1024];
cpu_set_t cpuset;
/* Set affinity mask to include CPUs 1 to MAX_CPUS */
/* CPU 0 is reserved for UHD threads */
/* CPU 1 is reserved for all TX threads */
/* Enable CPU Affinity only if number of CPUs >2 */
CPU_ZERO(&cpuset);
#ifdef CPU_AFFINITY
if (get_nprocs() > 2)
{
for (j = 1; j < get_nprocs(); j++)
CPU_SET(j, &cpuset);
s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (s != 0)
{
perror( "pthread_setaffinity_np");
exit_fun("Error setting processor affinity");
}
}
#endif //CPU_AFFINITY
/* Check the actual affinity mask assigned to the thread */
s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (s != 0)
{
perror( "pthread_getaffinity_np");
exit_fun("Error getting processor affinity ");
}
memset(cpu_affinity,0,sizeof(cpu_affinity));
for (j = 0; j < CPU_SETSIZE; j++)
if (CPU_ISSET(j, &cpuset))
{
char temp[1024];
sprintf (temp, " CPU_%d", j);
strcat(cpu_affinity, temp);
}
memset(&sparam, 0 , sizeof (sparam));
sparam.sched_priority = sched_get_priority_max(SCHED_FIFO)-1;
policy = SCHED_FIFO ;
s = pthread_setschedparam(pthread_self(), policy, &sparam);
if (s != 0)
{
perror("pthread_setschedparam : ");
exit_fun("Error setting thread priority");
}
s = pthread_getschedparam(pthread_self(), &policy, &sparam);
if (s != 0)
{
perror("pthread_getschedparam : ");
exit_fun("Error getting thread priority");
}
LOG_I( HW, "[SCHED][eNB] TX thread %d started on CPU %d TID %ld, sched_policy = %s , priority = %d, CPU Affinity=%s \n", proc->subframe, sched_getcpu(),gettid(),
(policy == SCHED_FIFO) ? "SCHED_FIFO" :
(policy == SCHED_RR) ? "SCHED_RR" :
(policy == SCHED_OTHER) ? "SCHED_OTHER" :
"???",
sparam.sched_priority, cpu_affinity );
#endif //LOW_LATENCY
mlockall(MCL_CURRENT | MCL_FUTURE);
while (!oai_exit) {
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_TX0+(2*proc->subframe), 0 );
if (pthread_mutex_lock(&proc->mutex_tx) != 0) {
LOG_E( PHY, "[SCHED][eNB] error locking mutex for eNB TX proc %d\n", proc->subframe );
exit_fun("nothing to add");
break;
}
while (proc->instance_cnt_tx < 0) {
// most of the time the thread is waiting here
// proc->instance_cnt_tx is -1
pthread_cond_wait( &proc->cond_tx, &proc->mutex_tx ); // this unlocks mutex_tx while waiting and then locks it again
}
if (pthread_mutex_unlock(&proc->mutex_tx) != 0) {
LOG_E(PHY,"[SCHED][eNB] error unlocking mutex for eNB TX proc %d\n",proc->subframe);
exit_fun("nothing to add");
break;
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_TX0+(2*proc->subframe), 1 );
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX_ENB, proc->frame_tx );
start_meas( &softmodem_stats_tx_sf[proc->subframe] );
if (oai_exit) break;
if (((PHY_vars_eNB_g[0][proc->CC_id]->lte_frame_parms.frame_type == TDD) &&
((subframe_select(&PHY_vars_eNB_g[0][proc->CC_id]->lte_frame_parms,proc->subframe_tx) == SF_DL) ||
(subframe_select(&PHY_vars_eNB_g[0][proc->CC_id]->lte_frame_parms,proc->subframe_tx) == SF_S))) ||
(PHY_vars_eNB_g[0][proc->CC_id]->lte_frame_parms.frame_type == FDD)) {
/* run PHY TX procedures the one after the other for all CCs to avoid race conditions
* (may be relaxed in the future for performance reasons)
*/
if (pthread_mutex_lock(&sync_phy_proc[proc->subframe].mutex_phy_proc_tx) != 0) {
LOG_E(PHY, "[SCHED][eNB] error locking PHY proc mutex for eNB TX proc %d\n", proc->subframe);
exit_fun("nothing to add");
break;
}
/* wait for our turn or oai_exit */
while (sync_phy_proc[proc->subframe].phy_proc_CC_id != proc->CC_id && !oai_exit) {
pthread_cond_wait(&sync_phy_proc[proc->subframe].cond_phy_proc_tx,
&sync_phy_proc[proc->subframe].mutex_phy_proc_tx);
}
if (pthread_mutex_unlock(&sync_phy_proc[proc->subframe].mutex_phy_proc_tx) != 0) {
LOG_E(PHY, "[SCHED][eNB] error unlocking PHY proc mutex for eNB TX proc %d\n", proc->subframe);
exit_fun("nothing to add");
}
if (oai_exit)
break;
phy_procedures_eNB_TX( proc->subframe, PHY_vars_eNB_g[0][proc->CC_id], 0, no_relay, NULL );
/* we're done, let the next one proceed */
if (pthread_mutex_lock(&sync_phy_proc[proc->subframe].mutex_phy_proc_tx) != 0) {
LOG_E(PHY, "[SCHED][eNB] error locking PHY proc mutex for eNB TX proc %d\n", proc->subframe);
exit_fun("nothing to add");
break;
}
sync_phy_proc[proc->subframe].phy_proc_CC_id++;
sync_phy_proc[proc->subframe].phy_proc_CC_id %= MAX_NUM_CCs;
pthread_cond_broadcast(&sync_phy_proc[proc->subframe].cond_phy_proc_tx);
if (pthread_mutex_unlock(&sync_phy_proc[proc->subframe].mutex_phy_proc_tx) != 0) {
LOG_E(PHY, "[SCHED][eNB] error unlocking PHY proc mutex for eNB TX proc %d\n", proc->subframe);
exit_fun("nothing to add");
break;
}
}
do_OFDM_mod_rt( proc->subframe_tx, PHY_vars_eNB_g[0][proc->CC_id] );
/*
short *txdata = (short*)&PHY_vars_eNB_g[0][proc->CC_id]->lte_eNB_common_vars.txdata[0][0][proc->subframe_tx*PHY_vars_eNB_g[0][proc->CC_id]->lte_frame_parms.samples_per_tti];
int i;
for (i=0;i<PHY_vars_eNB_g[0][proc->CC_id]->lte_frame_parms.samples_per_tti*2;i+=8) {
txdata[i] = 2047;
txdata[i+1] = 0;
txdata[i+2] = 0;
txdata[i+3] = 2047;
txdata[i+4] = -2047;
txdata[i+5] = 0;
txdata[i+6] = 0;
txdata[i+7] = -2047;
}
*/
if (pthread_mutex_lock(&proc->mutex_tx) != 0) {
LOG_E( PHY, "[SCHED][eNB] error locking mutex for eNB TX proc %d\n", proc->subframe );
exit_fun("nothing to add");
break;
}
proc->instance_cnt_tx--;
if (pthread_mutex_unlock(&proc->mutex_tx) != 0) {
LOG_E( PHY, "[SCHED][eNB] error unlocking mutex for eNB TX proc %d\n", proc->subframe );
exit_fun("nothing to add");
break;
}
proc->frame_tx++;
if (proc->frame_tx==1024)
proc->frame_tx=0;
stop_meas( &softmodem_stats_tx_sf[proc->subframe] );
#ifdef LOWLATENCY
if (opp_enabled){
if(softmodem_stats_tx_sf[proc->subframe].diff_now/(cpuf) > attr.sched_runtime){
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RUNTIME_TX_ENB, (softmodem_stats_tx_sf[proc->subframe].diff_now/cpuf - attr.sched_runtime)/1000000.0);
}
}
#endif
print_meas_now(&softmodem_stats_tx_sf[proc->subframe],"eNB_TX_SF",proc->subframe, tx_time_file);
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_TX0+(2*proc->subframe), 0 );
#ifdef DEBUG_THREADS
printf( "Exiting eNB thread TX %d\n", proc->subframe );
#endif
eNB_thread_tx_status[proc->subframe] = 0;
return &eNB_thread_tx_status[proc->subframe];
}
/*!
* \brief The receive thread of eNB.
* \ref NUM_ENB_THREADS threads of this type are active at the same time.
* \param param is a \ref eNB_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_rx( void* param )
{
static int eNB_thread_rx_status[NUM_ENB_THREADS];
eNB_proc_t *proc = (eNB_proc_t*)param;
FILE *rx_time_file = NULL;
char rx_time_name[101];
//int i;
if (opp_enabled == 1){
snprintf(rx_time_name, 100,"/tmp/%s_rx_time_thread_sf_%d", "eNB", proc->subframe);
rx_time_file = fopen(rx_time_name,"w");
}
// set default return value
eNB_thread_rx_status[proc->subframe] = 0;
MSC_START_USE();
#ifdef LOWLATENCY
struct sched_attr attr;
unsigned int flags = 0;
uint64_t runtime = 870000 ;
uint64_t deadline = 1 * 1000000;
uint64_t period = 1 * 10000000; // each rx thread has a period of 10ms from the starting point
attr.size = sizeof(attr);
attr.sched_flags = 0;
attr.sched_nice = 0;
attr.sched_priority = 0;
attr.sched_policy = SCHED_DEADLINE;
attr.sched_runtime = runtime;
attr.sched_deadline = deadline;
attr.sched_period = period;
if (sched_setattr(0, &attr, flags) < 0 ) {
perror("[SCHED] eNB RX sched_setattr failed\n");
return &eNB_thread_rx_status[proc->subframe];
}
LOG_I( HW, "[SCHED] eNB RX deadline thread %d(TID %ld) started on CPU %d\n", proc->subframe, gettid(), sched_getcpu() );
#else // LOW_LATENCY
int policy, s, j;
struct sched_param sparam;
char cpu_affinity[1024];
cpu_set_t cpuset;
/* Set affinity mask to include CPUs 1 to MAX_CPUS */
/* CPU 0 is reserved for UHD */
/* CPU 1 is reserved for all TX threads */
/* CPU 2..MAX_CPUS is reserved for all RX threads */
/* Set CPU Affinity only if number of CPUs >2 */
CPU_ZERO(&cpuset);
#ifdef CPU_AFFINITY
if (get_nprocs() >2)
{
for (j = 1; j < get_nprocs(); j++)
CPU_SET(j, &cpuset);
s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (s != 0)
{
perror( "pthread_setaffinity_np");
exit_fun (" Error setting processor affinity :");
}
}
#endif //CPU_AFFINITY
/* Check the actual affinity mask assigned to the thread */
s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (s != 0)
{
perror ("pthread_getaffinity_np");
exit_fun (" Error getting processor affinity :");
}
memset(cpu_affinity,0, sizeof(cpu_affinity));
for (j = 0; j < CPU_SETSIZE; j++)
if (CPU_ISSET(j, &cpuset))
{
char temp[1024];
sprintf (temp, " CPU_%d", j);
strcat(cpu_affinity, temp);
}
memset(&sparam, 0 , sizeof (sparam));
sparam.sched_priority = sched_get_priority_max(SCHED_FIFO)-1;
policy = SCHED_FIFO ;
s = pthread_setschedparam(pthread_self(), policy, &sparam);
if (s != 0)
{
perror("pthread_setschedparam : ");
exit_fun("Error setting thread priority");
}
memset(&sparam, 0 , sizeof (sparam));
s = pthread_getschedparam(pthread_self(), &policy, &sparam);
if (s != 0)
{
perror("pthread_getschedparam");
exit_fun("Error getting thread priority");
}
LOG_I( HW, "[SCHED][eNB] RX thread %d started on CPU %d TID %ld, sched_policy = %s, priority = %d, CPU Affinity = %s\n", proc->subframe, sched_getcpu(),gettid(),
(policy == SCHED_FIFO) ? "SCHED_FIFO" :
(policy == SCHED_RR) ? "SCHED_RR" :
(policy == SCHED_OTHER) ? "SCHED_OTHER" :
"???",
sparam.sched_priority, cpu_affinity);
#endif // LOWLATENCY
mlockall(MCL_CURRENT | MCL_FUTURE);
while (!oai_exit) {
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RX0+(2*proc->subframe), 0 );
if (pthread_mutex_lock(&proc->mutex_rx) != 0) {
LOG_E( PHY, "[SCHED][eNB] error locking mutex for eNB RX proc %d\n", proc->subframe );
exit_fun( "error locking mutex" );
break;
}
while (proc->instance_cnt_rx < 0) {
// most of the time the thread is waiting here
// proc->instance_cnt_rx is -1
pthread_cond_wait( &proc->cond_rx, &proc->mutex_rx ); // this unlocks mutex_rx while waiting and then locks it again
}
if (pthread_mutex_unlock(&proc->mutex_rx) != 0) {
LOG_E( PHY, "[SCHED][eNB] error unlocking mutex for eNB RX proc %d\n", proc->subframe );
exit_fun( "error unlocking mutex" );
break;
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RX0+(2*proc->subframe), 1 );
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX_ENB, proc->frame_rx );
start_meas( &softmodem_stats_rx_sf[proc->subframe] );
if (oai_exit) break;
if ((((PHY_vars_eNB_g[0][proc->CC_id]->lte_frame_parms.frame_type == TDD )&&(subframe_select(&PHY_vars_eNB_g[0][proc->CC_id]->lte_frame_parms,proc->subframe_rx)==SF_UL)) ||
(PHY_vars_eNB_g[0][proc->CC_id]->lte_frame_parms.frame_type == FDD))) {
phy_procedures_eNB_RX( proc->subframe, PHY_vars_eNB_g[0][proc->CC_id], 0, no_relay );
}
if ((subframe_select(&PHY_vars_eNB_g[0][proc->CC_id]->lte_frame_parms,proc->subframe_rx) == SF_S)) {
phy_procedures_eNB_S_RX( proc->subframe, PHY_vars_eNB_g[0][proc->CC_id], 0, no_relay );
}
if (pthread_mutex_lock(&proc->mutex_rx) != 0) {
LOG_E( PHY, "[SCHED][eNB] error locking mutex for eNB RX proc %d\n", proc->subframe );
exit_fun( "error locking mutex" );
break;
}
proc->instance_cnt_rx--;
if (pthread_mutex_unlock(&proc->mutex_rx) != 0) {
LOG_E( PHY, "[SCHED][eNB] error unlocking mutex for eNB RX proc %d\n", proc->subframe );
exit_fun( "error unlocking mutex" );
break;
}
proc->frame_rx++;
if (proc->frame_rx==1024)
proc->frame_rx=0;
stop_meas( &softmodem_stats_rx_sf[proc->subframe] );
#ifdef LOWLATENCY
if (opp_enabled){
if(softmodem_stats_rx_sf[proc->subframe].diff_now/(cpuf) > attr.sched_runtime){
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RUNTIME_RX_ENB, (softmodem_stats_rx_sf[proc->subframe].diff_now/cpuf - attr.sched_runtime)/1000000.0);
}
}
#endif // LOWLATENCY
print_meas_now(&softmodem_stats_rx_sf[proc->subframe],"eNB_RX_SF",proc->subframe, rx_time_file);
}
//stop_meas( &softmodem_stats_rx_sf[proc->subframe] );
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RX0+(2*proc->subframe), 0 );
#ifdef DEBUG_THREADS
printf( "Exiting eNB thread RX %d\n", proc->subframe );
#endif
eNB_thread_rx_status[proc->subframe] = 0;
return &eNB_thread_rx_status[proc->subframe];
}
void init_eNB_proc(void)
{
int i;
int CC_id;
for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
for (i=0; i<NUM_ENB_THREADS; i++) {
// set the stack size
#ifndef LOWLATENCY
/*
pthread_attr_init( &attr_eNB_proc_tx[CC_id][i] );
if (pthread_attr_setstacksize( &attr_eNB_proc_tx[CC_id][i], 64 *PTHREAD_STACK_MIN ) != 0)
perror("[ENB_PROC_TX] setting thread stack size failed\n");
pthread_attr_init( &attr_eNB_proc_rx[CC_id][i] );
if (pthread_attr_setstacksize( &attr_eNB_proc_rx[CC_id][i], 64 * PTHREAD_STACK_MIN ) != 0)
perror("[ENB_PROC_RX] setting thread stack size failed\n");
*/
// set the kernel scheduling policy and priority
sched_param_eNB_proc_tx[CC_id][i].sched_priority = sched_get_priority_max(SCHED_FIFO)-1; //OPENAIR_THREAD_PRIORITY;
pthread_attr_setschedparam (&attr_eNB_proc_tx[CC_id][i], &sched_param_eNB_proc_tx[CC_id][i]);
pthread_attr_setschedpolicy (&attr_eNB_proc_tx[CC_id][i], SCHED_FIFO);
sched_param_eNB_proc_rx[CC_id][i].sched_priority = sched_get_priority_max(SCHED_FIFO)-1; //OPENAIR_THREAD_PRIORITY;
pthread_attr_setschedparam (&attr_eNB_proc_rx[CC_id][i], &sched_param_eNB_proc_rx[CC_id][i]);
pthread_attr_setschedpolicy (&attr_eNB_proc_rx[CC_id][i], SCHED_FIFO);
printf("Setting OS scheduler to SCHED_FIFO for eNB [cc%d][thread%d] \n",CC_id, i);
#endif
PHY_vars_eNB_g[0][CC_id]->proc[i].instance_cnt_tx = -1;
PHY_vars_eNB_g[0][CC_id]->proc[i].instance_cnt_rx = -1;
PHY_vars_eNB_g[0][CC_id]->proc[i].subframe = i;
PHY_vars_eNB_g[0][CC_id]->proc[i].CC_id = CC_id;
pthread_mutex_init( &PHY_vars_eNB_g[0][CC_id]->proc[i].mutex_tx, NULL);
pthread_mutex_init( &PHY_vars_eNB_g[0][CC_id]->proc[i].mutex_rx, NULL);
pthread_cond_init( &PHY_vars_eNB_g[0][CC_id]->proc[i].cond_tx, NULL);
pthread_cond_init( &PHY_vars_eNB_g[0][CC_id]->proc[i].cond_rx, NULL);
#ifndef LOWLATENCY
pthread_create( &PHY_vars_eNB_g[0][CC_id]->proc[i].pthread_tx, &attr_eNB_proc_tx[CC_id][i], eNB_thread_tx, &PHY_vars_eNB_g[0][CC_id]->proc[i] );
pthread_create( &PHY_vars_eNB_g[0][CC_id]->proc[i].pthread_rx, &attr_eNB_proc_rx[CC_id][i], eNB_thread_rx, &PHY_vars_eNB_g[0][CC_id]->proc[i] );
#else
pthread_create( &PHY_vars_eNB_g[0][CC_id]->proc[i].pthread_tx, NULL, eNB_thread_tx, &PHY_vars_eNB_g[0][CC_id]->proc[i] );
pthread_create( &PHY_vars_eNB_g[0][CC_id]->proc[i].pthread_rx, NULL, eNB_thread_rx, &PHY_vars_eNB_g[0][CC_id]->proc[i] );
#endif
char name[16];
snprintf( name, sizeof(name), "TX %d", i );
pthread_setname_np( PHY_vars_eNB_g[0][CC_id]->proc[i].pthread_tx, name );
snprintf( name, sizeof(name), "RX %d", i );
pthread_setname_np( PHY_vars_eNB_g[0][CC_id]->proc[i].pthread_rx, name );
PHY_vars_eNB_g[0][CC_id]->proc[i].frame_tx = 0;
PHY_vars_eNB_g[0][CC_id]->proc[i].frame_rx = 0;
PHY_vars_eNB_g[0][CC_id]->proc[i].subframe_rx = i;
PHY_vars_eNB_g[0][CC_id]->proc[i].subframe_tx = (i+2)%10;
}
// TX processes subframe +2, RX subframe
// Note this inialization is because the first process awoken for frame 0 is number 1 and so processes 8,9 and 0 have to start with frame 1
// PHY_vars_eNB_g[0][CC_id]->proc[7].frame_tx = 1;
PHY_vars_eNB_g[0][CC_id]->proc[8].frame_tx = 1;
PHY_vars_eNB_g[0][CC_id]->proc[9].frame_tx = 1;
// PHY_vars_eNB_g[0][CC_id]->proc[0].frame_tx = 1;
}
/* setup PHY proc TX sync mechanism */
for (i=0; i<NUM_ENB_THREADS; i++) {
pthread_mutex_init(&sync_phy_proc[i].mutex_phy_proc_tx, NULL);
pthread_cond_init(&sync_phy_proc[i].cond_phy_proc_tx, NULL);
sync_phy_proc[i].phy_proc_CC_id = 0;
}
}
/*!
* \brief Terminate eNB TX and RX threads.
*/
void kill_eNB_proc(void)
{
int *status;
for (int CC_id=0; CC_id<MAX_NUM_CCs; CC_id++)
for (int i=0; i<NUM_ENB_THREADS; i++) {
#ifdef DEBUG_THREADS
printf( "Killing TX CC_id %d thread %d\n", CC_id, i );
#endif
PHY_vars_eNB_g[0][CC_id]->proc[i].instance_cnt_tx = 0; // FIXME data race!
pthread_cond_signal( &PHY_vars_eNB_g[0][CC_id]->proc[i].cond_tx );
pthread_cond_broadcast(&sync_phy_proc[i].cond_phy_proc_tx);
#ifdef DEBUG_THREADS
printf( "Joining eNB TX CC_id %d thread %d...\n", CC_id, i );
#endif
int result = pthread_join( PHY_vars_eNB_g[0][CC_id]->proc[i].pthread_tx, (void**)&status );
#ifdef DEBUG_THREADS
if (result != 0) {
printf( "Error joining thread.\n" );
} else {
if (status) {
printf( "status %d\n", *status );
} else {
printf( "The thread was killed. No status available.\n" );
}
}
#else
UNUSED(result)
#endif
#ifdef DEBUG_THREADS
printf( "Killing RX CC_id %d thread %d\n", CC_id, i );
#endif
PHY_vars_eNB_g[0][CC_id]->proc[i].instance_cnt_rx = 0; // FIXME data race!
pthread_cond_signal( &PHY_vars_eNB_g[0][CC_id]->proc[i].cond_rx );
#ifdef DEBUG_THREADS
printf( "Joining eNB RX CC_id %d thread %d...\n", CC_id, i );
#endif
result = pthread_join( PHY_vars_eNB_g[0][CC_id]->proc[i].pthread_rx, (void**)&status );
#ifdef DEBUG_THREADS
if (result != 0) {
printf( "Error joining thread.\n" );
} else {
if (status) {
printf( "status %d\n", *status );
} else {
printf( "The thread was killed. No status available.\n" );
}
}
#else
UNUSED(result)
#endif
pthread_mutex_destroy( &PHY_vars_eNB_g[0][CC_id]->proc[i].mutex_tx );
pthread_mutex_destroy( &PHY_vars_eNB_g[0][CC_id]->proc[i].mutex_rx );
pthread_cond_destroy( &PHY_vars_eNB_g[0][CC_id]->proc[i].cond_tx );
pthread_cond_destroy( &PHY_vars_eNB_g[0][CC_id]->proc[i].cond_rx );
}
}
/* this function maps the phy_vars_eNB tx and rx buffers to the available rf chains.
Each rf chain is is addressed by the card number and the chain on the card. The
rf_map specifies for each CC, on which rf chain the mapping should start. Multiple
antennas are mapped to successive RF chains on the same card. */
int setup_eNB_buffers(PHY_VARS_eNB **phy_vars_eNB, openair0_config_t *openair0_cfg, openair0_rf_map rf_map[MAX_NUM_CCs])
{
int i, CC_id;
#ifndef EXMIMO
uint16_t N_TA_offset = 0;
#else
int j;
#endif
LTE_DL_FRAME_PARMS *frame_parms;
for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
if (phy_vars_eNB[CC_id]) {
frame_parms = &(phy_vars_eNB[CC_id]->lte_frame_parms);
printf("setup_eNB_buffers: frame_parms = %p\n",frame_parms);
} else {
printf("phy_vars_eNB[%d] not initialized\n", CC_id);
return(-1);
}
#ifndef EXMIMO
if (frame_parms->frame_type == TDD) {
if (frame_parms->N_RB_DL == 100)
N_TA_offset = 624;
else if (frame_parms->N_RB_DL == 50)
N_TA_offset = 624/2;
else if (frame_parms->N_RB_DL == 25)
N_TA_offset = 624/4;
}
#endif
// replace RX signal buffers with mmaped HW versions
#ifdef EXMIMO
openair0_cfg[CC_id].tx_num_channels = 0;
openair0_cfg[CC_id].rx_num_channels = 0;
for (i=0; i<frame_parms->nb_antennas_rx; i++) {
printf("Mapping eNB CC_id %d, rx_ant %d, freq %u on card %d, chain %d\n",CC_id,i,downlink_frequency[CC_id][i]+uplink_frequency_offset[CC_id][i],rf_map[CC_id].card,rf_map[CC_id].chain+i);
free(phy_vars_eNB[CC_id]->lte_eNB_common_vars.rxdata[0][i]);
phy_vars_eNB[CC_id]->lte_eNB_common_vars.rxdata[0][i] = (int32_t*) openair0_exmimo_pci[rf_map[CC_id].card].adc_head[rf_map[CC_id].chain+i];
if (openair0_cfg[rf_map[CC_id].card].rx_freq[rf_map[CC_id].chain+i]) {
printf("Error with rf_map! A channel has already been allocated!\n");
return(-1);
} else {
openair0_cfg[rf_map[CC_id].card].rx_freq[rf_map[CC_id].chain+i] = downlink_frequency[CC_id][i]+uplink_frequency_offset[CC_id][i];
openair0_cfg[rf_map[CC_id].card].rx_gain[rf_map[CC_id].chain+i] = rx_gain[CC_id][i];
openair0_cfg[rf_map[CC_id].card].rx_num_channels++;
}
printf("rxdata[%d] @ %p\n",i,phy_vars_eNB[CC_id]->lte_eNB_common_vars.rxdata[0][i]);
for (j=0; j<16; j++) {
printf("rxbuffer %d: %x\n",j,phy_vars_eNB[CC_id]->lte_eNB_common_vars.rxdata[0][i][j]);
phy_vars_eNB[CC_id]->lte_eNB_common_vars.rxdata[0][i][j] = 16-j;
}
}
for (i=0; i<frame_parms->nb_antennas_tx; i++) {
printf("Mapping eNB CC_id %d, tx_ant %d, freq %u on card %d, chain %d\n",CC_id,i,downlink_frequency[CC_id][i],rf_map[CC_id].card,rf_map[CC_id].chain+i);
free(phy_vars_eNB[CC_id]->lte_eNB_common_vars.txdata[0][i]);
phy_vars_eNB[CC_id]->lte_eNB_common_vars.txdata[0][i] = (int32_t*) openair0_exmimo_pci[rf_map[CC_id].card].dac_head[rf_map[CC_id].chain+i];
if (openair0_cfg[rf_map[CC_id].card].tx_freq[rf_map[CC_id].chain+i]) {
printf("Error with rf_map! A channel has already been allocated!\n");
return(-1);
} else {
openair0_cfg[rf_map[CC_id].card].tx_freq[rf_map[CC_id].chain+i] = downlink_frequency[CC_id][i];
openair0_cfg[rf_map[CC_id].card].tx_gain[rf_map[CC_id].chain+i] = tx_gain[CC_id][i];
openair0_cfg[rf_map[CC_id].card].tx_num_channels++;
}
printf("txdata[%d] @ %p\n",i,phy_vars_eNB[CC_id]->lte_eNB_common_vars.txdata[0][i]);
for (j=0; j<16; j++) {
printf("txbuffer %d: %x\n",j,phy_vars_eNB[CC_id]->lte_eNB_common_vars.txdata[0][i][j]);
phy_vars_eNB[CC_id]->lte_eNB_common_vars.txdata[0][i][j] = 16-j;
}
}
#else // not EXMIMO
rxdata = (int32_t**)malloc16(frame_parms->nb_antennas_rx*sizeof(int32_t*));
txdata = (int32_t**)malloc16(frame_parms->nb_antennas_tx*sizeof(int32_t*));
for (i=0; i<frame_parms->nb_antennas_rx; i++) {
free(phy_vars_eNB[CC_id]->lte_eNB_common_vars.rxdata[0][i]);
rxdata[i] = (int32_t*)(32 + malloc16(32+openair0_cfg[rf_map[CC_id].card].samples_per_frame*sizeof(int32_t))); // FIXME broken memory allocation
phy_vars_eNB[CC_id]->lte_eNB_common_vars.rxdata[0][i] = rxdata[i]-N_TA_offset; // N_TA offset for TDD FIXME! N_TA_offset > 16 => access of unallocated memory
memset(rxdata[i], 0, openair0_cfg[rf_map[CC_id].card].samples_per_frame*sizeof(int32_t));
printf("rxdata[%d] @ %p (%p) (N_TA_OFFSET %d)\n", i, phy_vars_eNB[CC_id]->lte_eNB_common_vars.rxdata[0][i],rxdata[i],N_TA_offset);
}
for (i=0; i<frame_parms->nb_antennas_tx; i++) {
free(phy_vars_eNB[CC_id]->lte_eNB_common_vars.txdata[0][i]);
txdata[i] = (int32_t*)(32 + malloc16(32 + openair0_cfg[rf_map[CC_id].card].samples_per_frame*sizeof(int32_t))); // FIXME broken memory allocation
phy_vars_eNB[CC_id]->lte_eNB_common_vars.txdata[0][i] = txdata[i];
memset(txdata[i],0, openair0_cfg[rf_map[CC_id].card].samples_per_frame*sizeof(int32_t));
printf("txdata[%d] @ %p\n", i, phy_vars_eNB[CC_id]->lte_eNB_common_vars.txdata[0][i]);
}
#endif
}
return(0);
}
#if defined(ENABLE_ITTI)
static void wait_system_ready (char *message, volatile int *start_flag)
{
/* Wait for eNB application initialization to be complete (eNB registration to MME) */
{
static char *indicator[] = {". ", ".. ", "... ", ".... ", ".....",
" ....", " ...", " ..", " .", " "
};
int i = 0;
while ((!oai_exit) && (*start_flag == 0)) {
LOG_N(EMU, message, indicator[i]);
fflush(stdout);
i = (i + 1) % (sizeof(indicator) / sizeof(indicator[0]));
usleep(200000);
}
LOG_D(EMU,"\n");
}
}
#endif
/*!
* \brief This is the main eNB thread.
* \param arg unused
* \returns a pointer to an int. The storage is not on the heap and must not be freed.
*/
static void* eNB_thread( void* arg )
{
UNUSED(arg);
static int eNB_thread_status;
unsigned char slot;
// the USRP implementation operates on subframes, not slots
// one subframe consists of one even and one odd slot
slot = 1;
int spp;
int tx_launched = 0;
int card=0;
void *rxp[2]; // FIXME hard coded array size; indexed by lte_frame_parms.nb_antennas_rx
void *txp[2]; // FIXME hard coded array size; indexed by lte_frame_parms.nb_antennas_tx
int hw_subframe = 0; // 0..NUM_ENB_THREADS-1 => 0..9
unsigned int rx_pos = 0;
unsigned int tx_pos = 0;
int CC_id=0;
struct timespec trx_time0, trx_time1, trx_time2;
/* avoid gcc warnings */
(void)trx_time0;
(void)trx_time1;
(void)trx_time2;
#ifdef LOWLATENCY
struct sched_attr attr;
unsigned int flags = 0;
attr.size = sizeof(attr);
attr.sched_flags = 0;
attr.sched_nice = 0;
attr.sched_priority = 0;
/* This creates a .2 ms reservation */
attr.sched_policy = SCHED_DEADLINE;
attr.sched_runtime = (0.3 * 100) * 10000;
attr.sched_deadline = (0.9 * 100) * 10000;
attr.sched_period = 1 * 1000000;
if (sched_setattr(0, &attr, flags) < 0 ) {
perror("[SCHED] main eNB thread: sched_setattr failed\n");
exit_fun("Nothing to add");
} else {
LOG_I(HW,"[SCHED][eNB] eNB main deadline thread %ld started on CPU %d\n",
gettid(),sched_getcpu());
}
#else
int policy, s, j;
struct sched_param sparam;
char cpu_affinity[1024];
cpu_set_t cpuset;
/* Set affinity mask to include CPUs 1 to MAX_CPUS */
/* CPU 0 is reserved for UHD threads */
CPU_ZERO(&cpuset);
#ifdef CPU_AFFINITY
if (get_nprocs() >2)
{
for (j = 1; j < get_nprocs(); j++)
CPU_SET(j, &cpuset);
s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (s != 0)
{
perror( "pthread_setaffinity_np");
exit_fun("Error setting processor affinity");
}
}
#endif // CPU_AFFINITY
/* Check the actual affinity mask assigned to the thread */
s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (s != 0)
{
perror( "pthread_getaffinity_np");
exit_fun("Error getting processor affinity ");
}
memset(cpu_affinity, 0 , sizeof(cpu_affinity));
for (j = 0; j < CPU_SETSIZE; j++)
if (CPU_ISSET(j, &cpuset))
{
char temp[1024];
sprintf(temp, " CPU_%d ", j);
strcat(cpu_affinity, temp);
}
memset(&sparam, 0 , sizeof (sparam));
sparam.sched_priority = sched_get_priority_max(SCHED_FIFO);
policy = SCHED_FIFO ;
s = pthread_setschedparam(pthread_self(), policy, &sparam);
if (s != 0)
{
perror("pthread_setschedparam : ");
exit_fun("Error setting thread priority");
}
s = pthread_getschedparam(pthread_self(), &policy, &sparam);
if (s != 0)
{
perror("pthread_getschedparam : ");
exit_fun("Error getting thread priority");
}
LOG_I( HW, "[SCHED][eNB] Started eNB main thread on CPU %d TID %ld , sched_policy = %s, priority = %d, CPU Affinity = %s \n", (int)sched_getcpu(), gettid(),
(policy == SCHED_FIFO) ? "SCHED_FIFO" :
(policy == SCHED_RR) ? "SCHED_RR" :
(policy == SCHED_OTHER) ? "SCHED_OTHER" :
"???",
(int) sparam.sched_priority, cpu_affinity);
#endif //LOWLATENCY
// stop early, if an exit is requested
// FIXME really neccessary?
if (oai_exit)
goto eNB_thread_cleanup;
printf("eNB_thread: mlockall in ...\n");
mlockall(MCL_CURRENT | MCL_FUTURE);
printf("eNB_thread: mlockall out ...\n");
timing_info.time_min = 100000000ULL;
timing_info.time_max = 0;
timing_info.time_avg = 0;
timing_info.n_samples = 0;
printf( "waiting for sync (eNB_thread)\n" );
pthread_mutex_lock( &sync_mutex );
while (sync_var<0)
pthread_cond_wait( &sync_cond, &sync_mutex );
pthread_mutex_unlock(&sync_mutex);
printf( "got sync (eNB_thread)\n" );
int frame = 0;
spp = openair0_cfg[0].samples_per_packet;
tx_pos = openair0_cfg[0].tx_scheduling_advance;
#if defined(ENABLE_ITTI)
wait_system_ready ("Waiting for eNB application to be ready %s\r", &start_eNB);
#endif
while (!oai_exit) {
start_meas( &softmodem_stats_mt );
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_HW_SUBFRAME, hw_subframe );
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_HW_FRAME, frame );
tx_launched = 0;
while (rx_pos < ((1+hw_subframe)*PHY_vars_eNB_g[0][0]->lte_frame_parms.samples_per_tti)) {
unsigned int rxs;
#ifndef USRP_DEBUG
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 );
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TXCNT, tx_pos );
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RXCNT, rx_pos );
clock_gettime( CLOCK_MONOTONIC, &trx_time0 );
start_meas( &softmodem_stats_hw );
openair0_timestamp timestamp;
int i=0;
// prepare rx buffer pointers
for (i=0; i<PHY_vars_eNB_g[0][0]->lte_frame_parms.nb_antennas_rx; i++)
rxp[i] = (void*)&rxdata[i][rx_pos];
// check if nsymb_read == spp
// map antenna port i to the cc_id. Now use the 1:1 mapping
rxs = openair0.trx_read_func(&openair0,
&timestamp,
rxp,
spp,
PHY_vars_eNB_g[0][0]->lte_frame_parms.nb_antennas_rx);
stop_meas( &softmodem_stats_hw );
if (frame > 50) {
clock_gettime( CLOCK_MONOTONIC, &trx_time1 );
}
if (frame > 20){
if (rxs != spp)
exit_fun( "problem receiving samples" );
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 );
// Transmit TX buffer based on timestamp from RX
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 );
// prepare tx buffer pointers
for (i=0; i<PHY_vars_eNB_g[0][0]->lte_frame_parms.nb_antennas_tx; i++)
txp[i] = (void*)&txdata[i][tx_pos];
// if symb_written < spp ==> error
if (frame > 50) {
openair0.trx_write_func(&openair0,
(timestamp+(openair0_cfg[card].tx_scheduling_advance)-openair0_cfg[card].tx_sample_advance),
txp,
spp,
PHY_vars_eNB_g[0][0]->lte_frame_parms.nb_antennas_tx,
1);
}
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, timestamp&0xffffffff );
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, (timestamp+(openair0_cfg[card].tx_scheduling_advance)-openair0_cfg[card].tx_sample_advance)&0xffffffff );
stop_meas( &softmodem_stats_mt );
if (frame > 50) {
clock_gettime( CLOCK_MONOTONIC, &trx_time2 );
//update_difftimes(trx_time1, trx_time2);
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE,0);
#else
// USRP_DEBUG is active
rt_sleep_ns(1000000);
#endif
/* FT configurable tx lauch delay (in slots): txlaunch_wait, txlaunch_wait_slotcount is device specific and
set in the corresponding library (with txlaunch_wait=1 and txlaunch_wait_slotcount=1 the check is as it previously was) */
/* old check:
if ((frame>50) &&
(tx_launched == 0) &&
(rx_pos >= (((2*hw_subframe)+1)*PHY_vars_eNB_g[0][0]->lte_frame_parms.samples_per_tti>>1))) {*/
if ( (frame>50) && (tx_launched == 0) &&
((openair0_cfg[card].txlaunch_wait == 0) ||
((openair0_cfg[card].txlaunch_wait == 1) &&
(rx_pos >= (((2*hw_subframe)+openair0_cfg[card].txlaunch_wait_slotcount)*PHY_vars_eNB_g[0][0]->lte_frame_parms.samples_per_tti>>1))))) {
tx_launched = 1;
for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
if (pthread_mutex_lock(&PHY_vars_eNB_g[0][CC_id]->proc[hw_subframe].mutex_tx) != 0) {
LOG_E( PHY, "[eNB] ERROR pthread_mutex_lock for eNB TX thread %d (IC %d)\n", hw_subframe, PHY_vars_eNB_g[0][CC_id]->proc[hw_subframe].instance_cnt_tx );
exit_fun( "error locking mutex_tx" );
break;
}
int cnt_tx = ++PHY_vars_eNB_g[0][CC_id]->proc[hw_subframe].instance_cnt_tx;
pthread_mutex_unlock( &PHY_vars_eNB_g[0][CC_id]->proc[hw_subframe].mutex_tx );
if (cnt_tx == 0) {
// the thread was presumably waiting where it should and can now be woken up
if (pthread_cond_signal(&PHY_vars_eNB_g[0][CC_id]->proc[hw_subframe].cond_tx) != 0) {
LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB TX thread %d\n", hw_subframe );
exit_fun( "ERROR pthread_cond_signal" );
break;
}
} else {
LOG_W( PHY,"[eNB] Frame %d, eNB TX thread %d busy!! (rx_cnt %u, cnt_tx %i)\n", PHY_vars_eNB_g[0][CC_id]->proc[hw_subframe].frame_tx, hw_subframe, rx_pos, cnt_tx );
exit_fun( "TX thread busy" );
break;
}
}
}
rx_pos += spp;
tx_pos += spp;
if (tx_pos >= openair0_cfg[card].samples_per_frame)
tx_pos -= openair0_cfg[card].samples_per_frame;
}
if (rx_pos >= openair0_cfg[card].samples_per_frame)
rx_pos -= openair0_cfg[card].samples_per_frame;
if (oai_exit) break;
timing_info.time_last = timing_info.time_now;
timing_info.time_now = rt_get_time_ns();
if (timing_info.n_samples>0) {
RTIME time_diff = timing_info.time_now - timing_info.time_last;
if (time_diff < timing_info.time_min)
timing_info.time_min = time_diff;
if (time_diff > timing_info.time_max)
timing_info.time_max = time_diff;
timing_info.time_avg += time_diff;
}
timing_info.n_samples++;
if ((slot&1) == 1) {
// odd slot
int sf = hw_subframe;
if (frame>50) {
for (int CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
if (pthread_mutex_lock(&PHY_vars_eNB_g[0][CC_id]->proc[sf].mutex_rx) != 0) {
LOG_E( PHY, "[eNB] ERROR pthread_mutex_lock for eNB RX thread %d (IC %d)\n", sf, PHY_vars_eNB_g[0][CC_id]->proc[sf].instance_cnt_rx );
exit_fun( "error locking mutex_rx" );
break;
}
int cnt_rx = ++PHY_vars_eNB_g[0][CC_id]->proc[sf].instance_cnt_rx;
pthread_mutex_unlock( &PHY_vars_eNB_g[0][CC_id]->proc[sf].mutex_rx );
if (cnt_rx == 0) {
// the thread was presumably waiting where it should and can now be woken up
if (pthread_cond_signal(&PHY_vars_eNB_g[0][CC_id]->proc[sf].cond_rx) != 0) {
LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB RX thread %d\n", sf );
exit_fun( "ERROR pthread_cond_signal" );
break;
}
} else {
LOG_W( PHY, "[eNB] Frame %d, eNB RX thread %d busy!! instance_cnt %d CC_id %d\n", PHY_vars_eNB_g[0][CC_id]->proc[sf].frame_rx, sf, PHY_vars_eNB_g[0][CC_id]->proc[sf].instance_cnt_rx, CC_id );
exit_fun( "RX thread busy" );
break;
}
}
}
}
hw_subframe++;
slot += 2;
if (hw_subframe == NUM_ENB_THREADS) {
// the radio frame is complete, start over
hw_subframe = 0;
frame++;
slot = 1;
}
#if defined(ENABLE_ITTI)
itti_update_lte_time( frame, slot );
#endif
}
eNB_thread_cleanup:
#ifdef DEBUG_THREADS
printf( "eNB_thread: finished, ran %d times.\n", frame );
#endif
#ifdef DEBUG_THREADS
printf( "Exiting eNB_thread ..." );
#endif
eNB_thread_status = 0;
// print_difftimes();
return &eNB_thread_status;
}
void reset_opp_meas(void) {
int sfn;
reset_meas(&softmodem_stats_mt);
reset_meas(&softmodem_stats_hw);
for (sfn=0; sfn < 10; sfn++) {
reset_meas(&softmodem_stats_tx_sf[sfn]);
reset_meas(&softmodem_stats_rx_sf[sfn]);
}
}
void print_opp_meas(void) {
int sfn=0;
print_meas(&softmodem_stats_mt, "Main ENB Thread", NULL, NULL);
print_meas(&softmodem_stats_hw, "HW Acquisation", NULL, NULL);
for (sfn=0; sfn < 10; sfn++) {
print_meas(&softmodem_stats_tx_sf[sfn],"[eNB][total_phy_proc_tx]",NULL, NULL);
print_meas(&softmodem_stats_rx_sf[sfn],"[eNB][total_phy_proc_rx]",NULL,NULL);
}
}
void init_eNB() {
int error_code;
pthread_attr_init (&attr_dlsch_threads);
pthread_attr_setstacksize(&attr_dlsch_threads,4*PTHREAD_STACK_MIN);
#ifndef LOWLATENCY
sched_param_dlsch.sched_priority = sched_get_priority_max(SCHED_FIFO); //OPENAIR_THREAD_PRIORITY;
pthread_attr_setschedparam (&attr_dlsch_threads, &sched_param_dlsch);
pthread_attr_setschedpolicy (&attr_dlsch_threads, SCHED_FIFO);
printf("Setting eNB_thread FIFO scheduling policy with priority %d \n", sched_param_dlsch.sched_priority);
#endif
init_eNB_proc();
sleep(1);
LOG_D(HW,"[lte-softmodem.c] eNB threads created\n");
printf("Creating main eNB_thread \n");
error_code = pthread_create( &main_eNB_thread, &attr_dlsch_threads, eNB_thread, NULL );
if (error_code!= 0) {
LOG_D(HW,"[lte-softmodem.c] Could not allocate eNB_thread, error %d\n",error_code);
} else {
LOG_D( HW, "[lte-softmodem.c] Allocate eNB_thread successful\n" );
pthread_setname_np( main_eNB_thread, "main eNB" );
}
}
void stop_eNB() {
#ifdef DEBUG_THREADS
printf("Joining eNB_thread ...");
#endif
int *eNB_thread_status_p;
int result = pthread_join( main_eNB_thread, (void**)&eNB_thread_status_p );
#ifdef DEBUG_THREADS
if (result != 0) {
printf( "\nError joining main_eNB_thread.\n" );
} else {
if (eNB_thread_status_p) {
printf( "status %d\n", *eNB_thread_status_p );
} else {
printf( "The thread was killed. No status available.\n");
}
}
#else
UNUSED(result);
#endif // DEBUG_THREADS
printf("Killing eNB processing threads\n");
kill_eNB_proc();
}
......@@ -27,8 +27,8 @@
*******************************************************************************/
/*! \file lte-softmodem.c
* \brief main program to control HW and scheduling
/*! \file lte-enb.c
* \brief Top-level threads for eNodeB
* \author R. Knopp, F. Kaltenberger, Navid Nikaein
* \date 2012
* \version 0.1
......@@ -58,22 +58,13 @@
#include "assertions.h"
#include "msc.h"
#ifdef EMOS
#include <gps.h>
struct gps_fix_t dummy_gps_data;
#endif
#include "PHY/types.h"
#include "PHY/defs.h"
#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all
//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all
#ifdef EXMIMO
#include "openair0_lib.h"
#else
#include "../../ARCH/COMMON/common_lib.h"
#endif
//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all
......@@ -83,10 +74,6 @@ struct gps_fix_t dummy_gps_data;
#include "../../SIMU/USER/init_lte.h"
#ifdef EMOS
#include "SCHED/phy_procedures_emos.h"
#endif
#include "LAYER2/MAC/defs.h"
#include "LAYER2/MAC/vars.h"
#include "LAYER2/MAC/proto.h"
......@@ -126,34 +113,17 @@ unsigned short config_frames[4] = {2,9,11,13};
#include "stats.h"
#endif
#define FRAME_PERIOD 100000000ULL
#define DAQ_PERIOD 66667ULL
//#define DEBUG_THREADS 1
//#define USRP_DEBUG 1
// In lte-enb.c
extern int setup_eNB_buffers(PHY_VARS_eNB **phy_vars_eNB, openair0_config_t *openair0_cfg, openair0_rf_map rf_map[MAX_NUM_CCs]);
extern void init_eNB(void);
extern void stop_eNB(void);
extern void kill_eNB_proc(void);
struct timing_info_t {
//unsigned int frame, hw_slot, last_slot, next_slot;
RTIME time_min, time_max, time_avg, time_last, time_now;
//unsigned int mbox0, mbox1, mbox2, mbox_target;
unsigned int n_samples;
} timing_info;
openair0_config_t openair0_cfg[MAX_CARDS];
int32_t **rxdata;
int32_t **txdata;
int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue, openair0_config_t *openair0_cfg, openair0_rf_map rf_map[MAX_NUM_CCs]);
int setup_eNB_buffers(PHY_VARS_eNB **phy_vars_eNB, openair0_config_t *openair0_cfg, openair0_rf_map rf_map[MAX_NUM_CCs]);
uint16_t runtime_phy_rx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100]
uint16_t runtime_phy_tx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100]
double cpuf;
// In lte-ue.c
extern int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue, openair0_config_t *openair0_cfg, openair0_rf_map rf_map[MAX_NUM_CCs]);
extern void fill_ue_band_info(void);
extern void init_UE(void);
void fill_ue_band_info(void);
#ifdef XFORMS
// current status is that every UE has a DL scope for a SINGLE eNB (eNB_id=0)
// at eNB 0, an UL scope for every UE
......@@ -164,22 +134,10 @@ char title[255];
unsigned char scope_enb_num_ue = 2;
#endif //XFORMS
#ifdef RTAI
static long main_eNB_thread;
static long main_ue_thread;
#else
pthread_t main_eNB_thread;
pthread_t main_ue_thread;
pthread_attr_t attr_dlsch_threads;
pthread_attr_t attr_UE_thread;
#ifndef LOWLATENCY
struct sched_param sched_param_dlsch;
#endif
#endif
pthread_cond_t sync_cond;
pthread_mutex_t sync_mutex;
......@@ -188,45 +146,25 @@ int sync_var=-1; //!< protected by mutex \ref sync_mutex.
struct sched_param sched_param_UE_thread;
pthread_attr_t attr_eNB_proc_tx[MAX_NUM_CCs][NUM_ENB_THREADS];
pthread_attr_t attr_eNB_proc_rx[MAX_NUM_CCs][NUM_ENB_THREADS];
#ifndef LOWLATENCY
struct sched_param sched_param_eNB_proc_tx[MAX_NUM_CCs][NUM_ENB_THREADS];
struct sched_param sched_param_eNB_proc_rx[MAX_NUM_CCs][NUM_ENB_THREADS];
#endif
#ifdef XFORMS
static pthread_t forms_thread; //xforms
#endif
#ifdef EMOS
static pthread_t thread3; //emos
static pthread_t thread4; //GPS
#endif
openair0_device openair0;
/*
static int instance_cnt=-1; //0 means worker is busy, -1 means its free
int instance_cnt_ptr_kern,*instance_cnt_ptr_user;
int pci_interface_ptr_kern;
*/
//extern unsigned int bigphys_top;
//extern unsigned int mem_base;
//int card = 0;
uint16_t runtime_phy_rx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100]
uint16_t runtime_phy_tx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100]
#if defined(ENABLE_ITTI)
static volatile int start_eNB = 0;
static volatile int start_UE = 0;
volatile int start_eNB = 0;
volatile int start_UE = 0;
#endif
volatile int oai_exit = 0;
//static int time_offset[4] = {-138,-138,-138,-138};
//static int time_offset[4] = {-145,-145,-145,-145};
static int time_offset[4] = {0,0,0,0};
static char UE_flag=0;
......@@ -251,37 +189,18 @@ runmode_t mode = normal_txrx;
FILE *input_fd=NULL;
#ifdef EXMIMO
#if MAX_NUM_CCs == 1
double tx_gain[MAX_NUM_CCs][4] = {{20,20,0,0}};
double rx_gain[MAX_NUM_CCs][4] = {{20,20,0,0}};
#else
double tx_gain[MAX_NUM_CCs][4] = {{20,20,0,0},{20,20,0,0}};
double rx_gain[MAX_NUM_CCs][4] = {{20,20,0,0},{20,20,0,0}};
#endif
// these are for EXMIMO2 target only
/*
static unsigned int rxg_max[4] = {133,133,133,133};
static unsigned int rxg_med[4] = {127,127,127,127};
static unsigned int rxg_byp[4] = {120,120,120,120};
*/
// these are for EXMIMO2 card 39
unsigned int rxg_max[4] = {128,128,128,126};
unsigned int rxg_med[4] = {122,123,123,120};
unsigned int rxg_byp[4] = {116,117,116,116};
unsigned int nf_max[4] = {7,9,16,12};
unsigned int nf_med[4] = {12,13,22,17};
unsigned int nf_byp[4] = {15,20,29,23};
#if MAX_NUM_CCs == 1
rx_gain_t rx_gain_mode[MAX_NUM_CCs][4] = {{max_gain,max_gain,max_gain,max_gain}};
#else
rx_gain_t rx_gain_mode[MAX_NUM_CCs][4] = {{max_gain,max_gain,max_gain,max_gain},{max_gain,max_gain,max_gain,max_gain}};
#endif
#else
double tx_gain[MAX_NUM_CCs][4] = {{20,0,0,0}};
double rx_gain[MAX_NUM_CCs][4] = {{110,0,0,0}};
#else
rx_gain_t rx_gain_mode[MAX_NUM_CCs][4] = {{max_gain,max_gain,max_gain,max_gain},{max_gain,max_gain,max_gain,max_gain}};
double tx_gain[MAX_NUM_CCs][4] = {{20,0,0,0},{20,0,0,0}};
double rx_gain[MAX_NUM_CCs][4] = {{110,0,0,0},{20,0,0,0}};
#endif
double sample_rate=30.72e6;
double bw = 10.0e6;
......@@ -292,12 +211,10 @@ char rf_config_file[1024];
int chain_offset=0;
int phy_test = 0;
#ifndef EXMIMO
char ref[128] = "internal";
char channels[128] = "0";
#endif
int rx_input_level_dBm;
static int online_log_messages=0;
#ifdef XFORMS
......@@ -307,14 +224,11 @@ static char do_forms=0;
int otg_enabled;
#endif
//int number_of_cards = 1;
#ifdef EXMIMO
static int mbox_bounds[20] = {8,16,24,30,38,46,54,60,68,76,84,90,98,106,114,120,128,136,144, 0}; ///boundaries of slots in terms ob mbox counter rounded up to even numbers
//static int mbox_bounds[20] = {6,14,22,28,36,44,52,58,66,74,82,88,96,104,112,118,126,134,142, 148}; ///boundaries of slots in terms ob mbox counter rounded up to even numbers
#endif
static LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs];
int multi_thread=1;
uint32_t target_dl_mcs = 28; //maximum allowed mcs
uint32_t target_ul_mcs = 20;
uint32_t timing_advance = 0;
......@@ -322,12 +236,9 @@ uint8_t exit_missed_slots=1;
uint64_t num_missed_slots=0; // counter for the number of missed slots
time_stats_t softmodem_stats_mt; // main thread
time_stats_t softmodem_stats_hw; // hw acquisition
time_stats_t softmodem_stats_tx_sf[10]; // total tx time
time_stats_t softmodem_stats_rx_sf[10]; // total rx time
void reset_opp_meas(void);
void print_opp_meas(void);
extern void reset_opp_meas(void);
extern void print_opp_meas(void);
int transmission_mode=1;
int16_t glog_level = LOG_INFO;
......@@ -369,9 +280,13 @@ uint8_t local_remote_radio = BBU_LOCAL_RADIO_HEAD;
/* struct for ethernet specific parameters given in eNB conf file */
eth_params_t *eth_params;
openair0_config_t openair0_cfg[MAX_CARDS];
double cpuf;
char uecap_xer[1024],uecap_xer_in=0;
extern void *UE_thread(void *arg);
extern void init_UE_threads(void);
/*---------------------BMC: timespec helpers -----------------------------*/
......@@ -486,6 +401,7 @@ void help (void) {
printf(" -x Set the transmission mode, valid options: 1 \n"RESET);
}
void exit_fun(const char* s)
{
if (s != NULL) {
......@@ -499,9 +415,6 @@ void exit_fun(const char* s)
itti_terminate_tasks (TASK_UNKNOWN);
#endif
//rt_sleep_ns(FRAME_PERIOD);
//exit (-1);
}
......@@ -634,227 +547,8 @@ static void *scope_thread(void *arg)
}
#endif
#ifdef EMOS
#define NO_ESTIMATES_DISK 100 //No. of estimates that are aquired before dumped to disk
void* gps_thread (void *arg)
{
struct gps_data_t gps_data;
struct gps_data_t *gps_data_ptr = &gps_data;
struct sched_param sched_param;
int ret;
sched_param.sched_priority = sched_get_priority_min(SCHED_FIFO)+1;
sched_setscheduler(0, SCHED_FIFO,&sched_param);
printf("GPS thread has priority %d\n",sched_param.sched_priority);
memset(&dummy_gps_data,0,sizeof(struct gps_fix_t));
#if GPSD_API_MAJOR_VERSION>=5
ret = gps_open("127.0.0.1","2947",gps_data_ptr);
if (ret!=0)
#else
gps_data_ptr = gps_open("127.0.0.1","2947");
if (gps_data_ptr == NULL)
#endif
{
printf("[EMOS] Could not open GPS\n");
pthread_exit((void*)arg);
}
#if GPSD_API_MAJOR_VERSION>=4
else if (gps_stream(gps_data_ptr, WATCH_ENABLE,NULL) != 0)
#else
else if (gps_query(gps_data_ptr, "w+x") != 0)
#endif
{
printf("[EMOS] Error sending command to GPS\n");
pthread_exit((void*) arg);
} else
printf("[EMOS] Opened GPS, gps_data=%p\n", gps_data_ptr);
while (!oai_exit) {
printf("[EMOS] polling data from gps\n");
#if GPSD_API_MAJOR_VERSION>=5
if (gps_waiting(gps_data_ptr,500)) {
if (gps_read(gps_data_ptr) <= 0) {
#else
if (gps_waiting(gps_data_ptr)) {
if (gps_poll(gps_data_ptr) != 0) {
#endif
printf("[EMOS] problem polling data from gps\n");
} else {
memcpy(&dummy_gps_data,&(gps_data_ptr->fix),sizeof(struct gps_fix_t));
printf("[EMOS] lat %g, lon %g\n",gps_data_ptr->fix.latitude,gps_data_ptr->fix.longitude);
}
} //gps_waiting
else {
printf("[EMOS] WARNING: No GPS data available, storing dummy packet\n");
}
//rt_sleep_ns(1000000000LL);
sleep(1);
} //oai_exit
pthread_exit((void*) arg);
}
void *emos_thread (void *arg)
{
char c;
char *fifo2file_buffer, *fifo2file_ptr;
int fifo, counter=0, bytes;
FILE *dumpfile_id;
char dumpfile_name[1024];
time_t starttime_tmp;
struct tm starttime;
int channel_buffer_size,ret;
time_t timer;
struct tm *now;
struct sched_param sched_param;
sched_param.sched_priority = sched_get_priority_max(SCHED_FIFO)-1;
sched_setscheduler(0, SCHED_FIFO,&sched_param);
printf("EMOS thread has priority %d\n",sched_param.sched_priority);
timer = time(NULL);
now = localtime(&timer);
if (UE_flag==0)
channel_buffer_size = sizeof(fifo_dump_emos_eNB);
else
channel_buffer_size = sizeof(fifo_dump_emos_UE);
// allocate memory for NO_FRAMES_DISK channes estimations
fifo2file_buffer = malloc(NO_ESTIMATES_DISK*channel_buffer_size);
fifo2file_ptr = fifo2file_buffer;
if (fifo2file_buffer == NULL) {
printf("[EMOS] Cound not allocate memory for fifo2file_buffer\n");
exit(EXIT_FAILURE);
}
if ((fifo = open(CHANSOUNDER_FIFO_DEV, O_RDONLY)) < 0) {
fprintf(stderr, "[EMOS] Error opening the fifo\n");
exit(EXIT_FAILURE);
}
time(&starttime_tmp);
localtime_r(&starttime_tmp,&starttime);
snprintf(dumpfile_name,1024,"/tmp/%s_data_%d%02d%02d_%02d%02d%02d.EMOS",
(UE_flag==0) ? "eNB" : "UE",
1900+starttime.tm_year, starttime.tm_mon+1, starttime.tm_mday, starttime.tm_hour, starttime.tm_min, starttime.tm_sec);
dumpfile_id = fopen(dumpfile_name,"w");
if (dumpfile_id == NULL) {
fprintf(stderr, "[EMOS] Error opening dumpfile %s\n",dumpfile_name);
exit(EXIT_FAILURE);
}
printf("[EMOS] starting dump, channel_buffer_size=%d, fifo %d\n",channel_buffer_size,fifo);
while (!oai_exit) {
/*
bytes = rtf_read_timed(fifo, fifo2file_ptr, channel_buffer_size,100);
if (bytes==0)
continue;
*/
bytes = rtf_read_all_at_once(fifo, fifo2file_ptr, channel_buffer_size);
if (bytes<=0) {
usleep(100);
continue;
}
if (bytes != channel_buffer_size) {
printf("[EMOS] ERROR! Only got %d bytes instead of %d!\n",bytes,channel_buffer_size);
}
/*
if (UE_flag==0)
printf("eNB: count %d, frame %d, read: %d bytes from the fifo\n",counter, ((fifo_dump_emos_eNB*)fifo2file_ptr)->frame_tx,bytes);
else
printf("UE: count %d, frame %d, read: %d bytes from the fifo\n",counter, ((fifo_dump_emos_UE*)fifo2file_ptr)->frame_rx,bytes);
*/
fifo2file_ptr += channel_buffer_size;
counter ++;
if (counter == NO_ESTIMATES_DISK) {
//reset stuff
fifo2file_ptr = fifo2file_buffer;
counter = 0;
//flush buffer to disk
if (UE_flag==0)
printf("[EMOS] eNB: count %d, frame %d, flushing buffer to disk\n",
counter, ((fifo_dump_emos_eNB*)fifo2file_ptr)->frame_tx);
else
printf("[EMOS] UE: count %d, frame %d, flushing buffer to disk\n",
counter, ((fifo_dump_emos_UE*)fifo2file_ptr)->frame_rx);
if (fwrite(fifo2file_buffer, sizeof(char), NO_ESTIMATES_DISK*channel_buffer_size, dumpfile_id) != NO_ESTIMATES_DISK*channel_buffer_size) {
fprintf(stderr, "[EMOS] Error writing to dumpfile\n");
exit(EXIT_FAILURE);
}
if (fwrite(&dummy_gps_data, sizeof(char), sizeof(struct gps_fix_t), dumpfile_id) != sizeof(struct gps_fix_t)) {
printf("[EMOS] Error writing to dumpfile, stopping recording\n");
exit(EXIT_FAILURE);
}
}
}
free(fifo2file_buffer);
fclose(dumpfile_id);
close(fifo);
pthread_exit((void*) arg);
}
#endif
#if defined(ENABLE_ITTI)
static void wait_system_ready (char *message, volatile int *start_flag)
{
/* Wait for eNB application initialization to be complete (eNB registration to MME) */
{
static char *indicator[] = {". ", ".. ", "... ", ".... ", ".....",
" ....", " ...", " ..", " .", " "
};
int i = 0;
while ((!oai_exit) && (*start_flag == 0)) {
LOG_N(EMU, message, indicator[i]);
fflush(stdout);
i = (i + 1) % (sizeof(indicator) / sizeof(indicator[0]));
usleep(200000);
}
LOG_D(EMU,"\n");
}
}
#endif
#if defined(ENABLE_ITTI)
void *l2l1_task(void *arg)
......@@ -903,1379 +597,41 @@ void *l2l1_task(void *arg)
// Wait for a message
itti_receive_msg (TASK_L2L1, &message_p);
switch (ITTI_MSG_ID(message_p)) {
case TERMINATE_MESSAGE:
oai_exit=1;
itti_exit_task ();
break;
case ACTIVATE_MESSAGE:
start_UE = 1;
break;
case DEACTIVATE_MESSAGE:
start_UE = 0;
break;
case MESSAGE_TEST:
LOG_I(EMU, "Received %s\n", ITTI_MSG_NAME(message_p));
break;
default:
LOG_E(EMU, "Received unexpected message %s\n", ITTI_MSG_NAME(message_p));
break;
}
result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p);
AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
} while(!oai_exit);
return NULL;
}
#endif
void do_OFDM_mod_rt(int subframe,PHY_VARS_eNB *phy_vars_eNB)
{
unsigned int aa,slot_offset, slot_offset_F;
int dummy_tx_b[7680*4] __attribute__((aligned(32)));
int i, tx_offset;
int slot_sizeF = (phy_vars_eNB->lte_frame_parms.ofdm_symbol_size)*
((phy_vars_eNB->lte_frame_parms.Ncp==1) ? 6 : 7);
int len;
slot_offset_F = (subframe<<1)*slot_sizeF;
slot_offset = subframe*phy_vars_eNB->lte_frame_parms.samples_per_tti;
if ((subframe_select(&phy_vars_eNB->lte_frame_parms,subframe)==SF_DL)||
((subframe_select(&phy_vars_eNB->lte_frame_parms,subframe)==SF_S))) {
// LOG_D(HW,"Frame %d: Generating slot %d\n",frame,next_slot);
for (aa=0; aa<phy_vars_eNB->lte_frame_parms.nb_antennas_tx; aa++) {
if (phy_vars_eNB->lte_frame_parms.Ncp == EXTENDED) {
PHY_ofdm_mod(&phy_vars_eNB->lte_eNB_common_vars.txdataF[0][aa][slot_offset_F],
dummy_tx_b,
phy_vars_eNB->lte_frame_parms.ofdm_symbol_size,
6,
phy_vars_eNB->lte_frame_parms.nb_prefix_samples,
CYCLIC_PREFIX);
PHY_ofdm_mod(&phy_vars_eNB->lte_eNB_common_vars.txdataF[0][aa][slot_offset_F+slot_sizeF],
dummy_tx_b+(phy_vars_eNB->lte_frame_parms.samples_per_tti>>1),
phy_vars_eNB->lte_frame_parms.ofdm_symbol_size,
6,
phy_vars_eNB->lte_frame_parms.nb_prefix_samples,
CYCLIC_PREFIX);
} else {
normal_prefix_mod(&phy_vars_eNB->lte_eNB_common_vars.txdataF[0][aa][slot_offset_F],
dummy_tx_b,
7,
&(phy_vars_eNB->lte_frame_parms));
// if S-subframe generate first slot only
if (subframe_select(&phy_vars_eNB->lte_frame_parms,subframe) == SF_DL)
normal_prefix_mod(&phy_vars_eNB->lte_eNB_common_vars.txdataF[0][aa][slot_offset_F+slot_sizeF],
dummy_tx_b+(phy_vars_eNB->lte_frame_parms.samples_per_tti>>1),
7,
&(phy_vars_eNB->lte_frame_parms));
}
// if S-subframe generate first slot only
if (subframe_select(&phy_vars_eNB->lte_frame_parms,subframe) == SF_S)
len = phy_vars_eNB->lte_frame_parms.samples_per_tti>>1;
else
len = phy_vars_eNB->lte_frame_parms.samples_per_tti;
/*
for (i=0;i<len;i+=4) {
dummy_tx_b[i] = 0x100;
dummy_tx_b[i+1] = 0x01000000;
dummy_tx_b[i+2] = 0xff00;
dummy_tx_b[i+3] = 0xff000000;
}*/
for (i=0; i<len; i++) {
tx_offset = (int)slot_offset+time_offset[aa]+i;
if (tx_offset<0)
tx_offset += LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->lte_frame_parms.samples_per_tti;
if (tx_offset>=(LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->lte_frame_parms.samples_per_tti))
tx_offset -= LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->lte_frame_parms.samples_per_tti;
((short*)&phy_vars_eNB->lte_eNB_common_vars.txdata[0][aa][tx_offset])[0] = ((short*)dummy_tx_b)[2*i]<<openair0_cfg[0].iq_txshift;
((short*)&phy_vars_eNB->lte_eNB_common_vars.txdata[0][aa][tx_offset])[1] = ((short*)dummy_tx_b)[2*i+1]<<openair0_cfg[0].iq_txshift;
}
// if S-subframe switch to RX in second subframe
if (subframe_select(&phy_vars_eNB->lte_frame_parms,subframe) == SF_S) {
for (i=0; i<len; i++) {
phy_vars_eNB->lte_eNB_common_vars.txdata[0][aa][tx_offset++] = 0x00010001;
}
}
if ((((phy_vars_eNB->lte_frame_parms.tdd_config==0) ||
(phy_vars_eNB->lte_frame_parms.tdd_config==1) ||
(phy_vars_eNB->lte_frame_parms.tdd_config==2) ||
(phy_vars_eNB->lte_frame_parms.tdd_config==6)) &&
(subframe==0)) || (subframe==5)) {
// turn on tx switch N_TA_offset before
//LOG_D(HW,"subframe %d, time to switch to tx (N_TA_offset %d, slot_offset %d) \n",subframe,phy_vars_eNB->N_TA_offset,slot_offset);
for (i=0; i<phy_vars_eNB->N_TA_offset; i++) {
tx_offset = (int)slot_offset+time_offset[aa]+i-phy_vars_eNB->N_TA_offset/2;
if (tx_offset<0)
tx_offset += LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->lte_frame_parms.samples_per_tti;
if (tx_offset>=(LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->lte_frame_parms.samples_per_tti))
tx_offset -= LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->lte_frame_parms.samples_per_tti;
phy_vars_eNB->lte_eNB_common_vars.txdata[0][aa][tx_offset] = 0x00000000;
}
}
}
}
}
/* mutex, cond and variable to serialize phy proc TX calls
* (this mechanism may be relaxed in the future for better
* performances)
*/
static struct {
pthread_mutex_t mutex_phy_proc_tx;
pthread_cond_t cond_phy_proc_tx;
volatile uint8_t phy_proc_CC_id;
} sync_phy_proc[NUM_ENB_THREADS];
/*!
* \brief The transmit thread of eNB.
* \ref NUM_ENB_THREADS threads of this type are active at the same time.
* \param param is a \ref eNB_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_tx( void* param )
{
static int eNB_thread_tx_status[NUM_ENB_THREADS];
eNB_proc_t *proc = (eNB_proc_t*)param;
FILE *tx_time_file = NULL;
char tx_time_name[101];
if (opp_enabled == 1) {
snprintf(tx_time_name, 100,"/tmp/%s_tx_time_thread_sf_%d", "eNB", proc->subframe);
tx_time_file = fopen(tx_time_name,"w");
}
// set default return value
eNB_thread_tx_status[proc->subframe] = 0;
MSC_START_USE();
#ifdef RTAI
RT_TASK *task;
char task_name[8];
sprintf(task_name,"TXC%dS%d",proc->CC_id,proc->subframe);
task = rt_task_init_schmod(nam2num(task_name), 0, 0, 0, SCHED_FIFO, 0xF);
if (task == NULL) {
LOG_E(PHY,"[SCHED][eNB] Problem starting eNB_proc_TX thread_index %d (%s)!!!!\n",proc->subframe,task_name);
return 0;
} else {
LOG_I(PHY,"[SCHED][eNB] eNB TX thread CC %d SF %d started with id %p\n",
proc->CC_id,
proc->subframe,
task);
}
#else
#ifdef LOWLATENCY
struct sched_attr attr;
unsigned int flags = 0;
uint64_t runtime = 850000 ;
uint64_t deadline = 1 * 1000000 ; // each tx thread will finish within 1ms
uint64_t period = 1 * 10000000; // each tx thread has a period of 10ms from the starting point
attr.size = sizeof(attr);
attr.sched_flags = 0;
attr.sched_nice = 0;
attr.sched_priority = 0;
attr.sched_policy = SCHED_DEADLINE;
attr.sched_runtime = runtime;
attr.sched_deadline = deadline;
attr.sched_period = period;
if (sched_setattr(0, &attr, flags) < 0 ) {
perror("[SCHED] eNB tx thread: sched_setattr failed\n");
return &eNB_thread_tx_status[proc->subframe];
}
LOG_I( HW, "[SCHED] eNB TX deadline thread %d(TID %ld) started on CPU %d\n", proc->subframe, gettid(), sched_getcpu() );
#else
int policy, s, j;
struct sched_param sparam;
char cpu_affinity[1024];
cpu_set_t cpuset;
/* Set affinity mask to include CPUs 1 to MAX_CPUS */
/* CPU 0 is reserved for UHD threads */
/* CPU 1 is reserved for all TX threads */
/* Enable CPU Affinity only if number of CPUs >2 */
CPU_ZERO(&cpuset);
#ifdef CPU_AFFINITY
if (get_nprocs() > 2)
{
for (j = 1; j < get_nprocs(); j++)
CPU_SET(j, &cpuset);
s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (s != 0)
{
perror( "pthread_setaffinity_np");
exit_fun("Error setting processor affinity");
}
}
#endif
/* Check the actual affinity mask assigned to the thread */
s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (s != 0)
{
perror( "pthread_getaffinity_np");
exit_fun("Error getting processor affinity ");
}
memset(cpu_affinity,0,sizeof(cpu_affinity));
for (j = 0; j < CPU_SETSIZE; j++)
if (CPU_ISSET(j, &cpuset))
{
char temp[1024];
sprintf (temp, " CPU_%d", j);
strcat(cpu_affinity, temp);
}
memset(&sparam, 0 , sizeof (sparam));
sparam.sched_priority = sched_get_priority_max(SCHED_FIFO)-1;
policy = SCHED_FIFO ;
s = pthread_setschedparam(pthread_self(), policy, &sparam);
if (s != 0)
{
perror("pthread_setschedparam : ");
exit_fun("Error setting thread priority");
}
s = pthread_getschedparam(pthread_self(), &policy, &sparam);
if (s != 0)
{
perror("pthread_getschedparam : ");
exit_fun("Error getting thread priority");
}
LOG_I( HW, "[SCHED][eNB] TX thread %d started on CPU %d TID %ld, sched_policy = %s , priority = %d, CPU Affinity=%s \n", proc->subframe, sched_getcpu(),gettid(),
(policy == SCHED_FIFO) ? "SCHED_FIFO" :
(policy == SCHED_RR) ? "SCHED_RR" :
(policy == SCHED_OTHER) ? "SCHED_OTHER" :
"???",
sparam.sched_priority, cpu_affinity );
#endif
#endif
mlockall(MCL_CURRENT | MCL_FUTURE);
#ifdef HARD_RT
rt_make_hard_real_time();
#endif
while (!oai_exit) {
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_TX0+(2*proc->subframe), 0 );
if (pthread_mutex_lock(&proc->mutex_tx) != 0) {
LOG_E( PHY, "[SCHED][eNB] error locking mutex for eNB TX proc %d\n", proc->subframe );
exit_fun("nothing to add");
break;
}
while (proc->instance_cnt_tx < 0) {
// most of the time the thread is waiting here
// proc->instance_cnt_tx is -1
pthread_cond_wait( &proc->cond_tx, &proc->mutex_tx ); // this unlocks mutex_tx while waiting and then locks it again
}
if (pthread_mutex_unlock(&proc->mutex_tx) != 0) {
LOG_E(PHY,"[SCHED][eNB] error unlocking mutex for eNB TX proc %d\n",proc->subframe);
exit_fun("nothing to add");
break;
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_TX0+(2*proc->subframe), 1 );
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX_ENB, proc->frame_tx );
start_meas( &softmodem_stats_tx_sf[proc->subframe] );
if (oai_exit) break;
if (((PHY_vars_eNB_g[0][proc->CC_id]->lte_frame_parms.frame_type == TDD) &&
((subframe_select(&PHY_vars_eNB_g[0][proc->CC_id]->lte_frame_parms,proc->subframe_tx) == SF_DL) ||
(subframe_select(&PHY_vars_eNB_g[0][proc->CC_id]->lte_frame_parms,proc->subframe_tx) == SF_S))) ||
(PHY_vars_eNB_g[0][proc->CC_id]->lte_frame_parms.frame_type == FDD)) {
/* run PHY TX procedures the one after the other for all CCs to avoid race conditions
* (may be relaxed in the future for performance reasons)
*/
if (pthread_mutex_lock(&sync_phy_proc[proc->subframe].mutex_phy_proc_tx) != 0) {
LOG_E(PHY, "[SCHED][eNB] error locking PHY proc mutex for eNB TX proc %d\n", proc->subframe);
exit_fun("nothing to add");
break;
}
/* wait for our turn or oai_exit */
while (sync_phy_proc[proc->subframe].phy_proc_CC_id != proc->CC_id && !oai_exit) {
pthread_cond_wait(&sync_phy_proc[proc->subframe].cond_phy_proc_tx,
&sync_phy_proc[proc->subframe].mutex_phy_proc_tx);
}
if (pthread_mutex_unlock(&sync_phy_proc[proc->subframe].mutex_phy_proc_tx) != 0) {
LOG_E(PHY, "[SCHED][eNB] error unlocking PHY proc mutex for eNB TX proc %d\n", proc->subframe);
exit_fun("nothing to add");
}
if (oai_exit)
break;
phy_procedures_eNB_TX( proc->subframe, PHY_vars_eNB_g[0][proc->CC_id], 0, no_relay, NULL );
/* we're done, let the next one proceed */
if (pthread_mutex_lock(&sync_phy_proc[proc->subframe].mutex_phy_proc_tx) != 0) {
LOG_E(PHY, "[SCHED][eNB] error locking PHY proc mutex for eNB TX proc %d\n", proc->subframe);
exit_fun("nothing to add");
break;
}
sync_phy_proc[proc->subframe].phy_proc_CC_id++;
sync_phy_proc[proc->subframe].phy_proc_CC_id %= MAX_NUM_CCs;
pthread_cond_broadcast(&sync_phy_proc[proc->subframe].cond_phy_proc_tx);
if (pthread_mutex_unlock(&sync_phy_proc[proc->subframe].mutex_phy_proc_tx) != 0) {
LOG_E(PHY, "[SCHED][eNB] error unlocking PHY proc mutex for eNB TX proc %d\n", proc->subframe);
exit_fun("nothing to add");
break;
}
}
do_OFDM_mod_rt( proc->subframe_tx, PHY_vars_eNB_g[0][proc->CC_id] );
/*
short *txdata = (short*)&PHY_vars_eNB_g[0][proc->CC_id]->lte_eNB_common_vars.txdata[0][0][proc->subframe_tx*PHY_vars_eNB_g[0][proc->CC_id]->lte_frame_parms.samples_per_tti];
int i;
for (i=0;i<PHY_vars_eNB_g[0][proc->CC_id]->lte_frame_parms.samples_per_tti*2;i+=8) {
txdata[i] = 2047;
txdata[i+1] = 0;
txdata[i+2] = 0;
txdata[i+3] = 2047;
txdata[i+4] = -2047;
txdata[i+5] = 0;
txdata[i+6] = 0;
txdata[i+7] = -2047;
}
*/
if (pthread_mutex_lock(&proc->mutex_tx) != 0) {
LOG_E( PHY, "[SCHED][eNB] error locking mutex for eNB TX proc %d\n", proc->subframe );
exit_fun("nothing to add");
break;
}
proc->instance_cnt_tx--;
if (pthread_mutex_unlock(&proc->mutex_tx) != 0) {
LOG_E( PHY, "[SCHED][eNB] error unlocking mutex for eNB TX proc %d\n", proc->subframe );
exit_fun("nothing to add");
break;
}
proc->frame_tx++;
if (proc->frame_tx==1024)
proc->frame_tx=0;
stop_meas( &softmodem_stats_tx_sf[proc->subframe] );
#ifdef LOWLATENCY
if (opp_enabled){
if(softmodem_stats_tx_sf[proc->subframe].diff_now/(cpuf) > attr.sched_runtime){
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RUNTIME_TX_ENB, (softmodem_stats_tx_sf[proc->subframe].diff_now/cpuf - attr.sched_runtime)/1000000.0);
}
}
#endif
print_meas_now(&softmodem_stats_tx_sf[proc->subframe],"eNB_TX_SF",proc->subframe, tx_time_file);
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_TX0+(2*proc->subframe), 0 );
#ifdef HARD_RT
rt_make_soft_real_time();
#endif
#ifdef DEBUG_THREADS
printf( "Exiting eNB thread TX %d\n", proc->subframe );
#endif
// clean task
#ifdef RTAI
rt_task_delete(task);
#endif
eNB_thread_tx_status[proc->subframe] = 0;
return &eNB_thread_tx_status[proc->subframe];
}
/*!
* \brief The receive thread of eNB.
* \ref NUM_ENB_THREADS threads of this type are active at the same time.
* \param param is a \ref eNB_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_rx( void* param )
{
static int eNB_thread_rx_status[NUM_ENB_THREADS];
eNB_proc_t *proc = (eNB_proc_t*)param;
FILE *rx_time_file = NULL;
char rx_time_name[101];
//int i;
if (opp_enabled == 1){
snprintf(rx_time_name, 100,"/tmp/%s_rx_time_thread_sf_%d", "eNB", proc->subframe);
rx_time_file = fopen(rx_time_name,"w");
}
// set default return value
eNB_thread_rx_status[proc->subframe] = 0;
MSC_START_USE();
#ifdef RTAI
RT_TASK *task;
char task_name[8];
sprintf(task_name,"RXC%1dS%1d",proc->CC_id,proc->subframe);
task = rt_task_init_schmod(nam2num(task_name), 0, 0, 0, SCHED_FIFO, 0xF);
if (task==NULL) {
LOG_E(PHY,"[SCHED][eNB] Problem starting eNB_proc_RX thread_index %d (%s)!!!!\n",proc->subframe,task_name);
return 0;
} else {
LOG_I(PHY,"[SCHED][eNB] eNB RX thread CC_id %d SF %d started with id %p\n", /* on CPU %d*/
proc->CC_id,
proc->subframe,
task); /*,rtai_cpuid()*/
}
#else
#ifdef LOWLATENCY
struct sched_attr attr;
unsigned int flags = 0;
uint64_t runtime = 870000 ;
uint64_t deadline = 1 * 1000000;
uint64_t period = 1 * 10000000; // each rx thread has a period of 10ms from the starting point
attr.size = sizeof(attr);
attr.sched_flags = 0;
attr.sched_nice = 0;
attr.sched_priority = 0;
attr.sched_policy = SCHED_DEADLINE;
attr.sched_runtime = runtime;
attr.sched_deadline = deadline;
attr.sched_period = period;
if (sched_setattr(0, &attr, flags) < 0 ) {
perror("[SCHED] eNB RX sched_setattr failed\n");
return &eNB_thread_rx_status[proc->subframe];
}
LOG_I( HW, "[SCHED] eNB RX deadline thread %d(TID %ld) started on CPU %d\n", proc->subframe, gettid(), sched_getcpu() );
#else
int policy, s, j;
struct sched_param sparam;
char cpu_affinity[1024];
cpu_set_t cpuset;
/* Set affinity mask to include CPUs 1 to MAX_CPUS */
/* CPU 0 is reserved for UHD */
/* CPU 1 is reserved for all TX threads */
/* CPU 2..MAX_CPUS is reserved for all RX threads */
/* Set CPU Affinity only if number of CPUs >2 */
CPU_ZERO(&cpuset);
#ifdef CPU_AFFINITY
if (get_nprocs() >2)
{
for (j = 1; j < get_nprocs(); j++)
CPU_SET(j, &cpuset);
s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (s != 0)
{
perror( "pthread_setaffinity_np");
exit_fun (" Error setting processor affinity :");
}
}
#endif
/* Check the actual affinity mask assigned to the thread */
s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (s != 0)
{
perror ("pthread_getaffinity_np");
exit_fun (" Error getting processor affinity :");
}
memset(cpu_affinity,0, sizeof(cpu_affinity));
for (j = 0; j < CPU_SETSIZE; j++)
if (CPU_ISSET(j, &cpuset))
{
char temp[1024];
sprintf (temp, " CPU_%d", j);
strcat(cpu_affinity, temp);
}
memset(&sparam, 0 , sizeof (sparam));
sparam.sched_priority = sched_get_priority_max(SCHED_FIFO)-1;
policy = SCHED_FIFO ;
s = pthread_setschedparam(pthread_self(), policy, &sparam);
if (s != 0)
{
perror("pthread_setschedparam : ");
exit_fun("Error setting thread priority");
}
memset(&sparam, 0 , sizeof (sparam));
s = pthread_getschedparam(pthread_self(), &policy, &sparam);
if (s != 0)
{
perror("pthread_getschedparam");
exit_fun("Error getting thread priority");
}
LOG_I( HW, "[SCHED][eNB] RX thread %d started on CPU %d TID %ld, sched_policy = %s, priority = %d, CPU Affinity = %s\n", proc->subframe, sched_getcpu(),gettid(),
(policy == SCHED_FIFO) ? "SCHED_FIFO" :
(policy == SCHED_RR) ? "SCHED_RR" :
(policy == SCHED_OTHER) ? "SCHED_OTHER" :
"???",
sparam.sched_priority, cpu_affinity);
#endif
#endif // RTAI
mlockall(MCL_CURRENT | MCL_FUTURE);
#ifdef HARD_RT
rt_make_hard_real_time();
#endif
while (!oai_exit) {
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RX0+(2*proc->subframe), 0 );
if (pthread_mutex_lock(&proc->mutex_rx) != 0) {
LOG_E( PHY, "[SCHED][eNB] error locking mutex for eNB RX proc %d\n", proc->subframe );
exit_fun( "error locking mutex" );
break;
}
while (proc->instance_cnt_rx < 0) {
// most of the time the thread is waiting here
// proc->instance_cnt_rx is -1
pthread_cond_wait( &proc->cond_rx, &proc->mutex_rx ); // this unlocks mutex_rx while waiting and then locks it again
}
if (pthread_mutex_unlock(&proc->mutex_rx) != 0) {
LOG_E( PHY, "[SCHED][eNB] error unlocking mutex for eNB RX proc %d\n", proc->subframe );
exit_fun( "error unlocking mutex" );
break;
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RX0+(2*proc->subframe), 1 );
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX_ENB, proc->frame_rx );
start_meas( &softmodem_stats_rx_sf[proc->subframe] );
if (oai_exit) break;
if ((((PHY_vars_eNB_g[0][proc->CC_id]->lte_frame_parms.frame_type == TDD )&&(subframe_select(&PHY_vars_eNB_g[0][proc->CC_id]->lte_frame_parms,proc->subframe_rx)==SF_UL)) ||
(PHY_vars_eNB_g[0][proc->CC_id]->lte_frame_parms.frame_type == FDD))) {
phy_procedures_eNB_RX( proc->subframe, PHY_vars_eNB_g[0][proc->CC_id], 0, no_relay );
}
if ((subframe_select(&PHY_vars_eNB_g[0][proc->CC_id]->lte_frame_parms,proc->subframe_rx) == SF_S)) {
phy_procedures_eNB_S_RX( proc->subframe, PHY_vars_eNB_g[0][proc->CC_id], 0, no_relay );
}
if (pthread_mutex_lock(&proc->mutex_rx) != 0) {
LOG_E( PHY, "[SCHED][eNB] error locking mutex for eNB RX proc %d\n", proc->subframe );
exit_fun( "error locking mutex" );
break;
}
proc->instance_cnt_rx--;
if (pthread_mutex_unlock(&proc->mutex_rx) != 0) {
LOG_E( PHY, "[SCHED][eNB] error unlocking mutex for eNB RX proc %d\n", proc->subframe );
exit_fun( "error unlocking mutex" );
break;
}
proc->frame_rx++;
if (proc->frame_rx==1024)
proc->frame_rx=0;
stop_meas( &softmodem_stats_rx_sf[proc->subframe] );
#ifdef LOWLATENCY
if (opp_enabled){
if(softmodem_stats_rx_sf[proc->subframe].diff_now/(cpuf) > attr.sched_runtime){
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RUNTIME_RX_ENB, (softmodem_stats_rx_sf[proc->subframe].diff_now/cpuf - attr.sched_runtime)/1000000.0);
}
}
#endif
print_meas_now(&softmodem_stats_rx_sf[proc->subframe],"eNB_RX_SF",proc->subframe, rx_time_file);
}
//stop_meas( &softmodem_stats_rx_sf[proc->subframe] );
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RX0+(2*proc->subframe), 0 );
#ifdef HARD_RT
rt_make_soft_real_time();
#endif
#ifdef DEBUG_THREADS
printf( "Exiting eNB thread RX %d\n", proc->subframe );
#endif
// clean task
#ifdef RTAI
rt_task_delete(task);
#endif
eNB_thread_rx_status[proc->subframe] = 0;
return &eNB_thread_rx_status[proc->subframe];
}
void init_eNB_proc(void)
{
int i;
int CC_id;
for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
for (i=0; i<NUM_ENB_THREADS; i++) {
// set the stack size
#ifndef LOWLATENCY
/*
pthread_attr_init( &attr_eNB_proc_tx[CC_id][i] );
if (pthread_attr_setstacksize( &attr_eNB_proc_tx[CC_id][i], 64 *PTHREAD_STACK_MIN ) != 0)
perror("[ENB_PROC_TX] setting thread stack size failed\n");
pthread_attr_init( &attr_eNB_proc_rx[CC_id][i] );
if (pthread_attr_setstacksize( &attr_eNB_proc_rx[CC_id][i], 64 * PTHREAD_STACK_MIN ) != 0)
perror("[ENB_PROC_RX] setting thread stack size failed\n");
*/
// set the kernel scheduling policy and priority
sched_param_eNB_proc_tx[CC_id][i].sched_priority = sched_get_priority_max(SCHED_FIFO)-1; //OPENAIR_THREAD_PRIORITY;
pthread_attr_setschedparam (&attr_eNB_proc_tx[CC_id][i], &sched_param_eNB_proc_tx[CC_id][i]);
pthread_attr_setschedpolicy (&attr_eNB_proc_tx[CC_id][i], SCHED_FIFO);
sched_param_eNB_proc_rx[CC_id][i].sched_priority = sched_get_priority_max(SCHED_FIFO)-1; //OPENAIR_THREAD_PRIORITY;
pthread_attr_setschedparam (&attr_eNB_proc_rx[CC_id][i], &sched_param_eNB_proc_rx[CC_id][i]);
pthread_attr_setschedpolicy (&attr_eNB_proc_rx[CC_id][i], SCHED_FIFO);
printf("Setting OS scheduler to SCHED_FIFO for eNB [cc%d][thread%d] \n",CC_id, i);
#endif
PHY_vars_eNB_g[0][CC_id]->proc[i].instance_cnt_tx = -1;
PHY_vars_eNB_g[0][CC_id]->proc[i].instance_cnt_rx = -1;
PHY_vars_eNB_g[0][CC_id]->proc[i].subframe = i;
PHY_vars_eNB_g[0][CC_id]->proc[i].CC_id = CC_id;
pthread_mutex_init( &PHY_vars_eNB_g[0][CC_id]->proc[i].mutex_tx, NULL);
pthread_mutex_init( &PHY_vars_eNB_g[0][CC_id]->proc[i].mutex_rx, NULL);
pthread_cond_init( &PHY_vars_eNB_g[0][CC_id]->proc[i].cond_tx, NULL);
pthread_cond_init( &PHY_vars_eNB_g[0][CC_id]->proc[i].cond_rx, NULL);
#ifndef LOWLATENCY
pthread_create( &PHY_vars_eNB_g[0][CC_id]->proc[i].pthread_tx, &attr_eNB_proc_tx[CC_id][i], eNB_thread_tx, &PHY_vars_eNB_g[0][CC_id]->proc[i] );
pthread_create( &PHY_vars_eNB_g[0][CC_id]->proc[i].pthread_rx, &attr_eNB_proc_rx[CC_id][i], eNB_thread_rx, &PHY_vars_eNB_g[0][CC_id]->proc[i] );
#else
pthread_create( &PHY_vars_eNB_g[0][CC_id]->proc[i].pthread_tx, NULL, eNB_thread_tx, &PHY_vars_eNB_g[0][CC_id]->proc[i] );
pthread_create( &PHY_vars_eNB_g[0][CC_id]->proc[i].pthread_rx, NULL, eNB_thread_rx, &PHY_vars_eNB_g[0][CC_id]->proc[i] );
#endif
char name[16];
snprintf( name, sizeof(name), "TX %d", i );
pthread_setname_np( PHY_vars_eNB_g[0][CC_id]->proc[i].pthread_tx, name );
snprintf( name, sizeof(name), "RX %d", i );
pthread_setname_np( PHY_vars_eNB_g[0][CC_id]->proc[i].pthread_rx, name );
PHY_vars_eNB_g[0][CC_id]->proc[i].frame_tx = 0;
PHY_vars_eNB_g[0][CC_id]->proc[i].frame_rx = 0;
#ifdef EXMIMO
PHY_vars_eNB_g[0][CC_id]->proc[i].subframe_rx = (i+9)%10;
PHY_vars_eNB_g[0][CC_id]->proc[i].subframe_tx = (i+1)%10;
#else
PHY_vars_eNB_g[0][CC_id]->proc[i].subframe_rx = i;
PHY_vars_eNB_g[0][CC_id]->proc[i].subframe_tx = (i+2)%10;
#endif
}
#ifdef EXMIMO
// TX processes subframe + 1, RX subframe -1
// Note this inialization is because the first process awoken for frame 0 is number 1 and so processes 9 and 0 have to start with frame 1
//PHY_vars_eNB_g[0][CC_id]->proc[0].frame_rx = 1023;
PHY_vars_eNB_g[0][CC_id]->proc[9].frame_tx = 1;
PHY_vars_eNB_g[0][CC_id]->proc[0].frame_tx = 1;
#else
// TX processes subframe +2, RX subframe
// Note this inialization is because the first process awoken for frame 0 is number 1 and so processes 8,9 and 0 have to start with frame 1
// PHY_vars_eNB_g[0][CC_id]->proc[7].frame_tx = 1;
PHY_vars_eNB_g[0][CC_id]->proc[8].frame_tx = 1;
PHY_vars_eNB_g[0][CC_id]->proc[9].frame_tx = 1;
// PHY_vars_eNB_g[0][CC_id]->proc[0].frame_tx = 1;
#endif
}
/* setup PHY proc TX sync mechanism */
for (i=0; i<NUM_ENB_THREADS; i++) {
pthread_mutex_init(&sync_phy_proc[i].mutex_phy_proc_tx, NULL);
pthread_cond_init(&sync_phy_proc[i].cond_phy_proc_tx, NULL);
sync_phy_proc[i].phy_proc_CC_id = 0;
}
}
/*!
* \brief Terminate eNB TX and RX threads.
*/
void kill_eNB_proc(void)
{
int *status;
for (int CC_id=0; CC_id<MAX_NUM_CCs; CC_id++)
for (int i=0; i<NUM_ENB_THREADS; i++) {
#ifdef DEBUG_THREADS
printf( "Killing TX CC_id %d thread %d\n", CC_id, i );
#endif
PHY_vars_eNB_g[0][CC_id]->proc[i].instance_cnt_tx = 0; // FIXME data race!
pthread_cond_signal( &PHY_vars_eNB_g[0][CC_id]->proc[i].cond_tx );
pthread_cond_broadcast(&sync_phy_proc[i].cond_phy_proc_tx);
#ifdef DEBUG_THREADS
printf( "Joining eNB TX CC_id %d thread %d...\n", CC_id, i );
#endif
int result = pthread_join( PHY_vars_eNB_g[0][CC_id]->proc[i].pthread_tx, (void**)&status );
#ifdef DEBUG_THREADS
if (result != 0) {
printf( "Error joining thread.\n" );
} else {
if (status) {
printf( "status %d\n", *status );
} else {
printf( "The thread was killed. No status available.\n" );
}
}
#else
UNUSED(result)
#endif
#ifdef DEBUG_THREADS
printf( "Killing RX CC_id %d thread %d\n", CC_id, i );
#endif
PHY_vars_eNB_g[0][CC_id]->proc[i].instance_cnt_rx = 0; // FIXME data race!
pthread_cond_signal( &PHY_vars_eNB_g[0][CC_id]->proc[i].cond_rx );
#ifdef DEBUG_THREADS
printf( "Joining eNB RX CC_id %d thread %d...\n", CC_id, i );
#endif
result = pthread_join( PHY_vars_eNB_g[0][CC_id]->proc[i].pthread_rx, (void**)&status );
#ifdef DEBUG_THREADS
if (result != 0) {
printf( "Error joining thread.\n" );
} else {
if (status) {
printf( "status %d\n", *status );
} else {
printf( "The thread was killed. No status available.\n" );
}
}
#else
UNUSED(result)
#endif
pthread_mutex_destroy( &PHY_vars_eNB_g[0][CC_id]->proc[i].mutex_tx );
pthread_mutex_destroy( &PHY_vars_eNB_g[0][CC_id]->proc[i].mutex_rx );
pthread_cond_destroy( &PHY_vars_eNB_g[0][CC_id]->proc[i].cond_tx );
pthread_cond_destroy( &PHY_vars_eNB_g[0][CC_id]->proc[i].cond_rx );
}
}
/*!
* \brief This is the main eNB thread.
* \param arg unused
* \returns a pointer to an int. The storage is not on the heap and must not be freed.
*/
static void* eNB_thread( void* arg )
{
UNUSED(arg);
static int eNB_thread_status;
unsigned char slot;
#ifdef EXMIMO
slot=0;
RTIME time_in;
volatile unsigned int *DAQ_MBOX = openair0_daq_cnt();
int mbox_target=0,mbox_current=0;
int hw_slot,delay_cnt;
int diff;
int ret;
int first_run=1;
#else
// the USRP implementation operates on subframes, not slots
// one subframe consists of one even and one odd slot
slot = 1;
int spp;
int tx_launched = 0;
int card=0;
void *rxp[2]; // FIXME hard coded array size; indexed by lte_frame_parms.nb_antennas_rx
void *txp[2]; // FIXME hard coded array size; indexed by lte_frame_parms.nb_antennas_tx
int hw_subframe = 0; // 0..NUM_ENB_THREADS-1 => 0..9
unsigned int rx_pos = 0;
unsigned int tx_pos = 0;
#endif
int CC_id=0;
struct timespec trx_time0, trx_time1, trx_time2;
/* avoid gcc warnings */
(void)trx_time0;
(void)trx_time1;
(void)trx_time2;
#ifdef RTAI
RT_TASK* task = rt_task_init_schmod(nam2num("eNBmain"), 0, 0, 0, SCHED_FIFO, 0xF);
#else
#ifdef LOWLATENCY
struct sched_attr attr;
unsigned int flags = 0;
attr.size = sizeof(attr);
attr.sched_flags = 0;
attr.sched_nice = 0;
attr.sched_priority = 0;
/* This creates a .2 ms reservation */
attr.sched_policy = SCHED_DEADLINE;
attr.sched_runtime = (0.3 * 100) * 10000;
attr.sched_deadline = (0.9 * 100) * 10000;
attr.sched_period = 1 * 1000000;
if (sched_setattr(0, &attr, flags) < 0 ) {
perror("[SCHED] main eNB thread: sched_setattr failed\n");
exit_fun("Nothing to add");
} else {
LOG_I(HW,"[SCHED][eNB] eNB main deadline thread %ld started on CPU %d\n",
gettid(),sched_getcpu());
}
#else
int policy, s, j;
struct sched_param sparam;
char cpu_affinity[1024];
cpu_set_t cpuset;
/* Set affinity mask to include CPUs 1 to MAX_CPUS */
/* CPU 0 is reserved for UHD threads */
CPU_ZERO(&cpuset);
#ifdef CPU_AFFINITY
if (get_nprocs() >2)
{
for (j = 1; j < get_nprocs(); j++)
CPU_SET(j, &cpuset);
s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (s != 0)
{
perror( "pthread_setaffinity_np");
exit_fun("Error setting processor affinity");
}
}
#endif
/* Check the actual affinity mask assigned to the thread */
s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (s != 0)
{
perror( "pthread_getaffinity_np");
exit_fun("Error getting processor affinity ");
}
memset(cpu_affinity, 0 , sizeof(cpu_affinity));
for (j = 0; j < CPU_SETSIZE; j++)
if (CPU_ISSET(j, &cpuset))
{
char temp[1024];
sprintf(temp, " CPU_%d ", j);
strcat(cpu_affinity, temp);
}
memset(&sparam, 0 , sizeof (sparam));
sparam.sched_priority = sched_get_priority_max(SCHED_FIFO);
policy = SCHED_FIFO ;
s = pthread_setschedparam(pthread_self(), policy, &sparam);
if (s != 0)
{
perror("pthread_setschedparam : ");
exit_fun("Error setting thread priority");
}
s = pthread_getschedparam(pthread_self(), &policy, &sparam);
if (s != 0)
{
perror("pthread_getschedparam : ");
exit_fun("Error getting thread priority");
}
LOG_I( HW, "[SCHED][eNB] Started eNB main thread on CPU %d TID %ld , sched_policy = %s, priority = %d, CPU Affinity = %s \n", (int)sched_getcpu(), gettid(),
(policy == SCHED_FIFO) ? "SCHED_FIFO" :
(policy == SCHED_RR) ? "SCHED_RR" :
(policy == SCHED_OTHER) ? "SCHED_OTHER" :
"???",
(int) sparam.sched_priority, cpu_affinity);
#endif
#endif
// stop early, if an exit is requested
// FIXME really neccessary?
if (oai_exit)
goto eNB_thread_cleanup;
#ifdef RTAI
LOG_I( HW, "[SCHED][eNB] Started eNB main thread (id %p)\n", task );
#endif
#ifdef HARD_RT
rt_make_hard_real_time();
#endif
printf("eNB_thread: mlockall in ...\n");
mlockall(MCL_CURRENT | MCL_FUTURE);
printf("eNB_thread: mlockall out ...\n");
timing_info.time_min = 100000000ULL;
timing_info.time_max = 0;
timing_info.time_avg = 0;
timing_info.n_samples = 0;
printf( "waiting for sync (eNB_thread)\n" );
pthread_mutex_lock( &sync_mutex );
while (sync_var<0)
pthread_cond_wait( &sync_cond, &sync_mutex );
pthread_mutex_unlock(&sync_mutex);
printf( "got sync (eNB_thread)\n" );
int frame = 0;
#ifndef EXMIMO
spp = openair0_cfg[0].samples_per_packet;
tx_pos = openair0_cfg[0].tx_scheduling_advance;
#endif
#if defined(ENABLE_ITTI)
wait_system_ready ("Waiting for eNB application to be ready %s\r", &start_eNB);
#endif
while (!oai_exit) {
start_meas( &softmodem_stats_mt );
#ifdef EXMIMO
hw_slot = (((((volatile unsigned int *)DAQ_MBOX)[0]+1)%150)<<1)/15;
// LOG_D(HW,"eNB frame %d, time %llu: slot %d, hw_slot %d (mbox %d)\n",frame,rt_get_time_ns(),slot,hw_slot,((unsigned int *)DAQ_MBOX)[0]);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_HW_SUBFRAME, hw_slot>>1);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_HW_FRAME, frame);
//this is the mbox counter where we should be
mbox_target = mbox_bounds[slot];
//this is the mbox counter where we are
mbox_current = ((volatile unsigned int *)DAQ_MBOX)[0];
//this is the time we need to sleep in order to synchronize with the hw (in multiples of DAQ_PERIOD)
if ((mbox_current>=135) && (mbox_target<15)) //handle the frame wrap-arround
diff = 150-mbox_current+mbox_target;
else if ((mbox_current<15) && (mbox_target>=135))
diff = -150+mbox_target-mbox_current;
else
diff = mbox_target - mbox_current;
//when we start the aquisition we want to start with slot 0, so we rather wait for the hardware than to advance the slot number (a positive diff will cause the programm to go into the second if clause rather than the first)
if (first_run==1) {
first_run=0;
if (diff<0)
diff = diff + 150;
LOG_I(HW,"eNB Frame %d, time %llu: slot %d, hw_slot %d, diff %d\n",frame, rt_get_time_ns(), slot, hw_slot, diff);
}
if (((slot%2==0) && (diff < (-14))) || ((slot%2==1) && (diff < (-7)))) {
// at the eNB, even slots have double as much time since most of the processing is done here and almost nothing in odd slots
LOG_W(HW,"eNB Frame %d, time %llu: missed slot %d, proceeding with next one (slot %d, hw_slot %d, mbox_current %d, mbox_target %d, diff %d)\n",
frame, rt_get_time_ns(), num_missed_slots, slot, hw_slot, mbox_current,mbox_target, diff);
if (exit_missed_slots==1) {
stop_meas(&softmodem_stats_mt);
exit_fun("[HW][eNB] missed slot");
} else {
num_missed_slots++;
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_MISSED_SLOTS_ENB,num_missed_slots );
}
if ((slot&1) == 1) {
for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++){
if (PHY_vars_eNB_g[0][CC_id]->proc[((slot>>1)+1)%10].frame_rx==1023)
PHY_vars_eNB_g[0][CC_id]->proc[((slot>>1)+1)%10].frame_rx=0;
else
PHY_vars_eNB_g[0][CC_id]->proc[((slot>>1)+1)%10].frame_rx += 1;
if (PHY_vars_eNB_g[0][CC_id]->proc[((slot>>1)+1)%10].frame_tx==1023)
PHY_vars_eNB_g[0][CC_id]->proc[((slot>>1)+1)%10].frame_tx=0;
else
PHY_vars_eNB_g[0][CC_id]->proc[((slot>>1)+1)%10].frame_tx += 1;
}
}
slot++;
if (slot == 20) {
frame++;
slot = 0;
}
}
if (diff>8)
LOG_D(HW,"eNB Frame %d, time %llu: skipped slot, waiting for hw to catch up (slot %d, hw_slot %d, mbox_current %d, mbox_target %d, diff %d)\n",frame, rt_get_time_ns(), slot, hw_slot, mbox_current,
mbox_target, diff);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DAQ_MBOX, *DAQ_MBOX);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DIFF, diff);
delay_cnt = 0;
while ((diff>0) && (!oai_exit)) {
time_in = rt_get_time_ns();
//LOG_D(HW,"eNB Frame %d delaycnt %d : hw_slot %d (%d), slot %d, (slot+1)*15=%d, diff %d, time %llu\n",frame,delay_cnt,hw_slot,((unsigned int *)DAQ_MBOX)[0],slot,(((slot+1)*15)>>1),diff,time_in);
//LOG_D(HW,"eNB Frame %d, time %llu: sleeping for %llu (slot %d, hw_slot %d, diff %d, mbox %d, delay_cnt %d)\n", frame, time_in, diff*DAQ_PERIOD,slot,hw_slot,diff,((volatile unsigned int *)DAQ_MBOX)[0],delay_cnt);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RT_SLEEP,1);
ret = rt_sleep_ns(diff*DAQ_PERIOD);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RT_SLEEP,0);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DAQ_MBOX, *DAQ_MBOX);
if (ret)
LOG_D(HW,"eNB Frame %d, time %llu: rt_sleep_ns returned %d\n",frame, time_in);
hw_slot = (((((volatile unsigned int *)DAQ_MBOX)[0]+1)%150)<<1)/15;
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_HW_SUBFRAME, hw_slot>>1);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_HW_FRAME, frame);
//LOG_D(HW,"eNB Frame %d : hw_slot %d, time %llu\n",frame,hw_slot,rt_get_time_ns());
delay_cnt++;
if (delay_cnt == 10) {
stop_meas(&softmodem_stats_mt);
LOG_D(HW,"eNB Frame %d: HW stopped ... \n",frame);
exit_fun("[HW][eNB] HW stopped");
}
mbox_current = ((volatile unsigned int *)DAQ_MBOX)[0];
if ((mbox_current>=135) && (mbox_target<15)) //handle the frame wrap-arround
diff = 150-mbox_current+mbox_target;
else if ((mbox_current<15) && (mbox_target>=135))
diff = -150+mbox_target-mbox_current;
else
diff = mbox_target - mbox_current;
}
#else // EXMIMO
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_HW_SUBFRAME, hw_subframe );
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_HW_FRAME, frame );
tx_launched = 0;
while (rx_pos < ((1+hw_subframe)*PHY_vars_eNB_g[0][0]->lte_frame_parms.samples_per_tti)) {
unsigned int rxs;
#ifndef USRP_DEBUG
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 );
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TXCNT, tx_pos );
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RXCNT, rx_pos );
clock_gettime( CLOCK_MONOTONIC, &trx_time0 );
start_meas( &softmodem_stats_hw );
openair0_timestamp timestamp;
int i=0;
// prepare rx buffer pointers
for (i=0; i<PHY_vars_eNB_g[0][0]->lte_frame_parms.nb_antennas_rx; i++)
rxp[i] = (void*)&rxdata[i][rx_pos];
// check if nsymb_read == spp
// map antenna port i to the cc_id. Now use the 1:1 mapping
rxs = openair0.trx_read_func(&openair0,
&timestamp,
rxp,
spp,
PHY_vars_eNB_g[0][0]->lte_frame_parms.nb_antennas_rx);
stop_meas( &softmodem_stats_hw );
if (frame > 50) {
clock_gettime( CLOCK_MONOTONIC, &trx_time1 );
}
if (frame > 20){
if (rxs != spp)
exit_fun( "problem receiving samples" );
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 );
// Transmit TX buffer based on timestamp from RX
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 );
// prepare tx buffer pointers
for (i=0; i<PHY_vars_eNB_g[0][0]->lte_frame_parms.nb_antennas_tx; i++)
txp[i] = (void*)&txdata[i][tx_pos];
// if symb_written < spp ==> error
if (frame > 50) {
openair0.trx_write_func(&openair0,
(timestamp+(openair0_cfg[card].tx_scheduling_advance)-openair0_cfg[card].tx_sample_advance),
txp,
spp,
PHY_vars_eNB_g[0][0]->lte_frame_parms.nb_antennas_tx,
1);
}
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, timestamp&0xffffffff );
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, (timestamp+(openair0_cfg[card].tx_scheduling_advance)-openair0_cfg[card].tx_sample_advance)&0xffffffff );
stop_meas( &softmodem_stats_mt );
if (frame > 50) {
clock_gettime( CLOCK_MONOTONIC, &trx_time2 );
//update_difftimes(trx_time1, trx_time2);
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE,0);
#else
// USRP_DEBUG is active
rt_sleep_ns(1000000);
#endif
/* FT configurable tx lauch delay (in slots): txlaunch_wait, txlaunch_wait_slotcount is device specific and
set in the corresponding library (with txlaunch_wait=1 and txlaunch_wait_slotcount=1 the check is as it previously was) */
/* old check:
if ((frame>50) &&
(tx_launched == 0) &&
(rx_pos >= (((2*hw_subframe)+1)*PHY_vars_eNB_g[0][0]->lte_frame_parms.samples_per_tti>>1))) {*/
if ( (frame>50) && (tx_launched == 0) &&
((openair0_cfg[card].txlaunch_wait == 0) ||
((openair0_cfg[card].txlaunch_wait == 1) &&
(rx_pos >= (((2*hw_subframe)+openair0_cfg[card].txlaunch_wait_slotcount)*PHY_vars_eNB_g[0][0]->lte_frame_parms.samples_per_tti>>1))))) {
tx_launched = 1;
for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
if (pthread_mutex_lock(&PHY_vars_eNB_g[0][CC_id]->proc[hw_subframe].mutex_tx) != 0) {
LOG_E( PHY, "[eNB] ERROR pthread_mutex_lock for eNB TX thread %d (IC %d)\n", hw_subframe, PHY_vars_eNB_g[0][CC_id]->proc[hw_subframe].instance_cnt_tx );
exit_fun( "error locking mutex_tx" );
break;
}
int cnt_tx = ++PHY_vars_eNB_g[0][CC_id]->proc[hw_subframe].instance_cnt_tx;
pthread_mutex_unlock( &PHY_vars_eNB_g[0][CC_id]->proc[hw_subframe].mutex_tx );
if (cnt_tx == 0) {
// the thread was presumably waiting where it should and can now be woken up
if (pthread_cond_signal(&PHY_vars_eNB_g[0][CC_id]->proc[hw_subframe].cond_tx) != 0) {
LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB TX thread %d\n", hw_subframe );
exit_fun( "ERROR pthread_cond_signal" );
break;
}
} else {
LOG_W( PHY,"[eNB] Frame %d, eNB TX thread %d busy!! (rx_cnt %u, cnt_tx %i)\n", PHY_vars_eNB_g[0][CC_id]->proc[hw_subframe].frame_tx, hw_subframe, rx_pos, cnt_tx );
exit_fun( "TX thread busy" );
break;
}
}
}
rx_pos += spp;
tx_pos += spp;
if (tx_pos >= openair0_cfg[card].samples_per_frame)
tx_pos -= openair0_cfg[card].samples_per_frame;
}
if (rx_pos >= openair0_cfg[card].samples_per_frame)
rx_pos -= openair0_cfg[card].samples_per_frame;
#endif // USRP
if (oai_exit) break;
timing_info.time_last = timing_info.time_now;
timing_info.time_now = rt_get_time_ns();
if (timing_info.n_samples>0) {
RTIME time_diff = timing_info.time_now - timing_info.time_last;
if (time_diff < timing_info.time_min)
timing_info.time_min = time_diff;
if (time_diff > timing_info.time_max)
timing_info.time_max = time_diff;
timing_info.time_avg += time_diff;
}
timing_info.n_samples++;
if ((slot&1) == 1) {
// odd slot
#ifdef EXMIMO
int sf = ((slot>>1)+1)%10;
#else
int sf = hw_subframe;
#endif
if (frame>50) {
for (int CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
#ifdef EXMIMO
if (pthread_mutex_lock(&PHY_vars_eNB_g[0][CC_id]->proc[sf].mutex_tx) != 0) {
LOG_E(PHY,"[eNB] ERROR pthread_mutex_lock for eNB TX thread %d (IC %d)\n",sf,PHY_vars_eNB_g[0][CC_id]->proc[sf].instance_cnt_tx);
} else {
// LOG_I(PHY,"[eNB] Waking up eNB process %d (IC %d)\n",sf,PHY_vars_eNB_g[0][CC_id]->proc[sf].instance_cnt);
PHY_vars_eNB_g[0][CC_id]->proc[sf].instance_cnt_tx++;
pthread_mutex_unlock(&PHY_vars_eNB_g[0][CC_id]->proc[sf].mutex_tx);
if (PHY_vars_eNB_g[0][CC_id]->proc[sf].instance_cnt_tx == 0) {
if (pthread_cond_signal(&PHY_vars_eNB_g[0][CC_id]->proc[sf].cond_tx) != 0) {
LOG_E(PHY,"[eNB] ERROR pthread_cond_signal for eNB TX thread %d\n",sf);
exit_fun("nothing to add");
}
} else {
LOG_W(PHY,"[eNB] Frame %d, eNB TX thread %d busy!!\n",PHY_vars_eNB_g[0][CC_id]->proc[sf].frame_tx,sf);
exit_fun("nothing to add");
}
}
#endif
switch (ITTI_MSG_ID(message_p)) {
case TERMINATE_MESSAGE:
oai_exit=1;
itti_exit_task ();
break;
if (pthread_mutex_lock(&PHY_vars_eNB_g[0][CC_id]->proc[sf].mutex_rx) != 0) {
LOG_E( PHY, "[eNB] ERROR pthread_mutex_lock for eNB RX thread %d (IC %d)\n", sf, PHY_vars_eNB_g[0][CC_id]->proc[sf].instance_cnt_rx );
exit_fun( "error locking mutex_rx" );
break;
}
int cnt_rx = ++PHY_vars_eNB_g[0][CC_id]->proc[sf].instance_cnt_rx;
pthread_mutex_unlock( &PHY_vars_eNB_g[0][CC_id]->proc[sf].mutex_rx );
if (cnt_rx == 0) {
// the thread was presumably waiting where it should and can now be woken up
if (pthread_cond_signal(&PHY_vars_eNB_g[0][CC_id]->proc[sf].cond_rx) != 0) {
LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB RX thread %d\n", sf );
exit_fun( "ERROR pthread_cond_signal" );
break;
}
} else {
LOG_W( PHY, "[eNB] Frame %d, eNB RX thread %d busy!! instance_cnt %d CC_id %d\n", PHY_vars_eNB_g[0][CC_id]->proc[sf].frame_rx, sf, PHY_vars_eNB_g[0][CC_id]->proc[sf].instance_cnt_rx, CC_id );
exit_fun( "RX thread busy" );
break;
}
}
}
}
case ACTIVATE_MESSAGE:
start_UE = 1;
break;
#ifdef EXMIMO
slot++;
case DEACTIVATE_MESSAGE:
start_UE = 0;
break;
if (slot == 20) {
frame++;
slot = 0;
}
case MESSAGE_TEST:
LOG_I(EMU, "Received %s\n", ITTI_MSG_NAME(message_p));
break;
#else
hw_subframe++;
slot += 2;
if (hw_subframe == NUM_ENB_THREADS) {
// the radio frame is complete, start over
hw_subframe = 0;
frame++;
slot = 1;
default:
LOG_E(EMU, "Received unexpected message %s\n", ITTI_MSG_NAME(message_p));
break;
}
#endif
#if defined(ENABLE_ITTI)
itti_update_lte_time( frame, slot );
#endif
}
result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p);
AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
} while(!oai_exit);
eNB_thread_cleanup:
#ifdef DEBUG_THREADS
printf( "eNB_thread: finished, ran %d times.\n", frame );
return NULL;
}
#endif
#ifdef HARD_RT
rt_make_soft_real_time();
#endif
#ifdef DEBUG_THREADS
printf( "Exiting eNB_thread ..." );
#endif
// clean task
#ifdef RTAI
rt_task_delete(task);
#endif
eNB_thread_status = 0;
// print_difftimes();
return &eNB_thread_status;
}
......@@ -2290,12 +646,6 @@ static void get_options (int argc, char **argv)
int clock_src;
#endif
int CC_id;
#ifdef EXMIMO
char rxg_fname[256], line[1000];
FILE *rxg_fd;
int l;
#endif
......@@ -2586,30 +936,6 @@ static void get_options (int argc, char **argv)
break;
case 'F':
#ifdef EXMIMO
sprintf(rxg_fname,"%srxg.lime",optarg);
rxg_fd = fopen(rxg_fname,"r");
if (rxg_fd) {
printf("Loading RX Gain parameters from %s\n",rxg_fname);
l=0;
while (fgets(line, sizeof(line), rxg_fd)) {
if ((strlen(line)==0) || (*line == '#')) continue; //ignore empty or comment lines
else {
if (l==0) sscanf(line,"%d %d %d %d",&rxg_max[0],&rxg_max[1],&rxg_max[2],&rxg_max[3]);
if (l==1) sscanf(line,"%d %d %d %d",&rxg_med[0],&rxg_med[1],&rxg_med[2],&rxg_med[3]);
if (l==2) sscanf(line,"%d %d %d %d",&rxg_byp[0],&rxg_byp[1],&rxg_byp[2],&rxg_byp[3]);
l++;
}
}
} else
printf("%s not found, running with defaults\n",rxg_fname);
#endif
break;
case 'G':
......@@ -2786,7 +1112,7 @@ static void get_options (int argc, char **argv)
int main( int argc, char **argv )
{
int i,aa,card=0;
#if defined (XFORMS) || defined (EMOS) || defined (EXMIMO)
#if defined (XFORMS)
void *status;
#endif
......@@ -2795,16 +1121,9 @@ int main( int argc, char **argv )
uint8_t cooperation_flag=0, abstraction_flag=0;
uint8_t beta_ACK=0,beta_RI=0,beta_CQI=2;
#ifdef ENABLE_TCXO
unsigned int tcxo = 114;
#endif
#if defined (XFORMS)
int ret;
#endif
#if defined (EMOS) || (! defined (RTAI))
int error_code;
#endif
#ifdef DEBUG_CONSOLE
setvbuf(stdout, NULL, _IONBF, 0);
......@@ -2819,6 +1138,7 @@ int main( int argc, char **argv )
memset(tx_max_power,0,sizeof(int)*MAX_NUM_CCs);
set_latency_target();
// det defaults
for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
frame_parms[CC_id] = (LTE_DL_FRAME_PARMS*) malloc(sizeof(LTE_DL_FRAME_PARMS));
/* Set some default values that may be overwritten while reading options */
......@@ -2961,9 +1281,8 @@ int main( int argc, char **argv )
signal(SIGINT, signal_handler);
#endif
#ifndef RTAI
check_clock();
#endif
// init the parameters
for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
......@@ -3023,7 +1342,7 @@ int main( int argc, char **argv )
else
UE[CC_id]->mac_enabled = 1;
if (UE[CC_id]->mac_enabled == 0) {
if (UE[CC_id]->mac_enabled == 0) { //set default UL parameters for testing mode
for (i=0; i<NUMBER_OF_CONNECTED_eNB_MAX; i++) {
UE[CC_id]->pusch_config_dedicated[i].betaOffset_ACK_Index = beta_ACK;
UE[CC_id]->pusch_config_dedicated[i].betaOffset_RI_Index = beta_RI;
......@@ -3048,64 +1367,11 @@ int main( int argc, char **argv )
else
UE[CC_id]->lte_ue_pdcch_vars[0]->crnti = 0x1235;
#ifdef EXMIMO
for (i=0; i<4; i++) {
UE[CC_id]->rx_gain_max[i] = rxg_max[i];
UE[CC_id]->rx_gain_med[i] = rxg_med[i];
UE[CC_id]->rx_gain_byp[i] = rxg_byp[i];
}
if ((UE[0]->mode == normal_txrx) ||
(UE[0]->mode == rx_calib_ue) ||
(UE[0]->mode == no_L2_connect) ||
(UE[0]->mode == debug_prach)) {
for (i=0; i<4; i++)
rx_gain_mode[CC_id][i] = max_gain;
UE[CC_id]->rx_total_gain_dB = UE[CC_id]->rx_gain_max[0] + (int)rx_gain[CC_id][0] - 30; //-30 because it was calibrated with a 30dB gain
} else if ((mode == rx_calib_ue_med)) {
for (i=0; i<4; i++)
rx_gain_mode[CC_id][i] = med_gain;
UE[CC_id]->rx_total_gain_dB = UE[CC_id]->rx_gain_med[0] + (int)rx_gain[CC_id][0] - 30; //-30 because it was calibrated with a 30dB gain;
} else if ((mode == rx_calib_ue_byp)) {
for (i=0; i<4; i++)
rx_gain_mode[CC_id][i] = byp_gain;
UE[CC_id]->rx_total_gain_dB = UE[CC_id]->rx_gain_byp[0] + (int)rx_gain[CC_id][0] - 30; //-30 because it was calibrated with a 30dB gain;
}
#else
UE[CC_id]->rx_total_gain_dB = (int)rx_gain[CC_id][0];
#endif
UE[CC_id]->tx_power_max_dBm = tx_max_power[CC_id];
#ifdef EXMIMO
//N_TA_offset
if (UE[CC_id]->lte_frame_parms.frame_type == TDD) {
if (UE[CC_id]->lte_frame_parms.N_RB_DL == 100)
UE[CC_id]->N_TA_offset = 624;
else if (UE[CC_id]->lte_frame_parms.N_RB_DL == 50)
UE[CC_id]->N_TA_offset = 624/2;
else if (UE[CC_id]->lte_frame_parms.N_RB_DL == 25)
UE[CC_id]->N_TA_offset = 624/4;
} else {
UE[CC_id]->N_TA_offset = 0;
}
#else
//already taken care of in lte-softmodem
UE[CC_id]->N_TA_offset = 0;
#endif
}
openair_daq_vars.manual_timing_advance = 0;
openair_daq_vars.rx_gain_mode = DAQ_AGC_ON;
openair_daq_vars.auto_freq_correction = 0;
openair_daq_vars.use_ia_receiver = 0;
}
// printf("tx_max_power = %d -> amp %d\n",tx_max_power,get_tx_amp(tx_max_power,tx_max_power));
} else {
......@@ -3117,12 +1383,10 @@ int main( int argc, char **argv )
PHY_vars_eNB_g[0][CC_id] = init_lte_eNB(frame_parms[CC_id],0,frame_parms[CC_id]->Nid_cell,cooperation_flag,transmission_mode,abstraction_flag);
PHY_vars_eNB_g[0][CC_id]->CC_id = CC_id;
if (phy_test==1)
PHY_vars_eNB_g[0][CC_id]->mac_enabled = 0;
else
PHY_vars_eNB_g[0][CC_id]->mac_enabled = 1;
if (phy_test==1) PHY_vars_eNB_g[0][CC_id]->mac_enabled = 0;
else PHY_vars_eNB_g[0][CC_id]->mac_enabled = 1;
if (PHY_vars_eNB_g[0][CC_id]->mac_enabled == 0) {
if (PHY_vars_eNB_g[0][CC_id]->mac_enabled == 0) { //set default parameters for testing mode
for (i=0; i<NUMBER_OF_UE_MAX; i++) {
PHY_vars_eNB_g[0][CC_id]->pusch_config_dedicated[i].betaOffset_ACK_Index = beta_ACK;
PHY_vars_eNB_g[0][CC_id]->pusch_config_dedicated[i].betaOffset_RI_Index = beta_RI;
......@@ -3138,39 +1402,9 @@ int main( int argc, char **argv )
PHY_vars_eNB_g[0][CC_id]->lte_frame_parms.frame_type,
PHY_vars_eNB_g[0][CC_id]->X_u);
#ifndef EXMIMO
PHY_vars_eNB_g[0][CC_id]->rx_total_gain_eNB_dB = (int)rx_gain[CC_id][0];
#else
PHY_vars_eNB_g[0][CC_id]->rx_total_gain_eNB_dB = rxg_max[0] + (int)rx_gain[CC_id][0] - 30; //was measured at rxgain=30;
printf("Setting RX total gain to %d\n",PHY_vars_eNB_g[0][CC_id]->rx_total_gain_eNB_dB);
// set eNB to max gain
for (i=0; i<4; i++)
rx_gain_mode[CC_id][i] = max_gain;
#endif
#ifdef EXMIMO
//N_TA_offset
if (PHY_vars_eNB_g[0][CC_id]->lte_frame_parms.frame_type == TDD) {
if (PHY_vars_eNB_g[0][CC_id]->lte_frame_parms.N_RB_DL == 100)
PHY_vars_eNB_g[0][CC_id]->N_TA_offset = 624;
else if (PHY_vars_eNB_g[0][CC_id]->lte_frame_parms.N_RB_DL == 50)
PHY_vars_eNB_g[0][CC_id]->N_TA_offset = 624/2;
else if (PHY_vars_eNB_g[0][CC_id]->lte_frame_parms.N_RB_DL == 25)
PHY_vars_eNB_g[0][CC_id]->N_TA_offset = 624/4;
} else {
PHY_vars_eNB_g[0][CC_id]->N_TA_offset = 0;
}
#else
//already taken care of in lte-softmodem.c
PHY_vars_eNB_g[0][CC_id]->N_TA_offset = 0;
#endif
}
......@@ -3178,16 +1412,11 @@ int main( int argc, char **argv )
NB_eNB_INST=1;
NB_INST=1;
openair_daq_vars.ue_dl_rb_alloc=0x1fff;
openair_daq_vars.target_ue_dl_mcs=target_dl_mcs;
openair_daq_vars.ue_ul_nb_rb=6;
openair_daq_vars.target_ue_ul_mcs=target_ul_mcs;
}
#ifndef RTAI
fill_modeled_runtime_table(runtime_phy_rx,runtime_phy_tx);
cpuf=get_cpu_freq_GHz();
#endif
dump_frame_parms(frame_parms[0]);
......@@ -3254,7 +1483,7 @@ int main( int argc, char **argv )
// in the case of the USRP, the following variables need to be initialized before the init
// since the USRP only supports one CC (for the moment), we initialize all the cards with first CC.
// in the case of EXMIMO2, these values are overwirtten in the function setup_eNB/UE_buffer
#ifndef EXMIMO
openair0_cfg[card].tx_num_channels=min(2,((UE_flag==0) ? PHY_vars_eNB_g[0][0]->lte_frame_parms.nb_antennas_tx : PHY_vars_UE_g[0][0]->lte_frame_parms.nb_antennas_tx));
openair0_cfg[card].rx_num_channels=min(2,((UE_flag==0) ? PHY_vars_eNB_g[0][0]->lte_frame_parms.nb_antennas_rx : PHY_vars_UE_g[0][0]->lte_frame_parms.nb_antennas_rx));
......@@ -3277,32 +1506,10 @@ int main( int argc, char **argv )
openair0_cfg[card].rx_gain[i] = PHY_vars_UE_g[0][0]->rx_total_gain_dB;
}
#if 0 // UHD 3.8
switch(frame_parms[0]->N_RB_DL) {
case 6:
openair0_cfg[card].rx_gain[i] -= 12;
break;
case 25:
openair0_cfg[card].rx_gain[i] -= 6;
break;
case 50:
openair0_cfg[card].rx_gain[i] -= 3;
break;
case 100:
openair0_cfg[card].rx_gain[i] -= 0;
break;
default:
break;
}
#endif
}
#endif
}
#ifndef LOWLATENCY
......@@ -3412,30 +1619,7 @@ int main( int argc, char **argv )
mac_xface->mrbch_phy_sync_failure (0, 0, 0);
}
/* #ifdef OPENAIR2
//if (otg_enabled) {
init_all_otg(0);
g_otg->seed = 0;
init_seeds(g_otg->seed);
g_otg->num_nodes = 2;
for (i=0; i<g_otg->num_nodes; i++){
for (j=0; j<g_otg->num_nodes; j++){
g_otg->application_idx[i][j] = 1;
//g_otg->packet_gen_type=SUBSTRACT_STRING;
g_otg->aggregation_level[i][j][0]=1;
g_otg->application_type[i][j][0] = BCBR; //MCBR, BCBR
}
}
init_predef_traffic(UE_flag ? 1 : 0, UE_flag ? 0 : 1);
// }
#endif */
#ifdef EXMIMO
number_of_cards = openair0_num_detected_cards;
#else
number_of_cards = 1;
#endif
for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
......@@ -3445,11 +1629,16 @@ int main( int argc, char **argv )
// connect the TX/RX buffers
if (UE_flag==1) {
for (CC_id=0;CC_id<MAX_NUM_CCs; CC_id++) {
#ifdef OAI_USRP
openair_daq_vars.timing_advance = timing_advance;
UE[CC_id]->hw_timing_advance = timing_advance;
#else
openair_daq_vars.timing_advance = 160;
UE[CC_id]->hw_timing_advance = 160;
#endif
}
if (setup_ue_buffers(UE,&openair0_cfg[0],rf_map)!=0) {
printf("Error setting up eNB buffer\n");
exit(-1);
......@@ -3474,7 +1663,8 @@ int main( int argc, char **argv )
}
//p_exmimo_config->framing.tdd_config = TXRXSWITCH_TESTRX;
} else {
openair_daq_vars.timing_advance = 0;
if (setup_eNB_buffers(PHY_vars_eNB_g[0],&openair0_cfg[0],rf_map)!=0) {
printf("Error setting up eNB buffer\n");
......@@ -3485,59 +1675,18 @@ int main( int argc, char **argv )
// Set LSBs for antenna switch (ExpressMIMO)
for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
PHY_vars_eNB_g[0][CC_id]->hw_timing_advance = 0;
for (i=0; i<frame_parms[CC_id]->samples_per_tti*10; i++)
for (aa=0; aa<frame_parms[CC_id]->nb_antennas_tx; aa++)
PHY_vars_eNB_g[0][CC_id]->lte_eNB_common_vars.txdata[0][aa][i] = 0x00010001;
}
}
#ifdef EXMIMO
openair0_config(&openair0_cfg[0],UE_flag);
#endif
/*
for (ant=0;ant<4;ant++)
p_exmimo_config->rf.do_autocal[ant] = 0;
*/
#ifdef EMOS
error_code = rtf_create(CHANSOUNDER_FIFO_MINOR,CHANSOUNDER_FIFO_SIZE);
if (error_code==0)
printf("[OPENAIR][SCHED][INIT] Created EMOS FIFO %d\n",CHANSOUNDER_FIFO_MINOR);
else if (error_code==ENODEV)
printf("[OPENAIR][SCHED][INIT] Problem: EMOS FIFO %d is greater than or equal to RTF_NO\n",CHANSOUNDER_FIFO_MINOR);
else if (error_code==ENOMEM)
printf("[OPENAIR][SCHED][INIT] Problem: cannot allocate memory for EMOS FIFO %d\n",CHANSOUNDER_FIFO_MINOR);
else
printf("[OPENAIR][SCHED][INIT] Problem creating EMOS FIFO %d, error_code %d\n",CHANSOUNDER_FIFO_MINOR,error_code);
#endif
mlockall(MCL_CURRENT | MCL_FUTURE);
#ifdef RTAI
// make main thread LXRT soft realtime
/* task = */ rt_task_init_schmod(nam2num("MAIN"), 9, 0, 0, SCHED_FIFO, 0xF);
// start realtime timer and scheduler
//rt_set_oneshot_mode();
rt_set_periodic_mode();
start_rt_timer(0);
#endif
pthread_cond_init(&sync_cond,NULL);
pthread_mutex_init(&sync_mutex, NULL);
// this starts the DMA transfers
#ifdef EXMIMO
if (UE_flag!=1)
for (card=0; card<openair0_num_detected_cards; card++)
openair0_start_rt_acquisition(card);
#endif
#ifdef XFORMS
int UE_id;
......@@ -3573,13 +1722,16 @@ int main( int argc, char **argv )
sprintf (title, "LTE DL SCOPE UE");
fl_show_form (form_ue[UE_id]->lte_phy_scope_ue, FL_PLACE_HOTSPOT, FL_FULLBORDER, title);
/*
if (openair_daq_vars.use_ia_receiver) {
fl_set_button(form_ue[UE_id]->button_0,1);
fl_set_object_label(form_ue[UE_id]->button_0, "IA Receiver ON");
} else {
fl_set_button(form_ue[UE_id]->button_0,0);
fl_set_object_label(form_ue[UE_id]->button_0, "IA Receiver OFF");
}
}*/
fl_set_button(form_ue[UE_id]->button_0,0);
fl_set_object_label(form_ue[UE_id]->button_0, "IA Receiver OFF");
}
ret = pthread_create(&forms_thread, NULL, scope_thread, NULL);
......@@ -3592,99 +1744,21 @@ int main( int argc, char **argv )
#endif
#ifdef EMOS
ret = pthread_create(&thread3, NULL, emos_thread, NULL);
printf("EMOS thread created, ret=%d\n",ret);
ret = pthread_create(&thread4, NULL, gps_thread, NULL);
printf("GPS thread created, ret=%d\n",ret);
#endif
rt_sleep_ns(10*FRAME_PERIOD);
rt_sleep_ns(10*100000000ULL);
#ifndef RTAI
pthread_attr_init (&attr_dlsch_threads);
pthread_attr_setstacksize(&attr_dlsch_threads,4*PTHREAD_STACK_MIN);
pthread_attr_init (&attr_UE_thread);
pthread_attr_setstacksize(&attr_UE_thread,8192);//5*PTHREAD_STACK_MIN);
#ifndef LOWLATENCY
sched_param_UE_thread.sched_priority = sched_get_priority_max(SCHED_FIFO);
pthread_attr_setschedparam(&attr_UE_thread,&sched_param_UE_thread);
sched_param_dlsch.sched_priority = sched_get_priority_max(SCHED_FIFO); //OPENAIR_THREAD_PRIORITY;
pthread_attr_setschedparam (&attr_dlsch_threads, &sched_param_dlsch);
pthread_attr_setschedpolicy (&attr_dlsch_threads, SCHED_FIFO);
printf("Setting eNB_thread FIFO scheduling policy with priority %d \n", sched_param_dlsch.sched_priority);
#endif
#endif
// start the main thread
if (UE_flag == 1) {
printf("Intializing UE Threads ...\n");
init_UE_threads();
#ifdef DLSCH_THREAD
init_rx_pdsch_thread();
rt_sleep_ns(FRAME_PERIOD/10);
init_dlsch_threads();
#endif
sleep(1);
#ifdef RTAI
main_ue_thread = rt_thread_create(UE_thread, NULL, 100000000);
#else
error_code = pthread_create(&main_ue_thread, &attr_UE_thread, UE_thread, NULL);
if (error_code!= 0) {
LOG_D(HW,"[lte-softmodem.c] Could not allocate UE_thread, error %d\n",error_code);
return(error_code);
} else {
LOG_D( HW, "[lte-softmodem.c] Allocate UE_thread successful\n" );
pthread_setname_np( main_ue_thread, "main UE" );
}
#endif
printf("UE threads created\n");
#ifdef USE_MME
while (start_UE == 0) {
sleep(1);
}
#endif
} else {
if (multi_thread>0) {
init_eNB_proc();
sleep(1);
LOG_D(HW,"[lte-softmodem.c] eNB threads created\n");
}
printf("Creating main eNB_thread \n");
#ifdef RTAI
main_eNB_thread = rt_thread_create(eNB_thread, NULL, PTHREAD_STACK_MIN);
#else
error_code = pthread_create( &main_eNB_thread, &attr_dlsch_threads, eNB_thread, NULL );
if (error_code!= 0) {
LOG_D(HW,"[lte-softmodem.c] Could not allocate eNB_thread, error %d\n",error_code);
return(error_code);
} else {
LOG_D( HW, "[lte-softmodem.c] Allocate eNB_thread successful\n" );
pthread_setname_np( main_eNB_thread, "main eNB" );
}
#endif
}
if (UE_flag == 1) init_UE();
else init_eNB();
// Sleep to allow all threads to setup
sleep(1);
#ifndef EXMIMO
#ifndef USRP_DEBUG
if (mode!=loop_through_memory)
......@@ -3693,7 +1767,6 @@ int main( int argc, char **argv )
#endif
#endif
printf("Sending sync to all threads\n");
......@@ -3713,7 +1786,7 @@ int main( int argc, char **argv )
#else
while (oai_exit==0)
rt_sleep_ns(FRAME_PERIOD);
rt_sleep_ns(100000000ULL);
#endif
......@@ -3748,79 +1821,16 @@ int main( int argc, char **argv )
// cleanup
if (UE_flag == 1) {
#ifdef EXMIMO
#ifdef RTAI
rt_thread_join(main_ue_thread);
#else
pthread_join(main_ue_thread,&status);
#endif
#ifdef DLSCH_THREAD
cleanup_dlsch_threads();
cleanup_rx_pdsch_thread();
#endif
#endif
} else {
#ifdef DEBUG_THREADS
printf("Joining eNB_thread ...");
#endif
#ifdef RTAI
rt_thread_join(main_eNB_thread);
#else
int *eNB_thread_status_p;
int result = pthread_join( main_eNB_thread, (void**)&eNB_thread_status_p );
#ifdef DEBUG_THREADS
if (result != 0) {
printf( "\nError joining main_eNB_thread.\n" );
} else {
if (eNB_thread_status_p) {
printf( "status %d\n", *eNB_thread_status_p );
} else {
printf( "The thread was killed. No status available.\n");
}
}
#else
UNUSED(result);
#endif // DEBUG_THREADS
#endif // RTAI
if (multi_thread>0) {
printf("Killing eNB processing threads\n");
kill_eNB_proc();
}
stop_eNB();
}
#ifdef RTAI
stop_rt_timer();
#endif
pthread_cond_destroy(&sync_cond);
pthread_mutex_destroy(&sync_mutex);
#ifdef EXMIMO
printf("stopping card\n");
openair0_stop(0);
printf("closing openair0_lib\n");
openair0_close();
#else
openair0.trx_end_func(&openair0);
#endif
#ifdef EMOS
printf("waiting for EMOS thread\n");
pthread_cancel(thread3);
pthread_join(thread3,&status);
printf("waiting for GPS thread\n");
pthread_cancel(thread4);
pthread_join(thread4,&status);
#endif
#ifdef EMOS
error_code = rtf_destroy(CHANSOUNDER_FIFO_MINOR);
printf("[OPENAIR][SCHED][CLEANUP] EMOS FIFO closed, error_code %d\n", error_code);
#endif
if (ouput_vcd)
VCD_SIGNAL_DUMPER_CLOSE();
......@@ -3834,142 +1844,8 @@ int main( int argc, char **argv )
}
/* this function maps the phy_vars_eNB tx and rx buffers to the available rf chains.
Each rf chain is is addressed by the card number and the chain on the card. The
rf_map specifies for each CC, on which rf chain the mapping should start. Multiple
antennas are mapped to successive RF chains on the same card. */
int setup_eNB_buffers(PHY_VARS_eNB **phy_vars_eNB, openair0_config_t *openair0_cfg, openair0_rf_map rf_map[MAX_NUM_CCs])
{
int i, CC_id;
#ifndef EXMIMO
uint16_t N_TA_offset = 0;
#else
int j;
#endif
LTE_DL_FRAME_PARMS *frame_parms;
for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
if (phy_vars_eNB[CC_id]) {
frame_parms = &(phy_vars_eNB[CC_id]->lte_frame_parms);
printf("setup_eNB_buffers: frame_parms = %p\n",frame_parms);
} else {
printf("phy_vars_eNB[%d] not initialized\n", CC_id);
return(-1);
}
#ifndef EXMIMO
if (frame_parms->frame_type == TDD) {
if (frame_parms->N_RB_DL == 100)
N_TA_offset = 624;
else if (frame_parms->N_RB_DL == 50)
N_TA_offset = 624/2;
else if (frame_parms->N_RB_DL == 25)
N_TA_offset = 624/4;
}
#endif
// replace RX signal buffers with mmaped HW versions
#ifdef EXMIMO
openair0_cfg[CC_id].tx_num_channels = 0;
openair0_cfg[CC_id].rx_num_channels = 0;
for (i=0; i<frame_parms->nb_antennas_rx; i++) {
printf("Mapping eNB CC_id %d, rx_ant %d, freq %u on card %d, chain %d\n",CC_id,i,downlink_frequency[CC_id][i]+uplink_frequency_offset[CC_id][i],rf_map[CC_id].card,rf_map[CC_id].chain+i);
free(phy_vars_eNB[CC_id]->lte_eNB_common_vars.rxdata[0][i]);
phy_vars_eNB[CC_id]->lte_eNB_common_vars.rxdata[0][i] = (int32_t*) openair0_exmimo_pci[rf_map[CC_id].card].adc_head[rf_map[CC_id].chain+i];
if (openair0_cfg[rf_map[CC_id].card].rx_freq[rf_map[CC_id].chain+i]) {
printf("Error with rf_map! A channel has already been allocated!\n");
return(-1);
} else {
openair0_cfg[rf_map[CC_id].card].rx_freq[rf_map[CC_id].chain+i] = downlink_frequency[CC_id][i]+uplink_frequency_offset[CC_id][i];
openair0_cfg[rf_map[CC_id].card].rx_gain[rf_map[CC_id].chain+i] = rx_gain[CC_id][i];
openair0_cfg[rf_map[CC_id].card].rx_num_channels++;
}
printf("rxdata[%d] @ %p\n",i,phy_vars_eNB[CC_id]->lte_eNB_common_vars.rxdata[0][i]);
for (j=0; j<16; j++) {
printf("rxbuffer %d: %x\n",j,phy_vars_eNB[CC_id]->lte_eNB_common_vars.rxdata[0][i][j]);
phy_vars_eNB[CC_id]->lte_eNB_common_vars.rxdata[0][i][j] = 16-j;
}
}
for (i=0; i<frame_parms->nb_antennas_tx; i++) {
printf("Mapping eNB CC_id %d, tx_ant %d, freq %u on card %d, chain %d\n",CC_id,i,downlink_frequency[CC_id][i],rf_map[CC_id].card,rf_map[CC_id].chain+i);
free(phy_vars_eNB[CC_id]->lte_eNB_common_vars.txdata[0][i]);
phy_vars_eNB[CC_id]->lte_eNB_common_vars.txdata[0][i] = (int32_t*) openair0_exmimo_pci[rf_map[CC_id].card].dac_head[rf_map[CC_id].chain+i];
if (openair0_cfg[rf_map[CC_id].card].tx_freq[rf_map[CC_id].chain+i]) {
printf("Error with rf_map! A channel has already been allocated!\n");
return(-1);
} else {
openair0_cfg[rf_map[CC_id].card].tx_freq[rf_map[CC_id].chain+i] = downlink_frequency[CC_id][i];
openair0_cfg[rf_map[CC_id].card].tx_gain[rf_map[CC_id].chain+i] = tx_gain[CC_id][i];
openair0_cfg[rf_map[CC_id].card].tx_num_channels++;
}
printf("txdata[%d] @ %p\n",i,phy_vars_eNB[CC_id]->lte_eNB_common_vars.txdata[0][i]);
for (j=0; j<16; j++) {
printf("txbuffer %d: %x\n",j,phy_vars_eNB[CC_id]->lte_eNB_common_vars.txdata[0][i][j]);
phy_vars_eNB[CC_id]->lte_eNB_common_vars.txdata[0][i][j] = 16-j;
}
}
#else // not EXMIMO
rxdata = (int32_t**)malloc16(frame_parms->nb_antennas_rx*sizeof(int32_t*));
txdata = (int32_t**)malloc16(frame_parms->nb_antennas_tx*sizeof(int32_t*));
for (i=0; i<frame_parms->nb_antennas_rx; i++) {
free(phy_vars_eNB[CC_id]->lte_eNB_common_vars.rxdata[0][i]);
rxdata[i] = (int32_t*)(32 + malloc16(32+openair0_cfg[rf_map[CC_id].card].samples_per_frame*sizeof(int32_t))); // FIXME broken memory allocation
phy_vars_eNB[CC_id]->lte_eNB_common_vars.rxdata[0][i] = rxdata[i]-N_TA_offset; // N_TA offset for TDD FIXME! N_TA_offset > 16 => access of unallocated memory
memset(rxdata[i], 0, openair0_cfg[rf_map[CC_id].card].samples_per_frame*sizeof(int32_t));
printf("rxdata[%d] @ %p (%p) (N_TA_OFFSET %d)\n", i, phy_vars_eNB[CC_id]->lte_eNB_common_vars.rxdata[0][i],rxdata[i],N_TA_offset);
}
for (i=0; i<frame_parms->nb_antennas_tx; i++) {
free(phy_vars_eNB[CC_id]->lte_eNB_common_vars.txdata[0][i]);
txdata[i] = (int32_t*)(32 + malloc16(32 + openair0_cfg[rf_map[CC_id].card].samples_per_frame*sizeof(int32_t))); // FIXME broken memory allocation
phy_vars_eNB[CC_id]->lte_eNB_common_vars.txdata[0][i] = txdata[i];
memset(txdata[i],0, openair0_cfg[rf_map[CC_id].card].samples_per_frame*sizeof(int32_t));
printf("txdata[%d] @ %p\n", i, phy_vars_eNB[CC_id]->lte_eNB_common_vars.txdata[0][i]);
}
#endif
}
return(0);
}
void reset_opp_meas(void) {
int sfn;
reset_meas(&softmodem_stats_mt);
reset_meas(&softmodem_stats_hw);
for (sfn=0; sfn < 10; sfn++) {
reset_meas(&softmodem_stats_tx_sf[sfn]);
reset_meas(&softmodem_stats_rx_sf[sfn]);
}
}
void print_opp_meas(void) {
int sfn=0;
print_meas(&softmodem_stats_mt, "Main ENB Thread", NULL, NULL);
print_meas(&softmodem_stats_hw, "HW Acquisation", NULL, NULL);
for (sfn=0; sfn < 10; sfn++) {
print_meas(&softmodem_stats_tx_sf[sfn],"[eNB][total_phy_proc_tx]",NULL, NULL);
print_meas(&softmodem_stats_rx_sf[sfn],"[eNB][total_phy_proc_rx]",NULL,NULL);
}
}
......@@ -69,11 +69,7 @@
#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all
//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all
#ifdef EXMIMO
#include "openair0_lib.h"
#else
#include "../../ARCH/COMMON/common_lib.h"
#endif
#include "PHY/extern.h"
#include "SCHED/extern.h"
......@@ -96,10 +92,9 @@ typedef enum {
si=2
} sync_mode_t;
int init_dlsch_threads(void);
void cleanup_dlsch_threads(void);
int32_t init_rx_pdsch_thread(void);
void cleanup_rx_pdsch_thread(void);
void init_UE_threads(void);
void *UE_thread(void *arg);
void init_UE(void);
extern pthread_cond_t sync_cond;
extern pthread_mutex_t sync_mutex;
......@@ -125,19 +120,6 @@ extern uint64_t num_missed_slots; // counter for the number of missed slots
extern void exit_fun(const char* s);
#ifdef EXMIMO
extern unsigned int rxg_max[4];
extern unsigned int rxg_med[4];
extern unsigned int rxg_byp[4];
extern unsigned int nf_max[4];
extern unsigned int nf_med[4];
extern unsigned int nf_byp[4];
extern rx_gain_t rx_gain_mode[MAX_NUM_CCs][4];
extern double tx_gain[MAX_NUM_CCs][4];
extern double rx_gain[MAX_NUM_CCs][4];
#endif
#define KHz (1000UL)
#define MHz (1000 * KHz)
......@@ -189,6 +171,38 @@ static const eutra_band_t eutra_bands[] = {
{44, 703 * MHz, 803 * MHz, 703 * MHz, 803 * MHz, TDD},
};
pthread_t main_ue_thread;
pthread_attr_t attr_UE_thread;
struct sched_param sched_param_UE_thread;
void init_UE() {
int error_code;
printf("Intializing UE Threads ...\n");
init_UE_threads();
sleep(1);
error_code = pthread_create(&main_ue_thread, &attr_UE_thread, UE_thread, NULL);
if (error_code!= 0) {
LOG_D(HW,"[lte-softmodem.c] Could not allocate UE_thread, error %d\n",error_code);
return;
} else {
LOG_D( HW, "[lte-softmodem.c] Allocate UE_thread successful\n" );
pthread_setname_np( main_ue_thread, "main UE" );
}
printf("UE threads created\n");
#ifdef USE_MME
while (start_UE == 0) {
sleep(1);
}
#endif
}
/*!
* \brief This is the UE synchronize thread.
* It performs band scanning and synchonization.
......@@ -512,15 +526,10 @@ static void *UE_thread_synch(void *arg)
// openair0_cfg[0].rx_gain[0] -= 0;
break;
}
#ifndef EXMIMO
openair0.trx_set_freq_func(&openair0,&openair0_cfg[0],0);
//openair0.trx_set_gains_func(&openair0,&openair0_cfg[0]);
//openair0.trx_stop_func(0);
#else
openair0_set_frequencies(&openair0,&openair0_cfg[0],0);
openair0_set_gains(&openair0,&openair0_cfg[0]);
openair0_stop(0);
#endif
sleep(1);
init_frame_parms(&UE->lte_frame_parms,1);
}
......@@ -550,13 +559,9 @@ static void *UE_thread_synch(void *arg)
}
#ifndef EXMIMO
UE->slot_rx = 0;
UE->slot_tx = 4;
#else
UE->slot_rx = 18;
UE->slot_tx = 2;
#endif
}
} else {
// initial sync failed
......@@ -598,42 +603,13 @@ static void *UE_thread_synch(void *arg)
for (i=0; i<openair0_cfg[card].rx_num_channels; i++) {
openair0_cfg[card].rx_freq[i] = downlink_frequency[card][i]+freq_offset;
openair0_cfg[card].tx_freq[i] = downlink_frequency[card][i]+uplink_frequency_offset[card][i]+freq_offset;
#ifndef EXMIMO
openair0.trx_set_freq_func(&openair0,&openair0_cfg[0],0);
#else
openair0_set_frequencies(&openair0,&openair0_cfg[0],0);
#endif
#if defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
openair0_cfg[card].rx_gain[i] = UE->rx_total_gain_dB;//-USRP_GAIN_OFFSET;
#if 0
switch(UE->lte_frame_parms.N_RB_DL) {
case 6:
openair0_cfg[card].rx_gain[i] -= 12;
break;
case 25:
openair0_cfg[card].rx_gain[i] -= 6;
break;
case 50:
openair0_cfg[card].rx_gain[i] -= 0;//3;
break;
case 100:
openair0_cfg[card].rx_gain[i] -= 0;
break;
default:
printf("Unknown number of RBs %d\n",UE->lte_frame_parms.N_RB_DL);
break;
}
#endif
#endif
}
}
if (UE->UE_scan_carrier==1) {
......@@ -690,17 +666,6 @@ static void *UE_thread_tx(void *arg)
UE->instance_cnt_tx=-1;
#ifdef RTAI
RT_TASK *task = rt_task_init_schmod(nam2num("UE TX Thread"), 0, 0, 0, SCHED_FIFO, 0xF);
if (task==NULL) {
LOG_E(PHY,"[SCHED][UE] Problem starting UE TX thread!!!!\n");
return 0;
}
LOG_D(HW,"Started UE TX thread (id %p)\n",task);
#else
#ifdef LOWLATENCY
struct sched_attr attr;
unsigned int flags = 0;
......@@ -745,7 +710,7 @@ static void *UE_thread_tx(void *arg)
exit_fun("Error setting processor affinity");
}
}
#endif
#endif
/* Check the actual affinity mask assigned to the thread */
......@@ -790,7 +755,6 @@ static void *UE_thread_tx(void *arg)
(int) sparam.sched_priority, cpu_affinity);
#endif
#endif
printf("waiting for sync (UE_thread_tx)\n");
......@@ -909,17 +873,6 @@ static void *UE_thread_rx(void *arg)
UE->instance_cnt_rx=-1;
#ifdef RTAI
RT_TASK *task = rt_task_init_schmod(nam2num("UE RX Thread"), 0, 0, 0, SCHED_FIFO, 0xF);
if (task==NULL) {
LOG_E(PHY,"[SCHED][UE] Problem starting UE RX thread!!!!\n");
return &UE_thread_rx_retval;
}
LOG_D(HW,"Started UE RX thread (id %p)\n",task);
#else
#ifdef LOWLATENCY
struct sched_attr attr;
unsigned int flags = 0;
......@@ -1008,7 +961,6 @@ static void *UE_thread_rx(void *arg)
(int) sparam.sched_priority, cpu_affinity);
#endif
#endif
// Lock memory from swapping. This is a process wide call (not constraint to this thread).
......@@ -1186,7 +1138,7 @@ static void *UE_thread_rx(void *arg)
#ifndef EXMIMO
#define RX_OFF_MAX 10
#define RX_OFF_MIN 5
#define RX_OFF_MID ((RX_OFF_MAX+RX_OFF_MIN)/2)
......@@ -1227,16 +1179,6 @@ void *UE_thread(void *arg)
MessageDef *message_p;
#endif
#ifdef RTAI
RT_TASK *task = rt_task_init_schmod(nam2num("UE thread"), 0, 0, 0, SCHED_FIFO, 0xF);
if (task==NULL) {
LOG_E(PHY,"[SCHED][UE] Problem starting UE thread!!!!\n");
return 0;
}
#else
#ifdef LOWLATENCY
struct sched_attr attr;
unsigned int flags = 0;
......@@ -1264,7 +1206,6 @@ void *UE_thread(void *arg)
struct sched_param sp;
sp.sched_priority = sched_get_priority_max(SCHED_FIFO);
pthread_setschedparam(pthread_self(),SCHED_FIFO,&sp);
#endif
#endif
// Lock memory from swapping. This is a process wide call (not constraint to this thread).
......@@ -1591,409 +1532,8 @@ void *UE_thread(void *arg)
return &UE_thread_retval;
}
#endif
#ifdef EXMIMO
/* This is the main UE thread. Initially it is doing a periodic get_frame. One synchronized it gets woken up by the kernel driver using the RTAI message mechanism (rt_send and rt_receive). */
void *UE_thread(void *arg)
{
PHY_VARS_UE *UE=PHY_vars_UE_g[0][0];
#ifdef RTAI
RT_TASK *task;
#endif
// RTIME in, out, diff;
int slot=0,frame=0,hw_slot;
// unsigned int aa;
int delay_cnt;
RTIME time_in;
int /* hw_slot_offset=0, */ rx_offset_mbox=0,mbox_target=0,mbox_current=0;
int diff2;
int /* i, */ ret;
int /* CC_id, */ card;
volatile unsigned int *DAQ_MBOX = openair0_daq_cnt();
int wait_sync_cnt = 0;
int first_synch = 1;
#ifdef LOWLATENCY
struct sched_attr attr;
unsigned int flags = 0;
// unsigned long mask = 1; // processor 0
#endif
int freq_offset;
#ifdef RTAI
task = rt_task_init_schmod(nam2num("UE thread"), 0, 0, 0, SCHED_FIFO, 0xF);
if (task==NULL) {
LOG_E(PHY,"[SCHED][UE] Problem starting UE thread!!!!\n");
return 0;
}
#endif
#ifdef HARD_RT
rt_make_hard_real_time();
#endif
#ifdef LOWLATENCY
attr.size = sizeof(attr);
attr.sched_flags = 0;
attr.sched_nice = 0;
attr.sched_priority = 0;
// This creates a .25 ms reservation
attr.sched_policy = SCHED_DEADLINE;
attr.sched_runtime = (0.1 * 100) * 10000;
attr.sched_deadline = (0.25 * 100) * 10000;
attr.sched_period = (0.5 * 100) * 10000;
// pin the UE main thread to CPU0
// if (pthread_setaffinity_np(pthread_self(), sizeof(mask),&mask) <0) {
// perror("[MAIN_ENB_THREAD] pthread_setaffinity_np failed\n");
// }
if (sched_setattr(0, &attr, flags) < 0 ) {
perror("[SCHED] main UE thread: sched_setattr failed\n");
exit_fun("Nothing to add");
} else {
LOG_I(HW,"[SCHED][eNB] eNB main deadline thread %ld started on CPU %d\n",
gettid(),sched_getcpu());
}
#endif
mlockall(MCL_CURRENT | MCL_FUTURE);
printf("waiting for sync (UE_thread)\n");
pthread_mutex_lock(&sync_mutex);
printf("Locked sync_mutex, waiting (UE_thread)\n");
while (sync_var<0)
pthread_cond_wait(&sync_cond, &sync_mutex);
pthread_mutex_unlock(&sync_mutex);
printf("unlocked sync_mutex, waiting (UE_thread)\n");
printf("starting UE thread\n");
freq_offset = 0; //-7500;
first_synch = 1;
while (!oai_exit) {
hw_slot = (((((volatile unsigned int *)DAQ_MBOX)[0]+1)%150)<<1)/15; //the slot the hw is about to store
if (UE->is_synchronized) {
if (first_synch == 1) {
first_synch = 0;
for (card=0; card<openair0_num_detected_cards; card++)
openair0_start_rt_acquisition(card);
rt_sleep_ns(FRAME_PERIOD/10);
}
//this is the mbox counter that indicates the start of the frame
rx_offset_mbox = (UE->rx_offset * 150) / (10*UE->lte_frame_parms.samples_per_tti);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE_RX_OFFSET, UE->rx_offset);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE_OFFSET_MBOX, rx_offset_mbox);
//this is the mbox counter where we should be
mbox_target = (((((slot+1)%20)*15+1)>>1) + rx_offset_mbox + 1)%150;
// round up to the next multiple of two (mbox counter from express MIMO gives only even numbers)
mbox_target = ((mbox_target+1)-((mbox_target-1)%2))%150;
//this is the mbox counter where we are
mbox_current = ((volatile unsigned int *)DAQ_MBOX)[0];
//this is the time we need to sleep in order to synchronize with the hw (in multiples of DAQ_PERIOD)
if ((mbox_current>=120) && (mbox_target<30)) //handle the frame wrap-arround
diff2 = 150-mbox_current+mbox_target;
else if ((mbox_current<30) && (mbox_target>=120))
diff2 = -150+mbox_target-mbox_current;
else
diff2 = mbox_target - mbox_current;
if (diff2 <(-7)) {
LOG_D(HW,"UE Frame %d: missed slot, proceeding with next one (slot %d, hw_slot %d, diff %d)\n",frame, slot, hw_slot, diff2);
if (frame>0) {
if (exit_missed_slots==1)
exit_fun("[HW][UE] missed slot");
else {
num_missed_slots++;
LOG_W(HW,"[UE] just missed slot (total missed slots %ld)\n", num_missed_slots);
}
}
slot++;
if (slot==20) {
slot=0;
frame++;
}
// update thread slot/frame counters because of skipped slot
UE->slot_rx++;
UE->slot_tx++;
if (UE->slot_rx == 20) {
UE->slot_rx = 0;
UE->frame_rx++;
}
if (UE->slot_tx == 20) {
UE->slot_tx = 0;
UE->frame_tx++;
}
continue;
}
if (diff2>8)
LOG_D(HW,"UE Frame %d: skipped slot, waiting for hw to catch up (slot %d, hw_slot %d, mbox_current %d, mbox_target %d, diff %d)\n",frame, slot, hw_slot, mbox_current, mbox_target, diff2);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DAQ_MBOX, *DAQ_MBOX);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DIFF, diff2);
// This loop implements the delay of 1 slot to allow for processing
delay_cnt = 0;
while ((diff2>0) && (!oai_exit) ) {
time_in = rt_get_time_ns();
//LOG_D(HW,"eNB Frame %d delaycnt %d : hw_slot %d (%d), slot %d (%d), diff %d, time %llu\n",frame,delay_cnt,hw_slot,((volatile unsigned int *)DAQ_MBOX)[0],slot,mbox_target,diff2,time_in);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DAQ_MBOX, *DAQ_MBOX);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RT_SLEEP,1);
ret = rt_sleep_ns(diff2*DAQ_PERIOD);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RT_SLEEP,0);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DAQ_MBOX, *DAQ_MBOX);
if (ret)
LOG_D(HW,"eNB Frame %d, time %llu: rt_sleep_ns returned %d\n",frame, time_in);
hw_slot = (((((volatile unsigned int *)DAQ_MBOX)[0]+1)%150)<<1)/15;
//LOG_D(HW,"eNB Frame %d : hw_slot %d, time %llu\n",frame,hw_slot,rt_get_time_ns());
delay_cnt++;
if (delay_cnt == 30) {
LOG_D(HW,"UE frame %d: HW stopped ... \n",frame);
exit_fun("[HW][UE] HW stopped");
}
mbox_current = ((volatile unsigned int *)DAQ_MBOX)[0];
if ((mbox_current>=135) && (mbox_target<15)) //handle the frame wrap-arround
diff2 = 150-mbox_current+mbox_target;
else if ((mbox_current<15) && (mbox_target>=135))
diff2 = -150+mbox_target-mbox_current;
else
diff2 = mbox_target - mbox_current;
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DAQ_MBOX, *DAQ_MBOX);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DIFF, diff2);
}
// on even slots, schedule processing of entire subframe
if ((slot&1) == 0) {
if (pthread_mutex_lock(&UE->mutex_rx) != 0) {
LOG_E(PHY,"[SCHED][UE] error locking mutex for UE RX thread\n");
exit_fun("nothing to add");
} else {
int instance_cnt_rx = ++UE->instance_cnt_rx;
pthread_mutex_unlock(&UE->mutex_rx);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE_INST_CNT_RX, instance_cnt_rx);
if (instance_cnt_rx == 0) {
LOG_D(HW,"Scheduling UE RX for frame %d (hw frame %d), subframe %d (%d), mode %d\n",UE->frame_rx,frame,slot>>1,UE->slot_rx>>1,UE->mode);
if (pthread_cond_signal(&UE->cond_rx) != 0) {
LOG_E(PHY,"[SCHED][UE] ERROR pthread_cond_signal for UE RX thread\n");
exit_fun("nothing to add");
} else {
// printf("UE_thread: cond_signal for RX ok (%p) @ %llu\n",(void*)&UE->cond_rx,rt_get_time_ns()-T0);
}
if (UE->mode == rx_calib_ue) {
if (frame == 10) {
LOG_D(PHY,
"[SCHED][UE] Found cell with N_RB_DL %d, PHICH CONFIG (%d,%d), Nid_cell %d, NB_ANTENNAS_TX %d, initial frequency offset %d Hz, frequency offset %d Hz, RSSI (digital) %d dB, measured Gain %d dB, total_rx_gain %d dB, USRP rx gain %f dB\n",
UE->lte_frame_parms.N_RB_DL,
UE->lte_frame_parms.phich_config_common.phich_duration,
UE->lte_frame_parms.phich_config_common.phich_resource,
UE->lte_frame_parms.Nid_cell,
UE->lte_frame_parms.nb_antennas_tx_eNB,
freq_offset,
UE->lte_ue_common_vars.freq_offset,
UE->PHY_measurements.rx_power_avg_dB[0],
UE->PHY_measurements.rx_power_avg_dB[0] - rx_input_level_dBm,
UE->rx_total_gain_dB,
openair0_cfg[0].rx_gain[0]
);
exit_fun("[HW][UE] UE in RX calibration mode, exiting");
}
}
} else {
LOG_E(PHY,"[SCHED][UE] UE RX thread busy!!\n");
exit_fun("nothing to add");
}
}
if (pthread_mutex_lock(&UE->mutex_tx) != 0) {
LOG_E(PHY,"[SCHED][UE] error locking mutex for UE TX thread\n");
exit_fun("nothing to add");
} else {
int instance_cnt_tx = ++UE->instance_cnt_tx;
pthread_mutex_unlock(&UE->mutex_tx);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE_INST_CNT_TX, instance_cnt_tx);
if (instance_cnt_tx == 0) {
LOG_D(HW,"Scheduling UE TX for frame %d (hw frame %d), subframe %d (%d), mode %d\n",UE->frame_tx,frame,slot>>1,UE->slot_tx>>1,UE->mode);
if (pthread_cond_signal(&UE->cond_tx) != 0) {
LOG_E(PHY,"[SCHED][UE] ERROR pthread_cond_signal for UE TX thread\n");
exit_fun("nothing to add");
} else {
// printf("UE_thread: cond_signal for RX ok (%p) @ %llu\n",(void*)&UE->cond_rx,rt_get_time_ns()-T0);
}
} else {
LOG_E(PHY,"[SCHED][UE] UE TX thread busy!!\n");
exit_fun("nothing to add");
}
}
}
/*
if ((slot%2000)<10)
LOG_D(HW,"fun0: doing very hard work\n");
*/
// now increment slot and frame counters
slot++;
if (slot==20) {
slot=0;
frame++;
}
} else if (UE->is_synchronized == 0) { // we are not yet synchronized
//hw_slot_offset = 0;
first_synch = 1;
slot = 0;
// wait until we can lock mutex_synch
//printf("Locking mutex_synch (UE_thread)\n");
if (pthread_mutex_lock(&UE->mutex_synch) != 0) {
LOG_E(PHY,"[SCHED][UE] error locking mutex for UE initial synch thread\n");
exit_fun("noting to add");
} else {
if (UE->instance_cnt_synch < 0) {
wait_sync_cnt=0;
openair0_config(&openair0_cfg[0],1);
// openair0_set_gains(&openair0,&openair0_cfg[0]);
printf("Getting frame\n");
openair0_get_frame(0);
rt_sleep_ns(FRAME_PERIOD);
// increment instance count for sync thread
UE->instance_cnt_synch++;
pthread_mutex_unlock(&UE->mutex_synch);
if (pthread_cond_signal(&UE->cond_synch) != 0) {
LOG_E(PHY,"[SCHED][UE] ERROR pthread_cond_signal for UE sync thread\n");
exit_fun("nothing to add");
}
} else {
wait_sync_cnt++;
pthread_mutex_unlock(&UE->mutex_synch);
if (wait_sync_cnt>1000)
exit_fun("waiting to long for synch thread");
else
rt_sleep_ns(FRAME_PERIOD);
}
}
/*
if (initial_sync(UE,mode)==0) {
if (mode == rx_calib_ue) {
exit_fun("[HW][UE] UE in RX calibration mode");
}
else {
is_synchronized = 1;
//start the streaming DMA transfers
for (card=0;card<openair0_num_detected_cards;card++)
openair0_start_rt_acquisition(card);
hw_slot_offset = (UE->rx_offset<<1) / UE->lte_frame_parms.samples_per_tti;
}
}
else {
if (freq_offset >= 0) {
freq_offset += 100;
freq_offset *= -1;
}
else {
freq_offset *= -1;
}
if (abs(freq_offset) > 7500) {
LOG_I(PHY,"[initial_sync] No cell synchronization found, abondoning\n");
mac_xface->macphy_exit("No cell synchronization found, abondoning");
}
else {
// LOG_I(PHY,"[initial_sync] trying carrier off %d Hz\n",freq_offset);
#ifndef USRP
for (CC_id=0;CC_id<MAX_NUM_CCs;CC_id++) {
for (i=0; i<openair0_cfg[rf_map[CC_id].card].rx_num_channels; i++)
openair0_cfg[rf_map[CC_id].card].rx_freq[rf_map[CC_id].chain+i] = downlink_frequency[CC_id][i]+freq_offset;
for (i=0; i<openair0_cfg[rf_map[CC_id].card].tx_num_channels; i++)
openair0_cfg[rf_map[CC_id].card].tx_freq[rf_map[CC_id].chain+i] = downlink_frequency[CC_id][i]+freq_offset;
}
openair0_config(&openair0_cfg[0],UE_flag);
#endif
rt_sleep_ns(FRAME_PERIOD);
}
}
*/
}
}
LOG_D(HW,"UE_thread: finished, ran %d times.\n",frame);
#ifdef HARD_RT
rt_make_soft_real_time();
#endif
// clean task
#ifdef RTAI
rt_task_delete(task);
#endif
LOG_D(HW,"Task deleted. returning\n");
return 0;
}
#else // This is for USRP or ETHERNET targets
#endif
/*!
......@@ -2008,6 +1548,14 @@ void init_UE_threads(void)
{
PHY_VARS_UE *UE = PHY_vars_UE_g[0][0];
pthread_attr_init (&attr_UE_thread);
pthread_attr_setstacksize(&attr_UE_thread,8192);//5*PTHREAD_STACK_MIN);
#ifndef LOWLATENCY
sched_param_UE_thread.sched_priority = sched_get_priority_max(SCHED_FIFO);
pthread_attr_setschedparam(&attr_UE_thread,&sched_param_UE_thread);
#endif
// the threads are not yet active, therefore access is allowed without locking
UE->instance_cnt_tx = -1;
UE->instance_cnt_rx = -1;
......@@ -2063,97 +1611,50 @@ void fill_ue_band_info(void)
int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue, openair0_config_t *openair0_cfg, openair0_rf_map rf_map[MAX_NUM_CCs])
{
//#ifndef EXMIMO
// uint16_t N_TA_offset = 0;
//#endif
int i, CC_id;
LTE_DL_FRAME_PARMS *frame_parms;
for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
if (phy_vars_ue[CC_id]) {
frame_parms = &(phy_vars_ue[CC_id]->lte_frame_parms);
} else {
printf("phy_vars_UE[%d] not initialized\n", CC_id);
return(-1);
}
//#ifndef EXMIMO
// if (frame_parms->frame_type == TDD) {
// if (frame_parms->N_RB_DL == 100)
// N_TA_offset = 624;
// else if (frame_parms->N_RB_DL == 50)
// N_TA_offset = 624/2;
// else if (frame_parms->N_RB_DL == 25)
// N_TA_offset = 624/4;
// }
//#endif
#ifdef EXMIMO
openair0_cfg[CC_id].tx_num_channels = 0;
openair0_cfg[CC_id].rx_num_channels = 0;
// replace RX signal buffers with mmaped HW versions
for (i=0; i<frame_parms->nb_antennas_rx; i++) {
printf("Mapping UE CC_id %d, rx_ant %d, freq %u on card %d, chain %d\n",CC_id,i,downlink_frequency[CC_id][i],rf_map[CC_id].card,rf_map[CC_id].chain+i);
free(phy_vars_ue[CC_id]->lte_ue_common_vars.rxdata[i]);
phy_vars_ue[CC_id]->lte_ue_common_vars.rxdata[i] = (int32_t*) openair0_exmimo_pci[rf_map[CC_id].card].adc_head[rf_map[CC_id].chain+i];
if (openair0_cfg[rf_map[CC_id].card].rx_freq[rf_map[CC_id].chain+i]) {
printf("Error with rf_map! A channel has already been allocated!\n");
return(-1);
} else {
openair0_cfg[rf_map[CC_id].card].rx_freq[rf_map[CC_id].chain+i] = downlink_frequency[CC_id][i];
openair0_cfg[rf_map[CC_id].card].rx_gain[rf_map[CC_id].chain+i] = rx_gain[CC_id][i];
openair0_cfg[rf_map[CC_id].card].rxg_mode[rf_map[CC_id].chain+i] = rx_gain_mode[CC_id][i];
openair0_cfg[rf_map[CC_id].card].rx_num_channels++;
}
printf("rxdata[%d] @ %p\n",i,phy_vars_ue[CC_id]->lte_ue_common_vars.rxdata[i]);
}
for (i=0; i<frame_parms->nb_antennas_tx; i++) {
printf("Mapping UE CC_id %d, tx_ant %d, freq %u on card %d, chain %d\n",CC_id,i,downlink_frequency[CC_id][i],rf_map[CC_id].card,rf_map[CC_id].chain+i);
free(phy_vars_ue[CC_id]->lte_ue_common_vars.txdata[i]);
phy_vars_ue[CC_id]->lte_ue_common_vars.txdata[i] = (int32_t*) openair0_exmimo_pci[rf_map[CC_id].card].dac_head[rf_map[CC_id].chain+i];
if (openair0_cfg[rf_map[CC_id].card].tx_freq[rf_map[CC_id].chain+i]) {
printf("Error with rf_map! A channel has already been allocated!\n");
return(-1);
} else {
openair0_cfg[rf_map[CC_id].card].tx_freq[rf_map[CC_id].chain+i] = downlink_frequency[CC_id][i]+uplink_frequency_offset[CC_id][i];
openair0_cfg[rf_map[CC_id].card].tx_gain[rf_map[CC_id].chain+i] = tx_gain[CC_id][i];
openair0_cfg[rf_map[CC_id].card].tx_num_channels++;
}
if (phy_vars_ue[CC_id]) {
frame_parms = &(phy_vars_ue[CC_id]->lte_frame_parms);
} else {
printf("phy_vars_UE[%d] not initialized\n", CC_id);
return(-1);
}
printf("txdata[%d] @ %p\n",i,phy_vars_ue[CC_id]->lte_ue_common_vars.txdata[i]);
}
/*
if (frame_parms->frame_type == TDD) {
if (frame_parms->N_RB_DL == 100)
N_TA_offset = 624;
else if (frame_parms->N_RB_DL == 50)
N_TA_offset = 624/2;
else if (frame_parms->N_RB_DL == 25)
N_TA_offset = 624/4;
}
*/
#else
// replace RX signal buffers with mmaped HW versions
rxdata = (int32_t**)malloc16( frame_parms->nb_antennas_rx*sizeof(int32_t*) );
txdata = (int32_t**)malloc16( frame_parms->nb_antennas_tx*sizeof(int32_t*) );
for (i=0; i<frame_parms->nb_antennas_rx; i++) {
printf( "Mapping UE CC_id %d, rx_ant %d, freq %u on card %d, chain %d\n", CC_id, i, downlink_frequency[CC_id][i], rf_map[CC_id].card, rf_map[CC_id].chain+i );
free( phy_vars_ue[CC_id]->lte_ue_common_vars.rxdata[i] );
rxdata[i] = (int32_t*)malloc16_clear( 307200*sizeof(int32_t) );
phy_vars_ue[CC_id]->lte_ue_common_vars.rxdata[i] = rxdata[i]; // what about the "-N_TA_offset" ? // N_TA offset for TDD
}
for (i=0; i<frame_parms->nb_antennas_tx; i++) {
printf( "Mapping UE CC_id %d, tx_ant %d, freq %u on card %d, chain %d\n", CC_id, i, downlink_frequency[CC_id][i], rf_map[CC_id].card, rf_map[CC_id].chain+i );
free( phy_vars_ue[CC_id]->lte_ue_common_vars.txdata[i] );
txdata[i] = (int32_t*)malloc16_clear( 307200*sizeof(int32_t) );
phy_vars_ue[CC_id]->lte_ue_common_vars.txdata[i] = txdata[i];
}
// rxdata[x] points now to the same memory region as phy_vars_ue[CC_id]->lte_ue_common_vars.rxdata[x]
// txdata[x] points now to the same memory region as phy_vars_ue[CC_id]->lte_ue_common_vars.txdata[x]
// be careful when releasing memory!
// because no "release_ue_buffers"-function is available, at least rxdata and txdata memory will leak (only some bytes)
#endif
rxdata = (int32_t**)malloc16( frame_parms->nb_antennas_rx*sizeof(int32_t*) );
txdata = (int32_t**)malloc16( frame_parms->nb_antennas_tx*sizeof(int32_t*) );
for (i=0; i<frame_parms->nb_antennas_rx; i++) {
printf( "Mapping UE CC_id %d, rx_ant %d, freq %u on card %d, chain %d\n", CC_id, i, downlink_frequency[CC_id][i], rf_map[CC_id].card, rf_map[CC_id].chain+i );
free( phy_vars_ue[CC_id]->lte_ue_common_vars.rxdata[i] );
rxdata[i] = (int32_t*)malloc16_clear( 307200*sizeof(int32_t) );
phy_vars_ue[CC_id]->lte_ue_common_vars.rxdata[i] = rxdata[i]; // what about the "-N_TA_offset" ? // N_TA offset for TDD
}
for (i=0; i<frame_parms->nb_antennas_tx; i++) {
printf( "Mapping UE CC_id %d, tx_ant %d, freq %u on card %d, chain %d\n", CC_id, i, downlink_frequency[CC_id][i], rf_map[CC_id].card, rf_map[CC_id].chain+i );
free( phy_vars_ue[CC_id]->lte_ue_common_vars.txdata[i] );
txdata[i] = (int32_t*)malloc16_clear( 307200*sizeof(int32_t) );
phy_vars_ue[CC_id]->lte_ue_common_vars.txdata[i] = txdata[i];
}
// rxdata[x] points now to the same memory region as phy_vars_ue[CC_id]->lte_ue_common_vars.rxdata[x]
// txdata[x] points now to the same memory region as phy_vars_ue[CC_id]->lte_ue_common_vars.txdata[x]
// be careful when releasing memory!
// because no "release_ue_buffers"-function is available, at least rxdata and txdata memory will leak (only some bytes)
}
......
/*******************************************************************************
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenAirInterface is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/*! \file sched_dlsch.c
* \brief DLSCH decoding thread (RTAI)
* \author R. Knopp, F. Kaltenberger
* \date 2011
* \version 0.1
* \company Eurecom
* \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr
* \note
* \warning
*/
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include "rt_wrapper.h"
#include <sys/mman.h>
#include "PHY/types.h"
#include "PHY/defs.h"
#include "PHY/extern.h"
#include "SCHED/defs.h"
#include "UTIL/LOG/vcd_signal_dumper.h"
#define DEBUG_PHY
/// Mutex for instance count on dlsch scheduling
pthread_mutex_t dlsch_mutex[8];
/// Condition variable for dlsch thread
pthread_cond_t dlsch_cond[8];
pthread_t dlsch_threads[8];
pthread_attr_t attr_dlsch_threads;
unsigned char dlsch_thread_indices[8];
// activity indicators for harq_pid's
int dlsch_instance_cnt[8];
// process ids for cpu
int dlsch_cpuid[8];
// subframe number for each harq_pid (needed to store ack in right place for UL)
int dlsch_subframe[8];
extern int oai_exit;
/*
extern int dlsch_errors;
extern int dlsch_received;
extern int dlsch_errors_last;
extern int dlsch_received_last;
extern int dlsch_fer;
extern int current_dlsch_cqi;
*/
/** DLSCH Decoding Thread */
static void * dlsch_thread(void *param)
{
//unsigned long cpuid;
unsigned char dlsch_thread_index = *((unsigned char *)param);
unsigned int ret=0;
uint8_t harq_pid;
#ifdef RTAI
RT_TASK *task;
char task_name[8];
#endif
int eNB_id = 0, UE_id = 0, CC_id=0;
PHY_VARS_UE *phy_vars_ue = PHY_vars_UE_g[UE_id][CC_id];
if ((dlsch_thread_index <0) || (dlsch_thread_index>7)) {
LOG_E(PHY,"[SCHED][DLSCH] Illegal dlsch_thread_index %d (%p)!!!!\n",dlsch_thread_index,param);
return 0;
}
#ifdef RTAI
sprintf(task_name,"DLSCH%d",dlsch_thread_index);
task = rt_task_init_schmod(nam2num(task_name), 0, 0, 0, SCHED_FIFO, 0xF);
if (task==NULL) {
LOG_E(PHY,"[SCHED][DLSCH] Problem starting dlsch_thread_index %d (%s)!!!!\n",dlsch_thread_index,task_name);
return 0;
} else {
LOG_I(PHY,"[SCHED][DLSCH] dlsch_thread for process %d started with id %p\n",
dlsch_thread_index,
task);
}
#endif
mlockall(MCL_CURRENT | MCL_FUTURE);
//rt_set_runnable_on_cpuid(task,1);
//cpuid = rtai_cpuid();
#ifdef HARD_RT
rt_make_hard_real_time();
#endif
//dlsch_cpuid[dlsch_thread_index] = cpuid;
while (!oai_exit) {
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_THREAD0+dlsch_thread_index,0);
if (pthread_mutex_lock(&dlsch_mutex[dlsch_thread_index]) != 0) {
LOG_E(PHY,"[SCHED][DLSCH] error locking mutex.\n");
} else {
while (dlsch_instance_cnt[dlsch_thread_index] < 0) {
pthread_cond_wait(&dlsch_cond[dlsch_thread_index],&dlsch_mutex[dlsch_thread_index]);
}
if (pthread_mutex_unlock(&dlsch_mutex[dlsch_thread_index]) != 0) {
LOG_E(PHY,"[SCHED][DLSCH] error unlocking mutex.\n");
}
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_THREAD0+dlsch_thread_index,1);
if (oai_exit) break;
LOG_I(PHY,"[SCHED][DLSCH] Frame %d: Calling dlsch_decoding with dlsch_thread_index = %d\n",phy_vars_ue->frame_rx,dlsch_thread_index);
if (phy_vars_ue->frame_rx < phy_vars_ue->dlsch_errors[eNB_id]) {
phy_vars_ue->dlsch_errors[eNB_id]=0;
phy_vars_ue->dlsch_received[eNB_id] = 0;
}
harq_pid = dlsch_thread_index;
if (phy_vars_ue->dlsch_ue[eNB_id][0]) {
// rt_printk("[SCHED][DLSCH] Frame %d, slot %d, start %llu, end %llu, proc time: %llu ns\n",phy_vars_ue->frame,last_slot,time0,time1,(time1-time0));
dlsch_unscrambling(&phy_vars_ue->lte_frame_parms,
0,
phy_vars_ue->dlsch_ue[eNB_id][0],
phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->G,
phy_vars_ue->lte_ue_pdsch_vars[eNB_id]->llr[0],
0,
dlsch_subframe[dlsch_thread_index]<<1);
LOG_I(PHY,"[UE %d] PDSCH Calling dlsch_decoding for subframe %d, harq_pid %d, G%d\n", phy_vars_ue->Mod_id,dlsch_subframe[dlsch_thread_index], harq_pid,
phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->G);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DECODING0+dlsch_thread_index,1);
ret = dlsch_decoding(phy_vars_ue,
phy_vars_ue->lte_ue_pdsch_vars[eNB_id]->llr[0],
&phy_vars_ue->lte_frame_parms,
phy_vars_ue->dlsch_ue[eNB_id][0],
phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid],
dlsch_subframe[dlsch_thread_index],
harq_pid,
1, // is_crnti
0); // llr8_flag
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DECODING0+dlsch_thread_index,0);
LOG_D(PHY,"[UE %d][PDSCH %x/%d] Frame %d subframe %d: PDSCH/DLSCH decoding iter %d (mcs %d, rv %d, TBS %d)\n",
phy_vars_ue->Mod_id,
phy_vars_ue->dlsch_ue[eNB_id][0]->rnti,harq_pid,
phy_vars_ue->frame_rx,dlsch_subframe[dlsch_thread_index],ret,
phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->mcs,
phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->rvidx,
phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->TBS);
if (ret == (1+MAX_TURBO_ITERATIONS)) {
phy_vars_ue->dlsch_errors[eNB_id]++;
#ifdef DEBUG_PHY
LOG_I(PHY,"[UE %d][PDSCH %x/%d] Frame %d subframe %d DLSCH in error (rv %d,mcs %d)\n",
phy_vars_ue->Mod_id,phy_vars_ue->dlsch_ue[eNB_id][0]->rnti,
harq_pid,phy_vars_ue->frame_rx,dlsch_subframe[dlsch_thread_index],
phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->rvidx,
phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->mcs);
#endif
} else {
LOG_I(PHY,"[UE %d][PDSCH %x/%d] Frame %d subframe %d: Received DLSCH (rv %d,mcs %d)\n",
phy_vars_ue->Mod_id,phy_vars_ue->dlsch_ue[eNB_id][0]->rnti,
harq_pid,phy_vars_ue->frame_rx,dlsch_subframe[dlsch_thread_index],
phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->rvidx,
phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->mcs);
#ifdef OPENAIR2
mac_xface->ue_send_sdu(phy_vars_ue->Mod_id,
0, // CC_id
phy_vars_ue->frame_rx,
phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->b,
phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->TBS>>3,
eNB_id);
#endif
phy_vars_ue->total_TBS[eNB_id] = phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->TBS + phy_vars_ue->total_TBS[eNB_id];
phy_vars_ue->total_received_bits[eNB_id] = phy_vars_ue->total_received_bits[eNB_id] + phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->TBS;
}
}
// this is done in main thread
/*
if (phy_vars_ue->frame % 100 == 0) {
if ((phy_vars_ue->dlsch_received[eNB_id] - phy_vars_ue->dlsch_received_last[eNB_id]) != 0)
phy_vars_ue->dlsch_fer[eNB_id] = (100*(phy_vars_ue->dlsch_errors[eNB_id] - phy_vars_ue->dlsch_errors_last[eNB_id]))/(phy_vars_ue->dlsch_received[eNB_id] - phy_vars_ue->dlsch_received_last[eNB_id]);
phy_vars_ue->dlsch_errors_last[eNB_id] = phy_vars_ue->dlsch_errors[eNB_id];
phy_vars_ue->dlsch_received_last[eNB_id] = phy_vars_ue->dlsch_received[eNB_id];
}
*/
#ifdef DEBUG_PHY
if (phy_vars_ue->dlsch_ue[eNB_id][0]) {
LOG_I(PHY,"[UE %d][PDSCH %x/%d] Frame %d subframe %d: PDSCH/DLSCH decoding iter %d (mcs %d, rv %d, TBS %d)\n",
phy_vars_ue->Mod_id,
phy_vars_ue->dlsch_ue[eNB_id][0]->rnti,harq_pid,
phy_vars_ue->frame_rx,dlsch_subframe[dlsch_thread_index],ret,
phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->mcs,
phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->rvidx,
phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->TBS);
if (phy_vars_ue->frame_rx%100==0) {
LOG_D(PHY,"[UE %d][PDSCH %x] Frame %d subframe %d dlsch_errors %d, dlsch_received %d, dlsch_fer %d, current_dlsch_cqi %d\n",
phy_vars_ue->Mod_id,phy_vars_ue->dlsch_ue[eNB_id][0]->rnti,
phy_vars_ue->frame_rx,dlsch_subframe[dlsch_thread_index],
phy_vars_ue->dlsch_errors[eNB_id],
phy_vars_ue->dlsch_received[eNB_id],
phy_vars_ue->dlsch_fer[eNB_id],
phy_vars_ue->PHY_measurements.wideband_cqi_tot[eNB_id]);
}
} else {
LOG_I( PHY,"[UE %d][PDSCH ?/%d] Frame %d subframe %d: PDSCH/DLSCH decoding iter %d (phy_vars_ue->dlsch_ue[eNB_id][0] == 0)\n",
phy_vars_ue->Mod_id,
harq_pid,
phy_vars_ue->frame_rx, dlsch_subframe[dlsch_thread_index], ret );
}
#endif
if (pthread_mutex_lock(&dlsch_mutex[dlsch_thread_index]) != 0) {
msg("[openair][SCHED][DLSCH] error locking mutex.\n");
} else {
dlsch_instance_cnt[dlsch_thread_index]--;
if (pthread_mutex_unlock(&dlsch_mutex[dlsch_thread_index]) != 0) {
msg("[openair][SCHED][DLSCH] error unlocking mutex.\n");
}
}
}
#ifdef HARD_RT
rt_make_soft_real_time();
#endif
msg("[openair][SCHED][DLSCH] DLSCH thread %d exiting\n",dlsch_thread_index);
return 0;
}
int init_dlsch_threads(void)
{
int error_code;
struct sched_param p;
unsigned char dlsch_thread_index;
pthread_attr_init (&attr_dlsch_threads);
pthread_attr_setstacksize(&attr_dlsch_threads,OPENAIR_THREAD_STACK_SIZE);
//attr_dlsch_threads.priority = 1;
p.sched_priority = OPENAIR_THREAD_PRIORITY;
pthread_attr_setschedparam (&attr_dlsch_threads, &p);
#ifndef RTAI_ISNT_POSIX
pthread_attr_setschedpolicy (&attr_dlsch_threads, SCHED_FIFO);
#endif
for(dlsch_thread_index=0; dlsch_thread_index<8; dlsch_thread_index++) {
pthread_mutex_init(&dlsch_mutex[dlsch_thread_index],NULL);
pthread_cond_init(&dlsch_cond[dlsch_thread_index],NULL);
dlsch_instance_cnt[dlsch_thread_index] = -1;
dlsch_thread_indices[dlsch_thread_index] = dlsch_thread_index;
rt_printk("[openair][SCHED][DLSCH][INIT] Allocating DLSCH thread for dlsch_thread_index %d (%p)\n",dlsch_thread_index,&dlsch_thread_indices[dlsch_thread_index]);
error_code = pthread_create(&dlsch_threads[dlsch_thread_index],
&attr_dlsch_threads,
dlsch_thread,
(void *)&dlsch_thread_indices[dlsch_thread_index]);
if (error_code!= 0) {
rt_printk("[openair][SCHED][DLSCH][INIT] Could not allocate dlsch_thread %d, error %d\n",dlsch_thread_index,error_code);
return(error_code);
} else {
rt_printk("[openair][SCHED][DLSCH][INIT] Allocate dlsch_thread %d successful\n",dlsch_thread_index);
}
}
return(0);
}
void cleanup_dlsch_threads(void)
{
unsigned char dlsch_thread_index;
for(dlsch_thread_index=0; dlsch_thread_index<8; dlsch_thread_index++) {
// pthread_exit(&dlsch_threads[dlsch_thread_index]);
rt_printk("[openair][SCHED][DLSCH] Scheduling dlsch_thread %d to exit\n",dlsch_thread_index);
dlsch_instance_cnt[dlsch_thread_index] = 0;
if (pthread_cond_signal(&dlsch_cond[dlsch_thread_index]) != 0)
rt_printk("[openair][SCHED][DLSCH] ERROR pthread_cond_signal\n");
else
rt_printk("[openair][SCHED][DLSCH] Signalled dlsch_thread %d to exit\n",dlsch_thread_index);
rt_printk("[openair][SCHED][DLSCH] Exiting ...\n");
pthread_cond_destroy(&dlsch_cond[dlsch_thread_index]);
pthread_mutex_destroy(&dlsch_mutex[dlsch_thread_index]);
}
}
/*******************************************************************************
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenAirInterface is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/*! \file sched_dlsch.c
* \brief DLSCH decoding thread (RTAI)
* \author R. Knopp, F. Kaltenberger
* \date 2011
* \version 0.1
* \company Eurecom
* \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr
* \note
* \warning
*/
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include "rt_wrapper.h"
#include <sys/mman.h>
#include "PHY/types.h"
#include "PHY/defs.h"
#include "PHY/extern.h"
#include "SCHED/defs.h"
#include "SCHED/extern.h"
#include "UTIL/LOG/vcd_signal_dumper.h"
RTIME time0,time1;
#define DEBUG_PHY
/// Mutex for instance count on rx_pdsch scheduling
pthread_mutex_t rx_pdsch_mutex;
/// Condition variable for rx_pdsch thread
pthread_cond_t rx_pdsch_cond;
pthread_t rx_pdsch_thread_var;
pthread_attr_t attr_rx_pdsch_thread;
// activity indicators for harq_pid's
int rx_pdsch_instance_cnt;
// process ids for cpu
int rx_pdsch_cpuid;
// subframe number for each harq_pid (needed to store ack in right place for UL)
int rx_pdsch_slot;
extern int oai_exit;
extern pthread_mutex_t dlsch_mutex[8];
extern int dlsch_instance_cnt[8];
extern int dlsch_subframe[8];
extern pthread_cond_t dlsch_cond[8];
/** RX_PDSCH Decoding Thread */
static void * rx_pdsch_thread(void *param)
{
//unsigned long cpuid;
uint8_t dlsch_thread_index = 0;
uint8_t pilot2,harq_pid,subframe;
// uint8_t last_slot;
uint8_t dual_stream_UE = 0;
uint8_t i_mod = 0;
#ifdef RTAI
RT_TASK *task;
#endif
int m,eNB_id = 0;
int eNB_id_i = 1;
PHY_VARS_UE *UE = PHY_vars_UE_g[0][0];
#ifdef RTAI
task = rt_task_init_schmod(nam2num("RX_PDSCH_THREAD"), 0, 0, 0, SCHED_FIFO, 0xF);
if (task==NULL) {
LOG_E(PHY,"[SCHED][RX_PDSCH] Problem starting rx_pdsch thread!!!!\n");
return 0;
} else {
LOG_I(PHY,"[SCHED][RX_PDSCH] rx_pdsch_thread started for with id %p\n",task);
}
#endif
mlockall(MCL_CURRENT | MCL_FUTURE);
//rt_set_runnable_on_cpuid(task,1);
//cpuid = rtai_cpuid();
#ifdef HARD_RT
rt_make_hard_real_time();
#endif
if (UE->lte_frame_parms.Ncp == NORMAL) { // normal prefix
pilot2 = 7;
} else { // extended prefix
pilot2 = 6;
}
while (!oai_exit) {
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_THREAD, 0);
if (pthread_mutex_lock(&rx_pdsch_mutex) != 0) {
LOG_E(PHY,"[SCHED][RX_PDSCH] error locking mutex.\n");
} else {
while (rx_pdsch_instance_cnt < 0) {
pthread_cond_wait(&rx_pdsch_cond,&rx_pdsch_mutex);
}
if (pthread_mutex_unlock(&rx_pdsch_mutex) != 0) {
LOG_E(PHY,"[SCHED][RX_PDSCH] error unlocking mutex.\n");
}
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_THREAD, 1);
// last_slot = rx_pdsch_slot;
subframe = UE->slot_rx>>1;
// Important! assumption that PDCCH procedure of next SF is not called yet
harq_pid = UE->dlsch_ue[eNB_id][0]->current_harq_pid;
UE->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->G = get_G(&UE->lte_frame_parms,
UE->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->nb_rb,
UE->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->rb_alloc_even,
get_Qm(UE->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->mcs),
UE->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->Nl,
UE->lte_ue_pdcch_vars[eNB_id]->num_pdcch_symbols,
UE->frame_rx,subframe);
if ((UE->transmission_mode[eNB_id] == 5) &&
(UE->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->dl_power_off==0) &&
(openair_daq_vars.use_ia_receiver > 0)) {
dual_stream_UE = 1;
eNB_id_i = UE->n_connected_eNB;
if (openair_daq_vars.use_ia_receiver == 2) {
i_mod = get_Qm(((UE->frame_rx%1024)/3)%28);
} else {
i_mod = get_Qm(UE->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->mcs);
}
} else {
dual_stream_UE = 0;
eNB_id_i = eNB_id+1;
i_mod = 0;
}
if (oai_exit) break;
LOG_D(PHY,"[SCHED][RX_PDSCH] Frame %d, slot %d: Calling rx_pdsch_decoding with harq_pid %d\n",UE->frame_rx,UE->slot_rx,harq_pid);
// Check if we are in even or odd slot
if (UE->slot_rx%2) { // odd slots
// measure time
//time0 = rt_get_time_ns();
// rt_printk("[SCHED][RX_PDSCH][before rx_pdsch] Frame %d, slot %d, time %llu\n",UE->frame,last_slot,rt_get_time_ns());
for (m=pilot2; m<UE->lte_frame_parms.symbols_per_tti; m++) {
rx_pdsch(UE,
PDSCH,
eNB_id,
eNB_id_i,
subframe,
m,
0,
dual_stream_UE,
i_mod,
harq_pid);
}
// time1 = rt_get_time_ns();
// rt_printk("[SCHED][RX_PDSCH] Frame %d, slot %d, start %llu, end %llu, proc time: %llu ns\n",UE->frame_rx,last_slot,time0,time1,(time1-time0));
dlsch_thread_index = harq_pid;
if (pthread_mutex_lock (&dlsch_mutex[dlsch_thread_index]) != 0) { // Signal MAC_PHY Scheduler
LOG_E(PHY,"[UE %d] ERROR pthread_mutex_lock\n",UE->Mod_id); // lock before accessing shared resource
// VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX, VCD_FUNCTION_OUT);
//return(-1);
}
dlsch_instance_cnt[dlsch_thread_index]++;
dlsch_subframe[dlsch_thread_index] = subframe;
pthread_mutex_unlock (&dlsch_mutex[dlsch_thread_index]);
if (dlsch_instance_cnt[dlsch_thread_index] == 0) {
if (pthread_cond_signal(&dlsch_cond[dlsch_thread_index]) != 0) {
LOG_E(PHY,"[UE %d] ERROR pthread_cond_signal for dlsch_cond[%d]\n",UE->Mod_id,dlsch_thread_index);
// VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX, VCD_FUNCTION_OUT);
//return(-1);
}
} else {
LOG_W(PHY,"[UE %d] DLSCH thread for dlsch_thread_index %d busy!!!\n",UE->Mod_id,dlsch_thread_index);
// VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX, VCD_FUNCTION_OUT);
//return(-1);
}
} else { // even slots
for (m=UE->lte_ue_pdcch_vars[eNB_id]->num_pdcch_symbols; m<pilot2; m++) {
rx_pdsch(UE,
PDSCH,
eNB_id,
eNB_id_i,
subframe,
m,
(m==UE->lte_ue_pdcch_vars[eNB_id]->num_pdcch_symbols)?1:0, // first_symbol_flag
dual_stream_UE,
i_mod,
harq_pid);
}
}
if (pthread_mutex_lock(&rx_pdsch_mutex) != 0) {
msg("[openair][SCHED][RX_PDSCH] error locking mutex.\n");
} else {
rx_pdsch_instance_cnt--;
if (pthread_mutex_unlock(&rx_pdsch_mutex) != 0) {
msg("[openair][SCHED][RX_PDSCH] error unlocking mutex.\n");
}
}
}
#ifdef HARD_RT
rt_make_soft_real_time();
#endif
LOG_D(PHY,"[openair][SCHED][RX_PDSCH] RX_PDSCH thread exiting\n");
return 0;
}
int init_rx_pdsch_thread(void)
{
int error_code;
struct sched_param p;
pthread_mutex_init(&rx_pdsch_mutex,NULL);
pthread_cond_init(&rx_pdsch_cond,NULL);
pthread_attr_init (&attr_rx_pdsch_thread);
pthread_attr_setstacksize(&attr_rx_pdsch_thread,OPENAIR_THREAD_STACK_SIZE);
//attr_rx_pdsch_thread.priority = 1;
p.sched_priority = OPENAIR_THREAD_PRIORITY;
pthread_attr_setschedparam (&attr_rx_pdsch_thread, &p);
#ifndef RTAI_ISNT_POSIX
pthread_attr_setschedpolicy (&attr_rx_pdsch_thread, SCHED_FIFO);
#endif
rx_pdsch_instance_cnt = -1;
rt_printk("[openair][SCHED][RX_PDSCH][INIT] Allocating RX_PDSCH thread\n");
error_code = pthread_create(&rx_pdsch_thread_var,
&attr_rx_pdsch_thread,
rx_pdsch_thread,
0);
if (error_code!= 0) {
rt_printk("[openair][SCHED][RX_PDSCH][INIT] Could not allocate rx_pdsch_thread, error %d\n",error_code);
return(error_code);
} else {
rt_printk("[openair][SCHED][RX_PDSCH][INIT] Allocate rx_pdsch_thread successful\n");
return(0);
}
}
void cleanup_rx_pdsch_thread(void)
{
rt_printk("[openair][SCHED][RX_PDSCH] Scheduling rx_pdsch_thread to exit\n");
rx_pdsch_instance_cnt = 0;
if (pthread_cond_signal(&rx_pdsch_cond) != 0)
rt_printk("[openair][SCHED][RX_PDSCH] ERROR pthread_cond_signal\n");
else
rt_printk("[openair][SCHED][RX_PDSCH] Signalled rx_pdsch_thread to exit\n");
rt_printk("[openair][SCHED][RX_PDSCH] Exiting ...\n");
pthread_cond_destroy(&rx_pdsch_cond);
pthread_mutex_destroy(&rx_pdsch_mutex);
}
/*******************************************************************************
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenAirInterface is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/*! \file sched_ulsch.c
* \brief ULSCH decoding thread (RTAI)
* \author R. Knopp, F. Kaltenberger
* \date 2011
* \version 0.1
* \company Eurecom
* \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr
* \note
* \warning
*/
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include "rt_wrapper.h"
#include <sys/mman.h>
#include "PHY/types.h"
#include "PHY/defs.h"
#include "PHY/extern.h"
#include "SCHED/defs.h"
#include "MAC_INTERFACE/extern.h"
#ifdef CBMIMO1
#include "ARCH/CBMIMO1/DEVICE_DRIVER/cbmimo1_device.h"
#include "ARCH/CBMIMO1/DEVICE_DRIVER/extern.h"
#include "ARCH/CBMIMO1/DEVICE_DRIVER/defs.h"
#endif // CBMIMO1
#define DEBUG_PHY
/// Mutex for instance count on ulsch scheduling
pthread_mutex_t ulsch_mutex[NUMBER_OF_UE_MAX];
/// Condition variable for ulsch thread
pthread_cond_t ulsch_cond[NUMBER_OF_UE_MAX];
pthread_t ulsch_threads[NUMBER_OF_UE_MAX];
pthread_attr_t attr_ulsch_threads;
// activity indicators for harq_pid's
int ulsch_instance_cnt[NUMBER_OF_UE_MAX];
// process ids for cpu
int ulsch_cpuid[NUMBER_OF_UE_MAX];
// subframe number for each harq_pid (needed to store ack in right place for UL)
int ulsch_subframe[NUMBER_OF_UE_MAX];
extern int oai_exit;
/*
extern int ulsch_errors;
extern int ulsch_received;
extern int ulsch_errors_last;
extern int ulsch_received_last;
extern int ulsch_fer;
extern int current_ulsch_cqi;
*/
/** ULSCH Decoding Thread */
static void * ulsch_thread(void *param)
{
//unsigned long cpuid;
unsigned int ulsch_thread_index = (unsigned int)param;
RTIME time_in,time_out;
#ifdef RTAI
RT_TASK *task;
char ulsch_thread_name[64];
#endif
int eNB_id = 0, UE_id = 0;
PHY_VARS_eNB *phy_vars_eNB = PHY_vars_eNB_g[eNB_id];
if ((ulsch_thread_index <0) || (ulsch_thread_index>NUMBER_OF_UE_MAX)) {
LOG_E(PHY,"[SCHED][ULSCH] Illegal ulsch_thread_index %d!!!!\n",ulsch_thread_index);
return 0;
}
#ifdef RTAI
sprintf(ulsch_thread_name,"ULSCH_THREAD%d",ulsch_thread_index);
LOG_I(PHY,"[SCHED][ULSCH] starting ulsch_thread %s for process %d\n",
ulsch_thread_name,
ulsch_thread_index);
task = rt_task_init_schmod(nam2num(ulsch_thread_name), 0, 0, 0, SCHED_FIFO, 0xF);
if (task==NULL) {
LOG_E(PHY,"[SCHED][ULSCH] Problem starting ulsch_thread_index %d!!!!\n",ulsch_thread_index);
return 0;
} else {
LOG_I(PHY,"[SCHED][ULSCH] ulsch_thread for process %d started with id %p\n",
ulsch_thread_index,
task);
}
#endif
mlockall(MCL_CURRENT | MCL_FUTURE);
//rt_set_runnable_on_cpuid(task,1);
//cpuid = rtai_cpuid();
#ifdef HARD_RT
rt_make_hard_real_time();
#endif
//ulsch_cpuid[ulsch_thread_index] = cpuid;
while (!oai_exit) {
if (pthread_mutex_lock(&ulsch_mutex[ulsch_thread_index]) != 0) {
LOG_E(PHY,"[SCHED][ULSCH] error locking mutex.\n");
} else {
while (ulsch_instance_cnt[ulsch_thread_index] < 0) {
pthread_cond_wait(&ulsch_cond[ulsch_thread_index],&ulsch_mutex[ulsch_thread_index]);
}
if (pthread_mutex_unlock(&ulsch_mutex[ulsch_thread_index]) != 0) {
LOG_E(PHY,"[SCHED][ULSCH] error unlocking mutex.\n");
}
}
if (oai_exit) break;
LOG_D(PHY,"[SCHED][ULSCH] Frame %d: Calling ulsch_decoding with ulsch_thread_index = %d\n",phy_vars_eNB->proc[0].frame_tx,ulsch_thread_index);
time_in = rt_get_time_ns();
ulsch_decoding_procedures(ulsch_subframe[ulsch_thread_index]<<1,ulsch_thread_index,phy_vars_eNB,0);
time_out = rt_get_time_ns();
if (pthread_mutex_lock(&ulsch_mutex[ulsch_thread_index]) != 0) {
msg("[openair][SCHED][ULSCH] error locking mutex.\n");
} else {
ulsch_instance_cnt[ulsch_thread_index]--;
if (pthread_mutex_unlock(&ulsch_mutex[ulsch_thread_index]) != 0) {
msg("[openair][SCHED][ULSCH] error unlocking mutex.\n");
}
}
}
#ifdef HARD_RT
rt_make_soft_real_time();
#endif
msg("[openair][SCHED][ULSCH] ULSCH thread %d exiting\n",ulsch_thread_index);
return 0;
}
int init_ulsch_threads(void)
{
int error_code, return_code=0;
struct sched_param p;
int ulsch_thread_index;
// later loop on all harq_pids, do 0 for now
for (ulsch_thread_index=0; ulsch_thread_index<NUMBER_OF_UE_MAX; ulsch_thread_index++) {
pthread_mutex_init(&ulsch_mutex[ulsch_thread_index],NULL);
pthread_cond_init(&ulsch_cond[ulsch_thread_index],NULL);
pthread_attr_init (&attr_ulsch_threads);
pthread_attr_setstacksize(&attr_ulsch_threads,OPENAIR_THREAD_STACK_SIZE);
//attr_ulsch_threads.priority = 1;
p.sched_priority = OPENAIR_THREAD_PRIORITY;
pthread_attr_setschedparam (&attr_ulsch_threads, &p);
#ifndef RTAI_ISNT_POSIX
pthread_attr_setschedpolicy (&attr_ulsch_threads, SCHED_FIFO);
#endif
ulsch_instance_cnt[ulsch_thread_index] = -1;
rt_printk("[openair][SCHED][ULSCH][INIT] Allocating ULSCH thread for ulsch_thread_index %d\n",ulsch_thread_index);
error_code = pthread_create(&ulsch_threads[ulsch_thread_index],
&attr_ulsch_threads,
ulsch_thread,
(void *)ulsch_thread_index);
if (error_code!= 0) {
rt_printk("[openair][SCHED][ULSCH][INIT] Could not allocate ulsch_thread %d, error %d\n",ulsch_thread_index,error_code);
return_code+=error_code;
//return(error_code);
} else {
rt_printk("[openair][SCHED][ULSCH][INIT] Allocate ulsch_thread %d successful\n",ulsch_thread_index);
//return(0);
}
}
return(return_code);
}
void cleanup_ulsch_threads(void)
{
int ulsch_thread_index;
for (ulsch_thread_index=0; ulsch_thread_index<NUMBER_OF_UE_MAX; ulsch_thread_index++) {
// pthread_exit(&ulsch_threads[ulsch_thread_index]);
rt_printk("[openair][SCHED][ULSCH] Scheduling ulsch_thread %d to exit\n",ulsch_thread_index);
ulsch_instance_cnt[ulsch_thread_index] = 0;
if (pthread_cond_signal(&ulsch_cond[ulsch_thread_index]) != 0)
rt_printk("[openair][SCHED][ULSCH] ERROR pthread_cond_signal\n");
else
rt_printk("[openair][SCHED][ULSCH] Signalled ulsch_thread %d to exit\n",ulsch_thread_index);
rt_printk("[openair][SCHED][ULSCH] Exiting ...\n");
pthread_cond_destroy(&ulsch_cond[ulsch_thread_index]);
pthread_mutex_destroy(&ulsch_mutex[ulsch_thread_index]);
}
}
......@@ -500,7 +500,7 @@ l2l1_task (void *args_p)
sprintf (title, "LTE DL SCOPE eNB %d to UE %d CC_id %d", eNB_inst, UE_inst, CC_id);
fl_show_form (form_ue[CC_id][UE_inst]->lte_phy_scope_ue, FL_PLACE_HOTSPOT, FL_FULLBORDER, title);
if (openair_daq_vars.use_ia_receiver == 1) {
if (PHY_vars_UE_g[UE_inst][CC_id]->use_ia_receiver == 1) {
fl_set_button(form_ue[CC_id][UE_inst]->button_0,1);
fl_set_object_label(form_ue[CC_id][UE_inst]->button_0, "IA Receiver ON");
fl_set_object_color(form_ue[CC_id][UE_inst]->button_0, FL_GREEN, FL_GREEN);
......
......@@ -951,22 +951,23 @@ void init_openair1(void)
number_of_cards = 1;
openair_daq_vars.rx_rf_mode = 1;
openair_daq_vars.tdd = 1;
openair_daq_vars.rx_gain_mode = DAQ_AGC_ON;
// openair_daq_vars.rx_rf_mode = 1;
// openair_daq_vars.tdd = 1;
// openair_daq_vars.rx_gain_mode = DAQ_AGC_ON;
openair_daq_vars.dlsch_transmission_mode = oai_emulation.info.transmission_mode[0];
// openair_daq_vars.dlsch_transmission_mode = oai_emulation.info.transmission_mode[0];
//#warning "NN->FK: OAI EMU channel abstraction does not work for MCS higher than"
openair_daq_vars.target_ue_dl_mcs = cmin(target_dl_mcs,16);
openair_daq_vars.target_ue_ul_mcs = target_ul_mcs;
openair_daq_vars.ue_dl_rb_alloc=0x1fff;
openair_daq_vars.ue_ul_nb_rb=6;
openair_daq_vars.dlsch_rate_adaptation = rate_adaptation_flag;
openair_daq_vars.use_ia_receiver = 0;
// openair_daq_vars.target_ue_dl_mcs = cmin(target_dl_mcs,16);
// openair_daq_vars.target_ue_ul_mcs = target_ul_mcs;
// openair_daq_vars.ue_dl_rb_alloc=0x1fff;
// openair_daq_vars.ue_ul_nb_rb=6;
// openair_daq_vars.dlsch_rate_adaptation = rate_adaptation_flag;
//N_TA_offset
for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
for (UE_id=0; UE_id<NB_UE_INST; UE_id++) {
PHY_vars_UE_g[UE_id][CC_id]->use_ia_receiver = 0;
if (PHY_vars_UE_g[UE_id][CC_id]->lte_frame_parms.frame_type == TDD) {
if (PHY_vars_UE_g[UE_id][CC_id]->lte_frame_parms.N_RB_DL == 100)
PHY_vars_UE_g[UE_id][CC_id]->N_TA_offset = 624;
......
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