/******************************************************************************* Eurecom OpenAirInterface Copyright(c) 1999 - 2011 Eurecom This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, version 2, as published by the Free Software Foundation. This program is distributed in the hope 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 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. The full GNU General Public License is included in this distribution in the file called "COPYING". Contact Information Openair Admin: openair_admin@eurecom.fr Openair Tech : openair_tech@eurecom.fr Forums : http://forums.eurecom.fsr/openairinterface Address : Eurecom, 2229, route des crĂȘtes, 06560 Valbonne Sophia Antipolis, France *******************************************************************************/ /*! \file lte-softmodem.c * \brief main program to control HW and scheduling * \author R. Knopp, F. Kaltenberger * \date 2012 * \version 0.1 * \company Eurecom * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr * \note * \warning */ #include #include #include #include #include #include #include #include #include #include #include #include #include #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" #ifdef EMOS #include #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 #include "openair0_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/vars.h" #include "MAC_INTERFACE/vars.h" #include "SCHED/vars.h" #include "LAYER2/MAC/vars.h" #include "../../SIMU/USER/init_lte.h" #ifdef EMOS #include "SCHED/phy_procedures_emos.h" #endif #ifdef OPENAIR2 #include "LAYER2/MAC/defs.h" #include "LAYER2/MAC/vars.h" #ifndef CELLULAR #include "RRC/LITE/vars.h" #endif #include "PHY_INTERFACE/vars.h" #endif #include "UTIL/LOG/log_extern.h" #include "UTIL/OTG/otg.h" #include "UTIL/OTG/otg_vars.h" #include "UTIL/MATH/oml.h" #include "UTIL/LOG/vcd_signal_dumper.h" #include "enb_config.h" #if defined(ENABLE_ITTI) # include "intertask_interface_init.h" # include "create_tasks.h" # if defined(ENABLE_USE_MME) # include "s1ap_eNB.h" # endif #endif #ifdef XFORMS #include "PHY/TOOLS/lte_phy_scope.h" #include "stats.h" // 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 FD_lte_phy_scope_ue *form_ue[NUMBER_OF_UE_MAX]; FD_lte_phy_scope_enb *form_enb[NUMBER_OF_UE_MAX]; FD_stats_form *form_stats=NULL; char title[255]; int UE_id; unsigned char scope_enb_num_ue = 1; #endif //XFORMS unsigned char UE_flag=0; char *mme_ip; #define FRAME_PERIOD 100000000ULL #define DAQ_PERIOD 66667ULL #undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all #ifdef RTAI static SEM *mutex; //static CND *cond; static int thread0; static int thread1; //static int sync_thread; #else pthread_t thread0; pthread_t thread1; pthread_attr_t attr_dlsch_threads; struct sched_param sched_param_dlsch; #endif pthread_t thread2; pthread_t thread3; /* 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; exmimo_config_t *p_exmimo_config; exmimo_id_t *p_exmimo_id; volatile unsigned int *DAQ_MBOX; #if defined(ENABLE_ITTI) volatile int start_eNB = 0; #endif volatile int oai_exit = 0; int oai_flag = 0; //int time_offset[4] = {-138,-138,-138,-138}; //int time_offset[4] = {-145,-145,-145,-145}; int time_offset[4] = {0,0,0,0}; uint8_t eNB_id=0; uint32_t carrier_freq_fdd[4]= {2680e6,0,0,0}; uint32_t carrier_freq_tdd[4]= {2590e6-4000,0,0,0}; uint32_t carrier_freq[4]; static char *conf_config_file_name = NULL; 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; runmode_t mode; int rx_input_level_dBm; #ifdef XFORMS extern int otg_enabled; #else int otg_enabled; #endif int number_of_cards = 1; //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 //int mbox_bounds[10] = {15, 30, 45, 60, 75, 90, 105, 120, 135, 0}; // mbox boundaries of subframes int mbox_bounds[10] = {14, 28, 44, 58, 74, 88, 104, 118, 134, 148}; // mbox boundaries of subframes //int mbox_bounds[10] = {16, 30, 46, 60, 76, 90, 106, 120, 136, 0}; ///boundaries of slots in terms ob mbox counter rounded up to even numbers int init_dlsch_threads(void); void cleanup_dlsch_threads(void); int32_t init_rx_pdsch_thread(void); void cleanup_rx_pdsch_thread(void); int init_ulsch_threads(void); void cleanup_ulsch_threads(void); LTE_DL_FRAME_PARMS *frame_parms; void setup_eNB_buffers(PHY_VARS_eNB *phy_vars_eNB, LTE_DL_FRAME_PARMS *frame_parms, int carrier); void signal_handler(int sig) { void *array[10]; size_t size; if (sig==SIGSEGV) { // get void*'s for all entries on the stack size = backtrace(array, 10); // print out all the frames to stderr fprintf(stderr, "Error: signal %d:\n", sig); backtrace_symbols_fd(array, size, 2); exit(-1); } else { oai_exit=1; } } void exit_fun(const char *s) { if (s != NULL) { printf("Exiting: %s\n",s); } oai_exit=1; #if defined(ENABLE_ITTI) itti_terminate_tasks (TASK_UNKNOWN); #endif //rt_sleep_ns(FRAME_PERIOD); //exit (-1); } #ifdef XFORMS void *scope_thread(void *arg) { s16 prach_corr[1024], i; char stats_buffer[16384]; //FILE *UE_stats, *eNB_stats; int len=0; /* if (UE_flag==1) UE_stats = fopen("UE_stats.txt", "w"); else eNB_stats = fopen("eNB_stats.txt", "w"); */ while (!oai_exit) { len = dump_eNB_stats (PHY_vars_eNB_g[0], stats_buffer, 0); fl_set_object_label(form_stats->stats_text, stats_buffer); //rewind (eNB_stats); //fwrite (stats_buffer, 1, len, eNB_stats); for(UE_id=0; UE_idofdm_symbol_size)*(( frame_parms->Ncp == EXTENDED) ? 6 : 7); slot_offset = (next_slot)*(frame_parms->samples_per_tti>>1); for (aa = 0; aa < frame_parms->nb_antennas_tx; aa++) { if (frame_parms->Ncp == EXTENDED) { PHY_ofdm_mod(&txdataF[aa][slot_offset_F], &txdata[aa][slot_offset], frame_parms->log2_symbol_size, 6, frame_parms->nb_prefix_samples, frame_parms->twiddle_fft, frame_parms->rev, CYCLIC_PREFIX); } else { normal_prefix_mod(&txdataF[aa][slot_offset_F], &txdata[aa][slot_offset], 7, frame_parms); } } } int dummy_tx_buffer[3840*4] __attribute__((aligned(16))); #if defined(ENABLE_ITTI) void *l2l1_task(void *arg) { MessageDef *message_p = NULL; int result; itti_set_task_real_time(TASK_L2L1); itti_mark_task_ready(TASK_L2L1); if (UE_flag == 0) { /* Wait for the initialize message */ do { if (message_p != NULL) { result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p); AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); } itti_receive_msg (TASK_L2L1, &message_p); switch (ITTI_MSG_ID(message_p)) { case INITIALIZE_MESSAGE: /* Start eNB thread */ start_eNB = 1; break; case TERMINATE_MESSAGE: oai_exit=1; itti_exit_task (); break; default: LOG_E(EMU, "Received unexpected message %s\n", ITTI_MSG_NAME(message_p)); break; } } while (ITTI_MSG_ID(message_p) != INITIALIZE_MESSAGE); result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p); AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); } do { // 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 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(1); return NULL; } #endif /* This is the main eNB thread. It gets woken up by the kernel driver using the RTAI message mechanism (rt_send and rt_receive). */ static void *eNB_thread(void *arg) { #ifdef RTAI RT_TASK *task; SEM *sem; #endif unsigned char last_slot, next_slot; int subframe = 0, hw_subframe; int frame=0; int skip_first=1; unsigned int msg1; unsigned int aa,slot_offset, slot_offset_F; int diff; int delay_cnt; RTIME time_in, time_diff; RTIME period; int mbox_target=0,mbox_current=0; int i,ret; int tx_offset; #if defined(ENABLE_ITTI) /* Wait for eNB application initialization to be complete (eNB registration to MME) */ { char *indicator[] = {". ", ".. ", "...", " ..", " .", " "}; int i = 0; while ((!oai_exit) && (start_eNB == 0)) { LOG_D(HW,"Waiting for eNB application to be ready %s\r", indicator[i]); i = (i + 1) % (sizeof(indicator) / sizeof(indicator[0])); usleep(200000); } LOG_D(HW,"\n"); } #endif #ifdef RTAI task = rt_task_init_schmod(nam2num("TASK0"), 0, 0, 0, SCHED_FIFO, 0xF); rt_receive(0, (unsigned long *)((void *)&sem)); LOG_D(HW,"Started eNB thread (id %p)\n",task); #endif #ifdef HARD_RT rt_make_hard_real_time(); #endif mlockall(MCL_CURRENT | MCL_FUTURE); timing_info.time_min = 100000000ULL; timing_info.time_max = 0; timing_info.time_avg = 0; timing_info.n_samples = 0; // sync to HW subframe == 0 mbox_current = ((volatile unsigned int *)DAQ_MBOX)[0]; rt_sleep_ns((165-mbox_current)*DAQ_PERIOD); time_in = rt_get_time_ns(); while (!oai_exit) { //this is the mbox counter where we should be mbox_target = mbox_bounds[subframe]; //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; } if (diff < -15) { LOG_D(HW, "Time %.3f: Frame %d, missed subframe, proceeding with next one (subframe %d, hw_subframe %d, mbox_currend %d, mbox_target %d,diff %d) processing time %.3f\n", (float)(rt_get_time_ns()-time_in)/1e6, frame, subframe, hw_subframe, mbox_current, mbox_target, diff, (float)(timing_info.time_now-timing_info.time_last)/1e6); subframe++; if (frame>0) { oai_exit=1; } if (subframe==10) { subframe=0; frame++; } continue; } if (diff > 15) { LOG_D(HW, "Time %.3f: Frame %d, skipped subframe, waiting for hw to catch up (subframe %d, hw_subframe %d, mbox_current %d, mbox_target %d, diff %d), processing time %.3f\n", (float)(rt_get_time_ns()-time_in)/1e6, frame, subframe, hw_subframe, mbox_current, mbox_target, diff, (float)(timing_info.time_now-timing_info.time_last)/1e6); //exit(-1); } delay_cnt = 0; vcd_signal_dumper_dump_variable_by_name(VCD_SIGNAL_DUMPER_VARIABLES_DAQ_MBOX, *((volatile unsigned int *) openair0_exmimo_pci[card].rxcnt_ptr[0])); vcd_signal_dumper_dump_variable_by_name(VCD_SIGNAL_DUMPER_VARIABLES_DIFF, diff); while ((diff>0) && (!oai_exit)) { time_diff = rt_get_time_ns() - time_in; ret = rt_sleep_ns(diff*DAQ_PERIOD); if (ret) { LOG_D(HW,"eNB Frame %d, time %llu: rt_sleep_ns returned %d\n",frame, time_in); } delay_cnt++; if (delay_cnt == 10) { oai_exit = 1; LOG_D(HW,"eNB Frame %d: HW stopped ... \n",frame); } 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; } } hw_subframe = ((((volatile unsigned int *)DAQ_MBOX)[0]+135)%150)/15; LOG_D(HW, "Time: %.3f: Frame %d, subframe %d, hw_subframe %d (mbox %d) processing time %0.3f\n", (float)(rt_get_time_ns()-time_in)/1e6, frame,subframe,hw_subframe,((volatile unsigned int *)DAQ_MBOX)[0], (float)(timing_info.time_now-timing_info.time_last)/1e6); last_slot = (subframe<<1)+1; if (last_slot <0) { last_slot+=20; } next_slot = ((subframe<<1)+4)%LTE_SLOTS_PER_FRAME; if ((skip_first == 0) || (frame>5)) { skip_first = 0; timing_info.time_last = rt_get_time_ns(); //msg("subframe %d, last_slot %d,next_slot %d\n", subframe,last_slot,next_slot); vcd_signal_dumper_dump_variable_by_name(VCD_SIGNAL_DUMPER_VARIABLES_DAQ_MBOX, *((volatile unsigned int *) openair0_exmimo_pci[card].rxcnt_ptr[0])); vcd_signal_dumper_dump_variable_by_name(VCD_SIGNAL_DUMPER_VARIABLES_DIFF, diff); phy_procedures_eNB_lte (last_slot, next_slot, PHY_vars_eNB_g[0], 0,0,NULL); vcd_signal_dumper_dump_variable_by_name(VCD_SIGNAL_DUMPER_VARIABLES_DAQ_MBOX, *((volatile unsigned int *) openair0_exmimo_pci[card].rxcnt_ptr[0])); #ifndef IFFT_FPGA if ((subframe_select(&PHY_vars_eNB_g[0]->lte_frame_parms,next_slot>>1)==SF_DL)|| ((subframe_select(&PHY_vars_eNB_g[0]->lte_frame_parms,next_slot>>1)==SF_S) &&((next_slot&1)==0))) { //LOG_D(HW,"Frame %d: Generating slot %d\n",frame,next_slot); /* do_OFDM_mod(PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdataF[0], PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0], next_slot, &PHY_vars_eNB_g[0]->lte_frame_parms); do_OFDM_mod(PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdataF[0], PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0], next_slot+1, &PHY_vars_eNB_g[0]->lte_frame_parms); */ vcd_signal_dumper_dump_function_by_name( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_SFGEN,1); slot_offset_F = (next_slot)* (PHY_vars_eNB_g[0]->lte_frame_parms.ofdm_symbol_size)*7; slot_offset = (next_slot)* (PHY_vars_eNB_g[0]->lte_frame_parms.samples_per_tti>>1); normal_prefix_mod( &PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdataF[0][0][slot_offset_F], dummy_tx_buffer, 7, &(PHY_vars_eNB_g[0]->lte_frame_parms)); for (i = 0; i < PHY_vars_eNB_g[0]->lte_frame_parms.samples_per_tti/2; i++) { tx_offset = slot_offset + time_offset[0] + i; ((short *)&PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][0][tx_offset])[0] = ((short *)dummy_tx_buffer)[2*i]<<4; ((short *)&PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][0][tx_offset])[1] = ((short *)dummy_tx_buffer)[2*i+1]<<4; } slot_offset_F = (next_slot+1)* (PHY_vars_eNB_g[0]->lte_frame_parms.ofdm_symbol_size)*7; slot_offset = (next_slot+1)* (PHY_vars_eNB_g[0]->lte_frame_parms.samples_per_tti>>1); normal_prefix_mod( &PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdataF[0][0][slot_offset_F], dummy_tx_buffer, 7, &(PHY_vars_eNB_g[0]->lte_frame_parms)); for (i = 0; i < PHY_vars_eNB_g[0]->lte_frame_parms.samples_per_tti/2; i++) { tx_offset = slot_offset + i; ((short *)&PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][0][tx_offset])[0] = ((short *)dummy_tx_buffer)[2*i]<<4; ((short *)&PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][0][tx_offset])[1] = ((short *)dummy_tx_buffer)[2*i+1]<<4; } } vcd_signal_dumper_dump_function_by_name( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_SFGEN,0); timing_info.time_now = rt_get_time_ns(); #endif //IFFT_FPGA /* if (frame%100==0) LOG_D(HW,"hw_slot %d (after): DAQ_MBOX %d\n",hw_slot,DAQ_MBOX[0]); */ } /* if ((slot%2000)<10) LOG_D(HW,"fun0: doing very hard work\n"); */ if (oai_flag == 2) { //dump_ulsch(PHY_vars_eNB_g[0], subframe, 0); //exit(-1); oai_exit=1; exit_fun("[HW][eNB] HW stopped"); } if (oai_flag == 1) { oai_flag = 2; } subframe++; if (subframe==10) { subframe=0; frame++; } if(frame == 1024) { frame = 0; time_in = rt_get_time_ns(); } #if defined(ENABLE_ITTI) itti_update_lte_time(frame, subframe * 2); #endif } LOG_D(HW,"eNB_thread: finished, ran %d times.\n",frame); #ifdef HARD_RT rt_make_soft_real_time(); #endif // clean task #ifdef RTAI rt_sem_signal(mutex); rt_task_delete(task); #endif LOG_D(HW,"Task deleted. returning\n"); return 0; } int main(int argc, char **argv) { const Enb_properties_array_t *enb_properties; #ifdef RTAI RT_TASK *task; #endif int i,j,aa; void *status; /* uint32_t rf_mode_max[4] = {55759,55759,55759,55759}; uint32_t rf_mode_med[4] = {39375,39375,39375,39375}; uint32_t rf_mode_byp[4] = {22991,22991,22991,22991}; */ uint32_t my_rf_mode = RXEN + TXEN + TXLPFNORM + TXLPFEN + TXLPF25 + RXLPFNORM + RXLPFEN + RXLPF25 + LNA1ON +LNAMax + RFBBNORM + DMAMODE_RX + DMAMODE_TX; uint32_t rf_mode_base = TXLPFNORM + TXLPFEN + TXLPF25 + RXLPFNORM + RXLPFEN + RXLPF25 + LNA1ON + /*LNAMax Antennas*/ LNAByp + RFBBNORM; uint32_t rf_mode[4] = {my_rf_mode,0,0,0}; uint32_t rf_local[4] = {8255000,8255000,8255000,8255000}; // UE zepto //{8254617, 8254617, 8254617, 8254617}; //eNB khalifa //{8255067,8254810,8257340,8257340}; // eNB PETRONAS uint32_t rf_vcocal[4] = {910,910,910,910}; uint32_t rf_vcocal_850[4] = {2015, 2015, 2015, 2015}; uint32_t rf_rxdc[4] = {32896,32896,32896,32896}; // Gain for antennas connection //uint32_t rxgain[4] = {25,20,20,20}; //uint32_t txgain[4] = {30,25,25,25}; // Gain for Cable connection uint32_t rxgain[4] = {20,20,20,20}; uint32_t txgain[4] = {25,25,25,25}; uint8_t frame_type = FDD; uint8_t tdd_config = 3; uint8_t tdd_config_S = 0; uint8_t extended_prefix_flag = 0; uint16_t Nid_cell = 0; uint8_t N_RB_DL = 25; uint8_t cooperation_flag = 0; uint8_t transmission_mode = 1; uint8_t abstraction_flag = 0; uint8_t nb_antennas_rx = 1; uint8_t beta_ACK=0,beta_RI=0,beta_CQI=2; int c; char do_forms=0; unsigned int fd; int amp; unsigned int rxg_max[4]= {133,133,133,133}, rxg_med[4]= {127,127,127,127}, rxg_byp[4]= {120,120,120,120}; int tx_max_power=0; int ret, ant; int error_code; char *itti_dump_file = NULL; mode = normal_txrx; mme_ip = "146.208.175.6"; while ((c = getopt(argc, argv, "dC:K:O:T:N:R:Vi;")) != -1) { switch (c) { case 'd': do_forms=1; printf("Starting XFORMS ...\n"); break; case 'C': carrier_freq[0] = atoi(optarg); carrier_freq[1] = atoi(optarg); carrier_freq[2] = atoi(optarg); carrier_freq[3] = atoi(optarg); break; case 'T': frame_type = TDD; // default FDD tdd_config = atoi(optarg); break; case 'K': #if defined(ENABLE_ITTI) itti_dump_file = strdup(optarg); #else printf("-K option is disabled when ENABLE_ITTI is not defined\n"); #endif break; case 'O': conf_config_file_name = optarg; break; case 'R': N_RB_DL = atoi(optarg); if ((N_RB_DL != 6) && (N_RB_DL != 15) && (N_RB_DL != 25) && (N_RB_DL != 50) && (N_RB_DL != 75) && (N_RB_DL != 100)) { printf("Illegal N_RB_DL %d (should be one of 6,15,25,50,75,100)\n", N_RB_DL); exit(-1); } break; case 'i': mme_ip = optarg; break; case 'V': ouput_vcd = 1; break; default: break; } } NB_eNB_INST=1; NB_INST=1; if ((UE_flag == 0) && (conf_config_file_name != NULL)) { int i; /* Read eNB configuration file */ enb_properties = enb_config_init(conf_config_file_name); AssertFatal (NB_eNB_INST <= enb_properties->number, "Number of eNB is greater than eNB defined in configuration file %s (%d/%d)!", conf_config_file_name, NB_eNB_INST, enb_properties->number); /* Update some simulation parameters */ frame_type = enb_properties->properties[0]->frame_type; for (i = 0 ; i < (sizeof(carrier_freq) / sizeof (carrier_freq[0])); i++) { carrier_freq[i] = enb_properties->properties[0]->downlink_frequency; } } set_taus_seed (0); // initialize the log (see log.h for details) logInit(); if (ouput_vcd) { vcd_signal_dumper_init("/tmp/openair_dump_eNB.vcd"); } #if defined(ENABLE_ITTI) log_set_instance_type (LOG_INSTANCE_ENB); itti_init(TASK_MAX, THREAD_MAX, MESSAGES_ID_MAX, tasks_info, messages_info, messages_definition_xml, itti_dump_file); #endif #ifdef NAS_NETLINK netlink_init(); #endif #if !defined(ENABLE_ITTI) // to make a graceful exit when ctrl-c is pressed signal(SIGSEGV, signal_handler); signal(SIGINT, signal_handler); #endif #ifndef RTAI check_clock(); #endif init_lte_vars(&frame_parms, frame_type, tdd_config, tdd_config_S, extended_prefix_flag, N_RB_DL, Nid_cell, cooperation_flag, transmission_mode, abstraction_flag, nb_antennas_rx,0); g_log->level = LOG_WARNING; g_log->log_component[HW].level = LOG_WARNING; g_log->log_component[HW].flag = LOG_LOW; g_log->log_component[PHY].level = LOG_WARNING; g_log->log_component[PHY].flag = LOG_LOW; g_log->log_component[MAC].level = LOG_INFO; g_log->log_component[MAC].flag = LOG_LOW; g_log->log_component[RLC].level = LOG_WARNING; g_log->log_component[RLC].flag = LOG_LOW; g_log->log_component[PDCP].level = LOG_WARNING; g_log->log_component[PDCP].flag = LOG_LOW; g_log->log_component[RRC].level = LOG_INFO; g_log->log_component[RRC].flag = LOG_LOW; g_log->log_component[OIP].level = LOG_INFO; g_log->log_component[OIP].flag = LOG_HIGH; #if defined(ENABLE_ITTI) g_log->log_component[EMU].level = LOG_INFO; g_log->log_component[EMU].flag = LOG_HIGH; # if defined(ENABLE_USE_MME) g_log->log_component[S1AP].level = LOG_INFO; g_log->log_component[S1AP].flag = LOG_HIGH; g_log->log_component[SCTP].level = LOG_INFO; g_log->log_component[SCTP].flag = LOG_HIGH; # endif g_log->log_component[S1AP].level = LOG_INFO; g_log->log_component[S1AP].flag = LOG_LOW; #else #endif g_log->log_component[ENB_APP].level = LOG_INFO; g_log->log_component[ENB_APP].flag = LOG_HIGH; PHY_vars_eNB_g = malloc(sizeof(PHY_VARS_eNB *)); PHY_vars_eNB_g[0] = init_lte_eNB(frame_parms,eNB_id,Nid_cell,cooperation_flag, transmission_mode,abstraction_flag); #ifndef OPENAIR2 for (i=0; ipusch_config_dedicated[i].betaOffset_ACK_Index = beta_ACK; PHY_vars_eNB_g[0]->pusch_config_dedicated[i].betaOffset_RI_Index = beta_RI; PHY_vars_eNB_g[0]->pusch_config_dedicated[i].betaOffset_CQI_Index = beta_CQI; PHY_vars_eNB_g[0]->scheduling_request_config[i].sr_PUCCH_ResourceIndex = i; PHY_vars_eNB_g[0]->scheduling_request_config[i].sr_ConfigIndex = 7+(i%3); PHY_vars_eNB_g[0]->scheduling_request_config[i].dsr_TransMax = sr_n4; } #endif openair_daq_vars.ue_dl_rb_alloc=0x1fff; openair_daq_vars.target_ue_dl_mcs=16; openair_daq_vars.ue_ul_nb_rb=6; openair_daq_vars.target_ue_ul_mcs=9; // set eNB to max gain PHY_vars_eNB_g[0]->rx_total_gain_eNB_dB = rxg_max[0] + rxgain[0] - 30; //was measured at rxgain=30; for (i=0; i<4; i++) { // frame_parms->rfmode[i] = rf_mode_max[i]; rf_mode[i] = (rf_mode[i] & (~LNAGAINMASK)) | LNAMax; } // Initialize card ret = openair0_open(); if ( ret != 0 ) { if (ret == -1) { printf("Error opening /dev/openair0\n"); } if (ret == -2) { printf("Error mapping bigshm\n"); } if (ret == -3) { printf("Error mapping RX or TX buffer\n"); } return(ret); } printf ("Detected %d number of cards, %d number of antennas.\n", openair0_num_detected_cards, openair0_num_antennas[card]); p_exmimo_config = openair0_exmimo_pci[card].exmimo_config_ptr; p_exmimo_id = openair0_exmimo_pci[card].exmimo_id_ptr; printf("Card %d: ExpressMIMO %d, HW Rev %d, SW Rev 0x%d\n", card, p_exmimo_id->board_exmimoversion, p_exmimo_id->board_hwrev, p_exmimo_id->board_swrev); if (p_exmimo_id->board_swrev>=BOARD_SWREV_CNTL2) { p_exmimo_config->framing.eNB_flag = 0; } else { p_exmimo_config->framing.eNB_flag = 0; //!UE_flag; } p_exmimo_config->framing.tdd_config = DUPLEXMODE_FDD + TXRXSWITCH_LSB; for (ant = 0; ant < 4; ant++) { p_exmimo_config->framing.resampling_factor[ant] = 2; } for (ant=0; antnb_antennas_tx,frame_parms->nb_antennas_rx); ant++) { p_exmimo_config->rf.rf_mode[ant] = rf_mode_base; } for (ant=0; antnb_antennas_tx; ant++) { p_exmimo_config->rf.rf_mode[ant] += (TXEN + DMAMODE_TX); } for (ant=0; antnb_antennas_rx; ant++) { p_exmimo_config->rf.rf_mode[ant] += (RXEN + DMAMODE_RX); } for (ant=max(frame_parms->nb_antennas_tx,frame_parms->nb_antennas_rx); ant<4; ant++) { p_exmimo_config->rf.rf_mode[ant] = 0; carrier_freq[ant] = 0; //this turns off all other LIMEs } for (ant = 0; ant < 4; ant++) { if (frame_type == FDD) { carrier_freq[ant] = carrier_freq_fdd[ant]; } else { carrier_freq[ant] = carrier_freq_tdd[ant]; } } for (ant = 0; ant<1; ant++) { p_exmimo_config->rf.do_autocal[ant] = 1; if (frame_type == FDD) { p_exmimo_config->rf.rf_freq_rx[ant] = carrier_freq[ant]-120e6; // LTE FDD band 1 duplex space } else { p_exmimo_config->rf.rf_freq_rx[ant] = carrier_freq[ant]; } p_exmimo_config->rf.rf_freq_tx[ant] = carrier_freq[ant]; p_exmimo_config->rf.rx_gain[ant][0] = rxgain[ant]; p_exmimo_config->rf.tx_gain[ant][0] = txgain[ant]; p_exmimo_config->rf.rf_local[ant] = rf_local[ant]; p_exmimo_config->rf.rf_rxdc[ant] = rf_rxdc[ant]; if ((carrier_freq[ant] >= 850000000) && (carrier_freq[ant] <= 865000000)) { p_exmimo_config->rf.rf_vcocal[ant] = rf_vcocal_850[ant]; p_exmimo_config->rf.rffe_band_mode[ant] = DD_TDD; } else { p_exmimo_config->rf.rf_vcocal[ant] = rf_vcocal[ant]; p_exmimo_config->rf.rffe_band_mode[ant] = B19G_TDD; } p_exmimo_config->rf.rffe_gain_txlow[ant] = 63; p_exmimo_config->rf.rffe_gain_txhigh[ant] = 63; p_exmimo_config->rf.rffe_gain_rxfinal[ant] = 63; p_exmimo_config->rf.rffe_gain_rxlow[ant] = 63; } dump_frame_parms(frame_parms); mac_xface = malloc(sizeof(MAC_xface)); #ifdef OPENAIR2 int eMBMS_active=0; l2_init(frame_parms,eMBMS_active, 0,// cba_group_active 0); //HO active mac_xface->mrbch_phy_sync_failure (0, 0, 0); #endif mac_xface->macphy_exit = &exit_fun; #if defined(ENABLE_ITTI) if (create_tasks(UE_flag ? 0 : 1, UE_flag ? 1 : 0) < 0) { exit(-1); // need a softer mode } printf("ITTI tasks created\n"); #endif number_of_cards = openair0_num_detected_cards; if (p_exmimo_id->board_exmimoversion==1) { //ExpressMIMO1 openair_daq_vars.timing_advance = 138; } else { //ExpressMIMO2 openair_daq_vars.timing_advance = 15; } setup_eNB_buffers(PHY_vars_eNB_g[0],frame_parms,0); openair0_dump_config(card); printf("EXMIMO_CONFIG: rf_mode 0x %x %x %x %x, [0]: TXRXEn %d, TXLPFEn %d, TXLPF %d, RXLPFEn %d, RXLPF %d, RFBB %d, LNA %d, LNAGain %d, RXLPFMode %d, SWITCH %d, rf_rxdc %d, rf_local %d, rf_vcocal %d\n", p_exmimo_config->rf.rf_mode[0], p_exmimo_config->rf.rf_mode[1], p_exmimo_config->rf.rf_mode[2], p_exmimo_config->rf.rf_mode[3], (p_exmimo_config->rf.rf_mode[0]&3), // RXen+TXen (p_exmimo_config->rf.rf_mode[0]&4)>>2, //TXLPFen (p_exmimo_config->rf.rf_mode[0]&TXLPFMASK)>>3, //TXLPF (p_exmimo_config->rf.rf_mode[0]&128)>>7, //RXLPFen (p_exmimo_config->rf.rf_mode[0]&RXLPFMASK)>>8, //TXLPF (p_exmimo_config->rf.rf_mode[0]&RFBBMASK)>>16, // RFBB mode (p_exmimo_config->rf.rf_mode[0]&LNAMASK)>>12, // RFBB mode (p_exmimo_config->rf.rf_mode[0]&LNAGAINMASK)>>14, // RFBB mode (p_exmimo_config->rf.rf_mode[0]&RXLPFMODEMASK)>>19, // RXLPF mode (p_exmimo_config->framing.tdd_config&TXRXSWITCH_MASK)>>1, // Switch mode p_exmimo_config->rf.rf_rxdc[0], p_exmimo_config->rf.rf_local[0], p_exmimo_config->rf.rf_vcocal[0]); for (ant=0; ant<4; ant++) { p_exmimo_config->rf.do_autocal[ant] = 0; } mlockall(MCL_CURRENT | MCL_FUTURE); #ifdef RTAI // make main thread LXRT soft realtime task = rt_task_init_schmod(nam2num("MYTASK"), 9, 0, 0, SCHED_FIFO, 0xF); // start realtime timer and scheduler //rt_set_oneshot_mode(); rt_set_periodic_mode(); start_rt_timer(0); //now = rt_get_time() + 10*PERIOD; //rt_task_make_periodic(task, now, PERIOD); printf("Init mutex\n"); //mutex = rt_get_adr(nam2num("MUTEX")); mutex = rt_sem_init(nam2num("MUTEX"), 0); if (mutex==0) { printf("Error init mutex\n"); exit(-1); } else { printf("mutex=%p\n",mutex); } #endif DAQ_MBOX = (volatile unsigned int *) openair0_exmimo_pci[card].rxcnt_ptr[0]; // this starts the DMA transfers openair0_start_rt_acquisition(card); #ifdef XFORMS if (do_forms==1) { printf("Running XFORMS\n"); fl_initialize (&argc, argv, NULL, 0, 0); form_stats = create_form_stats_form(); for(UE_id=0; UE_idlte_phy_scope_enb, FL_PLACE_HOTSPOT, FL_FULLBORDER, title); } fl_show_form (form_stats->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "stats"); for (UE_id=0; UE_idbutton_0,1); fl_set_object_label(form_enb[UE_id]->button_0,"DL Traffic ON"); } else { fl_set_button(form_enb[UE_id]->button_0,0); fl_set_object_label(form_enb[UE_id]->button_0,"DL Traffic OFF"); } } ret = pthread_create(&thread2, NULL, scope_thread, NULL); printf("Scope thread created, ret=%d\n",ret); } #endif rt_sleep_ns(10*FRAME_PERIOD); #ifndef RTAI pthread_attr_init (&attr_dlsch_threads); pthread_attr_setstacksize(&attr_dlsch_threads,OPENAIR_THREAD_STACK_SIZE); //attr_dlsch_threads.priority = 1; 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); #endif // start the main thread #ifdef RTAI thread0 = rt_thread_create(eNB_thread, NULL, 10000000); rt_sleep_ns(FRAME_PERIOD*10); rt_send(rt_get_adr(nam2num("TASK0")), (unsigned long)mutex); #else error_code = pthread_create(&thread0, &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"); } #endif // #ifdef OPENAIR2 // init_pdcp_thread(1); // #endif #ifdef ULSCH_THREAD init_ulsch_threads(); #endif printf("eNB threads created\n"); // wait for end of program printf("TYPE TO TERMINATE\n"); //getchar(); //while (oai_exit==0) // rt_sleep_ns(FRAME_PERIOD); #if defined(ENABLE_ITTI) printf("Entering ITTI signals handler\n"); itti_wait_tasks_end(); #else rt_sem_wait(mutex); #endif // stop threads #ifdef XFORMS printf("waiting for XFORMS thread\n"); if (do_forms==1) { pthread_join(thread2,&status); fl_hide_form(form_stats->stats_form); fl_free_form(form_stats->stats_form); for(UE_id=0; UE_idlte_phy_scope_enb); fl_free_form(form_enb[UE_id]->lte_phy_scope_enb); } } #endif printf("stopping MODEM threads\n"); // cleanup #ifdef RTAI rt_thread_join(thread0); #else pthread_join(thread0,&status); #endif #ifdef ULSCH_THREAD cleanup_ulsch_threads(); #endif #ifdef RTAI rt_sem_delete(mutex); stop_rt_timer(); rt_task_delete(task); #endif printf("stopping card\n"); openair0_stop(card); printf("closing openair0_lib\n"); openair0_close(); if (ouput_vcd) { vcd_signal_dumper_close(); } logClean(); return 0; } void setup_eNB_buffers(PHY_VARS_eNB *phy_vars_eNB, LTE_DL_FRAME_PARMS *frame_parms, int carrier) { int i,j; uint16_t N_TA_offset = 0; if (frame_parms->frame_type == TDD) { N_TA_offset = 624/4; } if (phy_vars_eNB) { if ((frame_parms->nb_antennas_rx>1) && (carrier>0)) { printf("RX antennas > 1 and carrier > 0 not possible\n"); exit(-1); } if ((frame_parms->nb_antennas_tx>1) && (carrier>0)) { printf("TX antennas > 1 and carrier > 0 not possible\n"); exit(-1); } // replace RX signal buffers with mmaped HW versions for (i=0; inb_antennas_rx; i++) { free(phy_vars_eNB->lte_eNB_common_vars.rxdata[0][i]); phy_vars_eNB->lte_eNB_common_vars.rxdata[0][i] = ((int32_t *) openair0_exmimo_pci[card].adc_head[i+carrier]) - N_TA_offset; // N_TA offset for TDD /* printf("rxdata[%d] @ %p\n",i,phy_vars_eNB->lte_eNB_common_vars.rxdata[0][i]); for (j=0;j<16;j++) { printf("rxbuffer %d: %x\n",j,phy_vars_eNB->lte_eNB_common_vars.rxdata[0][i][j]); phy_vars_eNB->lte_eNB_common_vars.rxdata[0][i][j] = 16-j; } */ } for (i=0; inb_antennas_tx; i++) { free(phy_vars_eNB->lte_eNB_common_vars.txdata[0][i]); phy_vars_eNB->lte_eNB_common_vars.txdata[0][i] = (int32_t *) openair0_exmimo_pci[card].dac_head[i+carrier]; /* printf("txdata[%d] @ %p\n",i,phy_vars_eNB->lte_eNB_common_vars.txdata[0][i]); for (j=0;j<16;j++) { printf("txbuffer %d: %x\n",j,phy_vars_eNB->lte_eNB_common_vars.txdata[0][i][j]); phy_vars_eNB->lte_eNB_common_vars.txdata[0][i][j] = 16-j; } */ } } }