/******************************************************************************* 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 . Contact Information OpenAirInterface Admin: openair_admin@eurecom.fr OpenAirInterface Tech : openair_tech@eurecom.fr OpenAirInterface Dev : openair4g-devel@eurecom.fr Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, 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 #define __USE_GNU //#define _GNU_SOURCE #include #include #include #include //#include #include #include "rt_wrapper.h" #ifdef EMOS #include #endif #include "PHY/types.h" #include "PHY/defs.h" #include "openair0_lib.h" #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 #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.h" #include "UTIL/OTG/otg_vars.h" #include "UTIL/MATH/oml.h" #include "UTIL/LOG/vcd_signal_dumper.h" #include "stats.h" #include "../../ARCH/USRP/USERSPACE/LIB/def.h" #include "TOOLS/thread_ipc.c" #ifdef XFORMS #include "PHY/TOOLS/lte_phy_scope.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]; unsigned char scope_enb_num_ue = 1; #endif //XFORMS #define FRAME_PERIOD 100000000ULL #define DAQ_PERIOD 66667ULL //#define rt_printk printf #undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all #ifdef RTAI //by super static SEM *mutex; //static CND *cond; static int thread0; static int thread1; static int thread_recv; //static int sync_thread; #else pthread_t thread0; pthread_t thread1; pthread_t thread_recv; pthread_attr_t attr_dlsch_threads; struct sched_param sched_param_dlsch; #endif pthread_t thread2; pthread_t thread3; pthread_t tid_eNB; pthread_t tid_recv; pthread_t thread_tx_error; pthread_attr_t attr; pthread_mutex_t mutex_eNB; pthread_cond_t cond_eNB; int ret; // ------------------------------------ // functions and variables for USRP // ------------------------------------ extern int oai_tx_buff[SAMPLES_PER_FRM]; extern int oai_rx_buff[SAMPLES_PER_FRM]; extern void UHD_init(void); extern void UHD_init_display(void); extern void Init_send(void); extern void Init_recv(void); extern void set_freq(int freq_offset); extern void send_data(int hw_frm_head_pos); extern void recv_data(int hw_frm_head_pos); extern void send_end(); extern void tx_errorcode_handler(void); int tx_offset = 0; int hw_frm_head_pos = 0; extern volatile unsigned long long tx_timestamp,rx_timestamp,clock_usrp; extern volatile int flag_recv,flag_clock; extern volatile int recv_ready; extern volatile int w_pos_usrp_rcv; // value range [0:76800-1] extern volatile int w_slot_usrp_rcv, r_slot_usrp_send; // slot index for USRP thread. value range [0:19] extern volatile int r_slot_idx, t_slot_idx; // slot index for eNB thread. value range [0;19] extern volatile int send_slot_missed; double time_diff1,time_diff2,time_diff3,time_diff4; struct timespec time_1, time_2,time_3,time_4,time_5; // USRP debug output control extern int g_usrp_debug; //add for program run limit times int N_slot_cycle; // ----------------------------------- // Ctrl+c control // ----------------------------------- int oai_exit = 0; void sig_int_handler(void); int card = 0; exmimo_config_t *p_exmimo_config; exmimo_id_t *p_exmimo_id; volatile unsigned int *DAQ_MBOX; //int time_offset[4] = {-138,-138,-138,-138}; //int time_offset[4] = {-145,-145,-145,-145}; int time_offset[4] = {0,0,0,0}; int fs4_test=0; char UE_flag; u8 eNB_id=0,UE_id=0; u32 carrier_freq[4]= {1907600000,1907600000,1907600000,1907600000}; 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 s16* sync_corr_ue0; extern s16 prach_ifft[4][1024*2]; 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 init_dlsch_threads(void); void cleanup_dlsch_threads(void); s32 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_ue_buffers(PHY_VARS_UE *phy_vars_ue, LTE_DL_FRAME_PARMS *frame_parms, int carrier); void setup_eNB_buffers(PHY_VARS_eNB *phy_vars_eNB, LTE_DL_FRAME_PARMS *frame_parms, int carrier); void test_config(int card, int ant, unsigned int rf_mode, int UE_flag); unsigned int build_rflocal(txi, txq, rxi, rxq) { return (txi + (txq<<6) + (rxi<<12) + (rxq<<18)); } unsigned int build_rfdc(int dcoff_i_rxfe, int dcoff_q_rxfe) { return (dcoff_i_rxfe + (dcoff_q_rxfe<<8)); } 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) { void *array[10]; size_t size; printf("Exiting: %s\n",s); oai_exit=1; //rt_sleep_ns(FRAME_PERIOD); //exit (-1); } int dummy_tx_buffer[3840*4] __attribute__((aligned(16))); void sig_int_handler(void) { oai_exit = 1; } // ----------------------------------- // USRP tx underflow test // ----------------------------------- // FIXME HL_CHECK is this thread necessary? void *tx_error_handler(void *ptr) { (void)ptr; while (!oai_exit) { tx_errorcode_handler(); } printf("[USRP monitoring thread] Received oai_exit signal. Ends.\n"); pthread_exit(NULL); } // ----------------------------------- // USRP send and receive thread // ----------------------------------- void *usrp_thread(void *ptr) { (void)ptr; bind_thread2kernel(1); int i=0; // continuous receiving while (!oai_exit) { // receive one slot-len recv_data(hw_frm_head_pos); // send one slot send_data(hw_frm_head_pos); i++; if(i==N_slot_cycle) oai_exit=1;//control run N_slot_cycle slot and exit } send_end(); printf("[USRP thread] Received oai_exit signal. Ends. send slot missed: %d\n",send_slot_missed); pthread_exit(NULL); } /* 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) //void eNB_thread(void) { printf("Start eNB Server...\n\n"); bind_thread2kernel(2); #ifdef RTAI RT_TASK *task; #endif int slot=0,last_slot, next_slot,frame=0; unsigned int aa,slot_offset, slot_offset_F; int diff = 0; int i; int num_slot_missed = 0; #ifdef RTAI task = rt_task_init_schmod(nam2num("TASK0"), 0, 0, 0, SCHED_FIFO, 0xF); LOG_D(HW,"Started eNB thread (id %p)\n",task); //if(task==NULL) printf("RT Task creation failed\n"); else printf("Task success!\n"); #endif mlockall(MCL_CURRENT | MCL_FUTURE); #ifdef HARD_RT rt_make_hard_real_time(); #endif // initialize reading postition r_slot_idx = 0; t_slot_idx = 0; frame = 0; while (!oai_exit) { format_printf(g_usrp_debug,"[eNB ] r_eNB: %d w_usrp: %d num_slot_missed: %d diff: %d\n",r_slot_idx,w_slot_usrp_rcv, num_slot_missed,diff); // Update 'diff'. Handle the frame wrap-arround if ((w_slot_usrp_rcv<4)&&(r_slot_idx>=16)){ diff = r_slot_idx - (w_slot_usrp_rcv + 20) ; } else if((w_slot_usrp_rcv>=16)&&(r_slot_idx<4)){ diff = (r_slot_idx + 20) - w_slot_usrp_rcv; } else{ diff = r_slot_idx - w_slot_usrp_rcv; } // Reading is too slow. It's already late. if(diff < -4) { r_slot_idx++; num_slot_missed += abs(diff + 4); if(r_slot_idx==20){ r_slot_idx = 0; frame++; } continue; } // Wait for writing while((diff > 0)&& (!oai_exit)) { usleep(500); // Update 'diff'. Handle the frame wrap-arround if ((w_slot_usrp_rcv<4)&&(r_slot_idx>=16)){ diff = r_slot_idx - (w_slot_usrp_rcv + 20) ; } else if((w_slot_usrp_rcv>=16)&&(r_slot_idx<4)){ diff = (r_slot_idx + 20) - w_slot_usrp_rcv; } else{ diff = r_slot_idx - w_slot_usrp_rcv; } } // The slot is ready last_slot = r_slot_idx; next_slot = (r_slot_idx + N_slot_offset)%LTE_SLOTS_PER_FRAME; format_printf(g_usrp_debug, "[eNB ] r_eNB: %d w_usrp: %d last_slot: %d next_slot: %d diff: %d\n\n",r_slot_idx,w_slot_usrp_rcv,last_slot, next_slot,diff); //--------------------------- // eNB procedure //--------------------------- PHY_vars_eNB_g[0]->frame = frame; //if (frame>5) { if (fs4_test==0) // -- PHY procedure -- { //phy_procedures_eNB_lte(last_slot, next_slot, PHY_vars_eNB_g[0], 0);//for OAI version berfore 4160 phy_procedures_eNB_lte(last_slot, next_slot, PHY_vars_eNB_g[0], 0,0,NULL); #ifndef IFFT_FPGA slot_offset_F = (next_slot)* (PHY_vars_eNB_g[0]->lte_frame_parms.ofdm_symbol_size)* ((PHY_vars_eNB_g[0]->lte_frame_parms.Ncp==1) ? 6 : 7);//0for normal 7,1 for extened 6 slot_offset = (next_slot)* (PHY_vars_eNB_g[0]->lte_frame_parms.samples_per_tti>>1); 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))) { for (aa=0; aalte_frame_parms.nb_antennas_tx; aa++) { if (PHY_vars_eNB_g[0]->lte_frame_parms.Ncp == 1) { PHY_ofdm_mod(&PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdataF[0][aa][slot_offset_F], #ifdef BIT8_TX &PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][aa][slot_offset>>1], #else dummy_tx_buffer,//&PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][aa][slot_offset], #endif PHY_vars_eNB_g[0]->lte_frame_parms.log2_symbol_size, 6, PHY_vars_eNB_g[0]->lte_frame_parms.nb_prefix_samples, PHY_vars_eNB_g[0]->lte_frame_parms.twiddle_ifft, PHY_vars_eNB_g[0]->lte_frame_parms.rev, CYCLIC_PREFIX); } else { normal_prefix_mod(&PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdataF[0][aa][slot_offset_F], #ifdef BIT8_TX &PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][aa][slot_offset>>1], #else dummy_tx_buffer,//&PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][aa][slot_offset], #endif 7, &(PHY_vars_eNB_g[0]->lte_frame_parms)); } #ifdef EXMIMO for (i=0; ilte_frame_parms.samples_per_tti/2; 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_g[0]->lte_frame_parms.samples_per_tti; if (tx_offset>=(LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*PHY_vars_eNB_g[0]->lte_frame_parms.samples_per_tti)) tx_offset -= LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*PHY_vars_eNB_g[0]->lte_frame_parms.samples_per_tti; ((short*)&PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][aa][tx_offset])[0]= ((short*)dummy_tx_buffer)[2*i]<<4; ((short*)&PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][aa][tx_offset])[1]= ((short*)dummy_tx_buffer)[2*i+1]<<4; } #endif //EXMIMO } } }// end of PHY procedure #endif //IFFT_FPGA }// end of frame>5 // update slot index t_slot_idx = next_slot; // this slot is ready to send r_slot_idx++; if(r_slot_idx==20) { r_slot_idx = 0; frame++; } }// end of while format_printf(1,"\n[eNB thread] Received oai_exit signal. Ends. Ran %d frames. num_slot_missed: %d\n",frame, num_slot_missed); #ifdef HARD_RT rt_make_soft_real_time(); #endif // clean task #ifdef RTAI rt_task_delete(task); #endif return 0; } /* 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). */ static void *UE_thread(void *arg) { printf("Start UE Client...\n\n"); bind_thread2kernel(2); #ifdef RTAI RT_TASK *task; #endif int slot=0,last_slot, next_slot,frame=0; unsigned int aa,slot_offset, slot_offset_F; int diff = 0; int i; int num_slot_missed = 0; static int is_synchronized = 0; static int received_slots = 0; static int slot0 = 0; static int first_run=1; #ifdef RTAI task = rt_task_init_schmod(nam2num("TASK0"), 0, 0, 0, SCHED_FIFO, 0xF); LOG_D(HW,"Started UE thread (id %p)\n",task); //if(task==NULL) printf("RT Task creation failed\n"); else printf("Task success!\n"); #endif mlockall(MCL_CURRENT | MCL_FUTURE); #ifdef HARD_RT rt_make_hard_real_time(); #endif // initialize reading postition r_slot_idx = 0; t_slot_idx = 0; frame = 0; openair_daq_vars.freq_offset = 0; //-7500; set_freq(openair_daq_vars.freq_offset); if (mode == rx_calib_ue) { openair_daq_vars.freq_offset = -7500; set_freq(openair_daq_vars.freq_offset); } usleep(10000*(7.68/6.25));//wait frame data fill in buff //test synchronized or not char test_synchronize = 1; while (!oai_exit) { if (is_synchronized) { //test is synchronized or not if(test_synchronize) {printf("Found cell ,UE synchronized! hw_frm_head_pos = %d\n",hw_frm_head_pos); test_synchronize = 0;} format_printf(g_usrp_debug,"[UE ] r_ue: %d w_usrp: %d num_slot_missed: %d diff: %d\n",r_slot_idx,w_slot_usrp_rcv, num_slot_missed,diff); // Update 'diff'. Handle the frame wrap-arround if ((w_slot_usrp_rcv<4)&&(r_slot_idx>=16)){ diff = r_slot_idx - (w_slot_usrp_rcv + 20) ; } else if((w_slot_usrp_rcv>=16)&&(r_slot_idx<4)){ diff = (r_slot_idx + 20) - w_slot_usrp_rcv; } else{ diff = r_slot_idx - w_slot_usrp_rcv; } // Reading is too slow. It's already late. if(diff < -4) { r_slot_idx++; num_slot_missed += abs(diff + 4); if(r_slot_idx==20){ r_slot_idx = 0; frame++; } continue; } // Wait for writing while((diff > 0)&& (!oai_exit)) { usleep(500); // Update 'diff'. Handle the frame wrap-arround if ((w_slot_usrp_rcv<4)&&(r_slot_idx>=16)){ diff = r_slot_idx - (w_slot_usrp_rcv + 20) ; } else if((w_slot_usrp_rcv>=16)&&(r_slot_idx<4)){ diff = (r_slot_idx + 20) - w_slot_usrp_rcv; } else{ diff = r_slot_idx - w_slot_usrp_rcv; } } // The slot is ready last_slot = r_slot_idx; next_slot = (r_slot_idx + N_slot_offset)%LTE_SLOTS_PER_FRAME; format_printf(g_usrp_debug, "[UE ] r_ue: %d w_usrp: %d last_slot: %d next_slot: %d diff: %d\n\n",r_slot_idx,w_slot_usrp_rcv,last_slot, next_slot,diff); PHY_vars_UE_g[0]->frame = frame; //phy_procedures_UE_lte (last_slot, next_slot, PHY_vars_UE_g[0], 0, 0,mode);//for OAI version after 4160 phy_procedures_UE_lte (last_slot, next_slot, PHY_vars_UE_g[0], 0, 0,mode,0,NULL); // update slot index t_slot_idx = next_slot; // this slot is ready to send r_slot_idx++; if(r_slot_idx==20) { r_slot_idx = 0; frame++; } } else // we are not yet synchronized { hw_frm_head_pos = 0; slot = 0; if (initial_sync(PHY_vars_UE_g[0],mode)==0) { // acquired synchronization if (mode == rx_calib_ue) { oai_exit=1; } else { is_synchronized = 1; hw_frm_head_pos = PHY_vars_UE_g[0]->rx_offset; LOG_D(HW,"Got synch: hw_frm_head_pos %d\n",hw_frm_head_pos); } } else { // Not acquired synchronization. Adjust carrier frequency. if (openair_daq_vars.freq_offset >= 0) { openair_daq_vars.freq_offset += 100; // FIXME HL_CHECK why add 100Hz here openair_daq_vars.freq_offset *= -1; } else { openair_daq_vars.freq_offset *= -1; } if (abs(openair_daq_vars.freq_offset) > 7500) { // cannot handle the frequency offset larger than 7.5KHz LOG_I(PHY,"[initial_sync] No cell synchronization found, abondoning\n"); mac_xface->macphy_exit(""); oai_exit = 1; } else { LOG_I(PHY,"[initial_sync] trying carrier off %d Hz\n",openair_daq_vars.freq_offset); set_freq(openair_daq_vars.freq_offset); } } } } LOG_D(HW,"UE_thread: finished, ran %d times.\n",frame); format_printf(1,"\n[UE thread] Received oai_exit signal. Ends. Ran %d frames. num_slot_missed: %d\n",frame, num_slot_missed); #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; } int main(int argc, char **argv) { #ifdef RTAI RT_TASK *task; #endif int i,j,aa; void *status; /* u32 rf_mode_max[4] = {55759,55759,55759,55759}; u32 rf_mode_med[4] = {39375,39375,39375,39375}; u32 rf_mode_byp[4] = {22991,22991,22991,22991}; */ u32 my_rf_mode = RXEN + TXEN + TXLPFNORM + TXLPFEN + TXLPF25 + RXLPFNORM + RXLPFEN + RXLPF25 + LNA1ON +LNAMax + RFBBNORM + DMAMODE_RX + DMAMODE_TX; u32 my_rf_mode2 = RXEN + TXLPFNORM + TXLPFEN + TXLPF25 + RXLPFNORM + RXLPFEN + RXLPF25 + LNA1ON +LNAMax + RFBBNORM + DMAMODE_RX; u32 rf_mode[4] = {my_rf_mode,my_rf_mode2,0,0}; u32 rf_local[4] = {8255000,8255000,8255000,8255000}; // UE zepto //{8254617, 8254617, 8254617, 8254617}; //eNB khalifa //{8255067,8254810,8257340,8257340}; // eNB PETRONAS u32 rf_vcocal[4] = {910,910,910,910}; u32 rf_vcocal_850[4] = {2015, 2015, 2015, 2015}; u32 rf_rxdc[4] = {32896,32896,32896,32896}; u32 rxgain[4] = {20,20,20,20}; u32 txgain[4] = {25,25,25,25}; u16 Nid_cell = 0; u8 cooperation_flag=0, transmission_mode=1, abstraction_flag=0; u8 beta_ACK=0,beta_RI=0,beta_CQI=2; int c; char do_forms=0; unsigned int fd; unsigned int tcxo = 114; int amp; u8 prach_fmt; int N_ZC; char rxg_fname[100]; char txg_fname[100]; char rflo_fname[100]; char rfdc_fname[100]; FILE *rxg_fd=NULL; FILE *txg_fd=NULL; FILE *rflo_fd=NULL; FILE *rfdc_fd=NULL; 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; char line[1000]; int l; int ret, ant; int error_code; const struct option long_options[] = { {"calib-ue-rx", required_argument, NULL, 256}, {"calib-ue-rx-med", required_argument, NULL, 257}, {"calib-ue-rx-byp", required_argument, NULL, 258}, {"debug-ue-prach", no_argument, NULL, 259}, {"no-L2-connect", no_argument, NULL, 260}, {NULL, 0, NULL, 0}}; mode = normal_txrx; while ((c = getopt_long (argc, argv, "C:ST:UdF:V:Dn:",long_options,NULL)) != -1) { switch (c) { case 'D': printf("Enable debug output. \n\n"); g_usrp_debug = 1; break; case 'V': ouput_vcd = 1; break; case 'd': do_forms=1; break; case 'U': UE_flag = 1; 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 'S': fs4_test=1; break; case 'T': tcxo=atoi(optarg); break; case 'n': N_slot_cycle=atoi(optarg); break; case 'F': 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); sprintf(txg_fname,"%stxg.lime",optarg); txg_fd = fopen(txg_fname,"r"); if (txg_fd) { printf("Loading TX Gain parameters from %s\n",txg_fname); l=0; while (fgets(line, sizeof(line), txg_fd)) { if ((strlen(line)==0) || (*line == '#')) { continue; //ignore empty or comment lines } else { if (l==0) sscanf(line,"%d %d %d %d",&txgain[0],&txgain[1],&txgain[2],&txgain[3]); if (l==1) sscanf(line,"%d",&tx_max_power); l++; } } } else printf("%s not found, running with defaults\n",txg_fname); sprintf(rflo_fname,"%srflo.lime",optarg); rflo_fd = fopen(rflo_fname,"r"); if (rflo_fd) { printf("Loading RF LO parameters from %s\n",rflo_fname); fscanf(rflo_fd,"%d %d %d %d",&rf_local[0],&rf_local[1],&rf_local[2],&rf_local[3]); } else printf("%s not found, running with defaults\n",rflo_fname); sprintf(rfdc_fname,"%srfdc.lime",optarg); rfdc_fd = fopen(rfdc_fname,"r"); if (rfdc_fd) { printf("Loading RF DC parameters from %s\n",rfdc_fname); fscanf(rfdc_fd,"%d %d %d %d",&rf_rxdc[0],&rf_rxdc[1],&rf_rxdc[2],&rf_rxdc[3]); } else printf("%s not found, running with defaults\n",rfdc_fname); break; case 256: mode = rx_calib_ue; rx_input_level_dBm = atoi(optarg); printf("Running with UE calibration on (LNA max), input level %d dBm\n",rx_input_level_dBm); break; case 257: mode = rx_calib_ue_med; rx_input_level_dBm = atoi(optarg); printf("Running with UE calibration on (LNA med), input level %d dBm\n",rx_input_level_dBm); break; case 258: mode = rx_calib_ue_byp; rx_input_level_dBm = atoi(optarg); printf("Running with UE calibration on (LNA byp), input level %d dBm\n",rx_input_level_dBm); break; case 259: mode = debug_prach; break; case 260: mode = no_L2_connect; break; default: break; } } if (UE_flag==1) printf("configuring for UE\n"); else printf("configuring for eNB\n"); //randominit (0); set_taus_seed (0); // initialize the log (see log.h for details) logInit(); if (ouput_vcd) { if (UE_flag==1) vcd_signal_dumper_init("/tmp/openair_dump_UE.vcd"); else vcd_signal_dumper_init("/tmp/openair_dump_eNB.vcd"); } #ifdef NAS_NETLINK netlink_init(); #endif // to make a graceful exit when ctrl-c is pressed //signal(SIGSEGV, signal_handler); //signal(SIGINT, signal_handler); #ifndef RTAI check_clock(); #endif // init the parameters frame_parms = (LTE_DL_FRAME_PARMS*) malloc(sizeof(LTE_DL_FRAME_PARMS)); frame_parms->N_RB_DL = 25; frame_parms->N_RB_UL = 25; frame_parms->Ncp = 0; frame_parms->Ncp_UL = 0; frame_parms->Nid_cell = Nid_cell; frame_parms->nushift = 0; frame_parms->nb_antennas_tx_eNB = 1; //initial value overwritten by initial sync later // frame_parms->nb_antennas_tx = (UE_flag==0) ? 1 : 1; // frame_parms->nb_antennas_rx = (UE_flag==0) ? 1 : 1; frame_parms->nb_antennas_tx = 1; frame_parms->nb_antennas_rx = 1; frame_parms->mode1_flag = (transmission_mode == 1) ? 1 : 0; frame_parms->frame_type = 1; frame_parms->tdd_config = 3; frame_parms->tdd_config_S = 0; frame_parms->phich_config_common.phich_resource = oneSixth; frame_parms->phich_config_common.phich_duration = normal; // UL RS Config frame_parms->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift = 0;//n_DMRS1 set to 0 frame_parms->pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled = 0; frame_parms->pusch_config_common.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled = 0; frame_parms->pusch_config_common.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH = 0; //print [PHY] ... message init_ul_hopping(frame_parms); //print [PHY][I][INIT]... message init_frame_parms(frame_parms,1); phy_init_top(frame_parms); phy_init_lte_top(frame_parms); //init prach for openair1 test frame_parms->prach_config_common.rootSequenceIndex=22; frame_parms->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig=1; frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex=0; frame_parms->prach_config_common.prach_ConfigInfo.highSpeedFlag=0; frame_parms->prach_config_common.prach_ConfigInfo.prach_FreqOffset=0; prach_fmt = get_prach_fmt(frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex, frame_parms->frame_type); N_ZC = (prach_fmt <4)?839:139; if (UE_flag==1) { #ifdef OPENAIR2 g_log->log_component[PHY].level = LOG_INFO; #else g_log->log_component[PHY].level = LOG_INFO; #endif g_log->log_component[PHY].flag = LOG_HIGH; g_log->log_component[MAC].level = LOG_INFO; g_log->log_component[MAC].flag = LOG_HIGH; g_log->log_component[RLC].level = LOG_INFO; g_log->log_component[RLC].flag = LOG_HIGH; g_log->log_component[PDCP].level = LOG_INFO; g_log->log_component[PDCP].flag = LOG_HIGH; g_log->log_component[OTG].level = LOG_INFO; g_log->log_component[OTG].flag = LOG_HIGH; g_log->log_component[RRC].level = LOG_INFO; g_log->log_component[RRC].flag = LOG_HIGH; PHY_vars_UE_g = malloc(sizeof(PHY_VARS_UE*)); //print [PHY][I][init_lte_eNB]... messages PHY_vars_UE_g[0] = init_lte_UE(frame_parms, UE_id,abstraction_flag,transmission_mode); #ifndef OPENAIR2 for (i=0;ipusch_config_dedicated[i].betaOffset_ACK_Index = beta_ACK; PHY_vars_UE_g[0]->pusch_config_dedicated[i].betaOffset_RI_Index = beta_RI; PHY_vars_UE_g[0]->pusch_config_dedicated[i].betaOffset_CQI_Index = beta_CQI; PHY_vars_UE_g[0]->scheduling_request_config[i].sr_PUCCH_ResourceIndex = UE_id; PHY_vars_UE_g[0]->scheduling_request_config[i].sr_ConfigIndex = 7+(UE_id%3); PHY_vars_UE_g[0]->scheduling_request_config[i].dsr_TransMax = sr_n4; } #endif compute_prach_seq(&PHY_vars_UE_g[0]->lte_frame_parms.prach_config_common, PHY_vars_UE_g[0]->lte_frame_parms.frame_type, PHY_vars_UE_g[0]->X_u); PHY_vars_UE_g[0]->lte_ue_pdcch_vars[0]->crnti = 0x1234; #ifndef OPENAIR2 PHY_vars_UE_g[0]->lte_ue_pdcch_vars[0]->crnti = 0x1235; #endif NB_UE_INST=1; NB_INST=1; openair_daq_vars.manual_timing_advance = 0; //openair_daq_vars.timing_advance = TIMING_ADVANCE_HW; openair_daq_vars.rx_gain_mode = DAQ_AGC_OFF; openair_daq_vars.auto_freq_correction = 0; openair_daq_vars.use_ia_receiver = 1; // if AGC is off, the following values will be used // for (i=0;i<4;i++) // rxgain[i] = 20; rxgain[0] = 20; rxgain[1] = 20; rxgain[2] = 20; rxgain[3] = 20; for (i=0;i<4;i++) { PHY_vars_UE_g[0]->rx_gain_max[i] = rxg_max[i]; PHY_vars_UE_g[0]->rx_gain_med[i] = rxg_med[i]; PHY_vars_UE_g[0]->rx_gain_byp[i] = rxg_byp[i]; } if ((mode == normal_txrx) || (mode == rx_calib_ue) || (mode == no_L2_connect) || (mode == debug_prach)) { for (i=0; i<4; i++) { PHY_vars_UE_g[0]->rx_gain_mode[i] = max_gain; // frame_parms->rfmode[i] = rf_mode_max[i]; rf_mode[i] = (rf_mode[i] & (~LNAGAINMASK)) | LNAMax; } PHY_vars_UE_g[0]->rx_total_gain_dB = PHY_vars_UE_g[0]->rx_gain_max[0] + rxgain[0] - 30; //-30 because it was calibrated with a 30dB gain } else if ((mode == rx_calib_ue_med)) { for (i=0; i<4; i++) { PHY_vars_UE_g[0]->rx_gain_mode[i] = med_gain; // frame_parms->rfmode[i] = rf_mode_med[i]; rf_mode[i] = (rf_mode[i] & (~LNAGAINMASK)) | LNAMed; } PHY_vars_UE_g[0]->rx_total_gain_dB = PHY_vars_UE_g[0]->rx_gain_med[0] + rxgain[0] - 30; //-30 because it was calibrated with a 30dB gain; } else if ((mode == rx_calib_ue_byp)) { for (i=0; i<4; i++) { PHY_vars_UE_g[0]->rx_gain_mode[i] = byp_gain; // frame_parms->rfmode[i] = rf_mode_byp[i]; rf_mode[i] = (rf_mode[i] & (~LNAGAINMASK)) | LNAByp; } PHY_vars_UE_g[0]->rx_total_gain_dB = PHY_vars_UE_g[0]->rx_gain_byp[0] + rxgain[0] - 30; //-30 because it was calibrated with a 30dB gain; } PHY_vars_UE_g[0]->tx_power_max_dBm = tx_max_power; printf("tx_max_power = %d -> amp %d\n",tx_max_power,get_tx_amp(tx_max_power,tx_max_power)); } else { //this is eNB #ifdef OPENAIR2 g_log->log_component[PHY].level = LOG_INFO; #else g_log->log_component[PHY].level = LOG_INFO; #endif g_log->log_component[PHY].flag = LOG_HIGH; g_log->log_component[MAC].level = LOG_INFO; g_log->log_component[MAC].flag = LOG_HIGH; g_log->log_component[RLC].level = LOG_INFO; g_log->log_component[RLC].flag = LOG_HIGH; g_log->log_component[PDCP].level = LOG_INFO; g_log->log_component[PDCP].flag = LOG_HIGH; g_log->log_component[OTG].level = LOG_INFO; g_log->log_component[OTG].flag = LOG_HIGH; g_log->log_component[RRC].level = LOG_INFO; g_log->log_component[RRC].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 compute_prach_seq(&PHY_vars_eNB_g[0]->lte_frame_parms.prach_config_common, PHY_vars_eNB_g[0]->lte_frame_parms.frame_type, PHY_vars_eNB_g[0]->X_u); NB_eNB_INST=1; NB_INST=1; openair_daq_vars.ue_dl_rb_alloc=0x1fff; openair_daq_vars.target_ue_dl_mcs=20; openair_daq_vars.ue_ul_nb_rb=6; openair_daq_vars.target_ue_ul_mcs=9; // if AGC is off, the following values will be used // for (i=0;i<4;i++) // rxgain[i]=30; rxgain[0] = 20; rxgain[1] = 20; rxgain[2] = 20; rxgain[3] = 20; // 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; } } dump_frame_parms(frame_parms); mac_xface = malloc(sizeof(MAC_xface)); #ifdef OPENAIR2 int eMBMS_active=0; //print [MAC][I]... messages //l2_init(frame_parms,eMBMS_active); l2_init(frame_parms,eMBMS_active, 0,// cba_group_active 0); // HO flag if (UE_flag == 1) mac_xface->dl_phy_sync_success (0, 0, 0, 1); else mac_xface->mrbch_phy_sync_failure (0, 0, 0); #endif mac_xface->macphy_exit = &exit_fun; #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; inum_nodes; i++){ for (j=0; jnum_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(); //USRP INIT UHD_init(); UHD_init_display(); Init_send(); Init_recv(); printf("USRP init DONE...\n"); // } #endif // connect the TX/RX buffers if (UE_flag==1) { setup_ue_buffers(PHY_vars_UE_g[0],frame_parms,0); printf("Setting UE buffer to all-RX\n"); } else { setup_eNB_buffers(PHY_vars_eNB_g[0],frame_parms,0); if (fs4_test==0) { printf("Setting eNB buffer to all-RX\n"); } else { printf("Setting eNB buffer to fs/4 test signal\n"); for (j=0; jlte_frame_parms.samples_per_tti*10; j+=4) for (aa=0; aanb_antennas_tx; aa++) { amp = 0x8000; ((short*)PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][aa])[2*j+1] = 0; ((short*)PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][aa])[2*j+3] = amp-1; ((short*)PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][aa])[2*j+5] = 0; ((short*)PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][aa])[2*j+7] = amp; ((short*)PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][aa])[2*j] = amp-1; ((short*)PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][aa])[2*j+2] = 0; ((short*)PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][aa])[2*j+4] = amp; ((short*)PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][aa])[2*j+6] = 0; } } } //rt_sleep_ns(10*FRAME_PERIOD);//delay one second #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 if (UE_flag == 1) { #ifdef RTAI thread1 = rt_thread_create(UE_thread, NULL, 100000000); thread_recv = rt_thread_create(usrp_thread, NULL, 100000000); #else error_code = pthread_create(&thread1, &attr_dlsch_threads, 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_create(&thread_recv, NULL, usrp_thread, NULL); #endif #ifdef DLSCH_THREAD//defined init_rx_pdsch_thread(); //rt_sleep_ns(FRAME_PERIOD/10); init_dlsch_threads(); #endif } else { #ifdef RTAI thread0 = rt_thread_create(eNB_thread, NULL, 100000000); thread_recv = rt_thread_create(usrp_thread, NULL, 100000000); #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"); } pthread_create(&thread_recv, NULL, usrp_thread, NULL); #endif #ifdef ULSCH_THREAD//not defined init_ulsch_threads(); #endif } pthread_create(&thread_tx_error, NULL, tx_error_handler, NULL); // wait for end of program usleep(500); printf("TYPE TO TERMINATE\n"); signal(SIGINT, &sig_int_handler); while (oai_exit==0) sleep(1); // cleanup pthread_join(thread_tx_error,&status); if (UE_flag == 1) { #ifdef RTAI rt_thread_join(thread1); rt_thread_join(thread_recv); #else pthread_join(thread1,&status); pthread_join(thread_recv,&status); #endif #ifdef DLSCH_THREAD printf("waiting for DLSCH_THREAD thread\n"); cleanup_dlsch_threads(); cleanup_rx_pdsch_thread(); #endif } else { #ifdef RTAI printf("Cleanup eNB thread and usrp thread\n"); rt_thread_join(thread0); rt_thread_join(thread_recv); #else pthread_join(thread0,&status); pthread_join(thread_recv,&status); #endif #ifdef ULSCH_THREAD printf("waiting for ULSCH_THREAD thread\n"); cleanup_ulsch_threads(); #endif } logClean(); printf("Program Done!\n"); return 0; } void test_config(int card, int ant, unsigned int rf_mode, int UE_flag) { p_exmimo_config->framing.eNB_flag = !UE_flag; p_exmimo_config->framing.tdd_config = 0; p_exmimo_config->framing.resampling_factor = 2; p_exmimo_config->rf.rf_freq_rx[ant] = 1907600000; p_exmimo_config->rf.rf_freq_tx[ant] = 1907600000;; p_exmimo_config->rf.rx_gain[ant][0] = 20; p_exmimo_config->rf.tx_gain[ant][0] = 10; p_exmimo_config->rf.rf_mode[ant] = rf_mode; p_exmimo_config->rf.rf_local[ant] = build_rflocal(20,25,26,04); p_exmimo_config->rf.rf_rxdc[ant] = build_rfdc(128, 128); p_exmimo_config->rf.rf_vcocal[ant] = (0xE<<6) + 0xE; } void setup_ue_buffers(PHY_VARS_UE *phy_vars_ue, LTE_DL_FRAME_PARMS *frame_parms, int carrier) { int i; if (phy_vars_ue) { 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_ue->lte_ue_common_vars.rxdata[i]); phy_vars_ue->lte_ue_common_vars.rxdata[i] = (s32*) oai_rx_buff; printf("rxdata[%d] @ %p\n",i,phy_vars_ue->lte_ue_common_vars.rxdata[i]); } for (i=0;inb_antennas_tx;i++) { free(phy_vars_ue->lte_ue_common_vars.txdata[i]); phy_vars_ue->lte_ue_common_vars.txdata[i] = (s32*) oai_tx_buff; printf("txdata[%d] @ %p\n",i,phy_vars_ue->lte_ue_common_vars.txdata[i]); } } } void setup_eNB_buffers(PHY_VARS_eNB *phy_vars_eNB, LTE_DL_FRAME_PARMS *frame_parms, int carrier) { int i; 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] = (s32 *) oai_rx_buff; 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] = (s32 *) oai_tx_buff; 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; }*/ } } }