/******************************************************************************* 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@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 <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/mman.h> #include <sys/stat.h> #include <fcntl.h> #include <sched.h> #include <signal.h> #include <execinfo.h> #include <getopt.h> #include "rt_wrapper.h" #include "PHY/types.h" #include "PHY/TOOLS/defs.h" #include "openair0_lib.h" #include "UTIL/LOG/log.h" #include "UTIL/LOG/vcd_signal_dumper.h" #include "gain_control.h" #if defined(ENABLE_ITTI) # include "intertask_interface_init.h" # include "timer.h" # if defined(ENABLE_USE_MME) # include "s1ap_eNB.h" # include "sctp_eNB_task.h" # endif #endif #define OPENAIR_THREAD_PRIORITY 255 #define OPENAIR_THREAD_STACK_SIZE 8192 #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]; unsigned char scope_enb_num_ue = 1; */ #include "lte_scope.h" FD_lte_scope *form_lte; char title[255]; #endif //XFORMS #ifdef EMOS #include <gps.h> struct gps_fix_t dummy_gps_data; #ifdef RTAI #include <rtai_fifos.h> #endif //#define CHANSOUNDER_FIFO_SIZE 10485760 // 10 Mbytes FIFO //#define CHANSOUNDER_FIFO_SIZE 20971520 // 20 Mbytes FIFO #define CHANSOUNDER_FIFO_SIZE 52428800 // 50 Mbytes FIFO //#define CHANSOUNDER_FIFO_SIZE 104857600 // 100 Mbytes FIFO //#define CHANSOUNDER_FIFO_SIZE 1073741824 // 1Gbyte FIFO #define CHANSOUNDER_FIFO_MINOR 4 // minor of the FIFO device - this is /dev/rtf3 #define CHANSOUNDER_FIFO_DEV "/dev/rtf4" #endif #define FRAME_PERIOD 100000000ULL #define DAQ_PERIOD 66667ULL #define LTE_SLOTS_PER_FRAME 20 //#define RESAMPLING_FACTOR 0 #define SAMPLES_PER_SLOT 15360 #define FRAME_LENGTH_COMPLEX_SAMPLES (SAMPLES_PER_SLOT*LTE_SLOTS_PER_FRAME) #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 long int thread0; //static long int thread1; //static long 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; //xforms pthread_t thread3; //emos pthread_t thread4; //GPS pthread_t thread5; //log /* 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 number_of_cards = 1; exmimo_config_t *p_exmimo_config; exmimo_id_t *p_exmimo_id; volatile unsigned int *DAQ_MBOX; int oai_exit = 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}; int fs4_test=0; char UE_flag=0; uint8_t eNB_id=0,UE_id=0; // this array sets the bandwidth used for each card (and applies to all chains on one card). exmimo_bw_t bandwidth[MAX_CARDS] = {BW5,BW5,BW5,BW5}; // the array carrier_freq sets the frequency for each chain of each card. A 0 means that the chain is disabled. // Please make sure that the total number of channels enabled per card is in accordance with the following rules: // BW20: one channel, BW10: 2 channels, BW5: 4 channels //uint32_t carrier_freq[MAX_CARDS][4] = {{2590000000,0,0,0},{2590000000,0,0,0},{2605000000,2605000000,0,0},{0,0,0,0}}; //uint32_t carrier_freq[MAX_CARDS][4] = {{2590000000,0,0,0},{2605000000,2605000000,0,0},{0,0,0,0},{0,0,0,0}}; uint32_t carrier_freq[MAX_CARDS][4] = {{771500000,771500000,771500000,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}; // the following paramters set the aquisition time and period. These parameters have to be set in accordance with the write speed of your harddisk and the required throughput according to the setting above (see also channel_buffer_size which is computed later). #define AQU_LENGTH_FRAMES 100 //Aquisition time in frames #define AQU_PERIOD_FRAMES 100 //Repetition time of aquisition in frames #define AQU_LENGTH_SLOTS (AQU_LENGTH_FRAMES*LTE_SLOTS_PER_FRAME) //Aquisition time in slots #define AQU_PERIOD_SLOTS (AQU_PERIOD_FRAMES*LTE_SLOTS_PER_FRAME) //Repetition time of aquisition in slots int32_t rx_total_gain_dB[3] = {-112, -124, -136}; /* // this array sets the bandwidth used for each card (and applies to all chains on one card). exmimo_bw_t bandwidth[MAX_CARDS] = {BW20,BW20,BW10,BW5}; // the array carrier_freq sets the frequency for each chain of each card. A 0 means that the chain is disabled. // Please make sure that the total number of channels enabled per card is in accordance with the following rules: // BW20: one channel, BW10: 2 channels, BW5: 4 channels uint32_t carrier_freq[MAX_CARDS][4] = {{2590000000,0,0,0},{2590000000,0,0,0},{2605000000,2605000000,0,0},{0,0,0,0}}; //uint32_t carrier_freq[MAX_CARDS][4] = {{2590000000,0,0,0},{2605000000,2605000000,0,0},{0,0,0,0},{0,0,0,0}}; //uint32_t carrier_freq[MAX_CARDS][4] = {{2590000000,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}; // the following paramters set the aquisition time and period. These parameters have to be set in accordance with the write speed of your harddisk and the required throughput according to the setting above (see also channel_buffer_size which is computed later). #define AQU_LENGTH_FRAMES 100 //Aquisition time in frames #define AQU_PERIOD_FRAMES 200 //Repetition time of aquisition in frames #define AQU_LENGTH_SLOTS (AQU_LENGTH_FRAMES*LTE_SLOTS_PER_FRAME) //Aquisition time in slots #define AQU_PERIOD_SLOTS (AQU_PERIOD_FRAMES*LTE_SLOTS_PER_FRAME) //Repetition time of aquisition in slots int32_t rx_total_gain_dB[3] = {-105, -110, -115}; */ char dumpfile_dir[256] = "/mnt/emos"; char *conf_config_file_name = NULL; unsigned int lost_bytes=0; unsigned int rssi_lin[MAX_CARDS][4],rssi_lin_max[MAX_CARDS],rssi_lin_avg[MAX_CARDS]; uint8_t rssi_avg_dB[MAX_CARDS]; long long unsigned int total_bytes=0; 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 int16_t* sync_corr_ue0; extern int16_t prach_ifft[4][1024*2]; unsigned int frame; int rx_input_level_dBm; #ifdef XFORMS extern int otg_enabled; #else int otg_enabled; #endif 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[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 //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(int txi, int txq, int rxi, int 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); } #ifdef XFORMS extern void ia_receiver_on_off( FL_OBJECT * form, long arg) {} void *scope_thread(void *arg) { int16_t prach_corr[1024]; char stats_buffer[16384]; //FILE *UE_stats, *eNB_stats; int i,len=0; float rxsig_t_dB[4][FRAME_LENGTH_COMPLEX_SAMPLES]; float time[FRAME_LENGTH_COMPLEX_SAMPLES]; struct sched_param sched_param; int card,ant,idx; sched_param.sched_priority = sched_get_priority_min(SCHED_FIFO)+1; sched_setscheduler(0, SCHED_FIFO,&sched_param); printf("Scope thread has priority %d\n",sched_param.sched_priority); /* if (UE_flag==1) UE_stats = fopen("UE_stats.txt", "w"); else eNB_stats = fopen("eNB_stats.txt", "w"); */ while (!oai_exit) { /* if (UE_flag==1) { len = dump_ue_stats (PHY_vars_UE_g[0], stats_buffer, 0, mode,rx_input_level_dBm); fl_set_object_label(form_stats->stats_text, stats_buffer); //rewind (UE_stats); //fwrite (stats_buffer, 1, len, UE_stats); phy_scope_UE(form_ue[UE_id], PHY_vars_UE_g[UE_id], eNB_id, UE_id,7); } else { 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_id<scope_enb_num_ue;UE_id++) { phy_scope_eNB(form_enb[UE_id], PHY_vars_eNB_g[eNB_id], UE_id); } } */ idx = 0; for (card=0;card<number_of_cards;card++) { for (ant=0;ant<4;ant++) { if ((carrier_freq[card][ant] != 0) && (idx<4)) { len = FRAME_LENGTH_COMPLEX_SAMPLES/(1<<openair0_exmimo_pci[card].exmimo_config_ptr->framing.resampling_factor[ant]); for (i=0; i<len; i++) { //rxsig_t_dB[0][i] = 10*log10(1.0+(float) ((((int16_t*) openair0_exmimo_pci[card].adc_head[0])[2*i])*(((int16_t*) openair0_exmimo_pci[card].adc_head[0])[2*i])+(((int16_t*) openair0_exmimo_pci[card].adc_head[0])[2*i+1])*(((int16_t*) openair0_exmimo_pci[card].adc_head[0])[2*i+1]))); rxsig_t_dB[0][i] = (float) ((((int16_t*) openair0_exmimo_pci[card].adc_head[ant])[2*i])); rxsig_t_dB[1][i] = (float) ((((int16_t*) openair0_exmimo_pci[card].adc_head[ant])[2*i+1])); time[i] = (float) i; } fl_set_xyplot_data(form_lte->channel_t_re[idx],time,rxsig_t_dB[0],len,"","",""); fl_set_xyplot_data(form_lte->channel_t_im[idx],time,rxsig_t_dB[1],len,"","",""); idx++; } } } //printf("doing forms\n"); usleep(100000); } //fclose (UE_stats); //fclose (eNB_stats); pthread_exit((void*)arg); } #endif int dummy_tx_buffer[3840*4] __attribute__((aligned(16))); #ifdef EMOS 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 *log_thread (void *arg) { //struct tm now_sec; struct timeval now; int card; FILE *logfile_id; char logfile_name[1024]; time_t starttime_tmp; struct tm starttime; //open file time(&starttime_tmp); localtime_r(&starttime_tmp,&starttime); snprintf(logfile_name,1024,"%s/%s_data_%d%02d%02d_%02d%02d%02d.log", dumpfile_dir, (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); logfile_id = fopen(logfile_name,"w"); if ((logfile_id == NULL)) { fprintf(stderr, "[EMOS] Error opening logfile %s\n",logfile_name); exit(EXIT_FAILURE); } fprintf(logfile_id,"#time, frame, total bytes wrote, total bytes lost, GPS time, GPS mode, lat, lon, alt, speed, rssi_lin_max[0], rssi_lin_avg[0], rssi_avg_dBm[0], rssi_avg_dB[0], rx_gain[0], LNA[0], ...\n"); while (!oai_exit) { gettimeofday(&now,NULL); //localtime_r(&(now.tv_sec),&now_sec); fprintf(logfile_id,"%d.%06d, %d, %llu, %u, %e, %d, %e, %e, %e, %e, ", (int) now.tv_sec, (int)now.tv_usec, frame, total_bytes,lost_bytes, dummy_gps_data.time, dummy_gps_data.mode, dummy_gps_data.latitude, dummy_gps_data.longitude, dummy_gps_data.altitude, dummy_gps_data.speed); for (card=0;card<number_of_cards;card++) if (carrier_freq[card][0] != 0) fprintf(logfile_id,"%d, %d, %d, %d, %d, %d, ", rssi_lin_max[card], rssi_lin_avg[card], rssi_avg_dB[card] + rx_total_gain_dB[((openair0_exmimo_pci[card].exmimo_config_ptr->rf.rf_mode[0] & LNAGAINMASK) >> 14)-1] - openair0_exmimo_pci[card].exmimo_config_ptr->rf.rx_gain[0][0], rssi_avg_dB[card], openair0_exmimo_pci[card].exmimo_config_ptr->rf.rx_gain[0][0], (openair0_exmimo_pci[card].exmimo_config_ptr->rf.rf_mode[0] & LNAGAINMASK) >> 14); fprintf(logfile_id,"\n"); usleep(10000); } //close file fclose(logfile_id); 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; //time_t timer; struct tm now_sec; struct timeval now; struct sched_param sched_param; int ret; int card, ant; int channel_buffer_size=0; //in bytes pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL); 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); for (card=0; card<number_of_cards; card++) for (ant=0; ant<4; ant++) if (carrier_freq[card][ant] != 0) { printf("card %d, ant %d: freq %u, BW %d\n",card,ant,carrier_freq[card][ant],bandwidth[card]); channel_buffer_size += SAMPLES_PER_SLOT/(1<<openair0_exmimo_pci[card].exmimo_config_ptr->framing.resampling_factor[ant]); } channel_buffer_size *= 4; //4 bytes per sample // allocate memory for NO_FRAMES_DISK channes estimations fifo2file_buffer = malloc(AQU_LENGTH_SLOTS*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,"%s/%s_data_%d%02d%02d_%02d%02d%02d.EMOS", dumpfile_dir, (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 ...\n",channel_buffer_size); while (!oai_exit) { //bytes = rtf_read_timed(fifo, fifo2file_ptr, channel_buffer_size,100); 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] Frame %d: ERROR! Only got %d bytes instead of %d!\n",frame,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 ++; total_bytes += bytes; if ((counter%AQU_LENGTH_SLOTS)==0) { //reset stuff fifo2file_ptr = fifo2file_buffer; //counter = 0; printf("[EMOS] Frame %d: start writing %d bytes to disk\n",frame,AQU_LENGTH_SLOTS*channel_buffer_size); //flush buffer to disk if (fwrite(fifo2file_buffer, sizeof(char), AQU_LENGTH_SLOTS*channel_buffer_size, dumpfile_id) != AQU_LENGTH_SLOTS*channel_buffer_size) { fprintf(stderr, "[EMOS] Error writing to dumpfile\n"); exit(EXIT_FAILURE); } else printf("[EMOS] Frame %d: wrote %d bytes to disk\n",frame,AQU_LENGTH_SLOTS*channel_buffer_size); } if ((counter%AQU_LENGTH_SLOTS)==0) { //time(&starttime_tmp); gettimeofday(&now,NULL); localtime_r(&(now.tv_sec),&now_sec); printf("[EMOS] %02d:%02d:%02d.%03d, frame %d, total bytes wrote %llu, bytes lost %u\n", now_sec.tm_hour, now_sec.tm_min, now_sec.tm_sec, (int)(now.tv_usec/1000), frame, total_bytes,lost_bytes); for (card=0;card<number_of_cards;card++) if (carrier_freq[card][0] != 0) printf("[EMOS] %02d:%02d:%02d.%03d, card %d, rssi_lin_max %d, rssi_lin_avg %d, rssi_avg_dBm %d (rssi_avg_dB %d, rx_gain %d, LNA %d)\n", now_sec.tm_hour, now_sec.tm_min, now_sec.tm_sec, (int)(now.tv_usec/1000), card, rssi_lin_max[card], rssi_lin_avg[card], rssi_avg_dB[card] + rx_total_gain_dB[((openair0_exmimo_pci[card].exmimo_config_ptr->rf.rf_mode[0] & LNAGAINMASK) >> 14)-1] - openair0_exmimo_pci[card].exmimo_config_ptr->rf.rx_gain[0][0], rssi_avg_dB[card], openair0_exmimo_pci[card].exmimo_config_ptr->rf.rx_gain[0][0], (openair0_exmimo_pci[card].exmimo_config_ptr->rf.rf_mode[0] & LNAGAINMASK) >> 14); //printf("[EMOS] %02d:%02d:%02d, frame %d, GPS time %e, GPS mode %d, lat %e, lon %e, alt %e, speed %e\n", starttime.tm_hour, starttime.tm_min, starttime.tm_sec, counter/20, dummy_gps_data.time, dummy_gps_data.mode, dummy_gps_data.latitude, dummy_gps_data.longitude, dummy_gps_data.altitude, dummy_gps_data.speed); } } free(fifo2file_buffer); fclose(dumpfile_id); close(fifo); pthread_exit((void*) arg); } #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; #endif unsigned char slot=0,last_slot, next_slot, hw_slot; unsigned int msg1; unsigned int aa,slot_offset, slot_offset_F; int diff; int delay_cnt; RTIME time_in, time_diff; int mbox_target=0,mbox_current=0; int i,ret; int tx_offset; int bytes, bytes_tot=0, bytes_len; long long int k1=1000; long long int k2=1024-k1; int ant,len,card = 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); #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; while (!oai_exit) { 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]); //this is the mbox counter where we should be //mbox_target = ((((slot+1)%20)*15+1)>>1)%150; 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; if (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_D(HW,"eNB Frame %d, time %llu: missed slot, proceeding with next one (slot %d, hw_slot %d, diff %d)\n",frame, rt_get_time_ns(), slot, hw_slot, diff); slot++; //if (frame>0) //oai_exit=1; if (slot==20){ slot=0; frame++; } continue; } 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); 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); 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); 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 == 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; } last_slot = (slot)%LTE_SLOTS_PER_FRAME; if (last_slot <0) last_slot+=20; next_slot = (slot+3)%LTE_SLOTS_PER_FRAME; if (frame>=AQU_LENGTH_FRAMES) { timing_info.time_last = timing_info.time_now; timing_info.time_now = rt_get_time_ns(); if (timing_info.n_samples>0) { 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++; // do measurements for rssi if (last_slot==0) { for (card=0;card<number_of_cards;card++) { len = SAMPLES_PER_SLOT/(1<<openair0_exmimo_pci[card].exmimo_config_ptr->framing.resampling_factor[0]); rssi_lin_max[card] = 0; for (ant=0;ant<4;ant++) { if (carrier_freq[card][ant] != 0) { rssi_lin[card][ant] = signal_energy(&(((int32_t*) openair0_exmimo_pci[card].adc_head[ant])[last_slot*len]), len); rssi_lin_max[card] = max(rssi_lin_max[card],rssi_lin[card][ant]); } } rssi_lin_avg[card] = (int) ((k1*((long long int)(rssi_lin_avg[card])) + (k2*((long long int)(rssi_lin_max[card]))))>>10); rssi_avg_dB[card] = dB_fixed(rssi_lin_avg[card]); if (frame%100==0) { gain_control_all(rssi_avg_dB[card],card); //printf("AGC for card %d: rx_power_fil_dB=%d, rx_gain=%d, LNA=%d (1=Byp,2=Med,3=Max)\n",card,rssi_avg_dB,openair0_exmimo_pci[card].exmimo_config_ptr->rf.rx_gain[0][0],(openair0_exmimo_pci[card].exmimo_config_ptr->rf.rf_mode[0]&LNAGAINMASK)>>14); } } } #ifdef EMOS // save raw samples here if ((last_slot==0) && ((frame%AQU_PERIOD_FRAMES)==0)) { printf("[EMOS] Frame %d: start writing to FIFO\n",frame); bytes_tot=0; } if ((frame%AQU_PERIOD_FRAMES)<AQU_LENGTH_FRAMES) { for (card=0; card<number_of_cards; card++) { for (ant=0; ant<4; ant++) { if (carrier_freq[card][ant] != 0) { len = SAMPLES_PER_SLOT/(1<<openair0_exmimo_pci[card].exmimo_config_ptr->framing.resampling_factor[ant]); bytes_len = len*4; bytes = rtf_put(CHANSOUNDER_FIFO_MINOR, &(((int32_t*) openair0_exmimo_pci[card].adc_head[ant])[last_slot*len]), bytes_len); bytes_tot += bytes; if (bytes!=bytes_len) { lost_bytes += bytes_len - bytes; LOG_W(PHY,"Frame %d, slot %d: Problem writing EMOS data to FIFO (bytes=%d, size=%d)\n", frame, last_slot, bytes, bytes_len); } } } } if ((last_slot==19) && ((frame%AQU_PERIOD_FRAMES)==99)) printf("[EMOS] Frame %d: sent %d bytes to FIFO\n",frame,bytes_tot); } #endif } slot++; if (slot==20) { slot=0; frame++; } #if defined(ENABLE_ITTI) itti_update_lte_time(frame, slot); #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_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; int card = 0; uint32_t rf_mode_base = TXLPFNORM + TXLPFEN + RXLPFNORM + RXLPFEN + LNA1ON +LNAMax + RFBBNORM; 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}; uint32_t rxgain[4] = {30,30,30,30}; uint32_t txgain[4] = {0,0,0,0}; uint16_t Nid_cell = 0; uint8_t cooperation_flag=0, transmission_mode=1, abstraction_flag=0; uint8_t beta_ACK=0,beta_RI=0,beta_CQI=2; int c; char do_forms=0; unsigned int fd; unsigned int tcxo = 114; int amp; uint8_t 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 ant_offset=0; int error_code; char *itti_dump_file = NULL; 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:K:O:ST:UdF:V",long_options,NULL)) != -1) { switch (c) { case 'V': ouput_vcd = 1; break; case 'd': do_forms=1; break; case 'U': UE_flag = 1; break; case 'C': for (card=0;card<MAX_CARDS;card++) { carrier_freq[card][0] = atof(optarg); carrier_freq[card][1] = atof(optarg); carrier_freq[card][2] = atof(optarg); carrier_freq[card][3] = atof(optarg); } break; case 'S': fs4_test=1; break; case 'T': tcxo=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 '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 defined(ENABLE_ITTI) itti_init(TASK_MAX, THREAD_MAX, MESSAGES_ID_MAX, tasks_info, messages_info, messages_definition_xml, itti_dump_file); # if defined(ENABLE_USE_MME) if (itti_create_task(TASK_SCTP, sctp_eNB_task, NULL) < 0) { LOG_E(EMU, "Create task failed"); LOG_D(EMU, "Initializing SCTP task interface: FAILED\n"); return -1; } if (itti_create_task(TASK_S1AP, s1ap_eNB_task, NULL) < 0) { LOG_E(EMU, "Create task failed"); LOG_D(EMU, "Initializing S1AP task interface: FAILED\n"); return -1; } # endif if (itti_create_task(TASK_L2L1, l2l1_task, NULL) < 0) { LOG_E(EMU, "Create task failed"); LOG_D(EMU, "Initializing L2L1 task interface: FAILED\n"); return -1; } // Handle signals until all tasks are terminated // itti_wait_tasks_end(); #endif 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 g_log->log_component[HW].level = LOG_DEBUG; g_log->log_component[HW].flag = LOG_HIGH; #ifdef OPENAIR2 g_log->log_component[PHY].level = LOG_INFO; #else g_log->log_component[PHY].level = LOG_DEBUG; #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; // Initialize card ret = openair0_open(); if ( ret != 0 ) { if (ret == -1) printf("Error opening /dev/openair0"); if (ret == -2) printf("Error mapping bigshm"); if (ret == -3) printf("Error mapping RX or TX buffer"); return(ret); } number_of_cards = openair0_num_detected_cards; for (card=0; card<number_of_cards; card++) { printf ("Configuring card %d of %d (number of antennas %d).\n", card, 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 = !UE_flag; if (card==0) p_exmimo_config->framing.multicard_syncmode = SYNCMODE_MASTER; else p_exmimo_config->framing.multicard_syncmode = SYNCMODE_SLAVE; //p_exmimo_config->framing.multicard_syncmode = SYNCMODE_FREE; p_exmimo_config->framing.tdd_config = DUPLEXMODE_FDD + TXRXSWITCH_TESTRX; //TXRXSWITCH_LSB; /* for (ant=0;ant<max(frame_parms->nb_antennas_tx,frame_parms->nb_antennas_rx);ant++) p_exmimo_config->rf.rf_mode[ant] = rf_mode_base; for (ant=0;ant<frame_parms->nb_antennas_tx;ant++) p_exmimo_config->rf.rf_mode[ant] += (TXEN + DMAMODE_TX); for (ant=0;ant<frame_parms->nb_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 (carrier_freq[card][ant] != 0) { p_exmimo_config->rf.rf_mode[ant] = rf_mode_base; switch (bandwidth[card]) { case BW20: p_exmimo_config->framing.resampling_factor[ant] = 0; p_exmimo_config->rf.rf_mode[ant] += RXLPF10 + TXLPF10; break; case BW10: p_exmimo_config->framing.resampling_factor[ant] = 1; p_exmimo_config->rf.rf_mode[ant] += RXLPF5 + TXLPF5; break; case BW5: p_exmimo_config->framing.resampling_factor[ant] = 2; p_exmimo_config->rf.rf_mode[ant] += RXLPF25 + TXLPF25; break; } //p_exmimo_config->rf.rf_mode[ant] += (TXEN + DMAMODE_TX); p_exmimo_config->rf.rf_mode[ant] += (RXEN + DMAMODE_RX); } else { p_exmimo_config->rf.rf_mode[ant] = 0; } } for (ant = 0; ant<4; ant++) { p_exmimo_config->rf.do_autocal[ant] = 1; p_exmimo_config->rf.rf_freq_rx[ant] = carrier_freq[card][ant]; p_exmimo_config->rf.rf_freq_tx[ant] = carrier_freq[card][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[card][ant] >= 850000000) && (carrier_freq[card][ant] <= 865000000)) { p_exmimo_config->rf.rf_vcocal[ant] = rf_vcocal_850[ant]; p_exmimo_config->rf.rffe_band_mode[ant] = DD_TDD; } else if ((carrier_freq[card][ant] >= 1900000000) && (carrier_freq[card][ant] <= 2000000000)) { p_exmimo_config->rf.rf_vcocal[ant] = rf_vcocal[ant]; p_exmimo_config->rf.rffe_band_mode[ant] = B19G_TDD; } else { p_exmimo_config->rf.rf_vcocal[ant] = rf_vcocal[ant]; p_exmimo_config->rf.rffe_band_mode[ant] = 0; } p_exmimo_config->rf.rffe_gain_txlow[ant] = 31; p_exmimo_config->rf.rffe_gain_txhigh[ant] = 31; p_exmimo_config->rf.rffe_gain_rxfinal[ant] = 52; p_exmimo_config->rf.rffe_gain_rxlow[ant] = 31; } openair0_dump_config(card); printf("EXMIMO_CONFIG card %d: freq0..3 %u %u %u %u Hz, freqtx0..1 %u %u Hz, RX gain0..1 %d %d dB\n", card, p_exmimo_config->rf.rf_freq_rx[0], p_exmimo_config->rf.rf_freq_rx[1], p_exmimo_config->rf.rf_freq_rx[2], p_exmimo_config->rf.rf_freq_rx[3], p_exmimo_config->rf.rf_freq_tx[0], p_exmimo_config->rf.rf_freq_tx[1], p_exmimo_config->rf.rx_gain[0][0], p_exmimo_config->rf.rx_gain[1][0]); printf("EXMIMO_CONFIG card %d: 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", card, 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; } //card card=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("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"), 1); 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[0].rxcnt_ptr[0]; // this starts the DMA transfers if (UE_flag!=1) for (card=0;card<number_of_cards;card++) openair0_start_rt_acquisition(card); #ifdef XFORMS if (do_forms==1) { fl_initialize (&argc, argv, NULL, 0, 0); /* form_stats = create_form_stats_form(); if (UE_flag==1) { form_ue[UE_id] = create_lte_phy_scope_ue(); sprintf (title, "LTE DL SCOPE UE"); fl_show_form (form_ue[UE_id]->lte_phy_scope_ue, FL_PLACE_HOTSPOT, FL_FULLBORDER, title); } else { for(UE_id=0;UE_id<scope_enb_num_ue;UE_id++) { form_enb[UE_id] = create_lte_phy_scope_enb(); sprintf (title, "UE%d LTE UL SCOPE eNB",UE_id+1); fl_show_form (form_enb[UE_id]->lte_phy_scope_enb, FL_PLACE_HOTSPOT, FL_FULLBORDER, title); } } fl_show_form (form_stats->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "stats"); if (UE_flag==0) { for (UE_id=0;UE_id<scope_enb_num_ue;UE_id++) { if (otg_enabled) { fl_set_button(form_enb[UE_id]->button_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"); } } } else { 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"); } } */ form_lte = create_form_lte_scope(); fl_show_form (form_lte->lte_scope, FL_PLACE_HOTSPOT, FL_FULLBORDER, "Scope"); ret = pthread_create(&thread2, NULL, scope_thread, NULL); printf("Scope thread created, ret=%d\n",ret); } #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); ret = pthread_create(&thread5, NULL, log_thread, NULL); printf("LOG 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 if (UE_flag == 1) { /* #ifdef RTAI thread1 = rt_thread_create(UE_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"); } #endif #ifdef DLSCH_THREAD init_rx_pdsch_thread(); rt_sleep_ns(FRAME_PERIOD/10); init_dlsch_threads(); #endif printf("UE threads created\n"); */ } else { #ifdef RTAI thread0 = rt_thread_create(eNB_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"); } #endif #ifdef ULSCH_THREAD init_ulsch_threads(); #endif printf("eNB threads created\n"); } // wait for end of program printf("TYPE <CTRL-C> TO TERMINATE\n"); //getchar(); while (oai_exit==0) rt_sleep_ns(FRAME_PERIOD); // 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); if (UE_flag==1) { fl_hide_form(form_ue[UE_id]->lte_phy_scope_ue); fl_free_form(form_ue[UE_id]->lte_phy_scope_ue); } else { for(UE_id=0;UE_id<scope_enb_num_ue;UE_id++) { fl_hide_form(form_enb[UE_id]->lte_phy_scope_enb); fl_free_form(form_enb[UE_id]->lte_phy_scope_enb); } } */ fl_hide_form(form_lte->lte_scope); fl_free_form(form_lte->lte_scope); } #endif printf("stopping MODEM threads\n"); // cleanup if (UE_flag == 1) { /* #ifdef RTAI rt_thread_join(thread1); #else pthread_join(thread1,&status); #endif #ifdef DLSCH_THREAD cleanup_dlsch_threads(); cleanup_rx_pdsch_thread(); #endif */ } else { #ifdef RTAI rt_thread_join(thread0); #else pthread_join(thread0,&status); #endif #ifdef ULSCH_THREAD cleanup_ulsch_threads(); #endif } #ifdef OPENAIR2 //cleanup_pdcp_thread(); #endif #ifdef RTAI stop_rt_timer(); #endif printf("stopping card\n"); for (card=0;card<number_of_cards;card++) openair0_stop(card); printf("closing openair0_lib\n"); openair0_close(); #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); printf("waiting for log thread\n"); pthread_cancel(thread5); pthread_join(thread5,&status); #endif #ifdef EMOS error_code = rtf_destroy(CHANSOUNDER_FIFO_MINOR); while (error_code>0) 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(); logClean(); 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[ant] = 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;i<frame_parms->nb_antennas_rx;i++) { free(phy_vars_ue->lte_ue_common_vars.rxdata[i]); phy_vars_ue->lte_ue_common_vars.rxdata[i] = (int32_t*) openair0_exmimo_pci[card].adc_head[i+carrier]; printf("rxdata[%d] @ %p\n",i,phy_vars_ue->lte_ue_common_vars.rxdata[i]); } for (i=0;i<frame_parms->nb_antennas_tx;i++) { free(phy_vars_ue->lte_ue_common_vars.txdata[i]); phy_vars_ue->lte_ue_common_vars.txdata[i] = (int32_t*) openair0_exmimo_pci[card].dac_head[i+carrier]; 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,j; 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;i<frame_parms->nb_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]; 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;i<frame_parms->nb_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; } } } } */