From 27a311ab120e62b88e5c3cc727b8d69a4c2a86f8 Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger <florian.kaltenberger@eurecom.fr> Date: Tue, 1 Oct 2013 16:30:29 +0000 Subject: [PATCH] vcd: added some more traces for PHY pdcp_thread: bugfix in init lte-softmodem: changed thread priority for emos and xforms, changed gains for external rf, changed compile options to O2 (now possible with dlsch_demodulation fix) new firmware version (see changelog openair0) dlsch_demodulation: using sse4 extract for llrs pmi_feedback now stored independend of harq_process_id dlsim: fixed memory leak, improved csv output, changed compile option to O2 (now possible with dlsch_demodulation fix) removed unused files git-svn-id: http://svn.eurecom.fr/openair4G/trunk@4174 818b1a75-f10b-46b9-bf7c-635c3b92a50f --- openair1/PHY/LTE_TRANSPORT/dci_tools.c | 7 +- openair1/PHY/LTE_TRANSPORT/defs.h | 2 + openair1/PHY/LTE_TRANSPORT/dlsch_coding.c | 5 + .../PHY/LTE_TRANSPORT/dlsch_demodulation.c | 4 +- .../PHY/LTE_TRANSPORT/dlsch_llr_computation.c | 56 +- openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c | 5 + openair1/PHY/LTE_TRANSPORT/dlsch_scrambling.c | 6 + openair1/PHY/LTE_TRANSPORT/print_stats.c | 3 +- openair1/PHY/LTE_TRANSPORT/uci_tools.c | 34 +- openair1/PHY/LTE_TRANSPORT/ulsch_coding.c | 7 +- openair1/PHY/TOOLS/file_output.c | 4 +- openair1/PHY/TOOLS/lte_phy_scope.c | 2 +- openair1/SCHED/phy_procedures_lte_eNb.c | 28 +- openair1/SCHED/phy_procedures_lte_ue.c | 16 +- openair1/SCHED/sched.c | 1375 ----------------- openair1/SCHED/sched_lte.c | 1000 ------------ openair1/SCHED/sched_lte_fw2011.c | 1012 ------------ openair1/SCHED/sched_lte_user.c | 445 ------ openair1/SIMULATION/LTE_PHY/Makefile | 4 +- openair1/SIMULATION/LTE_PHY/dlsim.c | 98 +- .../USERSPACE/OAI_FW_INIT/sdr_expressmimo2_v9 | Bin 226368 -> 226672 bytes targets/RTAI/USER/.runinfo | 62 +- targets/RTAI/USER/Makefile | 14 +- targets/RTAI/USER/lte-softmodem.c | 97 +- targets/RTAI/USER/sched_rx_pdsch.c | 12 - 25 files changed, 276 insertions(+), 4022 deletions(-) delete mode 100755 openair1/SCHED/sched.c delete mode 100644 openair1/SCHED/sched_lte.c delete mode 100644 openair1/SCHED/sched_lte_fw2011.c delete mode 100644 openair1/SCHED/sched_lte_user.c diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index b03b99337b..9b850f5ea1 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -2058,7 +2058,8 @@ int generate_ue_dlsch_params_from_dci(uint8_t subframe, case 5: dlsch0->harq_processes[harq_pid]->mimo_mode = PUSCH_PRECODING0; // pmi stored from ulsch allocation routine - //msg("using PMI %x\n",pmi2hex_2Ar1(dlsch0->harq_processes[harq_pid]->pmi_alloc)); + dlsch0->harq_processes[harq_pid]->pmi_alloc = dlsch0->pmi_alloc; + //LOG_I(PHY,"XXX using PMI %x\n",pmi2hex_2Ar1(dlsch0->harq_processes[harq_pid]->pmi_alloc)); break; case 6: dlsch0->harq_processes[harq_pid]->mimo_mode = PUSCH_PRECODING1; @@ -2214,7 +2215,9 @@ int generate_ue_dlsch_params_from_dci(uint8_t subframe, case 5: dlsch0->harq_processes[harq_pid]->mimo_mode = PUSCH_PRECODING0; // pmi stored from ulsch allocation routine - break; + dlsch0->harq_processes[harq_pid]->pmi_alloc = dlsch0->pmi_alloc; + //LOG_I(PHY,"XXX using PMI %x\n",pmi2hex_2Ar1(dlsch0->harq_processes[harq_pid]->pmi_alloc)); + break; case 6: dlsch0->harq_processes[harq_pid]->mimo_mode = PUSCH_PRECODING1; LOG_E(PHY,"Unsupported TPMI\n"); diff --git a/openair1/PHY/LTE_TRANSPORT/defs.h b/openair1/PHY/LTE_TRANSPORT/defs.h index 4581873036..5e685a3824 100644 --- a/openair1/PHY/LTE_TRANSPORT/defs.h +++ b/openair1/PHY/LTE_TRANSPORT/defs.h @@ -614,6 +614,8 @@ typedef struct { uint32_t cqi_alloc1; /// Current subband CQI2 allocation uint32_t cqi_alloc2; + /// saved subband PMI allocation from last PUSCH/PUCCH report + uint16_t pmi_alloc; /// HARQ-ACKs harq_status_t harq_ack[10]; /// Pointers to up to 8 HARQ processes diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c index a21566b399..90926004cd 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c @@ -45,6 +45,7 @@ #include "PHY/CODING/lte_interleaver_inline.h" #include "PHY/LTE_TRANSPORT/defs.h" #include "defs.h" +#include "UTIL/LOG/vcd_signal_dumper.h" //#define DEBUG_DLSCH_CODING //#define DEBUG_DLSCH_FREE 1 @@ -223,6 +224,8 @@ int dlsch_encoding(unsigned char *a, unsigned int Kr=0,Kr_bytes,r,r_offset=0; unsigned short m=dlsch->harq_processes[harq_pid]->mcs; + vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ENCODING, VCD_FUNCTION_IN); + A = dlsch->harq_processes[harq_pid]->TBS; //6228 // printf("Encoder: A: %d\n",A); mod_order = get_Qm(dlsch->harq_processes[harq_pid]->mcs); @@ -353,6 +356,8 @@ int dlsch_encoding(unsigned char *a, write_output("enc_output.m","enc",dlsch->e,r_offset,1,4); #endif } + vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ENCODING, VCD_FUNCTION_OUT); + return(0); } diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c index 503b755976..8b817c0f45 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c @@ -152,7 +152,7 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, if (frame_parms->nb_antennas_tx_eNB>1) { #ifdef DEBUG_DLSCH_MOD - msg("dlsch: using pmi %x (%p), rb_alloc %x\n",pmi2hex_2Ar1(dlsch_ue[0]->harq_processes[harq_pid]->pmi_alloc),dlsch_ue[0],dlsch_ue[0]->harq_processes[harq_pid]->rb_alloc[0]); + LOG_I(PHY,"dlsch: using pmi %x (%p), rb_alloc %x\n",pmi2hex_2Ar1(dlsch_ue[0]->harq_processes[harq_pid]->pmi_alloc),dlsch_ue[0],dlsch_ue[0]->harq_processes[harq_pid]->rb_alloc[0]); #endif nb_rb = dlsch_extract_rbs_dual(lte_ue_common_vars->rxdataF, lte_ue_common_vars->dl_ch_estimates[eNB_id], @@ -261,7 +261,7 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, // avgs = cmax(avgs,avg[(aarx<<1)+aatx]); - lte_ue_pdsch_vars[eNB_id]->log2_maxh = (log2_approx(avgs)/2);// + 2 + lte_ue_pdsch_vars[eNB_id]->log2_maxh = (log2_approx(avgs)/2); // + log2_approx(frame_parms->nb_antennas_tx_eNB-1) //-1 because log2_approx counts the number of bits // + log2_approx(frame_parms->nb_antennas_rx-1); diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation.c index dcaf9fd975..f539dd7adf 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation.c @@ -46,6 +46,9 @@ #include <pmmintrin.h> #include <tmmintrin.h> #endif +#ifdef __SSE4_1__ +#include <smmintrin.h> +#endif #include "PHY/defs.h" #include "PHY/extern.h" #include "defs.h" @@ -757,14 +760,14 @@ void dlsch_16qam_llr(LTE_DL_FRAME_PARMS *frame_parms, // lambda_1=y_R, lambda_2=|y_R|-|h|^2, lamda_3=y_I, lambda_4=|y_I|-|h|^2 llr128[0] = _mm_unpacklo_epi32(rxF[i],xmm0); llr128[1] = _mm_unpackhi_epi32(rxF[i],xmm0); - llr32[0] = ((u32 *)&llr128[0])[0]; - llr32[1] = ((u32 *)&llr128[0])[1]; - llr32[2] = ((u32 *)&llr128[0])[2]; - llr32[3] = ((u32 *)&llr128[0])[3]; - llr32[4] = ((u32 *)&llr128[1])[0]; - llr32[5] = ((u32 *)&llr128[1])[1]; - llr32[6] = ((u32 *)&llr128[1])[2]; - llr32[7] = ((u32 *)&llr128[1])[3]; + llr32[0] = _mm_extract_epi32(llr128[0],0); //((u32 *)&llr128[0])[0]; + llr32[1] = _mm_extract_epi32(llr128[0],1); //((u32 *)&llr128[0])[1]; + llr32[2] = _mm_extract_epi32(llr128[0],2); //((u32 *)&llr128[0])[2]; + llr32[3] = _mm_extract_epi32(llr128[0],3); //((u32 *)&llr128[0])[3]; + llr32[4] = _mm_extract_epi32(llr128[1],0); //((u32 *)&llr128[1])[0]; + llr32[5] = _mm_extract_epi32(llr128[1],1); //((u32 *)&llr128[1])[1]; + llr32[6] = _mm_extract_epi32(llr128[1],2); //((u32 *)&llr128[1])[2]; + llr32[7] = _mm_extract_epi32(llr128[1],3); //((u32 *)&llr128[1])[3]; llr32+=8; } _mm_empty(); @@ -788,7 +791,7 @@ void dlsch_64qam_llr(LTE_DL_FRAME_PARMS *frame_parms, __m128i *rxF = (__m128i*)&rxdataF_comp[0][(symbol*frame_parms->N_RB_DL*12)]; __m128i *ch_mag,*ch_magb; - int j=0,i,len,len2; + int i,len,len2; unsigned char symbol_mod,len_mod4; short *llr; s16 *llr2; @@ -828,6 +831,7 @@ void dlsch_64qam_llr(LTE_DL_FRAME_PARMS *frame_parms, xmm2 = _mm_subs_epi16(ch_magb[i],xmm2); // loop over all LLRs in quad word (24 coded bits) + /* for (j=0;j<8;j+=2) { llr2[0] = ((short *)&rxF[i])[j]; llr2[1] = ((short *)&rxF[i])[j+1]; @@ -838,6 +842,40 @@ void dlsch_64qam_llr(LTE_DL_FRAME_PARMS *frame_parms, llr2+=6; } + */ + llr2[0] = ((short *)&rxF[i])[0]; + llr2[1] = ((short *)&rxF[i])[1]; + llr2[2] = _mm_extract_epi16(xmm1,0); + llr2[3] = _mm_extract_epi16(xmm1,1);//((short *)&xmm1)[j+1]; + llr2[4] = _mm_extract_epi16(xmm2,0);//((short *)&xmm2)[j]; + llr2[5] = _mm_extract_epi16(xmm2,1);//((short *)&xmm2)[j+1]; + + llr2+=6; + llr2[0] = ((short *)&rxF[i])[2]; + llr2[1] = ((short *)&rxF[i])[3]; + llr2[2] = _mm_extract_epi16(xmm1,2); + llr2[3] = _mm_extract_epi16(xmm1,3);//((short *)&xmm1)[j+1]; + llr2[4] = _mm_extract_epi16(xmm2,2);//((short *)&xmm2)[j]; + llr2[5] = _mm_extract_epi16(xmm2,3);//((short *)&xmm2)[j+1]; + + llr2+=6; + llr2[0] = ((short *)&rxF[i])[4]; + llr2[1] = ((short *)&rxF[i])[5]; + llr2[2] = _mm_extract_epi16(xmm1,4); + llr2[3] = _mm_extract_epi16(xmm1,5);//((short *)&xmm1)[j+1]; + llr2[4] = _mm_extract_epi16(xmm2,4);//((short *)&xmm2)[j]; + llr2[5] = _mm_extract_epi16(xmm2,5);//((short *)&xmm2)[j+1]; + + llr2+=6; + llr2[0] = ((short *)&rxF[i])[6]; + llr2[1] = ((short *)&rxF[i])[7]; + llr2[2] = _mm_extract_epi16(xmm1,6); + llr2[3] = _mm_extract_epi16(xmm1,7);//((short *)&xmm1)[j+1]; + llr2[4] = _mm_extract_epi16(xmm2,6);//((short *)&xmm2)[j]; + llr2[5] = _mm_extract_epi16(xmm2,7);//((short *)&xmm2)[j+1]; + + llr2+=6; + } *llr_save = llr; _mm_empty(); diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c index d223f79c61..68c272df90 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c @@ -44,6 +44,7 @@ #include "PHY/CODING/lte_interleaver_inline.h" #include "PHY/LTE_TRANSPORT/defs.h" #include "defs.h" +#include "UTIL/LOG/vcd_signal_dumper.h" //#define DEBUG_DLSCH_MODULATION @@ -768,6 +769,8 @@ int dlsch_modulation(mod_sym_t **txdataF, int16_t qam16_table_a[4],qam64_table_a[8],qam16_table_b[4],qam64_table_b[8]; int16_t *qam_table_s; + vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_MODULATION, VCD_FUNCTION_IN); + nsymb = (frame_parms->Ncp==0) ? 14:12; amp_rho_a = (int16_t)(((int32_t)amp*dlsch->sqrt_rho_a)>>13); @@ -995,6 +998,8 @@ int dlsch_modulation(mod_sym_t **txdataF, msg("generate_dlsch : jj = %d,re_allocated = %d (G %d)\n",jj,re_allocated,get_G(frame_parms,dlsch->nb_rb,dlsch->rb_alloc,mod_order,2,0,subframe_offset)); #endif + vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_MODULATION, VCD_FUNCTION_OUT); + return (re_allocated); } diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_scrambling.c b/openair1/PHY/LTE_TRANSPORT/dlsch_scrambling.c index a8010408a8..ed5f387b22 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_scrambling.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_scrambling.c @@ -46,6 +46,8 @@ #include "defs.h" #include "extern.h" #include "PHY/extern.h" +#include "UTIL/LOG/vcd_signal_dumper.h" + void dlsch_scrambling(LTE_DL_FRAME_PARMS *frame_parms, int mbsfn_flag, LTE_eNB_DLSCH_t *dlsch, @@ -58,6 +60,8 @@ void dlsch_scrambling(LTE_DL_FRAME_PARMS *frame_parms, u32 x1, x2, s=0; u8 *e=dlsch->e; + vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_SCRAMBLING, VCD_FUNCTION_IN); + // reset = 1; // x1 is set in lte_gold_generic if (mbsfn_flag == 0) { @@ -84,6 +88,8 @@ void dlsch_scrambling(LTE_DL_FRAME_PARMS *frame_parms, s = lte_gold_generic(&x1, &x2, 0); } + vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_SCRAMBLING, VCD_FUNCTION_OUT); + } diff --git a/openair1/PHY/LTE_TRANSPORT/print_stats.c b/openair1/PHY/LTE_TRANSPORT/print_stats.c index c818a52b82..724413d4c3 100644 --- a/openair1/PHY/LTE_TRANSPORT/print_stats.c +++ b/openair1/PHY/LTE_TRANSPORT/print_stats.c @@ -200,7 +200,7 @@ int dump_ue_stats(PHY_VARS_UE *phy_vars_ue, char* buffer, int length, runmode_t if (phy_vars_ue->transmission_mode[eNB] == 6) len += sprintf(&buffer[len], "[UE PROC] Mode 6 Wideband CQI eNB %d : %d dB\n",eNB,phy_vars_ue->PHY_measurements.precoded_cqi_dB[eNB][0]); if (phy_vars_ue->dlsch_ue[0] && phy_vars_ue->dlsch_ue[0][0] && phy_vars_ue->dlsch_ue[0][1]) { - len += sprintf(&buffer[len], "[UE PROC] Saved PMI for DLSCH eNB %d : %x (%p)\n",eNB,pmi2hex_2Ar1(phy_vars_ue->dlsch_ue[0][0]->harq_processes[0]->pmi_alloc),phy_vars_ue->dlsch_ue[0][0]); + len += sprintf(&buffer[len], "[UE PROC] Saved PMI for DLSCH eNB %d : %x (%p)\n",eNB,pmi2hex_2Ar1(phy_vars_ue->dlsch_ue[0][0]->pmi_alloc),phy_vars_ue->dlsch_ue[0][0]); len += sprintf(&buffer[len], "[UE PROC] eNB %d: dl_power_off = %d\n",eNB,phy_vars_ue->dlsch_ue[0][0]->harq_processes[0]->dl_power_off); @@ -222,6 +222,7 @@ int dump_ue_stats(PHY_VARS_UE *phy_vars_ue, char* buffer, int length, runmode_t #endif len += sprintf(&buffer[len], "[UE PROC] DLSCH Bitrate %dkbps\n",(phy_vars_ue->bitrate[0]/1000)); len += sprintf(&buffer[len], "[UE PROC] Total Received Bits %dkbits\n",(phy_vars_ue->total_received_bits[0]/1000)); + len += sprintf(&buffer[len], "[UE PROC] IA receiver %d\n",openair_daq_vars.use_ia_receiver); } diff --git a/openair1/PHY/LTE_TRANSPORT/uci_tools.c b/openair1/PHY/LTE_TRANSPORT/uci_tools.c index 523a6e643c..335027f000 100644 --- a/openair1/PHY/LTE_TRANSPORT/uci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/uci_tools.c @@ -297,43 +297,43 @@ void print_CQI(void *o,UCI_format_t uci_format,unsigned char eNB_id) { switch(uci_format){ case wideband_cqi_rank1_2A: #ifdef DEBUG_UCI - LOG_D(PHY,"[PRINT CQI] wideband_cqi rank 1: eNB %d, cqi %d\n",eNB_id,((wideband_cqi_rank1_2A_5MHz *)o)->cqi1); - LOG_D(PHY,"[PRINT CQI] wideband_cqi rank 1: eNB %d, pmi (%x) %8x\n",eNB_id,((wideband_cqi_rank1_2A_5MHz *)o)->pmi,pmi2hex_2Ar1(((wideband_cqi_rank1_2A_5MHz *)o)->pmi)); + LOG_I(PHY,"[PRINT CQI] wideband_cqi rank 1: eNB %d, cqi %d\n",eNB_id,((wideband_cqi_rank1_2A_5MHz *)o)->cqi1); + LOG_I(PHY,"[PRINT CQI] wideband_cqi rank 1: eNB %d, pmi (%x) %8x\n",eNB_id,((wideband_cqi_rank1_2A_5MHz *)o)->pmi,pmi2hex_2Ar1(((wideband_cqi_rank1_2A_5MHz *)o)->pmi)); #endif //DEBUG_UCI break; case wideband_cqi_rank2_2A: #ifdef DEBUG_UCI - LOG_D(PHY,"[PRINT CQI] wideband_cqi rank 2: eNB %d, cqi1 %d\n",eNB_id,((wideband_cqi_rank2_2A_5MHz *)o)->cqi1); - LOG_D(PHY,"[PRINT CQI] wideband_cqi rank 2: eNB %d, cqi2 %d\n",eNB_id,((wideband_cqi_rank2_2A_5MHz *)o)->cqi2); - LOG_D(PHY,"[PRINT CQI] wideband_cqi rank 2: eNB %d, pmi %8x\n",eNB_id,pmi2hex_2Ar2(((wideband_cqi_rank2_2A_5MHz *)o)->pmi)); + LOG_I(PHY,"[PRINT CQI] wideband_cqi rank 2: eNB %d, cqi1 %d\n",eNB_id,((wideband_cqi_rank2_2A_5MHz *)o)->cqi1); + LOG_I(PHY,"[PRINT CQI] wideband_cqi rank 2: eNB %d, cqi2 %d\n",eNB_id,((wideband_cqi_rank2_2A_5MHz *)o)->cqi2); + LOG_I(PHY,"[PRINT CQI] wideband_cqi rank 2: eNB %d, pmi %8x\n",eNB_id,pmi2hex_2Ar2(((wideband_cqi_rank2_2A_5MHz *)o)->pmi)); #endif //DEBUG_UCI break; case HLC_subband_cqi_nopmi: #ifdef DEBUG_UCI - LOG_D(PHY,"[PRINT CQI] hlc_cqi (no pmi) : eNB %d, cqi1 %d\n",eNB_id,((HLC_subband_cqi_rank1_2A_5MHz *)o)->cqi1); - LOG_D(PHY,"[PRINT CQI] hlc_cqi (no pmi) : eNB %d, diffcqi1 %8x\n",eNB_id,cqi2hex(((HLC_subband_cqi_rank1_2A_5MHz *)o)->diffcqi1)); + LOG_I(PHY,"[PRINT CQI] hlc_cqi (no pmi) : eNB %d, cqi1 %d\n",eNB_id,((HLC_subband_cqi_rank1_2A_5MHz *)o)->cqi1); + LOG_I(PHY,"[PRINT CQI] hlc_cqi (no pmi) : eNB %d, diffcqi1 %8x\n",eNB_id,cqi2hex(((HLC_subband_cqi_rank1_2A_5MHz *)o)->diffcqi1)); #endif //DEBUG_UCI break; case HLC_subband_cqi_rank1_2A: #ifdef DEBUG_UCI - LOG_D(PHY,"[PRINT CQI] hlc_cqi rank 1: eNB %d, cqi1 %d\n",eNB_id,((HLC_subband_cqi_rank1_2A_5MHz *)o)->cqi1); - LOG_D(PHY,"[PRINT CQI] hlc_cqi rank 1: eNB %d, diffcqi1 %8x\n",eNB_id,cqi2hex(((HLC_subband_cqi_rank1_2A_5MHz *)o)->diffcqi1)); - LOG_D(PHY,"[PRINT CQI] hlc_cqi rank 1: eNB %d, pmi %d\n",eNB_id,((HLC_subband_cqi_rank1_2A_5MHz *)o)->pmi); + LOG_I(PHY,"[PRINT CQI] hlc_cqi rank 1: eNB %d, cqi1 %d\n",eNB_id,((HLC_subband_cqi_rank1_2A_5MHz *)o)->cqi1); + LOG_I(PHY,"[PRINT CQI] hlc_cqi rank 1: eNB %d, diffcqi1 %8x\n",eNB_id,cqi2hex(((HLC_subband_cqi_rank1_2A_5MHz *)o)->diffcqi1)); + LOG_I(PHY,"[PRINT CQI] hlc_cqi rank 1: eNB %d, pmi %d\n",eNB_id,((HLC_subband_cqi_rank1_2A_5MHz *)o)->pmi); #endif //DEBUG_UCI break; case HLC_subband_cqi_rank2_2A: #ifdef DEBUG_UCI - LOG_D(PHY,"[PRINT CQI] hlc_cqi rank 2: eNB %d, cqi1 %d\n",eNB_id,((HLC_subband_cqi_rank2_2A_5MHz *)o)->cqi1); - LOG_D(PHY,"[PRINT CQI] hlc_cqi rank 2: eNB %d, cqi2 %d\n",eNB_id,((HLC_subband_cqi_rank2_2A_5MHz *)o)->cqi2); - LOG_D(PHY,"[PRINT CQI] hlc_cqi rank 2: eNB %d, diffcqi1 %8x\n",eNB_id,cqi2hex(((HLC_subband_cqi_rank2_2A_5MHz *)o)->diffcqi1)); - LOG_D(PHY,"[PRINT CQI] hlc_cqi rank 2: eNB %d, diffcqi2 %8x\n",eNB_id,cqi2hex(((HLC_subband_cqi_rank2_2A_5MHz *)o)->diffcqi2)); - LOG_D(PHY,"[PRINT CQI] hlc_cqi rank 2: eNB %d, pmi %d\n",eNB_id,((HLC_subband_cqi_rank2_2A_5MHz *)o)->pmi); + LOG_I(PHY,"[PRINT CQI] hlc_cqi rank 2: eNB %d, cqi1 %d\n",eNB_id,((HLC_subband_cqi_rank2_2A_5MHz *)o)->cqi1); + LOG_I(PHY,"[PRINT CQI] hlc_cqi rank 2: eNB %d, cqi2 %d\n",eNB_id,((HLC_subband_cqi_rank2_2A_5MHz *)o)->cqi2); + LOG_I(PHY,"[PRINT CQI] hlc_cqi rank 2: eNB %d, diffcqi1 %8x\n",eNB_id,cqi2hex(((HLC_subband_cqi_rank2_2A_5MHz *)o)->diffcqi1)); + LOG_I(PHY,"[PRINT CQI] hlc_cqi rank 2: eNB %d, diffcqi2 %8x\n",eNB_id,cqi2hex(((HLC_subband_cqi_rank2_2A_5MHz *)o)->diffcqi2)); + LOG_I(PHY,"[PRINT CQI] hlc_cqi rank 2: eNB %d, pmi %d\n",eNB_id,((HLC_subband_cqi_rank2_2A_5MHz *)o)->pmi); #endif //DEBUG_UCI break; case HLC_subband_cqi_mcs_CBA: #ifdef DEBUG_UCI - LOG_D(PHY,"[PRINT CQI] hlc_cqi_mcs_CBA : eNB %d, mcs %d\n",eNB_id,((HLC_subband_cqi_mcs_CBA_5MHz *)o)->mcs); - LOG_D(PHY,"[PRINT CQI] hlc_cqi_mcs_CBA : eNB %d, rnti %x\n",eNB_id,((HLC_subband_cqi_mcs_CBA_5MHz *)o)->crnti); + LOG_I(PHY,"[PRINT CQI] hlc_cqi_mcs_CBA : eNB %d, mcs %d\n",eNB_id,((HLC_subband_cqi_mcs_CBA_5MHz *)o)->mcs); + LOG_I(PHY,"[PRINT CQI] hlc_cqi_mcs_CBA : eNB %d, rnti %x\n",eNB_id,((HLC_subband_cqi_mcs_CBA_5MHz *)o)->crnti); #endif //DEBUG_UCI break; case ue_selected: diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c index 743698d6fc..e17b6b339a 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c @@ -248,9 +248,10 @@ u32 ulsch_encoding(u8 *a, print_CQI(ulsch->o,ulsch->uci_format,0); // save PUSCH pmi for later (transmission modes 4,5,6) - // msg("ulsch: saving pmi for DL %x\n",pmi2hex_2Ar1(((wideband_cqi_rank1_2A_5MHz *)ulsch->o)->pmi)); - if (dlsch[0]) - dlsch[0]->harq_processes[harq_pid]->pmi_alloc = ((wideband_cqi_rank1_2A_5MHz *)ulsch->o)->pmi; + if (dlsch[0]) { + //LOG_I(PHY,"XXX saving pmi for DL %x\n",pmi2hex_2Ar1(((wideband_cqi_rank1_2A_5MHz *)ulsch->o)->pmi)); + dlsch[0]->pmi_alloc = ((wideband_cqi_rank1_2A_5MHz *)ulsch->o)->pmi; + } } if (ulsch->O<=32) { diff --git a/openair1/PHY/TOOLS/file_output.c b/openair1/PHY/TOOLS/file_output.c index 000286a84e..3b2069b011 100755 --- a/openair1/PHY/TOOLS/file_output.c +++ b/openair1/PHY/TOOLS/file_output.c @@ -10,8 +10,8 @@ int write_output(const char *fname,const char *vname,void *data,int length,int d int i; - // printf("Writing %d elements of type %d to %s\n",length,format,fname); - // printf("Writing %d elements of type %d to %s\n",length,format,fname); + printf("Writing %d elements of type %d to %s\n",length,format,fname); + printf("Writing %d elements of type %d to %s\n",length,format,fname); if (format == 10 || format ==11 || format == 12 ) diff --git a/openair1/PHY/TOOLS/lte_phy_scope.c b/openair1/PHY/TOOLS/lte_phy_scope.c index 929f2fb4f6..e701d59878 100644 --- a/openair1/PHY/TOOLS/lte_phy_scope.c +++ b/openair1/PHY/TOOLS/lte_phy_scope.c @@ -374,7 +374,7 @@ FD_lte_phy_scope_ue *create_lte_phy_scope_ue( void ) { // Generic UE Button fdui->button_0 = fl_add_button( FL_PUSH_BUTTON, 540, 720, 240, 40, "" ); fl_set_object_lalign(fdui->button_0, FL_ALIGN_CENTER ); - openair_daq_vars.use_ia_receiver = 0; + //openair_daq_vars.use_ia_receiver = 0; fl_set_button(fdui->button_0,0); fl_set_object_label(fdui->button_0, "IA Receiver OFF"); fl_set_object_color(fdui->button_0, FL_RED, FL_RED); diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index fca5c17b15..768c3e1d76 100755 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -488,7 +488,7 @@ void phy_procedures_emos_eNB_RX(unsigned char last_slot,PHY_VARS_eNB *phy_vars_e } else { if (phy_vars_eNB->frame%100==0) { - LOG_D(PHY,"[eNB %d] Frame %d (%d), slot %d, Writing %d bytes EMOS data to FIFO\n", + LOG_I(PHY,"[eNB %d] Frame %d (%d), slot %d, Writing %d bytes EMOS data to FIFO\n", phy_vars_eNB->Mod_id,phy_vars_eNB->frame, ((fifo_dump_emos_eNB*)&emos_dump_eNB)->frame_tx, last_slot, bytes); } } @@ -517,7 +517,6 @@ void fill_dci(DCI_PDU *DCI_pdu, u8 subframe, PHY_VARS_eNB *phy_vars_eNB) { DCI_pdu->Num_ue_spec_dci=0; switch (subframe) { - /* case 5: DCI_pdu->Num_common_dci = 1; DCI_pdu->dci_alloc[0].dci_length = sizeof_DCI1A_5MHz_TDD_1_6_t; @@ -536,7 +535,6 @@ void fill_dci(DCI_PDU *DCI_pdu, u8 subframe, PHY_VARS_eNB *phy_vars_eNB) { BCCH_alloc_pdu.TPC = 1; // set to 3 PRB memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],&BCCH_alloc_pdu,sizeof(DCI1A_5MHz_TDD_1_6_t)); break; - */ case 6: /* DCI_pdu->Num_ue_spec_dci = 1; @@ -558,8 +556,8 @@ void fill_dci(DCI_PDU *DCI_pdu, u8 subframe, PHY_VARS_eNB *phy_vars_eNB) { memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&DLSCH_alloc_pdu1,sizeof(DCI2_5MHz_2A_M10PRB_TDD_t)); */ break; - case 5: - DCI_pdu->Num_ue_spec_dci = 1; + case 7: + DCI_pdu->Num_ue_spec_dci = 1; if (transmission_mode<3) { //user 1 @@ -606,7 +604,7 @@ void fill_dci(DCI_PDU *DCI_pdu, u8 subframe, PHY_VARS_eNB *phy_vars_eNB) { DLSCH_alloc_pdu1E.tpmi = 5; //5=use feedback DLSCH_alloc_pdu1E.rv = 0; DLSCH_alloc_pdu1E.ndi = 1; - DLSCH_alloc_pdu1E.mcs = openair_daq_vars.target_ue_dl_mcs; + DLSCH_alloc_pdu1E.mcs = cqi_to_mcs[phy_vars_eNB->eNB_UE_stats->DL_cqi[0]];//openair_daq_vars.target_ue_dl_mcs; DLSCH_alloc_pdu1E.harq_pid = 0; DLSCH_alloc_pdu1E.dai = 0; DLSCH_alloc_pdu1E.TPC = 0; @@ -621,6 +619,7 @@ void fill_dci(DCI_PDU *DCI_pdu, u8 subframe, PHY_VARS_eNB *phy_vars_eNB) { DCI_pdu->dci_alloc[1].rnti = 0x1236; DCI_pdu->dci_alloc[1].format = format1E_2A_M10PRB; DCI_pdu->dci_alloc[1].ra_flag = 0; + //DLSCH_alloc_pdu1E.mcs = openair_daq_vars.target_ue_dl_mcs; DLSCH_alloc_pdu1E.mcs = (unsigned char) (taus()%28); memcpy((void*)&DCI_pdu->dci_alloc[1].dci_pdu[0],(void *)&DLSCH_alloc_pdu1E,sizeof(DCI1E_5MHz_2A_M10PRB_TDD_t)); @@ -651,7 +650,7 @@ void fill_dci(DCI_PDU *DCI_pdu, u8 subframe, PHY_VARS_eNB *phy_vars_eNB) { break; */ case 9: - DCI_pdu->Num_ue_spec_dci = 1; + DCI_pdu->Num_ue_spec_dci = 2; //user 1 DCI_pdu->dci_alloc[0].dci_length = sizeof_DCI0_5MHz_TDD_1_6_t ; @@ -668,10 +667,9 @@ void fill_dci(DCI_PDU *DCI_pdu, u8 subframe, PHY_VARS_eNB *phy_vars_eNB) { UL_alloc_pdu.TPC = 0; UL_alloc_pdu.cshift = 0; UL_alloc_pdu.dai = 0; - UL_alloc_pdu.cqi_req = 0; + UL_alloc_pdu.cqi_req = 1; memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&UL_alloc_pdu,sizeof(DCI0_5MHz_TDD_1_6_t)); - //user 2 DCI_pdu->dci_alloc[1].dci_length = sizeof_DCI0_5MHz_TDD_1_6_t ; DCI_pdu->dci_alloc[1].L = 2; DCI_pdu->dci_alloc[1].rnti = 0x1236; @@ -692,7 +690,7 @@ void fill_dci(DCI_PDU *DCI_pdu, u8 subframe, PHY_VARS_eNB *phy_vars_eNB) { else UL_alloc_pdu.cshift = 1; UL_alloc_pdu.dai = 0; - UL_alloc_pdu.cqi_req = 0; + UL_alloc_pdu.cqi_req = 1; memcpy((void*)&DCI_pdu->dci_alloc[1].dci_pdu[0],(void *)&UL_alloc_pdu,sizeof(DCI0_5MHz_TDD_1_6_t)); break; @@ -1253,12 +1251,16 @@ void phy_procedures_eNB_TX(unsigned char next_slot,PHY_VARS_eNB *phy_vars_eNB,u8 next_slot>>1); #else DCI_pdu = &DCI_pdu_tmp; - /* - if ((phy_vars_eNB->frame%1000 == 0) && (phy_vars_eNB->frame>=500) && (next_slot == 0) && (openair_daq_vars.target_ue_dl_mcs<28)) { +#ifdef EMOS + if ((phy_vars_eNB->frame%1000 == 0) && (phy_vars_eNB->frame>1000) && (next_slot == 0) && (openair_daq_vars.target_ue_dl_mcs<28)) { openair_daq_vars.target_ue_dl_mcs++; msg("[MYEMOS] frame %d, increasing MCS to %d\n",phy_vars_eNB->frame,openair_daq_vars.target_ue_dl_mcs); } - */ + if (phy_vars_eNB->frame > 28000) { + LOG_E(PHY,"More that 28000 frames reached! Exiting!\n"); + mac_xface->macphy_exit(""); + } +#endif #ifdef EMOS_CHANNEL fill_dci_emos(DCI_pdu,next_slot>>1,phy_vars_eNB); #else diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 901db1d5e4..cc06d6b415 100755 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -1521,8 +1521,8 @@ void phy_procedures_emos_UE_RX(PHY_VARS_UE *phy_vars_ue,u8 last_slot,u8 eNB_id) emos_dump_UE.total_TBS_last = phy_vars_ue->total_TBS_last[eNB_id]; emos_dump_UE.bitrate = phy_vars_ue->bitrate[eNB_id]; emos_dump_UE.total_received_bits = phy_vars_ue->total_received_bits[eNB_id]; - emos_dump_UE.pmi_saved = phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[1]->pmi_alloc; - emos_dump_UE.mcs = phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[1]->mcs; + emos_dump_UE.pmi_saved = phy_vars_ue->dlsch_ue[eNB_id][0]->pmi_alloc; + emos_dump_UE.mcs = phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[phy_vars_ue->dlsch_ue[eNB_id][0]->current_harq_pid]->mcs; emos_dump_UE.use_ia_receiver = openair_daq_vars.use_ia_receiver; bytes = rtf_put(CHANSOUNDER_FIFO_MINOR, &emos_dump_UE, sizeof(fifo_dump_emos_UE)); @@ -1749,8 +1749,12 @@ void lte_ue_pbch_procedures(u8 eNB_id,u8 last_slot, PHY_VARS_UE *phy_vars_ue,u8 phy_vars_ue->lte_ue_pbch_vars[eNB_id]->pdu_errors++; #ifdef OPENAIR2 mac_xface->out_of_sync_ind(phy_vars_ue->Mod_id,phy_vars_ue->frame,eNB_id); +#else + if (phy_vars_ue->lte_ue_pbch_vars[eNB_id]->pdu_errors_conseq>=100) { + LOG_E(PHY,"More that 100 consecutive PBCH errors! Exiting!\n"); + mac_xface->macphy_exit(""); + } #endif - //mac_xface->macphy_exit(""); } if (phy_vars_ue->frame % 100 == 0) { @@ -2200,6 +2204,12 @@ int lte_ue_pdcch_procedures(u8 eNB_id,u8 last_slot, PHY_VARS_UE *phy_vars_ue,u8 (r_type == multicast_relay) ? "RN/UE" : "UE", phy_vars_ue->Mod_id,phy_vars_ue->frame, last_slot>>1, last_slot); #endif +#ifdef EMOS + if ((phy_vars_ue->frame%500 == 0) && (phy_vars_ue->frame>=500) && (last_slot == 0)) { + openair_daq_vars.use_ia_receiver = !openair_daq_vars.use_ia_receiver; + LOG_I(PHY,"[MYEMOS] frame %d, IA receiver %d, MCS %d, bitrate %d\n",phy_vars_ue->frame,openair_daq_vars.use_ia_receiver, phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->mcs,phy_vars_ue->bitrate[eNB_id]); + } +#endif if (phy_vars_ue->lte_frame_parms.Ncp == 0) { // normal prefix pilot1 = 4; diff --git a/openair1/SCHED/sched.c b/openair1/SCHED/sched.c deleted file mode 100755 index bc79102683..0000000000 --- a/openair1/SCHED/sched.c +++ /dev/null @@ -1,1375 +0,0 @@ - -/* - // \author R. Knopp - // \date 02.06.2004 (initial WIDENS version) - // updated 04.04.2006 (migration to 2.6.x kernels) - // updated 01.06.2006 (updates by M. Guillaud for MIMO sounder, new HW tracking mechanism) - // updated 01.08.2006 (integration of PLATON hardware support) - // updated 15.01.2007 (RX/TX FIFO debug support, RK) - // updated 21.05.2007 (structural changes,GET Frame fifo support, RK) - * @{ - */ - -/* -* @addtogroup _physical_layer_ref_implementation_ -\section _process_scheduling_ Process Scheduling -This section deals with real-time process scheduling for PHY and synchronization with certain hardware targets (PLATON,CBMIMO1). -*/ - -#ifndef USER_MODE -#define __NO_VERSION__ - - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/version.h> -#include <linux/types.h> -#include <linux/netdevice.h> - -#include <asm/io.h> -#include <asm/bitops.h> - -#include <asm/uaccess.h> -#include <asm/segment.h> -#include <asm/page.h> - -#ifdef RTAI_ISNT_POSIX -#include "rt_compat.h" -#endif /* RTAI_ISNT_POSIX */ - -#include "MAC_INTERFACE/extern.h" - -#ifdef CBMIMO1 -#include "ARCH/CBMIMO1/DEVICE_DRIVER/cbmimo1_device.h" -#include "ARCH/CBMIMO1/DEVICE_DRIVER/extern.h" -#include "ARCH/CBMIMO1/DEVICE_DRIVER/defs.h" -#endif // CBMIMO1 - -#ifdef RTAI_ENABLED -#include <rtai.h> -#include <rtai_posix.h> -#include <rtai_fifos.h> -#endif // - -#else -#include <stdio.h> -#include <stdlib.h> -#endif // /* USER_MODE */ - - -#include "PHY/types.h" -#include "PHY/defs.h" -#include "PHY/extern.h" -#include "PHY/TRANSPORT/defs.h" -#include "extern.h" -//#include "dummy_driver.h" - -#ifdef CBMIMO1 -#include "ARCH/CBMIMO1/DEVICE_DRIVER/from_grlib_softregs.h" -#endif //CBMIMO1 - -#ifdef SERIAL_IO -#include "rtai_serial.h" -#endif - -#ifdef EMOS -#include "phy_procedures_emos.h" -#endif - -/// Mutex for instance count on MACPHY scheduling -pthread_mutex_t openair_mutex; -/// Condition variable for MACPHY thread -pthread_cond_t openair_cond; -/// Threads -pthread_t threads[openair_SCHED_NB_THREADS]={NULL,NULL,NULL}; -/// Thread Attributes -pthread_attr_t attr_threads[openair_SCHED_NB_THREADS]; -/// RX Signal FIFO for Testing without hardware -#define RX_SIG_FIFO_NUMBER 59 -int rx_sig_fifo = RX_SIG_FIFO_NUMBER; -/// RX Control FIFO for testing without hardware -#define RF_CNTL_FIFO_NUMBER 60 -int rf_cntl_fifo = RF_CNTL_FIFO_NUMBER; - -#ifdef NOCARD_TEST - -/// RX Signal FIFO Mutex -pthread_mutex_t openair_rx_fifo_mutex; -/// RX Signal FIFO Condition variable -pthread_cond_t openair_rx_fifo_cond; - -/// Packet for RX Signal Control -RF_CNTL_PACKET rf_cntl_packet; -#endif //NOCARD_TEST - -/// Global exit variable (exit on error or manual stop via IOCTL) -int exit_openair = 0; - -#define NO_SYNC_TEST 1 - -#ifdef CBMIMO1 -#define NUMBER_OF_CHUNKS_PER_SLOT NUMBER_OF_OFDM_SYMBOLS_PER_SLOT -#define NUMBER_OF_CHUNKS_PER_FRAME (NUMBER_OF_CHUNKS_PER_SLOT * SLOTS_PER_FRAME) -#ifdef CLOCK768 -#define NS_PER_CHUNK 41667 // (7.68 msps, 320 samples per OFDM symbol/CHUNK) //44308 // (6.5 msps, 288 samples per OFDM symbol) -#else -#define NS_PER_CHUNK 49231 // (6.5 msps, 320 samples per OFDM symbol/CHUNK) -#endif -#define SYNCH_WAIT_TIME 4096 // number of symbols between SYNCH retries -#define SYNCH_WAIT_TIME_RUNNING 128 // number of symbols between SYNCH retries -#define DRIFT_OFFSET 300 -#define NS_PER_SLOT (NS_PER_CHUNK * NUMBER_OF_CHUNKS_PER_SLOT) -#define US_PER_SLOT (NS_PER_SLOT * 0.001) - -#define MAX_DRIFT_COMP 3000 -#endif // CBMIMO1 - -#ifdef PLATON -#define NUMBER_OF_CHUNKS_PER_SLOT 10 -#define NUMBER_OF_CHUNKS_PER_FRAME (NUMBER_OF_CHUNKS_PER_SLOT * SLOTS_PER_FRAME) -#define NS_PER_CHUNK 66667 // (7.68 msps, 512 samples per chunk -#define SYNCH_WAIT_TIME 2048 -#define SYNCH_WAIT_TIME_RUNNING 128 // number of symbols between SYNCH retries -//#define SLOTS_PER_FRAME 15 -#define DRIFT_OFFSET 300 -#define MAX_DRIFT_COMP 10000 -#endif // PLATON -#define MAX_SCHED_CNT 50000000 - - -unsigned char first_sync_call; - - -//----------------------------------------------------------------------------- -/** MACPHY Thread */ -static void * openair_thread(void *param) { - //----------------------------------------------------------------------------- - - //------------------------------ -#ifndef USER_MODE - struct sched_param p; - -#endif // /* USER_MODE */ - - - u8 next_slot, last_slot,i; - unsigned int time_in,time_out; - - -#ifdef SERIAL_IO - msg("[SCHED][OPENAIR THREAD] Opening RT serial port interface\n"); - rt_spopen(COM1,38400,8,1,RT_SP_PARITY_NONE,RT_SP_NO_HAND_SHAKE,RT_SP_FIFO_SIZE_14); - rt_msg("[SCHED][OPENAIR THREAD] Opened RT Serial Port Interface\n"); -#endif - - p.sched_priority = OPENAIR_THREAD_PRIORITY; - pthread_attr_setschedparam (&attr_threads[OPENAIR_THREAD_INDEX], &p); -#ifndef RTAI_ISNT_POSIX - pthread_attr_setschedpolicy (&attr_threads[OPENAIR_THREAD_INDEX], SCHED_FIFO); -#endif - - msg("[openair][SCHED][openair_thread] openair_thread started with id %x, fpu_flag = %x\n",(unsigned int)pthread_self(),pthread_self()->uses_fpu); - - if (mac_xface->is_primary_cluster_head == 1) - msg("[openair][SCHED][openair_thread] Configuring openair_thread for primary clusterhead\n"); - else if (mac_xface->is_secondary_cluster_head == 1) - msg("[openair][SCHED][openair_thread] Configuring openair_thread for secondary clusterhead\n"); - else - msg("[openair][SCHED][INFO] Configuring OPENAIR THREAD for regular node\n"); - - - exit_openair = 0; - - - PHY_vars->rx_vars[0].rx_total_gain_dB = MIN_RF_GAIN;//138; - -#ifdef CBMIMO1 - openair_set_rx_gain_cal_openair(PHY_vars->rx_vars[0].rx_total_gain_dB); - - // turn on AGC by default - openair_daq_vars.rx_gain_mode = DAQ_AGC_ON; -#endif - - openair_daq_vars.synch_source = 1; //by default we sync to CH1 - - for (i=0;i<PHY_config->total_no_chsch;i++){ -#ifdef DEBUG_PHY - msg("[OPENAIR][SCHED] Initializing CHSCH %d\n",i); -#endif //DEBUG_PHY - phy_chsch_init_rt_part(i); - } - for (i=0;i<PHY_config->total_no_sch;i++){ -#ifdef DEBUG_PHY - msg("[OPENAIR][SCHED] Initializing SCH %d\n",i); -#endif //DEBUG_PHY - phy_sch_init_rt_part(i); - } - - // Inner thread endless loop - // exits on error or normally - - sach_error_cnt = 0; - openair_daq_vars.sched_cnt = 0; - openair_daq_vars.instance_cnt = -1; - -#ifdef PLATON - for (i=0;i<NB_ANTENNAS_RX;i++) - Zero_Buffer(&PHY_vars->tx_vars[i].TX_DMA_BUFFER[0], - 4*SLOT_LENGTH_BYTES_NO_PREFIX); -#else - Zero_Buffer(&PHY_vars->tx_vars[0].TX_DMA_BUFFER[0], - 4*SLOT_LENGTH_BYTES_NO_PREFIX); -#endif - - // fk 20090324: This code is in phy_procedures_emos.c - /* -#ifdef EMOS - // Initialization of the TX signal for EMOS Part I: Pilot symbols - if (mac_xface->is_primary_cluster_head) { - for (i = 12; i < 21; i++) - { -#ifdef CBMIMO1 - // cbmimo1 already removes the cyclic prefix - phy_generate_sch (0, 1, i, 0xFFFF, 0, NB_ANTENNAS_TX); -#else // User-space simulation or PLATON - phy_generate_sch (0, 1, i, 0xFFFF, 1, NB_ANTENNAS_TX); -#endif - } - } - else if (mac_xface->is_secondary_cluster_head) { - for (i = 22; i < 31; i++) - { -#ifdef CBMIMO1 - // cbmimo1 already removes the cyclic prefix - phy_generate_sch (0, 2, i, 0xFFFF, 0, NB_ANTENNAS_TX); -#else // User-space simulation or PLATON - phy_generate_sch (0, 2, i, 0xFFFF, 1, NB_ANTENNAS_TX); -#endif - } - } - -#endif //EMOS - */ - - while (exit_openair == 0){ - - pthread_mutex_lock(&openair_mutex); - - while (openair_daq_vars.instance_cnt < 0) { - pthread_cond_wait(&openair_cond,&openair_mutex); - } - - openair_daq_vars.instance_cnt--; - pthread_mutex_unlock(&openair_mutex); - - next_slot = (openair_daq_vars.slot_count + 1 ) % SLOTS_PER_FRAME; - last_slot = (openair_daq_vars.slot_count - 1 ) % SLOTS_PER_FRAME; - // msg("[SCHED][Thread] In, Synched ? %d, %d\n",openair_daq_vars.mode,SYNCHED); - if ((openair_daq_vars.mode != openair_NOT_SYNCHED) && (openair_daq_vars.node_running == 1)) { - time_in = openair_get_mbox(); - -#ifndef EMOS - mac_xface->macphy_scheduler(last_slot); -#endif - // phy_procedures(last_slot); - - if (last_slot== 2) - mac_xface->frame++; - - time_out = openair_get_mbox(); - - -#ifdef CBMIMO1 - switch (last_slot) { - case 0: - if (time_in>22) { - msg("[SCHED][OPENAIR_THREAD] Frame %d: last_slot %d, macphy_scheduler time_in %d,time_out %d, scheduler_interval_ns %d\n", mac_xface->frame, last_slot, - time_in,time_out,openair_daq_vars.scheduler_interval_ns); - // exit_openair = 1; - openair1_restart(); - } - - break; - case 1: - if (time_in>38) { - msg("[SCHED][OPENAIR_THREAD] Frame %d: last_slot %d, macphy_scheduler time_in %d,time_out %d, scheduler_interval_ns %d\n", mac_xface->frame, last_slot, - time_in,time_out,openair_daq_vars.scheduler_interval_ns); - // exit_openair = 1; - openair1_restart(); - } - break; - case 2: - if (time_in>54) { - msg("[SCHED][OPENAIR_THREAD] Frame %d: last_slot %d, macphy_scheduler time_in %d,time_out %d, scheduler_interval_ns %d\n", mac_xface->frame, last_slot, - time_in,time_out,openair_daq_vars.scheduler_interval_ns); - // exit_openair = 1; - openair1_restart(); - } - break; - case 3: - if (time_in>6) { - msg("[SCHED][OPENAIR_THREAD] Frame %d: last_slot %d, macphy_scheduler time_in %d,time_out %d, scheduler_interval_ns %d\n", mac_xface->frame, last_slot, - time_in,time_out,openair_daq_vars.scheduler_interval_ns); - msg("[SCHED][OPENAIR_THREAD] Frame %d: last_slot %d, NUMBER_OF_SYMBOLS_PER_FRAME = %d\n",mac_xface->frame, last_slot, pci_interface->ofdm_symbols_per_frame); - openair1_restart(); - // exit_openair = 1; - } - break; - } - // } -#endif //CBMIMO1 - - if ((mac_xface->is_primary_cluster_head == 0) && (last_slot == 0)) { - - -#ifdef CBMIMO1 // Note this code cannot run on PLATON!!! - if (openair_daq_vars.first_sync_call == 1) - openair_daq_vars.first_sync_call = 0; -#endif // CBMIMO1 - } - } // daq_mode != NOT_SYNCHED - } // end while (1) - - // report what happened - - msg ("[SCHED][OPENAIR_THREAD] Exited : openair_daq_vars.slot_count = %d, MODE = %d\n", openair_daq_vars.slot_count, openair_daq_vars.mode); - - // rt_task_delete(rt_whoami); - /* pthread_exit(NULL); */ -#ifdef SERIAL_IO - rt_spclose(COM1); -#endif - - return(0); -} - -#ifdef CBMIMO1 - -static unsigned char dummy_mac_pdu[256] __attribute__((aligned(16))); -static unsigned char dummy_mac_pdu2[256] __attribute__((aligned(16))); - -#define NUMBER_OF_CHSCH_SYNCH_RETRIES 8 -#define NUMBER_OF_SCH_SYNCH_RETRIES 8 - - - -unsigned int find_chbch(void) { - - unsigned int target_SCH_index; - unsigned char chbch_status=0; - int ret[2]; - unsigned char chsch_indices[2] = {1, 2}; - unsigned char *chbch_pdu_rx[2]; - int rssi1_max,rssi2_max; - - chbch_pdu_rx[0] = dummy_mac_pdu; - chbch_pdu_rx[1] = dummy_mac_pdu2; - - for (target_SCH_index = 1; - target_SCH_index < 4; - target_SCH_index++) { - - phy_channel_estimation_top(PHY_vars->rx_vars[0].offset, - SYMBOL_OFFSET_CHSCH+target_SCH_index, - 0, - target_SCH_index, - NB_ANTENNAS_RX, - CHSCH); - } - - // get maximum rssi for first two CHSCH - rssi1_max = max(PHY_vars->PHY_measurements.rx_rssi_dBm[1][0],PHY_vars->PHY_measurements.rx_rssi_dBm[1][1]); rssi2_max = max(PHY_vars->PHY_measurements.rx_rssi_dBm[2][0],PHY_vars->PHY_measurements.rx_rssi_dBm[2][1]); - - // try to decode both streams - phy_decode_chbch_2streams_ml(chsch_indices, - ML, - NB_ANTENNAS_RX, - NB_ANTENNAS_TX, - chbch_pdu_rx, - ret, - CHBCH_PDU_SIZE); - - if (ret[0] == 0) { // first CHBCH is decoded correctly - PHY_vars->PHY_measurements.chbch_detection_count[1]++; - openair_daq_vars.synch_source = 1; - chbch_status = 1; - } - if (ret[1] == 0) { // second CHBCH is decoded correctly - PHY_vars->PHY_measurements.chbch_detection_count[2]++; - if ( (chbch_status == 0) || (rssi2_max>rssi1_max) ) // first is not decoded or second has higher rssi - openair_daq_vars.synch_source = 2; - chbch_status += 2; - - } - - // msg("Find CHBCH: chbch_status = %d (%d,%d), rssi1 %d dBm, rssi2 %d dBm\n",chbch_status,ret[0],ret[1],rssi1_max,rssi2_max); - - return(chbch_status); -} - -unsigned int find_mrbch(void) { - - unsigned int target_SCH_index = MRSCH_INDEX; - unsigned char mrbch_status = 0; - - phy_channel_estimation_top(PHY_vars->rx_vars[0].offset, - SYMBOL_OFFSET_MRSCH, - 0, - target_SCH_index, - NB_ANTENNAS_RX, - SCH); - - if (phy_decode_mrbch(target_SCH_index, -#ifdef BIT8_RXDEMUX - 1, -#endif - NB_ANTENNAS_RX, - NB_ANTENNAS_TXRX, - (unsigned char*)&dummy_mac_pdu, -#ifdef OPENAIR2 - sizeof(MRBCH_PDU)) == 0) -#else - MRBCH_PDU_SIZE) == 0) -#endif - - { - PHY_vars->PHY_measurements.mrbch_detection_count++; - -#ifdef DEBUG_PHY - msg("[openair][SCHED][SYNCH] MRBCH %d detected successfully, RSSI Rx1 %d, RSSI Rx2 %d\n", - target_SCH_index,PHY_vars->PHY_measurements.rx_rssi_dBm[0][0], - target_SCH_index,PHY_vars->PHY_measurements.rx_rssi_dBm[0][1]); -#endif - mrbch_status = 1; - } - - return(mrbch_status); - -} - -void openair1_restart(void) { - - openair_dma(FROM_GRLIB_IRQ_FROM_PCI_IS_ACQ_DMA_STOP); - openair_daq_vars.tx_test=0; - openair_daq_vars.sync_state = 0; - mac_xface->frame = 0; - - - if ((mac_xface->is_cluster_head) && (mac_xface->is_primary_cluster_head)) { - openair_daq_vars.mode = openair_SYNCHED_TO_MRSCH; - } - else { - openair_daq_vars.mode = openair_NOT_SYNCHED; - } - -#ifndef EMOS -#ifdef OPENAIR2 - // msg("[openair][SCHED][SYNCH] Clearing MAC Interface\n"); - //mac_resynch(); -#endif //OPENAIR2 -#endif //EMOS - -} - - -void openair_sync(void) { - // mode looking_for_CH, looking_for_MR - // synch_source SCH index - - int i; - //int size,j; - int status; - int length; - int ret; - static unsigned char clear = 1; - static unsigned char clear_mesh = 1; - - static SCH_t searching_mode = CHSCH; - unsigned char target_SCH_index = 0; - static unsigned char SCH_retries = 0; - static unsigned char CHSCH_retries = 0; - unsigned char chbch_status,mrbch_status; - - RTIME time; - - openair_daq_vars.mode = openair_NOT_SYNCHED; - - //openair_set_lo_freq_openair(openair_daq_vars.freq,openair_daq_vars.freq); - - - ret = setup_regs(); - - -#ifndef NOCARD_TEST - openair_get_frame(); -#else ///NOCARD_TEST - rf_cntl_packet.frame = mac_xface->frame; - rf_cntl_packet.rx_offset = 0; - rtf_put(rf_cntl_fifo,&rf_cntl_packet,sizeof(RF_CNTL_PACKET)); - pthread_cond_wait(&openair_rx_fifo_cond,&openair_rx_fifo_mutex); -#endif //NOCARD_TEST - - - - // sleep during acquisition of frame - - time = rt_get_cpu_time_ns(); - - for (i=0;i<2*NUMBER_OF_CHUNKS_PER_FRAME;i++) { - - -#ifdef RTAI_ENABLED - rt_sleep(nano2count(NS_PER_CHUNK)); -#endif // - - } - - time = rt_get_cpu_time_ns(); - - - if (openair_daq_vars.one_shot_get_frame == 1) { // we're in a non real-time mode so just grab a frame and write to fifo - - status=rtf_reset(rx_sig_fifo); - - for (i=0;i<NB_ANTENNAS_RX;i++) { - length=rtf_put(rx_sig_fifo,PHY_vars->rx_vars[i].RX_DMA_BUFFER,FRAME_LENGTH_BYTES); - if (length < FRAME_LENGTH_BYTES) - msg("[openair][sched][rx_sig_fifo_handler] Didn't put %d bytes for antenna %d (put %d)\n",FRAME_LENGTH_BYTES,i,length); - } - - // signal that acquisition is done in control fifo - rtf_put(rf_cntl_fifo,&openair_daq_vars.sched_cnt,sizeof(int)); - openair_daq_vars.one_shot_get_frame = 0; - } - - if (openair_daq_vars.one_shot_get_frame == 0) { // we're in a real-time mode so do basic decoding - - - memcpy((void *)&PHY_vars->rx_vars[0].RX_DMA_BUFFER[FRAME_LENGTH_COMPLEX_SAMPLES],(void*)PHY_vars->rx_vars[0].RX_DMA_BUFFER,OFDM_SYMBOL_SIZE_BYTES); - memcpy((void *)&PHY_vars->rx_vars[1].RX_DMA_BUFFER[FRAME_LENGTH_COMPLEX_SAMPLES],(void*)PHY_vars->rx_vars[1].RX_DMA_BUFFER,OFDM_SYMBOL_SIZE_BYTES); - -#ifdef DEBUG_PHY - msg("[openair][openair SYNC] freq %d:%d, RX_DMA ADR 0 %x, RX_DMA ADR 1 %x, OFDM_SPF %d, RX_GAIN_VAL %x, TX_RX_SW %d, TCXO %d, NODE_ID %d\n", - (pci_interface->freq_info>>1)&3, - (pci_interface->freq_info>>3)&3, - pci_interface->adc_head[0], - pci_interface->adc_head[1], - pci_interface->ofdm_symbols_per_frame, - pci_interface->rx_gain_val, - pci_interface->tx_rx_switch_point, - pci_interface->tcxo_dac, - pci_interface->node_id); - -#endif - - // For debugging we overrule the searching_mode - if (openair_daq_vars.node_running == 1) { - if ((mac_xface->is_cluster_head == 1) && (mac_xface->is_secondary_cluster_head == 1)) { - searching_mode = SCH; - target_SCH_index = MRSCH_INDEX; //this is needed for the initial synch of the 2nd CH. - // msg("[openair][openair SYNC] Synching to MRSCH %d\n",target_SCH_index); - } - else if (mac_xface->is_cluster_head == 0) { - // msg("[openair][openair SYNC] Synching to CHSCH %d\n",target_SCH_index); - searching_mode = CHSCH; - target_SCH_index = 0; - } - else { //This should not happen - msg("[openair][openair SYNC] searching_mode for primary clusterhead undefined (mode %d)!\n"); - exit_openair=1; - } - } - - /* - //SENSING - openair_daq_vars.channel_vacant[openair_daq_vars.freq] = - openair_daq_vars.channel_vacant[openair_daq_vars.freq] + model_based_detection(); - msg("[OPENAIR][SCHED] Sensing results = [%d %d %d %d]\n",openair_daq_vars.channel_vacant[0],openair_daq_vars.channel_vacant[1],openair_daq_vars.channel_vacant[2],openair_daq_vars.channel_vacant[3]); - */ - - // Do initial timing acquisition - - phy_synch_time((short*)PHY_vars->rx_vars[0].RX_DMA_BUFFER, - &sync_pos, - FRAME_LENGTH_COMPLEX_SAMPLES-768, - 768, - searching_mode, - target_SCH_index); - - - //msg("[openair][openair SYNC] sync_pos = %d\n",sync_pos); - - PHY_vars->rx_vars[0].offset = sync_pos; - -#ifndef NOCARD_TEST - pci_interface->frame_offset = sync_pos; -#endif //NOCARD_TEST - - openair_daq_vars.mode = openair_NOT_SYNCHED; - - - // Try to decode CHBCH - if (searching_mode == CHSCH) { - - chbch_status = 0; - PHY_vars->PHY_measurements.chbch_search_count++; - - - chbch_status = find_chbch(); - - if ((chbch_status >0 ) && (openair_daq_vars.node_running == 1)) { - - - openair_daq_vars.mode = openair_SYNCHED_TO_CHSCH; - - PHY_vars->chbch_data[0].pdu_errors = 0; - PHY_vars->chbch_data[0].pdu_errors_last = 0; - PHY_vars->chbch_data[0].pdu_errors_conseq = 0; - PHY_vars->chbch_data[1].pdu_errors = 0; - PHY_vars->chbch_data[1].pdu_errors_last = 0; - PHY_vars->chbch_data[1].pdu_errors_conseq = 0; - PHY_vars->chbch_data[2].pdu_errors = 0; - PHY_vars->chbch_data[2].pdu_errors_last = 0; - PHY_vars->chbch_data[2].pdu_errors_conseq = 0; - PHY_vars->chbch_data[3].pdu_errors = 0; - PHY_vars->chbch_data[3].pdu_errors_last = 0; - PHY_vars->chbch_data[3].pdu_errors_conseq = 0; - - mac_xface->frame = 0; -#ifndef EMOS -#ifdef OPENAIR2 - // msg("[openair][SCHED][SYNCH] Clearing MAC Interface\n"); - mac_resynch(); -#endif //OPENAIR2 -#endif //EMOS - openair_daq_vars.scheduler_interval_ns=NUMBER_OF_CHUNKS_PER_SLOT*NS_PER_CHUNK; // initial guess - - openair_daq_vars.last_adac_cnt=-1; - - // msg("[openair][SCHED][SYNCH] Resynching hardware\n"); - // phy_adjust_synch(1,openair_daq_vars.synch_source,16384,CHSCH); - phy_adjust_synch_multi_CH(1,16384,CHSCH); - - openair_daq_vars.tx_rx_switch_point = TX_RX_SWITCH_SYMBOL; - - pci_interface->tx_rx_switch_point = openair_daq_vars.tx_rx_switch_point; - - } - else { - if (chbch_status == 0) -#ifdef DEBUG_PHY - msg("[openair][SCHED][SYNCH] No CHBCH detected successfully, retrying (%d/%d)... \n", - CHSCH_retries,NUMBER_OF_CHSCH_SYNCH_RETRIES); -#endif - openair_daq_vars.mode = openair_NOT_SYNCHED; - - } - - //AGC mesh - if (openair_daq_vars.rx_gain_mode == DAQ_AGC_ON) { - // msg("[openair][SCHED][AGC] Running mesh AGC on CHSCHes\n" ); - phy_adjust_gain_mesh (clear_mesh, 16384); - if (clear_mesh == 1) - clear_mesh = 0; - } - - CHSCH_retries++; - - if (CHSCH_retries == NUMBER_OF_CHSCH_SYNCH_RETRIES){ - CHSCH_retries = 0; - searching_mode = SCH; - - /* - if (!mac_xface->is_cluster_head) { - openair_daq_vars.freq = (openair_daq_vars.freq+1) % 4; - openair_daq_vars.freq_info = 1 + (openair_daq_vars.freq<<1) + (openair_daq_vars.freq<<4); - clear_mesh=1; - if (openair_daq_vars.rx_gain_mode == DAQ_AGC_ON) { - PHY_vars->rx_vars[0].rx_total_gain_dB = MIN_RF_GAIN;//138; -#ifdef CBMIMO1 - openair_set_rx_gain_cal_openair(PHY_vars->rx_vars[0].rx_total_gain_dB); -#endif //CBMIMO1 - } - } - */ - } - - } // end of search for CHSCH - else { // Search for MRSCH - - target_SCH_index = MRSCH_INDEX; - PHY_vars->PHY_measurements.mrbch_search_count++; - - - mrbch_status = find_mrbch(); - - - if (mrbch_status == 1) { - if (openair_daq_vars.node_running == 1) { - - msg("[openair][SCHED] Found MRBCH, gain = %d, offset =%d\n",PHY_vars->rx_vars[0].rx_total_gain_dB,PHY_vars->rx_vars[0].offset); - msg("[OPENAIR][SCHED] Frame %d:, mrbch_pdu = "); - for (i=0; i<MRBCH_PDU_SIZE; i++) - msg("%d, ",dummy_mac_pdu[i]); - msg("\n"); - - - openair_daq_vars.mode = openair_SYNCHED_TO_MRSCH; - - PHY_vars->mrbch_data[0].pdu_errors = 0; - PHY_vars->mrbch_data[0].pdu_errors_last = 0; - PHY_vars->mrbch_data[0].pdu_errors_conseq = 0; - - mac_xface->frame = 0; - -#ifndef EMOS -#ifdef OPENAIR2 - // msg("[openair][SCHED][SYNCH] Clearing MAC Interface\n"); - mac_resynch(); -#endif //OPENAIR2 -#endif //EMOS - openair_daq_vars.scheduler_interval_ns=NUMBER_OF_CHUNKS_PER_SLOT*NS_PER_CHUNK; // initial guess - - openair_daq_vars.last_adac_cnt=-1; - - phy_adjust_synch(1,MRSCH_INDEX,16384,SCH); - - openair_daq_vars.tx_rx_switch_point = TX_RX_SWITCH_SYMBOL; - - pci_interface->tx_rx_switch_point = openair_daq_vars.tx_rx_switch_point; - - } - - - } - else { -#ifdef DEBUG_PHY - msg("[openair][SCHED][SYNCH] MRBCH %d not detected successfully, retrying (%d/%d)... \n", - target_SCH_index,SCH_retries,NUMBER_OF_SCH_SYNCH_RETRIES); -#endif - } - - // run AGC - if (openair_daq_vars.rx_gain_mode == DAQ_AGC_ON) { - // msg("[openair][SCHED][AGC] Running AGC on MRSCH %d\n", target_SCH_index); - phy_adjust_gain (clear, 16384, target_SCH_index); - if (clear == 1) - clear = 0; - } - - SCH_retries++; - if (SCH_retries == NUMBER_OF_SCH_SYNCH_RETRIES){ - SCH_retries = 0; - searching_mode = CHSCH; - - /* - if (mac_xface->is_cluster_head) { - openair_daq_vars.freq = (openair_daq_vars.freq+1) % 4; - openair_daq_vars.freq_info = 1 + (openair_daq_vars.freq<<1) + (openair_daq_vars.freq<<4); - clear_mesh=1; - if (openair_daq_vars.rx_gain_mode == DAQ_AGC_ON) { - PHY_vars->rx_vars[0].rx_total_gain_dB = MIN_RF_GAIN;//138; -#ifdef CBMIMO1 - openair_set_rx_gain_cal_openair(PHY_vars->rx_vars[0].rx_total_gain_dB); -#endif //CBMIMO1 - } - } - */ - } - - } // search for mrbch - - - } - else { // store frame to RX fifo and clear one shot flag - - openair_daq_vars.one_shot_get_frame=0; - // msg("[openair][SCHED] Putting RF_CNTL_FIFO info\n"); - - rtf_put(rf_cntl_fifo,&openair_daq_vars.sched_cnt,sizeof(int)); - } - -// msg("[openair][SCHED][SYNCH] Returning\n"); -} - -void openair_sensing(void) { - - int i; - int ret; - static unsigned char clear = 1; - static unsigned char clear_mesh = 1; - static unsigned int sensing_counter = 0; - int sensing_result; - - RTIME time; - - //msg("[OPENAIR][SENSING] freq=%d, freq_info=%d\n",openair_daq_vars.freq,openair_daq_vars.freq_info); - ret = setup_regs(); - -#ifndef NOCARD_TEST - openair_get_frame(); -#else ///NOCARD_TEST - rf_cntl_packet.frame = mac_xface->frame; - rf_cntl_packet.rx_offset = 0; - rtf_put(rf_cntl_fifo,&rf_cntl_packet,sizeof(RF_CNTL_PACKET)); - pthread_cond_wait(&openair_rx_fifo_cond,&openair_rx_fifo_mutex); -#endif //NOCARD_TEST - - // msg("[openair][openair SYNC] openair_get_frame done\n"); - // sleep during acquisition of frame - - time = rt_get_cpu_time_ns(); - - // msg("Sleeping at %d ns... \n",(unsigned int)time); - for (i=0;i<2*NUMBER_OF_CHUNKS_PER_FRAME;i++) { - - -#ifdef RTAI_ENABLED - rt_sleep(nano2count(NS_PER_CHUNK)); -#endif // - - } - - time = rt_get_cpu_time_ns(); - - // msg("Awakening at %d ns... \n",(unsigned int)time); - - if (openair_daq_vars.one_shot_get_frame == 0) { // we're in a real-time mode so do basic decoding - - - memcpy((void *)&PHY_vars->rx_vars[0].RX_DMA_BUFFER[FRAME_LENGTH_COMPLEX_SAMPLES],(void*)PHY_vars->rx_vars[0].RX_DMA_BUFFER,OFDM_SYMBOL_SIZE_BYTES); - memcpy((void *)&PHY_vars->rx_vars[1].RX_DMA_BUFFER[FRAME_LENGTH_COMPLEX_SAMPLES],(void*)PHY_vars->rx_vars[1].RX_DMA_BUFFER,OFDM_SYMBOL_SIZE_BYTES); - - //AGC mesh - if (openair_daq_vars.rx_gain_mode == DAQ_AGC_ON) { - // msg("[openair][SCHED][AGC] Running mesh AGC on CHSCHes\n" ); - phy_adjust_gain_mesh (clear_mesh, 16384); - if (clear_mesh == 1) - clear_mesh = 0; - } - - sensing_counter++; - - openair_daq_vars.channel_vacant[openair_daq_vars.freq] = 0; - - if (sensing_counter >= 12){ - - sensing_result = model_based_detection(); - - msg("[OPENAIR][SENSING] sensing_counter=%d, freq=%d, sensing_result=%d\n",sensing_counter,openair_daq_vars.freq,sensing_result); - - if (sensing_result==1) { - - openair_daq_vars.freq = (openair_daq_vars.freq+1) % 4; - openair_daq_vars.freq_info = 1 + (openair_daq_vars.freq<<1) + (openair_daq_vars.freq<<4); - sensing_counter = 0; - clear_mesh=1; - if (openair_daq_vars.rx_gain_mode == DAQ_AGC_ON) { - PHY_vars->rx_vars[0].rx_total_gain_dB = MIN_RF_GAIN;//138; -#ifdef CBMIMO1 - openair_set_rx_gain_cal_openair(PHY_vars->rx_vars[0].rx_total_gain_dB); -#endif //CBMIMO1 - } - } - else { - openair_daq_vars.channel_vacant[openair_daq_vars.freq] = 1; - } - } - } -} - - -#endif // //CBMIMO1 -//----------------------------------------------------------------------------- - -static void * top_level_scheduler(void *param) { - -#ifdef CBMIMO1 - unsigned int adac_cnt; -#endif // CBMIMO1 -#ifdef PLATON - unsigned int adac_cnt,chunk_count,chunk_offset,slot_count_new; -#endif // PLATON - - int adac_offset; - int first_increment = 0; - int i; - int ret=0; - - msg("[openair][SCHED][top_level_scheduler] top_level_scheduler started with id %x, MODE %d\n",(unsigned int)pthread_self(),openair_daq_vars.mode); - - openair_daq_vars.sched_cnt = 0; - - msg("[openair][SCHED][top_level_scheduler] SLOTS_PER_FRAME=%d, NUMBER_OF_CHUNKS_PER_SLOT=%d, PHY_vars->mbox %p\n",SLOTS_PER_FRAME,NUMBER_OF_CHUNKS_PER_SLOT,(void*)mbox); - //*************************************************************************************** - -#ifdef PLATON - for (i = 0; i < hardware_configuration.number_of_DAQ_cards; i++) { - setup_regs (i); - *rx_mbox[i] = 0; - *tx_mbox[i] = 0; - } - - // Arm slave DMA engines - for (i = 0; i <NB_ANTENNAS_RX; i++) { - if (i != hardware_configuration.master_id) { - msg ("[openair][sched][top_level_scheduler] Arming card %d\n", i); - daq_writel (DMA_ADC_ON + DMA_DAC_ON, m_device[i].data_base + PCI_START_STOP_DMA); - } - } - daq_writel (DMA_DAC_ON + CNT_DAC_ON + DMA_ADC_ON + CNT_ADC_ON, m_device[hardware_configuration.master_id].data_base + PCI_START_STOP_DMA); - - - //*************************************************************************************** -#endif // PLATON - - - -#ifdef RTAI_ENABLED - // msg("[OPENAIR][SCHED] Sleeping ... MODE = %d\n",openair_daq_vars.mode); - rt_sleep(nano2count(2*NUMBER_OF_CHUNKS_PER_SLOT * NS_PER_CHUNK)); - // msg("[OPENAIR][SCHED] Awakening ... MODE = %d\n",openair_daq_vars.mode); -#endif // - - openair_daq_vars.sync_state=0; - - for (i=0;i<4;i++) { - PHY_vars->PHY_measurements.chbch_detection_count[i]= 0; - } - PHY_vars->PHY_measurements.mrbch_detection_count= 0; - PHY_vars->PHY_measurements.chbch_search_count= 0; - PHY_vars->PHY_measurements.mrbch_search_count= 0; - - - while (exit_openair == 0) { - -#ifdef PLATON - adac_cnt = (*PHY_vars->mbox>>1)%NUMBER_OF_CHUNKS_PER_FRAME; /* counts from 0 to NUMBER_OF_CHUNKS_PER_FRAME-1 */ -#endif // - -#ifdef CBMIMO1 - adac_cnt = (*(unsigned int *)mbox)%NUMBER_OF_CHUNKS_PER_FRAME; /* counts from 0 to NUMBER_OF_CHUNKS_PER_FRAME-1 */ -#endif // - - openair_daq_vars.sched_cnt++; - - if ((openair_daq_vars.mode == openair_NOT_SYNCHED) && (openair_daq_vars.node_id != PRIMARY_CH)) { - - - // DO Nothing - if (openair_daq_vars.synch_wait_cnt <= 0) { - - - rt_sleep(nano2count(NUMBER_OF_CHUNKS_PER_SLOT * NS_PER_CHUNK)); - -#ifdef CBMIMO1 // Note this code cannot run on PLATON!!! - if (openair_daq_vars.tx_test == 0) - openair_sync(); -#endif // CBMIMO1 - - if ( (openair_daq_vars.mode != openair_NOT_SYNCHED) && - (openair_daq_vars.node_running == 1) ){ - -#ifdef CBMIMO1 - openair_dma(FROM_GRLIB_IRQ_FROM_PCI_IS_ACQ_START_RT_ACQUISITION); -#endif //CBMIMO1 - openair_daq_vars.sync_state = 1; - - for (i=0;i<NB_ANTENNAS_RX;i++){ - bzero((void *)PHY_vars->rx_vars[i].RX_DMA_BUFFER,FRAME_LENGTH_BYTES); - } - rt_sleep(nano2count(NUMBER_OF_CHUNKS_PER_SLOT*NS_PER_CHUNK*SLOTS_PER_FRAME)); - } -#ifdef DEBUG_PHY - else { - if (((openair_daq_vars.sched_cnt - 1) % (SYNCH_WAIT_TIME<<2) ) == 0) - msg("[openair][SCHED][SYNCH] Return MODE : NOT SYNCHED, sched_cnt = %d\n",openair_daq_vars.sched_cnt); - } -#endif //DEBUG_PHY - - if (openair_daq_vars.node_running == 0){ - openair_daq_vars.synch_wait_cnt = SYNCH_WAIT_TIME; - } - else { - openair_daq_vars.synch_wait_cnt = SYNCH_WAIT_TIME_RUNNING; - } - } - openair_daq_vars.synch_wait_cnt--; - - rt_sleep(nano2count(NUMBER_OF_CHUNKS_PER_SLOT * NS_PER_CHUNK)); - - } - - /* - else if ((openair_daq_vars.mode == openair_NOT_SYNCHED) && (openair_daq_vars.node_id == PRIMARY_CH)) { //this is for cognitive operation - openair_sensing(); // this also does the sensing - - if (openair_daq_vars.channel_vacant[openair_daq_vars.freq]==1) { //check if the current frequency band is vacant - ret = setup_regs(); - if (ret == 0) { - msg("[OPENAIR][SCHED] Starting CH on frequency %d\n",openair_daq_vars.freq); - openair_daq_vars.mode = openair_SYNCHED_TO_MRSCH; - openair_daq_vars.node_running = 1; - openair_daq_vars.sync_state = 0; - } - else { - msg("[OPENAIR][SCHED] Starting CH in cognitive mode failed\n"); - } - } - - } - */ - - else { // We're in synch with the CH or are a 1ary clusterhead -#ifndef NOCARD_TEST - - if (openair_daq_vars.sync_state == 0) { // This means we're a CH, so start RT acquisition!! - openair_daq_vars.rach_detection_count=0; - openair_daq_vars.sync_state = 1; - //openair_daq_vars.tx_rx_switch_point = TX_RX_SWITCH_SYMBOL; - - //PHY_vars->rx_vars[0].rx_total_gain_dB = 115; - //openair_set_rx_gain_cal_openair(PHY_vars->rx_vars[0].rx_total_gain_dB); - - msg("OFDM_Symbols_per_frame %d, log2_symbol_size %d\n",NUMBER_OF_SYMBOLS_PER_FRAME, LOG2_NUMBER_OF_OFDM_CARRIERS); - -#ifdef CBMIMO1 - openair_dma(FROM_GRLIB_IRQ_FROM_PCI_IS_ACQ_START_RT_ACQUISITION); - pci_interface->tx_rx_switch_point = openair_daq_vars.tx_rx_switch_point; -#endif //CBMIMO1 - - mac_xface->frame = 0; - - openair_daq_vars.scheduler_interval_ns=NUMBER_OF_CHUNKS_PER_SLOT*NS_PER_CHUNK; // initial guess - - openair_daq_vars.last_adac_cnt=-1; - - } - - if (openair_daq_vars.sync_state==1) // waiting for first wrap-around of frame - { - - if (adac_cnt==0) - { - //msg("[openair][SCHED][top_level_scheduler] got adac_cnt=0, starting acquisition\n"); - openair_daq_vars.sync_state=2; - openair_daq_vars.last_adac_cnt=0; - openair_daq_vars.slot_count=0; - openair_daq_vars.sched_cnt = 0; - first_increment = 0; - rt_sleep(nano2count(openair_daq_vars.scheduler_interval_ns)); /* sleep for one slot */ - } - else - { - //msg("[openair][SCHED][top_level_scheduler] sync startup, current time=%llu, waiting for adac_cnt=0 (current adac_cnt=%d)\n",rt_get_time_ns(),adac_cnt); - rt_sleep(nano2count(NS_PER_CHUNK/2)); /* sleep for half a SYMBOL */ - - } - - - } - else if (openair_daq_vars.sync_state==2) /* acquisition running, track hardware.... */ - { - - // if (mac_xface->frame % 100 == 0) - // msg("[openair][SCHED] frame %d: scheduler interval %d\n",mac_xface->frame,openair_daq_vars.scheduler_interval_ns); - - adac_offset=((int)adac_cnt-((int)openair_daq_vars.slot_count*NUMBER_OF_CHUNKS_PER_SLOT)); - if (adac_offset > NUMBER_OF_CHUNKS_PER_FRAME) - adac_offset -= NUMBER_OF_CHUNKS_PER_FRAME; - else if (adac_offset < 0) - adac_offset += NUMBER_OF_CHUNKS_PER_FRAME; - - //if (mac_xface->frame % 100 == 0) - // msg("[openair][SCHED] frame %d: adac_offset %d\n",mac_xface->frame,adac_offset); - -#ifdef CBMIMO1 - if (adac_offset > 20) { - msg("[openair][sched][top_level_scheduler] Frame %d : Scheduling too late (adac_offset %d), exiting ...\n",mac_xface->frame,adac_offset); - // exit_openair = 1; - - // restart CBMIMO1 - - openair1_restart(); - - } -#endif //CBMIMO1 - - if (adac_offset>=NUMBER_OF_CHUNKS_PER_SLOT) - { - if (adac_offset>NUMBER_OF_CHUNKS_PER_SLOT) /* adjust openair_daq_vars.scheduler_interval_ns to track the ADAC counter */ - { - openair_daq_vars.scheduler_interval_ns-= DRIFT_OFFSET; - if (openair_daq_vars.scheduler_interval_ns < NUMBER_OF_CHUNKS_PER_SLOT*NS_PER_CHUNK - MAX_DRIFT_COMP) - openair_daq_vars.scheduler_interval_ns = NUMBER_OF_CHUNKS_PER_SLOT*NS_PER_CHUNK - MAX_DRIFT_COMP; - /* msg("adac_offset=%d, openair_daq_vars.scheduler_interval_ns=%d\n",adac_offset,openair_daq_vars.scheduler_interval_ns); */ - } - if (pthread_mutex_lock (&openair_mutex) != 0) // Signal MAC_PHY Scheduler - msg("[openair][SCHED][SCHED] ERROR pthread_mutex_lock\n");// lock before accessing shared resource - openair_daq_vars.instance_cnt++; - pthread_mutex_unlock (&openair_mutex); - // msg("[openair][SCHED][SCHED] Signaling MACPHY scheduler\n"); - if (openair_daq_vars.instance_cnt == 0) // PHY must have finished by now - if (pthread_cond_signal(&openair_cond) != 0) - msg("[openair][SCHED][SCHED] ERROR pthread_cond_signal\n");// schedule L2/L1H TX thread - - openair_daq_vars.slot_count=(openair_daq_vars.slot_count+1) % SLOTS_PER_FRAME; - openair_daq_vars.last_adac_cnt=adac_cnt; - rt_sleep(nano2count(openair_daq_vars.scheduler_interval_ns)); - first_increment = 0; - } - else if (adac_offset<NUMBER_OF_CHUNKS_PER_SLOT) - { - - if (first_increment == 0) { - openair_daq_vars.scheduler_interval_ns+=DRIFT_OFFSET; - first_increment = 1; - } - - if (openair_daq_vars.scheduler_interval_ns > NUMBER_OF_CHUNKS_PER_SLOT*NS_PER_CHUNK + MAX_DRIFT_COMP) - openair_daq_vars.scheduler_interval_ns = NUMBER_OF_CHUNKS_PER_SLOT*NS_PER_CHUNK + MAX_DRIFT_COMP; - - - // msg("adac_offset=%d, openair_daq_vars.scheduler_interval_ns=%d, sleeping for 2us\n",adac_offset,openair_daq_vars.scheduler_interval_ns); - rt_sleep(nano2count(2000)); - } - - } // tracking mode -#else //NOCARD_TEST - - if ((openair_daq_vars.slot_count % SLOTS_PER_FRAME) == 0) { - msg("[openair][SCHED][top_level_thread] Waiting for frame signal in fifo (instance cnt %d)\n", - openair_daq_vars.instance_cnt); - rf_cntl_packet.frame = mac_xface->frame; - rf_cntl_packet.rx_offset = PHY_vars->rx_vars[0].offset; - - rtf_put(rf_cntl_fifo,&rf_cntl_packet,sizeof(RF_CNTL_PACKET)); - - pthread_cond_wait(&openair_rx_fifo_cond,&openair_rx_fifo_mutex); - } - - // here, wait for data in the test fifo - if (pthread_mutex_lock (&openair_mutex) != 0) // Signal MAC_PHY Scheduler - msg("[openair][SCHED][SCHED] ERROR pthread_mutex_lock\n");// lock before accessing shared resource - openair_daq_vars.instance_cnt++; - pthread_mutex_unlock (&openair_mutex); - if (openair_daq_vars.instance_cnt == 0) // PHY must have finished by now - if (pthread_cond_signal(&openair_cond) != 0) - msg("[openair][SCHED][SCHED] ERROR pthread_cond_signal\n");// schedule L2/L1H TX thread - - - openair_daq_vars.slot_count=(openair_daq_vars.slot_count+1) % SLOTS_PER_FRAME; - rt_sleep(nano2count(10000000)); /* sleep for one slot */ - - -#endif //NOCARD_TEST - } // in synch - } // exit_openair = 0 - - msg("[openair][SCHED][top_level_thread] Exiting ... openair_daq_vars.sched_cnt = %d\n",openair_daq_vars.sched_cnt); - openair_daq_vars.mode = openair_SCHED_EXIT; - // schedule openair_thread to exit - msg("[openair][SCHED][top_level_thread] Scheduling openair_thread to exit ... \n"); - if (pthread_mutex_lock (&openair_mutex) != 0) - msg("[openair][SCHED][top_level_thread] ERROR pthread_mutex_lock\n");// lock before accessing shared resource - - openair_daq_vars.instance_cnt = 10; - pthread_mutex_unlock (&openair_mutex); - - - if (pthread_cond_signal(&openair_cond) != 0) - msg("[openair][SCHED][top_level_thread] ERROR pthread_cond_signal\n");// schedule L2/L1H TX thread - - openair_daq_vars.node_running = 0; - // rt_task_delete(rt_whoami); - /* pthread_exit(NULL); */ - msg("[openair][SCHED][top_level_thread] Exiting top_level_scheduler ... \n"); - - return(0); - } - -#ifdef NOCARD_TEST -int rx_sig_fifo_handler(unsigned int fifo, int rw) { - - int status,i; - int length; - - if (rw=='w') { - - for (i=0;i<NB_ANTENNAS_RX;i++) { - length=rtf_get(fifo,PHY_vars->rx_vars[i].RX_DMA_BUFFER,FRAME_LENGTH_BYTES); - if (length < FRAME_LENGTH_BYTES) - msg("[openair][sched][rx_sig_fifo_handler] Didn't get %d bytes for antenna %d (got %d)\n",FRAME_LENGTH_BYTES,i,length); - } - status=rtf_reset(fifo); - msg("[openair][sched][rx_sig_fifo_handler] fifo reset status=%d\n",status); - pthread_cond_signal(&openair_rx_fifo_cond); - return(0); - } - else - return(0); -} - - -#endif //NOCARD_TEST - - - - -int openair_sched_init(void) { - - int error_code; - - - mac_xface->frame = 0; - - openair_daq_vars.scheduler_interval_ns=NUMBER_OF_CHUNKS_PER_SLOT*NS_PER_CHUNK; // initial guess - - openair_daq_vars.last_adac_cnt=-1; - - - - pthread_mutex_init(&openair_mutex,NULL); - - pthread_cond_init(&openair_cond,NULL); - - - if (mac_xface->is_primary_cluster_head == 1) { - printk("[openair][SCHED][init] Configuring primary clusterhead\n"); - } - else if (mac_xface->is_secondary_cluster_head == 1) { - printk("[openair][SCHED][init] Configuring secondary clusterhead\n"); - } - else { - printk("[openair][SCHED][init] Configuring regular node\n"); - } - - openair_daq_vars.mode = openair_NOT_SYNCHED; - - error_code = rtf_create(rx_sig_fifo, NB_ANTENNAS_RX*FRAME_LENGTH_BYTES); - printk("[openair][SCHED][INIT] Created rx_sig_fifo (%d bytes), error_code %d\n", - NB_ANTENNAS_RX*FRAME_LENGTH_BYTES, - error_code); - error_code = rtf_create(rf_cntl_fifo, 256); - printk("[openair][SCHED][INIT] Created rx_cntl_fifo, error_code %d\n",error_code); -#ifdef EMOS - error_code = rtf_create(CHANSOUNDER_FIFO_MINOR,CHANSOUNDER_FIFO_SIZE); - printk("[OPENAIR][SCHED][INIT] Created EMOS FIFO, error code %d\n",error_code); -#endif - - - - -#ifdef NOCARD_TEST - /*RX Signal FIFOS HANDLER*/ - - pthread_mutex_init(&openair_rx_fifo_mutex,NULL); - pthread_cond_init(&openair_rx_fifo_cond,NULL); - - -#endif //NOCARD_TEST - - pthread_attr_init (&attr_threads[OPENAIR_THREAD_INDEX]); - pthread_attr_setstacksize(&attr_threads[OPENAIR_THREAD_INDEX],OPENAIR_THREAD_STACK_SIZE); - - attr_threads[OPENAIR_THREAD_INDEX].priority = 1; - - openair_daq_vars.instance_cnt = -1; - - // Create openair_thread - - error_code = pthread_create(&threads[OPENAIR_THREAD_INDEX], - &attr_threads[OPENAIR_THREAD_INDEX], - openair_thread, - (void *)0); - - - if (error_code!= 0) { - printk("[SCHED][OPENAIR_THREAD][INIT] Could not allocate openair_thread, error %d\n",error_code); - return(error_code); - } - else { - printk("[SCHED][OPENAIR_THREAD][INIT] Allocate openair_thread successful\n"); - } - - pthread_attr_init (&attr_threads[TOP_LEVEL_SCHEDULER_THREAD_INDEX]); - pthread_attr_setstacksize(&attr_threads[TOP_LEVEL_SCHEDULER_THREAD_INDEX],OPENAIR_THREAD_STACK_SIZE); - attr_threads[TOP_LEVEL_SCHEDULER_THREAD_INDEX].priority = 0; - - // Create top_level_scheduler - error_code = pthread_create(&threads[TOP_LEVEL_SCHEDULER_THREAD_INDEX], - &attr_threads[TOP_LEVEL_SCHEDULER_THREAD_INDEX], //default attributes - top_level_scheduler, - (void *)0); - - - - // rt_change_prio(threads[TOP_LEVEL_SCHEDULER_THREAD_INDEX],0); - if (error_code!= 0) { - printk("[openair][SCHED][INIT] Could not allocate top_level_scheduler, error %d\n",error_code); - return(error_code); - } - else { - printk("[openair][SCHED][INIT] Allocate top_level_scheduler successfull\n"); - } - - // Done by pthread_create in rtai_posix.h - // rt_task_use_fpu(threads[TOP_LEVEL_SCHEDULER_THREAD_INDEX],1); - - -#ifdef NOCARD_TEST - /*RX Signal FIFOS HANDLER*/ - - pthread_mutex_init(&openair_rx_fifo_mutex,NULL); - pthread_cond_init(&openair_rx_fifo_cond,NULL); - error_code = rtf_create(rx_sig_fifo, NB_ANTENNAS_RX*FRAME_LENGTH_BYTES); - printk("[openair][SCHED][INIT] Created rx_sig_fifo, error_code %d\n",error_code); - error_code = rtf_create_handler(rx_sig_fifo, X_FIFO_HANDLER(rx_sig_fifo_handler)); - printk("[openair][SCHED][INIT] Created rx_sig_fifo handler, error_code %d\n",error_code); -#endif //NOCARD_TEST - return(0); -} - -void openair_sched_cleanup() { - - int error_code; - - exit_openair = 1; - openair_daq_vars.mode = openair_SCHED_EXIT; - pthread_exit(&threads[TOP_LEVEL_SCHEDULER_THREAD_INDEX]);//H.A - -#ifdef NOCARD_TEST - pthread_cond_destroy(&openair_rx_fifo_cond); -#endif //NOCARD_TEST - - pthread_mutex_destroy(&openair_mutex); - pthread_cond_destroy(&openair_cond); - - error_code = rtf_destroy(rx_sig_fifo); - printk("[OPENAIR][SCHED][CLEANUP] rx_sig_fifo closed, error_code %d\n", error_code); - error_code = rtf_destroy(rf_cntl_fifo); - printk("[OPENAIR][SCHED][CLEANUP] rf_cntl_fifo closed, error_code %d\n", error_code); -#ifdef EMOS - error_code = rtf_destroy(CHANSOUNDER_FIFO_MINOR); - printk("[OPENAIR][SCHED][CLEANUP] EMOS FIFO closed, error_code %d\n", error_code); -#endif - - - printk("[openair][SCHED][CLEANUP] Done!\n"); - -} - - -void openair_sched_exit(char *str) { - - // msg("%s\n",str); - // msg("[OPENAIR][SCHED] TTI %d: openair_sched_exit() called, preparing to exit ...\n",mac_xface->frame); - - exit_openair = 1; - openair_daq_vars.mode = openair_SCHED_EXIT; -} - -/*@}*/ - - diff --git a/openair1/SCHED/sched_lte.c b/openair1/SCHED/sched_lte.c deleted file mode 100644 index e067e9a418..0000000000 --- a/openair1/SCHED/sched_lte.c +++ /dev/null @@ -1,1000 +0,0 @@ - -/* - // \author R. Knopp - // \date 02.06.2004 (initial WIDENS version) - // updated 04.04.2006 (migration to 2.6.x kernels) - // updated 01.06.2006 (updates by M. Guillaud for MIMO sounder, new HW tracking mechanism) - // updated 15.01.2007 (RX/TX FIFO debug support, RK) - // updated 21.05.2007 (structural changes,GET Frame fifo support, RK) - // Created LTE version 02.10.2009 - * @{ - */ - -/* -* @addtogroup _physical_layer_ref_implementation_ -\section _process_scheduling_ Process Scheduling -This section deals with real-time process scheduling for PHY and synchronization with certain hardware targets (CBMIMO1). -*/ - -#ifndef USER_MODE -#define __NO_VERSION__ - -/* -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/version.h> -#include <linux/types.h> -#include <linux/netdevice.h> - -#include <asm/io.h> -#include <asm/bitops.h> - -#include <asm/uaccess.h> -#include <asm/segment.h> -#include <asm/page.h> -*/ - - -#ifdef RTAI_ISNT_POSIX -#include "rt_compat.h" -#endif /* RTAI_ISNT_POSIX */ - -#include "MAC_INTERFACE/extern.h" - -#ifdef CBMIMO1 -#include "ARCH/CBMIMO1/DEVICE_DRIVER/cbmimo1_device.h" -#include "ARCH/CBMIMO1/DEVICE_DRIVER/extern.h" -#include "ARCH/CBMIMO1/DEVICE_DRIVER/defs.h" -#endif // CBMIMO1 - -#ifdef RTAI_ENABLED -#include <rtai.h> -#include <rtai_posix.h> -#include <rtai_fifos.h> -#endif // - -#else -#include <stdio.h> -#include <stdlib.h> -#endif // /* USER_MODE */ - - -#include "PHY/types.h" -#include "PHY/defs.h" -#include "PHY/extern.h" -#include "defs.h" -#include "extern.h" - -#ifdef CBMIMO1 -#include "ARCH/CBMIMO1/DEVICE_DRIVER/from_grlib_softregs.h" -#endif //CBMIMO1 - -#ifdef SERIAL_IO -#include "rtai_serial.h" -#endif - -#ifdef EMOS -#include "phy_procedures_emos.h" -extern fifo_dump_emos_UE emos_dump_UE; -#endif - -/// Mutex for instance count on MACPHY scheduling -pthread_mutex_t openair_mutex; -/// Condition variable for MACPHY thread -pthread_cond_t openair_cond; -/// Threads -pthread_t threads[openair_SCHED_NB_THREADS]={NULL,NULL,NULL}; -/// Thread Attributes -pthread_attr_t attr_threads[openair_SCHED_NB_THREADS]; -/// RX Signal FIFO for Testing without hardware -#define RX_SIG_FIFO_NUMBER 59 -int rx_sig_fifo = RX_SIG_FIFO_NUMBER; -/// RX Control FIFO for testing without hardware -#define RF_CNTL_FIFO_NUMBER 60 -int rf_cntl_fifo = RF_CNTL_FIFO_NUMBER; - -#ifdef NOCARD_TEST - -/// RX Signal FIFO Mutex -pthread_mutex_t openair_rx_fifo_mutex; -/// RX Signal FIFO Condition variable -pthread_cond_t openair_rx_fifo_cond; - -/// Packet for RX Signal Control -RF_CNTL_PACKET rf_cntl_packet; -#endif //NOCARD_TEST - -/// Global exit variable (exit on error or manual stop via IOCTL) -int exit_openair = 0; - -extern int init_dlsch_threads(void); -extern void cleanup_dlsch_threads(void); - -extern int dlsch_instance_cnt[8]; -extern pthread_mutex_t dlsch_mutex[8]; -extern pthread_cond_t dlsch_cond[8]; - -#define NO_SYNC_TEST 1 - -#ifdef CBMIMO1 -#define NUMBER_OF_CHUNKS_PER_SLOT NUMBER_OF_OFDM_SYMBOLS_PER_SLOT -#define NUMBER_OF_CHUNKS_PER_FRAME (NUMBER_OF_CHUNKS_PER_SLOT * SLOTS_PER_FRAME) -#define SYNCH_WAIT_TIME 4000 // number of symbols between SYNCH retries -#define SYNCH_WAIT_TIME_RUNNING 100 // number of symbols between SYNCH retries -#define DRIFT_OFFSET 300 -#define NS_PER_SLOT 500000 -#define MAX_DRIFT_COMP 3000 -#endif // CBMIMO1 - -#define MAX_SCHED_CNT 50000000 - - -unsigned char first_sync_call; - -rtheap_t rt_heap; - -void openair1_restart(void) { - - int i; - - for (i=0;i<number_of_cards;i++) - openair_dma(i,FROM_GRLIB_IRQ_FROM_PCI_IS_ACQ_DMA_STOP); - // openair_daq_vars.tx_test=0; - openair_daq_vars.sync_state = 0; - mac_xface->frame = 0; - - /* - if ((mac_xface->is_cluster_head) && (mac_xface->is_primary_cluster_head)) { - openair_daq_vars.mode = openair_SYNCHED_TO_MRSCH; - } - else { - openair_daq_vars.mode = openair_NOT_SYNCHED; - } - */ - -#ifdef OPENAIR2 - msg("[openair][SCHED][SYNCH] Clearing MAC Interface\n"); - //mac_resynch(); -#endif //OPENAIR2 - -} - -//----------------------------------------------------------------------------- -/** MACPHY Thread */ -static void * openair_thread(void *param) { - //-----------------------------------------------------------------------------ddd - - //------------------------------ -#ifndef USER_MODE - struct sched_param p; -#endif // USER_MODE - - u8 next_slot, last_slot; - unsigned int time_in,time_out,i; - int diff; - - LTE_DL_FRAME_PARMS *frame_parms = lte_frame_parms_g; - - // run on CPU 1, which should be reserved only for this (by adding isolcpus=1 noirqbalance to the kernel options). Also use IsolCpusMaks=0x2 when loading rtai_hal - rt_set_runnable_on_cpuid(pthread_self(),0); - rt_sleep(nano2count(NS_PER_SLOT)); - - -#ifdef SERIAL_IO - msg("[SCHED][OPENAIR THREAD] Opening RT serial port interface\n"); - rt_spopen(COM1,38400,8,1,RT_SP_PARITY_NONE,RT_SP_NO_HAND_SHAKE,RT_SP_FIFO_SIZE_14); - rt_msg("[SCHED][OPENAIR THREAD] Opened RT Serial Port Interface\n"); -#endif - - p.sched_priority = OPENAIR_THREAD_PRIORITY; - pthread_attr_setschedparam (&attr_threads[OPENAIR_THREAD_INDEX], &p); -#ifndef RTAI_ISNT_POSIX - pthread_attr_setschedpolicy (&attr_threads[OPENAIR_THREAD_INDEX], SCHED_FIFO); -#endif - - printk("[openair][SCHED][openair_thread] openair_thread started with id %x, fpu_flag = %x, cpuid = %d\n",(unsigned int)pthread_self(),pthread_self()->uses_fpu,rtai_cpuid()); - - if (mac_xface->is_primary_cluster_head == 1) { - msg("[openair][SCHED][openair_thread] Configuring openair_thread for primary eNodeB/clusterhead\n"); - } - else if (mac_xface->is_secondary_cluster_head == 1) { - msg("[openair][SCHED][openair_thread] Configuring openair_thread for secondary eNodeB/clusterhead\n"); - } - else { - msg("[openair][SCHED][openair_thread] Configuring OPENAIR THREAD for regular UE/node\n"); - } - - - exit_openair = 0; - - // Inner thread endless loop - // exits on error or normally - - openair_daq_vars.sched_cnt = 0; - openair_daq_vars.instance_cnt = -1; - - for (i=0;i<number_of_cards;i++) - Zero_Buffer((void*)TX_DMA_BUFFER[i][0], - 4*SLOT_LENGTH_BYTES_NO_PREFIX); - - while (exit_openair == 0) - { - - pthread_mutex_lock(&openair_mutex); - - while (openair_daq_vars.instance_cnt < 0) { - pthread_cond_wait(&openair_cond,&openair_mutex); - } - - openair_daq_vars.instance_cnt--; - pthread_mutex_unlock(&openair_mutex); - - next_slot = (openair_daq_vars.slot_count + 1 ) % SLOTS_PER_FRAME; - if (openair_daq_vars.slot_count==0) - last_slot = SLOTS_PER_FRAME-1; - else - last_slot = (openair_daq_vars.slot_count - 1 ) % SLOTS_PER_FRAME; - - //msg("[SCHED][Thread] Mode = %d (openair_NOT_SYNCHED=%d), slot_count = %d, instance_cnt = %d\n",openair_daq_vars.mode,openair_NOT_SYNCHED,openair_daq_vars.slot_count,openair_daq_vars.instance_cnt); - - if ((openair_daq_vars.mode != openair_NOT_SYNCHED) && (openair_daq_vars.node_running == 1)) { - time_in = openair_get_mbox(); - -#ifdef DEBUG_PHY - if (mac_xface->frame % 100 == 0) { - msg("[SCHED][OPENAIR_THREAD] frame = %d, slot_count %d, last %d, next %d\n", mac_xface->frame, openair_daq_vars.slot_count, last_slot, next_slot); - } -#endif - -#ifdef OPENAIR_LTE - if (mac_xface->is_cluster_head) { - if (PHY_vars_eNB_g && PHY_vars_eNB_g[0]) - phy_procedures_eNB_lte(last_slot,next_slot,PHY_vars_eNB_g[0],0); - } - else { - if (PHY_vars_UE_g && PHY_vars_UE_g[0]) - phy_procedures_UE_lte(last_slot,next_slot,PHY_vars_UE_g[0],0,0); - } -#else -#ifdef EMOS - phy_procedures_emos(last_slot); -#else - phy_procedures(last_slot); -#endif -#endif - - - if (last_slot==SLOTS_PER_FRAME-2) - mac_xface->frame++; - - time_out = openair_get_mbox(); - diff = ((int) time_out - (int) time_in) % ((int) (NUMBER_OF_SYMBOLS_PER_FRAME)); - - if (diff > (NUMBER_OF_OFDM_SYMBOLS_PER_SLOT+4)) { // we scheduled too late - msg("[SCHED][OPENAIR_THREAD] Frame %d: last_slot %d, macphy_scheduler time_in %d, time_out %d, diff %d, scheduler_interval_ns %d\n", - mac_xface->frame, last_slot, - time_in,time_out, - diff, - openair_daq_vars.scheduler_interval_ns); - //openair1_restart(); - //exit_openair = 1; - } - - /* -#ifdef CBMIMO1 - switch (last_slot) { - case 0: - if (time_in>22) { - msg("[SCHED][OPENAIR_THREAD] Frame %d: last_slot %d, macphy_scheduler time_in %d,time_out %d, scheduler_interval_ns %d\n", mac_xface->frame, last_slot, - time_in,time_out,openair_daq_vars.scheduler_interval_ns); - // exit_openair = 1; - openair1_restart(); - } - - break; - case 1: - if (time_in>38) { - msg("[SCHED][OPENAIR_THREAD] Frame %d: last_slot %d, macphy_scheduler time_in %d,time_out %d, scheduler_interval_ns %d\n", mac_xface->frame, last_slot, - time_in,time_out,openair_daq_vars.scheduler_interval_ns); - // exit_openair = 1; - openair1_restart(); - } - break; - case 2: - if (time_in>54) { - msg("[SCHED][OPENAIR_THREAD] Frame %d: last_slot %d, macphy_scheduler time_in %d,time_out %d, scheduler_interval_ns %d\n", mac_xface->frame, last_slot, - time_in,time_out,openair_daq_vars.scheduler_interval_ns); - // exit_openair = 1; - openair1_restart(); - } - break; - case 3: - if (time_in>6) { - msg("[SCHED][OPENAIR_THREAD] Frame %d: last_slot %d, macphy_scheduler time_in %d,time_out %d, scheduler_interval_ns %d\n", mac_xface->frame, last_slot, - time_in,time_out,openair_daq_vars.scheduler_interval_ns); - msg("[SCHED][OPENAIR_THREAD] Frame %d: last_slot %d, NUMBER_OF_SYMBOLS_PER_FRAME = %d\n",mac_xface->frame, last_slot, pci_interface[0]->ofdm_symbols_per_frame); - openair1_restart(); - // exit_openair = 1; - } - break; - } -#endif //CBMIMO1 - */ - -#ifdef CBMIMO1 // Note this code cannot run on PLATON!!! - if ((mac_xface->is_primary_cluster_head == 0) && (last_slot == 0)) { - if (openair_daq_vars.first_sync_call == 1) - openair_daq_vars.first_sync_call = 0; - } -#endif // CBMIMO1 - - } // daq_mode != NOT_SYNCHED - } // end while (1) - - // report what happened - - msg ("[SCHED][OPENAIR_THREAD] Exited : openair_daq_vars.slot_count = %d, MODE = %d\n", openair_daq_vars.slot_count, openair_daq_vars.mode); - - // rt_task_delete(rt_whoami); - /* pthread_exit(NULL); */ -#ifdef SERIAL_IO - rt_spclose(COM1); -#endif - - return(0); -} - - -void openair_sync(void) { - int i; - //int size,j; - int status; - int length; - int ret; - static unsigned char clear=1, clear2=1; - int Nsymb, sync_pos, sync_pos_slot; - int Ns; - int l; - int rx_power; - unsigned int adac_cnt; - int pbch_decoded = 0; - int frame_mod4,pbch_tx_ant; - u8 dummy; - - RTIME time; - - LTE_DL_FRAME_PARMS *frame_parms = lte_frame_parms_g; - - openair_daq_vars.mode = openair_NOT_SYNCHED; - - //openair_set_lo_freq_openair(openair_daq_vars.freq,openair_daq_vars.freq); - - for (i=0;i<number_of_cards;i++) { - ret = setup_regs(i,frame_parms); - - openair_get_frame(i); //received frame is stored in PHY_vars->RX_DMA_BUFFER - } - // sleep during acquisition of frame - - time = rt_get_cpu_time_ns(); - - for (i=0;i<3*NUMBER_OF_CHUNKS_PER_FRAME;i++) { - rt_sleep(nano2count(NS_PER_SLOT/NUMBER_OF_OFDM_SYMBOLS_PER_SLOT)); - } - - time = rt_get_cpu_time_ns(); - - - if (openair_daq_vars.one_shot_get_frame == 1) { // we're in a non real-time mode so just grab a frame and write to fifo - - status=rtf_reset(rx_sig_fifo); - - for (i=0;i<NB_ANTENNAS_RX;i++) { - length=rtf_put(rx_sig_fifo,(unsigned char*)RX_DMA_BUFFER[0][i],FRAME_LENGTH_BYTES); - if (length < FRAME_LENGTH_BYTES) { - msg("[openair][sched][rx_sig_fifo_handler] Didn't put %d bytes for antenna %d (put %d)\n",FRAME_LENGTH_BYTES,i,length); - } - else { - msg("[openair][sched][rx_sig_fifo_handler] Worte %d bytes for antenna %d to fifo (put %d)\n",FRAME_LENGTH_BYTES,i,length); - } - } - - // signal that acquisition is done in control fifo - rtf_put(rf_cntl_fifo,&openair_daq_vars.sched_cnt,sizeof(int)); - openair_daq_vars.one_shot_get_frame = 0; - } - - if (openair_daq_vars.one_shot_get_frame == 0) { // we're in a real-time mode so do basic decoding - - - memcpy((void *)(RX_DMA_BUFFER[0][0]+FRAME_LENGTH_COMPLEX_SAMPLES),(void*)RX_DMA_BUFFER[0][0],OFDM_SYMBOL_SIZE_BYTES); - memcpy((void *)(RX_DMA_BUFFER[0][1]+FRAME_LENGTH_COMPLEX_SAMPLES),(void*)RX_DMA_BUFFER[0][1],OFDM_SYMBOL_SIZE_BYTES); - -#ifdef DEBUG_PHY - for (i=0;i<number_of_cards;i++) - msg("[openair][SCHED][SYNC] card %d freq %d:%d, RX_DMA ADR 0 %x, RX_DMA ADR 1 %x, OFDM_SPF %d, RX_GAIN_VAL %x, TCXO %d, NODE_ID %d\n", - (pci_interface[i]->freq_info>>1)&3, - (pci_interface[i]->freq_info>>3)&3, - pci_interface[i]->adc_head[0], - pci_interface[i]->adc_head[1], - pci_interface[i]->ofdm_symbols_per_frame, - pci_interface[i]->rx_gain_val, - pci_interface[i]->tcxo_dac, - pci_interface[i]->node_id); - -#endif - - if (openair_daq_vars.node_configured == 3) { // the node has been cofigured as a UE - - msg("[openair][SCHED][SYNCH] starting sync\n"); - - if (initial_sync(PHY_vars_UE_g[0]) == 0) { - - if (openair_daq_vars.node_running == 1) { - - pci_interface[0]->frame_offset = PHY_vars_UE_g[0]->rx_offset; - - openair_daq_vars.mode = openair_SYNCHED; - openair_daq_vars.scheduler_interval_ns=NS_PER_SLOT; // initial guess - openair_daq_vars.last_adac_cnt=-1; - msg("[openair][SCHED][SYNCH] openair synched \n"); - } - } - } - - /* - // Measurements - rx_power = 0; - for (i=0;i<NB_ANTENNAS_RX; i++) { - // energy[i] = signal_energy(lte_eNB_common_vars->rxdata[i], FRAME_LENGTH_COMPLEX_SAMPLES); - PHY_vars_UE_g[0]->PHY_measurements.wideband_cqi[0][i] = signal_energy((int*)RX_DMA_BUFFER[0][i],FRAME_LENGTH_COMPLEX_SAMPLES); - PHY_vars_UE_g[0]->PHY_measurements.wideband_cqi_dB[0][i] = dB_fixed(PHY_vars_UE_g[0]->PHY_measurements.wideband_cqi[0][i]); - rx_power += PHY_vars_UE_g[0]->PHY_measurements.wideband_cqi[0][i]; - } - PHY_vars_UE_g[0]->PHY_measurements.wideband_cqi_tot[0] = dB_fixed(rx_power); - if (openair_daq_vars.rx_rf_mode == 0) - PHY_vars_UE_g[0]->PHY_measurements.rx_rssi_dBm[0] = PHY_vars_UE_g[0]->PHY_measurements.wideband_cqi_tot[0] - PHY_vars_UE_g[0]->rx_total_gain_dB + 25; - else - PHY_vars_UE_g[0]->PHY_measurements.rx_rssi_dBm[0] = PHY_vars_UE_g[0]->PHY_measurements.wideband_cqi_tot[0] - PHY_vars_UE_g[0]->rx_total_gain_dB; - - msg("[openair][SCHED] RX RSSI %d dBm, digital (%d, %d) dB, linear (%d, %d), RX gain %d dB, TDD %d, Dual_tx %d\n", - PHY_vars_UE_g[0]->PHY_measurements.rx_rssi_dBm[0], - PHY_vars_UE_g[0]->PHY_measurements.wideband_cqi_dB[0][0], - PHY_vars_UE_g[0]->PHY_measurements.wideband_cqi_dB[0][1], - PHY_vars_UE_g[0]->PHY_measurements.wideband_cqi[0][0], - PHY_vars_UE_g[0]->PHY_measurements.wideband_cqi[0][1], - PHY_vars_UE_g[0]->rx_total_gain_dB, - pci_interface[0]->tdd, - pci_interface[0]->dual_tx); - - */ - -#ifdef EMOS - memcpy(&emos_dump_UE.PHY_measurements[0], &PHY_vars_UE_g[0]->PHY_measurements, sizeof(PHY_MEASUREMENTS)); - emos_dump_UE.timestamp = rt_get_time_ns(); - emos_dump_UE.UE_mode = UE_mode; - emos_dump_UE.rx_total_gain_dB = PHY_vars_UE_g[0]->rx_total_gain_dB; - - debug_msg("[SCHED_LTE] Writing EMOS data to FIFO\n"); - if (rtf_put(CHANSOUNDER_FIFO_MINOR, &emos_dump_UE, sizeof(fifo_dump_emos_UE))!=sizeof(fifo_dump_emos_UE)) { - msg("[SCHED_LTE] Problem writing EMOS data to FIFO\n"); - } -#endif - - /* - // Do AGC - if (openair_daq_vars.node_configured==3 && openair_daq_vars.rx_gain_mode == DAQ_AGC_ON) { - phy_adjust_gain(PHY_vars_UE_g[0], 0); - if (clear == 1) - clear = 0; - } - - if (openair_daq_vars.node_configured==3) { - lte_adjust_synch(&PHY_vars_UE_g[0]->lte_frame_parms, - PHY_vars_UE_g[0], - 0, - clear2, - 16384); - if (clear2 == 1) - clear2 = 0; - } - */ - - } - - msg("[openair][SCHED] leaving openair_sync()\n"); -} - - - -static void * top_level_scheduler(void *param) { - -#ifdef CBMIMO1 - unsigned int adac_cnt; -#endif // CBMIMO1 - - int adac_offset; - int first_increment = 0; - int i; - int ret=0; - - LTE_DL_FRAME_PARMS *frame_parms=lte_frame_parms_g; - - msg("[openair][SCHED][top_level_scheduler] top_level_scheduler started with id %x, MODE %d, cpuid = %d, fpu_flag = %d\n",(unsigned int)pthread_self(),openair_daq_vars.mode,rtai_cpuid(),pthread_self()->uses_fpu); - - openair_daq_vars.sched_cnt = 0; - - msg("[openair][SCHED][top_level_scheduler] SLOTS_PER_FRAME=%d, NUMBER_OF_CHUNKS_PER_SLOT=%d, NUMBER_OF_CHUNKS_PER_FRAME=%d, PHY_vars->mbox %p\n", - SLOTS_PER_FRAME,NUMBER_OF_CHUNKS_PER_SLOT, NUMBER_OF_CHUNKS_PER_FRAME, (void*)mbox); - - // Do initialization routines that use SSE here. They should not be run from the main kernel module because they might screw up the floating point unit when interrupted. - lte_sync_time_init(frame_parms); - - /* - // Init the heap - if (rtheap_init(&rt_heap, NULL, 4096, 4096) == 0) { - msg("[OPENAIR][SCHED] Heap initialized successfully\n"); - } - else { - openair_sched_exit("[OPENAIR][SCHED] Cannot initialized heap\n"); - } - */ - -#ifdef RTAI_ENABLED - msg("[OPENAIR][SCHED] Sleeping %d ns (MODE = %d)\n",2*NS_PER_SLOT,openair_daq_vars.mode); - rt_sleep(nano2count(2*NS_PER_SLOT)); - //rt_sleep(2*NS_PER_SLOT); - msg("[OPENAIR][SCHED] Awakening (MODE = %d)\n",openair_daq_vars.mode); -#endif // - - openair_daq_vars.sync_state=0; - - while (exit_openair == 0) { - -#ifdef CBMIMO1 - adac_cnt = (*(unsigned int *)mbox)%NUMBER_OF_CHUNKS_PER_FRAME; // counts from 0 to NUMBER_OF_CHUNKS_PER_FRAME-1 -#endif // - - openair_daq_vars.sched_cnt++; - - if ((openair_daq_vars.mode == openair_NOT_SYNCHED) && (openair_daq_vars.node_id != PRIMARY_CH)) { - - - // DO Nothing - if (openair_daq_vars.synch_wait_cnt <= 0) { - - - rt_sleep(nano2count(NS_PER_SLOT)); - //rt_sleep(NS_PER_SLOT); - -#ifdef CBMIMO1 // Note this code cannot run on PLATON!!! - if (openair_daq_vars.tx_test == 0) - openair_sync(); -#endif // CBMIMO1 - - if ( (openair_daq_vars.mode != openair_NOT_SYNCHED) && - (openair_daq_vars.node_running == 1) ){ - - msg("[openair][SCHED] staring RT acquisition, adac_cnt = %d\n",adac_cnt); -#ifdef CBMIMO1 - for (i=0;i<number_of_cards;i++) - openair_dma(i,FROM_GRLIB_IRQ_FROM_PCI_IS_ACQ_START_RT_ACQUISITION); -#endif //CBMIMO1 - openair_daq_vars.sync_state = 1; - openair_daq_vars.sched_cnt = 0; - /* - for (i=0;i<NB_ANTENNAS_RX;i++){ - bzero((void *)RX_DMA_BUFFER[0][0],FRAME_LENGTH_BYTES); - } - */ - - for (i=0;i<NUMBER_OF_CHUNKS_PER_FRAME;i++) { - rt_sleep(nano2count(NS_PER_SLOT/NUMBER_OF_OFDM_SYMBOLS_PER_SLOT)); - } - //rt_sleep(nano2count(NS_PER_SLOT*SLOTS_PER_FRAME)); - //rt_sleep(NS_PER_SLOT*SLOTS_PER_FRAME); - } -#ifdef DEBUG_PHY - else { - if (((openair_daq_vars.sched_cnt - 1) % (SYNCH_WAIT_TIME<<2) ) == 0) - msg("[openair][SCHED][SYNCH] Return MODE : NOT SYNCHED, sched_cnt = %d\n",openair_daq_vars.sched_cnt); - } -#endif //DEBUG_PHY - - if (openair_daq_vars.node_running == 0){ - openair_daq_vars.synch_wait_cnt = SYNCH_WAIT_TIME; - } - else { - openair_daq_vars.synch_wait_cnt = SYNCH_WAIT_TIME_RUNNING; - } - } - openair_daq_vars.synch_wait_cnt--; - - rt_sleep(nano2count(NS_PER_SLOT)); - //rt_sleep(NS_PER_SLOT)); - - } - else { // We're in synch with the CH or are a 1ary clusterhead - -#ifndef NOCARD_TEST - - if (openair_daq_vars.sync_state == 0) { // This means we're a CH, so start RT acquisition!! - openair_daq_vars.rach_detection_count=0; - openair_daq_vars.sync_state = 1; - openair_daq_vars.sched_cnt = 0; - - msg("[openair][sched][top_level_scheduler] Starting RT acquisition, ofdm_symbols_per_frame %d, log2_symbol_size %d\n", - NUMBER_OF_SYMBOLS_PER_FRAME, LOG2_NUMBER_OF_OFDM_CARRIERS); - -#ifdef CBMIMO1 - for (i=0;i<number_of_cards;i++) { - openair_dma(i,FROM_GRLIB_IRQ_FROM_PCI_IS_ACQ_START_RT_ACQUISITION); - - } -#endif //CBMIMO1 - -#ifdef OPENAIR2 - if (openair_daq_vars.node_id == PRIMARY_CH) { - msg("[openair][SCHED][SYNCH] Calling mrbch_phy_sync_failure\n"); - mac_xface->mrbch_phy_sync_failure(0,0); - mac_xface->frame = 0; - } -#endif - - openair_daq_vars.scheduler_interval_ns=NS_PER_SLOT; // initial guess - - openair_daq_vars.last_adac_cnt=-1; - - } - - if (openair_daq_vars.sync_state==1) // waiting for first wrap-around of frame - { - - if (adac_cnt==0) - { - msg("[openair][SCHED][top_level_scheduler] got adac_cnt=0, starting acquisition\n"); - openair_daq_vars.sync_state=2; - openair_daq_vars.last_adac_cnt=0; - openair_daq_vars.slot_count=0; - openair_daq_vars.sched_cnt = 0; - first_increment = 0; - rt_sleep(nano2count(openair_daq_vars.scheduler_interval_ns)); /* sleep for one slot */ - //rt_sleep(openair_daq_vars.scheduler_interval_ns); /* sleep for one slot */ - } - else - { - //msg("[openair][SCHED][top_level_scheduler] sync startup, current time=%llu, waitig for adac_cnt=0 (current adac_cnt=%d)\n",rt_get_time_ns(),adac_cnt); - //msg("[openair][SCHED][top_level_scheduler] waiting for adac_cnt=0 (current adac_cnt=%d)\n",adac_cnt); - rt_sleep(nano2count(NS_PER_SLOT/NUMBER_OF_OFDM_SYMBOLS_PER_SLOT/2)); /* sleep for half a SYMBOL */ - //rt_sleep(NS_PER_SLOT/NUMBER_OF_OFDM_SYMBOLS_PER_SLOT/2); /* sleep for half a SYMBOL */ - - if (openair_daq_vars.sched_cnt > 3*NUMBER_OF_SYMBOLS_PER_FRAME) { - msg("[openair][SCHED][top_level_scheduler] got sched_cnt =%d, stopping\n",openair_daq_vars.sched_cnt); - openair_daq_vars.mode = openair_NOT_SYNCHED; - openair_daq_vars.sync_state=0; - openair1_restart(); - //openair_sched_exit("exit"); - } - - } - - - } - else if (openair_daq_vars.sync_state==2) /* acquisition running, track hardware.... */ - { - - // if (mac_xface->frame % 100 == 0) - // msg("[openair][SCHED] frame %d: scheduler interval %d\n",mac_xface->frame,openair_daq_vars.scheduler_interval_ns); - - adac_offset=((int)adac_cnt-((int)openair_daq_vars.slot_count*NUMBER_OF_CHUNKS_PER_SLOT)); - if (adac_offset > NUMBER_OF_CHUNKS_PER_FRAME) - adac_offset -= NUMBER_OF_CHUNKS_PER_FRAME; - else if (adac_offset < 0) - adac_offset += NUMBER_OF_CHUNKS_PER_FRAME; - - // if (mac_xface->frame % 100 == 0) - // msg("[openair][SCHED] frame %d: adac_offset %d\n",mac_xface->frame,adac_offset); - - if (adac_offset > 20) { - msg("[openair][sched][top_level_scheduler] Frame %d : Scheduling too late (adac_offset %d, adac_cnt %d, slot_count %d, tx_test = %d), restarting ...\n", - mac_xface->frame, adac_offset, adac_cnt, openair_daq_vars.slot_count,openair_daq_vars.tx_test); - openair1_restart(); - } - - if (adac_offset>=NUMBER_OF_CHUNKS_PER_SLOT) - { - if (adac_offset>NUMBER_OF_CHUNKS_PER_SLOT) /* adjust openair_daq_vars.scheduler_interval_ns to track the ADAC counter */ - { - openair_daq_vars.scheduler_interval_ns-= DRIFT_OFFSET; - if (openair_daq_vars.scheduler_interval_ns < NS_PER_SLOT - MAX_DRIFT_COMP) - openair_daq_vars.scheduler_interval_ns = NS_PER_SLOT - MAX_DRIFT_COMP; - /* msg("adac_offset=%d, openair_daq_vars.scheduler_interval_ns=%d\n",adac_offset,openair_daq_vars.scheduler_interval_ns); */ - } - if (pthread_mutex_lock (&openair_mutex) != 0) // Signal MAC_PHY Scheduler - msg("[openair][SCHED][SCHED] ERROR pthread_mutex_lock\n");// lock before accessing shared resource - openair_daq_vars.instance_cnt++; - pthread_mutex_unlock (&openair_mutex); - // msg("[openair][SCHED][SCHED] Signaling MACPHY scheduler\n"); - if (openair_daq_vars.instance_cnt == 0) // PHY must have finished by now - if (pthread_cond_signal(&openair_cond) != 0) - msg("[openair][SCHED][SCHED] ERROR pthread_cond_signal\n");// schedule L2/L1H TX thread - - openair_daq_vars.slot_count=(openair_daq_vars.slot_count+1) % SLOTS_PER_FRAME; - openair_daq_vars.last_adac_cnt=adac_cnt; - rt_sleep(nano2count(openair_daq_vars.scheduler_interval_ns)); - //rt_sleep(openair_daq_vars.scheduler_interval_ns); - first_increment = 0; - } - else if (adac_offset<NUMBER_OF_CHUNKS_PER_SLOT) - { - - if (first_increment == 0) { - openair_daq_vars.scheduler_interval_ns+=DRIFT_OFFSET; - first_increment = 1; - } - - if (openair_daq_vars.scheduler_interval_ns > NS_PER_SLOT + MAX_DRIFT_COMP) - openair_daq_vars.scheduler_interval_ns = NS_PER_SLOT + MAX_DRIFT_COMP; - - - // msg("adac_offset=%d, openair_daq_vars.scheduler_interval_ns=%d, sleeping for 2us\n",adac_offset,openair_daq_vars.scheduler_interval_ns); - rt_sleep(nano2count(2000)); - //rt_sleep(2000); - } - - } // tracking mode -#else //NOCARD_TEST - - if ((openair_daq_vars.slot_count % SLOTS_PER_FRAME) == 0) { - msg("[openair][SCHED][top_level_thread] Waiting for frame signal in fifo (instance cnt %d)\n", - openair_daq_vars.instance_cnt); - rf_cntl_packet.frame = mac_xface->frame; - rf_cntl_packet.rx_offset = PHY_vars->rx_offset; - - rtf_put(rf_cntl_fifo,&rf_cntl_packet,sizeof(RF_CNTL_PACKET)); - - pthread_cond_wait(&openair_rx_fifo_cond,&openair_rx_fifo_mutex); - } - - // here, wait for data in the test fifo - if (pthread_mutex_lock (&openair_mutex) != 0) // Signal MAC_PHY Scheduler - msg("[openair][SCHED][SCHED] ERROR pthread_mutex_lock\n");// lock before accessing shared resource - openair_daq_vars.instance_cnt++; - pthread_mutex_unlock (&openair_mutex); - if (openair_daq_vars.instance_cnt == 0) // PHY must have finished by now - if (pthread_cond_signal(&openair_cond) != 0) - msg("[openair][SCHED][SCHED] ERROR pthread_cond_signal\n");// schedule L2/L1H TX thread - - - openair_daq_vars.slot_count=(openair_daq_vars.slot_count+1) % SLOTS_PER_FRAME; - rt_sleep(nano2count(openair_daq_vars.scheduler_interval_ns)); /* sleep for one slot */ - //rt_sleep(openair_daq_vars.scheduler_interval_ns); /* sleep for one slot */ - - msg("[openair][SCHED][top_level_thread] slot_count =%d, scheduler_interval_ns = %d\n",openair_daq_vars.slot_count, openair_daq_vars.scheduler_interval_ns); - - -#endif //NOCARD_TEST - } // in synch - } // exit_openair = 0 - - msg("[openair][SCHED][top_level_thread] Frame %d: Exiting ... openair_daq_vars.sched_cnt = %d\n",mac_xface->frame, openair_daq_vars.sched_cnt); - openair_daq_vars.mode = openair_SCHED_EXIT; - // schedule openair_thread to exit - msg("[openair][SCHED][top_level_thread] Scheduling openair_thread to exit ... \n"); - if (pthread_mutex_lock (&openair_mutex) != 0) - msg("[openair][SCHED][top_level_thread] ERROR pthread_mutex_lock\n");// lock before accessing shared resource - - openair_daq_vars.instance_cnt = 10; - pthread_mutex_unlock (&openair_mutex); - - - if (pthread_cond_signal(&openair_cond) != 0) - msg("[openair][SCHED][top_level_thread] ERROR pthread_cond_signal\n");// schedule L2/L1H TX thread - - openair_daq_vars.node_running = 0; - // rt_task_delete(rt_whoami); - /* pthread_exit(NULL); */ - msg("[openair][SCHED][top_level_thread] Exiting top_level_scheduler ... \n"); - - return(0); -} - -#ifdef NOCARD_TEST -int rx_sig_fifo_handler(unsigned int fifo, int rw) { - - int status,i; - int length; - - if (rw=='w') { - - for (i=0;i<NB_ANTENNAS_RX;i++) { - length=rtf_get(fifo,(unsigned char*)RX_DMA_BUFFER[0][0],FRAME_LENGTH_BYTES); - if (length < FRAME_LENGTH_BYTES) - msg("[openair][sched][rx_sig_fifo_handler] Didn't get %d bytes for antenna %d (got %d)\n",FRAME_LENGTH_BYTES,i,length); - } - status=rtf_reset(fifo); - msg("[openair][sched][rx_sig_fifo_handler] fifo reset status=%d\n",status); - pthread_cond_signal(&openair_rx_fifo_cond); - return(0); - } - else - return(0); -} - - -#endif //NOCARD_TEST - - - - -s32 openair_sched_init(void) { - - int error_code; - int* tmp; - - LTE_DL_FRAME_PARMS *frame_parms = lte_frame_parms_g; - - mac_xface->frame = 0; - - openair_daq_vars.scheduler_interval_ns=NS_PER_SLOT; // initial guess - - openair_daq_vars.last_adac_cnt=-1; - - - - pthread_mutex_init(&openair_mutex,NULL); - - pthread_cond_init(&openair_cond,NULL); - - - if (mac_xface->is_primary_cluster_head == 1) { - printk("[openair][SCHED][init] Configuring primary eNodeB/clusterhead\n"); - } - else if (mac_xface->is_secondary_cluster_head == 1) { - printk("[openair][SCHED][init] Configuring secondary eNodeB/clusterhead\n"); - } - else { - printk("[openair][SCHED][init] Configuring regular UE/node\n"); - } - - openair_daq_vars.mode = openair_NOT_SYNCHED; - - error_code = rtf_create(rx_sig_fifo, NB_ANTENNAS_RX*FRAME_LENGTH_BYTES); - printk("[openair][SCHED][INIT] Created rx_sig_fifo (%d bytes), error_code %d\n", - NB_ANTENNAS_RX*FRAME_LENGTH_BYTES, - error_code); - error_code = rtf_create(rf_cntl_fifo, 256); - printk("[openair][SCHED][INIT] Created rx_cntl_fifo, error_code %d\n",error_code); -#ifdef EMOS - error_code = rtf_create(CHANSOUNDER_FIFO_MINOR,CHANSOUNDER_FIFO_SIZE); - printk("[OPENAIR][SCHED][INIT] Created EMOS FIFO, error code %d\n",error_code); -#endif - - - - -#ifdef NOCARD_TEST - /*RX Signal FIFOS HANDLER*/ - - pthread_mutex_init(&openair_rx_fifo_mutex,NULL); - pthread_cond_init(&openair_rx_fifo_cond,NULL); - - -#endif //NOCARD_TEST - - pthread_attr_init (&attr_threads[OPENAIR_THREAD_INDEX]); - pthread_attr_setstacksize(&attr_threads[OPENAIR_THREAD_INDEX],OPENAIR_THREAD_STACK_SIZE); - - attr_threads[OPENAIR_THREAD_INDEX].priority = 1; - - openair_daq_vars.instance_cnt = -1; - - // Create openair_thread - error_code = pthread_create(&threads[OPENAIR_THREAD_INDEX], - &attr_threads[OPENAIR_THREAD_INDEX], - openair_thread, - (void *)0); - - - if (error_code!= 0) { - printk("[OPENAIR][SCHED][INIT] Could not allocate openair_thread, error %d\n",error_code); - return(error_code); - } - else { - printk("[OPENAIR][SCHED][INIT] Allocate openair_thread successful\n"); - } - - pthread_attr_init (&attr_threads[TOP_LEVEL_SCHEDULER_THREAD_INDEX]); - pthread_attr_setstacksize(&attr_threads[TOP_LEVEL_SCHEDULER_THREAD_INDEX],OPENAIR_THREAD_STACK_SIZE); - attr_threads[TOP_LEVEL_SCHEDULER_THREAD_INDEX].priority = 0; - - // Create top_level_scheduler - error_code = pthread_create(&threads[TOP_LEVEL_SCHEDULER_THREAD_INDEX], - &attr_threads[TOP_LEVEL_SCHEDULER_THREAD_INDEX], //default attributes - top_level_scheduler, - (void *)0); - - - - // rt_change_prio(threads[TOP_LEVEL_SCHEDULER_THREAD_INDEX],0); - if (error_code!= 0) { - printk("[openair][SCHED][INIT] Could not allocate top_level_scheduler, error %d\n",error_code); - return(error_code); - } - else { - printk("[openair][SCHED][INIT] Allocate top_level_scheduler successfull\n"); - } - - // Done by pthread_create in rtai_posix.h - // rt_task_use_fpu(threads[TOP_LEVEL_SCHEDULER_THREAD_INDEX],1); - -#ifdef NOCARD_TEST - /*RX Signal FIFOS HANDLER*/ - - pthread_mutex_init(&openair_rx_fifo_mutex,NULL); - pthread_cond_init(&openair_rx_fifo_cond,NULL); - error_code = rtf_create(rx_sig_fifo, NB_ANTENNAS_RX*FRAME_LENGTH_BYTES); - printk("[openair][SCHED][INIT] Created rx_sig_fifo, error_code %d\n",error_code); - error_code = rtf_create_handler(rx_sig_fifo, X_FIFO_HANDLER(rx_sig_fifo_handler)); - printk("[openair][SCHED][INIT] Created rx_sig_fifo handler, error_code %d\n",error_code); -#endif //NOCARD_TEST - - tmp = rt_malloc(sizeof(int)); - printk("[openair][SCHED][INIT] tmp= %p\n",tmp); - rt_free(tmp); - - return(error_code); - -} - -void openair_sched_cleanup(void) { - - int error_code; - - exit_openair = 1; - openair_daq_vars.mode = openair_SCHED_EXIT; - - //pthread_exit(&threads[TOP_LEVEL_SCHEDULER_THREAD_INDEX]);//H.A - //pthread_exit(&threads[OPENAIR_THREAD_INDEX]);//F.K - -#ifdef NOCARD_TEST - pthread_cond_destroy(&openair_rx_fifo_cond); -#endif //NOCARD_TEST - - pthread_mutex_destroy(&openair_mutex); - pthread_cond_destroy(&openair_cond); - - error_code = rtf_destroy(rx_sig_fifo); - printk("[OPENAIR][SCHED][CLEANUP] rx_sig_fifo closed, error_code %d\n", error_code); - error_code = rtf_destroy(rf_cntl_fifo); - printk("[OPENAIR][SCHED][CLEANUP] rf_cntl_fifo closed, error_code %d\n", error_code); -#ifdef EMOS - error_code = rtf_destroy(CHANSOUNDER_FIFO_MINOR); - printk("[OPENAIR][SCHED][CLEANUP] EMOS FIFO closed, error_code %d\n", error_code); -#endif - - //rtheap_destroy(rt_heap); - - printk("[openair][SCHED][CLEANUP] Done!\n"); -} - - -void openair_sched_exit(char *str) { - u8 i; - - msg("%s\n",str); - msg("[OPENAIR][SCHED] Frame %d: openair_sched_exit() called, preparing to exit ...\n",mac_xface->frame); - - exit_openair = 1; - openair_daq_vars.mode = openair_SCHED_EXIT; - for (i=0;i<number_of_cards;i++) - openair_dma(i,FROM_GRLIB_IRQ_FROM_PCI_IS_ACQ_DMA_STOP); - -} - - - -/*@}*/ - - diff --git a/openair1/SCHED/sched_lte_fw2011.c b/openair1/SCHED/sched_lte_fw2011.c deleted file mode 100644 index 59324bd1bf..0000000000 --- a/openair1/SCHED/sched_lte_fw2011.c +++ /dev/null @@ -1,1012 +0,0 @@ -/******************************************************************************* - - 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 sched_lte_fw2011.c -* \brief RTAI scheduler for LTE UE/eNB procedures (CBMIMO1 2011 FPGA firmware) -* \author R. Knopp, M. Guillaud, F. Kaltenberger -* \date 2011 -* \version 0.1 -* \company Eurecom -* \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr -* \note -* \warning -*/ -/* - * @{ - */ - -/* -* @addtogroup _physical_layer_ref_implementation_ -\section _process_scheduling_ Process Scheduling -This section deals with real-time process scheduling for PHY and synchronization with certain hardware targets (CBMIMO1). -*/ - -#ifndef USER_MODE -#define __NO_VERSION__ - -/* -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/version.h> -#include <linux/types.h> -#include <linux/netdevice.h> - -#include <asm/io.h> -#include <asm/bitops.h> - -#include <asm/uaccess.h> -#include <asm/segment.h> -#include <asm/page.h> -*/ - - -#ifdef RTAI_ISNT_POSIX -#include "rt_compat.h" -#endif /* RTAI_ISNT_POSIX */ - -#include "MAC_INTERFACE/extern.h" - -#ifdef CBMIMO1 -#include "ARCH/CBMIMO1/DEVICE_DRIVER/cbmimo1_device.h" -#include "ARCH/CBMIMO1/DEVICE_DRIVER/extern.h" -#include "ARCH/CBMIMO1/DEVICE_DRIVER/defs.h" -#endif // CBMIMO1 - -#ifdef RTAI_ENABLED -#include <rtai.h> -#include <rtai_posix.h> -#include <rtai_fifos.h> -#endif // - - -#include <linux/pci.h> - -#else -#include <stdio.h> -#include <stdlib.h> -#endif // /* USER_MODE */ - - -#include "PHY/types.h" -#include "PHY/defs.h" -#include "PHY/extern.h" -#include "defs.h" -#include "extern.h" - -#ifdef CBMIMO1 -#include "ARCH/CBMIMO1/DEVICE_DRIVER/from_grlib_softregs.h" -#endif //CBMIMO1 - -#ifdef SERIAL_IO -#include "rtai_serial.h" -#endif - -#ifdef EMOS -#include "phy_procedures_emos.h" -extern fifo_dump_emos_UE emos_dump_UE; -#endif - -/// Mutex for instance count on MACPHY scheduling -pthread_mutex_t openair_mutex; -/// Condition variable for MACPHY thread -pthread_cond_t openair_cond; -/// Threads -pthread_t threads[openair_SCHED_NB_THREADS]={NULL,NULL,NULL}; -/// Thread Attributes -pthread_attr_t attr_threads[openair_SCHED_NB_THREADS]; -/// RX Signal FIFO for Testing without hardware -#define RX_SIG_FIFO_NUMBER 59 -int rx_sig_fifo = RX_SIG_FIFO_NUMBER; -/// RX Control FIFO for testing without hardware -#define RF_CNTL_FIFO_NUMBER 60 -int rf_cntl_fifo = RF_CNTL_FIFO_NUMBER; - -#ifdef NOCARD_TEST - -/// RX Signal FIFO Mutex -pthread_mutex_t openair_rx_fifo_mutex; -/// RX Signal FIFO Condition variable -pthread_cond_t openair_rx_fifo_cond; - -/// Packet for RX Signal Control -RF_CNTL_PACKET rf_cntl_packet; -#endif //NOCARD_TEST - -/// Global exit variable (exit on error or manual stop via IOCTL) -int exit_openair = 0; - -extern int init_dlsch_threads(void); -extern void cleanup_dlsch_threads(void); - -extern int dlsch_instance_cnt[8]; -extern pthread_mutex_t dlsch_mutex[8]; -extern pthread_cond_t dlsch_cond[8]; - -#define NO_SYNC_TEST 1 - -#ifdef CBMIMO1 -#define NUMBER_OF_CHUNKS_PER_SLOT NUMBER_OF_OFDM_SYMBOLS_PER_SLOT -#define NUMBER_OF_CHUNKS_PER_FRAME (NUMBER_OF_CHUNKS_PER_SLOT * LTE_SLOTS_PER_FRAME) -#define SYNCH_WAIT_TIME 4000 // number of symbols between SYNCH retries -#define SYNCH_WAIT_TIME_RUNNING 100 // number of symbols between SYNCH retries -#define DRIFT_OFFSET 300 -#define NS_PER_SLOT 500000 -#define MAX_DRIFT_COMP 3000 -#endif // CBMIMO1 - -#define MAX_SCHED_CNT 50000000 - - -rtheap_t rt_heap; - -unsigned int sync_slot_cnt=0; -unsigned int sync_getting_frame = 0; - -//static int hw_frame = 0; -static int intr_cnt = 0; -int intr_cnt2 = 0; - -int intr_in = 0; - - -void openair1_restart(void) { - - int i; - - for (i=0;i<number_of_cards;i++) - openair_dma(i,FROM_GRLIB_IRQ_FROM_PCI_IS_ACQ_DMA_STOP); - // openair_daq_vars.tx_test=0; - openair_daq_vars.sync_state = 0; - if (openair_daq_vars.is_eNB==0) - PHY_vars_eNB_g[0]->frame = 0; - else - PHY_vars_UE_g[0]->frame = 0; - /* - if ((mac_xface->is_cluster_head) && (mac_xface->is_primary_cluster_head)) { - openair_daq_vars.mode = openair_SYNCHED_TO_MRSCH; - } - else { - openair_daq_vars.mode = openair_NOT_SYNCHED; - } - */ - -#ifdef OPENAIR2 - msg("[openair][SCHED][SYNCH] Clearing MAC Interface\n"); - //mac_resynch(); -#endif //OPENAIR2 - -} - -void openair_sync(void) { - int i; - //int size,j; - int status; - int length; - int ret; - // static unsigned char clear=1, clear2=1; - // int Nsymb, sync_pos, sync_pos_slot; - // int Ns; - // int l; - // int rx_power; - // unsigned int adac_cnt; - // int pbch_decoded = 0; - // int frame_mod4,pbch_tx_ant; - // u8 dummy; - - // RTIME time; - - LTE_DL_FRAME_PARMS *frame_parms = lte_frame_parms_g; - - openair_daq_vars.mode = openair_NOT_SYNCHED; - - //openair_set_lo_freq_openair(openair_daq_vars.freq,openair_daq_vars.freq); - - - // sleep during acquisition of frame - - /* - time = rt_get_cpu_time_ns(); - - for (i=0;i<3*NUMBER_OF_CHUNKS_PER_FRAME;i++) { - rt_sleep(nano2count(NS_PER_SLOT/NUMBER_OF_OFDM_SYMBOLS_PER_SLOT)); - } - - time = rt_get_cpu_time_ns(); - - */ - - if (openair_daq_vars.one_shot_get_frame == 1) { // we're in a non real-time mode so just grab a frame and write to fifo - if (sync_getting_frame == 0) { - for (i=0;i<number_of_cards;i++) { - ret = setup_regs(i,frame_parms); - - openair_get_frame(i); //received frame is stored in PHY_vars->RX_DMA_BUFFER - } - sync_getting_frame = 1; - sync_slot_cnt = 0; - } - - if (sync_slot_cnt == 40) { // wait 2 frames worth of samples - - msg("[PHY][SYNC] Getting frame, slot %d, adac %d\n",sync_slot_cnt,openair_get_mbox()); - status=rtf_reset(rx_sig_fifo); - - for (i=0;i<NB_ANTENNAS_RX;i++) { - length=rtf_put(rx_sig_fifo,(unsigned char*)RX_DMA_BUFFER[0][i],FRAME_LENGTH_BYTES); - if (length < FRAME_LENGTH_BYTES) { - msg("[openair][sched][rx_sig_fifo_handler] Didn't put %d bytes for antenna %d (put %d)\n",FRAME_LENGTH_BYTES,i,length); - } - else { - msg("[openair][sched][rx_sig_fifo_handler] Worte %d bytes for antenna %d to fifo (put %d)\n",FRAME_LENGTH_BYTES,i,length); - } - } - - // signal that acquisition is done in control fifo - rtf_put(rf_cntl_fifo,&openair_daq_vars.sched_cnt,sizeof(int)); - openair_daq_vars.one_shot_get_frame = 0; - - sync_getting_frame = 0; - sync_slot_cnt = 0; - } - sync_slot_cnt++; - } //(openair_daq_vars.one_shot_get_frame == 0) - -#ifdef OPENAIR1 - if ((openair_daq_vars.do_synch==1) && (openair_daq_vars.node_configured == 3)) {// the node has been cofigured as a UE and we do sync - - if (sync_getting_frame == 0) { - ret = setup_regs(0,frame_parms); - openair_get_frame(0); //received frame is stored in PHY_vars->RX_DMA_BUFFER - sync_getting_frame = 1; - sync_slot_cnt = 0; - } - - if (sync_slot_cnt == 40) { // wait 2 frames worth of samples - - //memcpy((void *)(RX_DMA_BUFFER[0][0]+FRAME_LENGTH_COMPLEX_SAMPLES),(void*)RX_DMA_BUFFER[0][0],OFDM_SYMBOL_SIZE_BYTES); - //memcpy((void *)(RX_DMA_BUFFER[0][1]+FRAME_LENGTH_COMPLEX_SAMPLES),(void*)RX_DMA_BUFFER[0][1],OFDM_SYMBOL_SIZE_BYTES); - -#ifdef DEBUG_PHY - for (i=0;i<number_of_cards;i++) - msg("[openair][SCHED][SYNC] card %d freq %d:%d, RX_DMA ADR 0 %x, RX_DMA ADR 1 %x, RX_GAIN_VAL %x, TDD_CONFIG %d, TCXO %d, NODE_ID %d\n", - (pci_interface[i]->freq_info>>1)&3, - (pci_interface[i]->freq_info>>3)&3, - pci_interface[i]->adc_head[0], - pci_interface[i]->adc_head[1], - //pci_interface[i]->ofdm_symbols_per_frame, - pci_interface[i]->rx_gain_val, - pci_interface[i]->tdd_config, - pci_interface[i]->tcxo_dac, - pci_interface[i]->node_id); - -#endif - - msg("[openair][SCHED][SYNCH] starting sync\n"); - - - if (initial_sync(PHY_vars_UE_g[0]) == 0) { - - if (openair_daq_vars.node_running == 1) { - - for (i=0;i<number_of_cards;i++) - pci_interface[i]->frame_offset = PHY_vars_UE_g[0]->rx_offset; - - openair_daq_vars.mode = openair_SYNCHED; - - /* - lte_adjust_synch(&PHY_vars_UE_g[0]->lte_frame_parms, - PHY_vars_UE_g[0], - 0, - clear2, - 16384); - if (clear2 == 1) - clear2 = 0; - */ - - msg("[openair][SCHED][SYNCH] Starting RT aquisition\n"); - for (i=0;i<number_of_cards;i++) - openair_dma(i,FROM_GRLIB_IRQ_FROM_PCI_IS_ACQ_START_RT_ACQUISITION); - - } - - } - else { - msg("[openair][SCHED][SYNCH] PBCH not decoded!\n"); - } - - /* - // Do AGC - if (openair_daq_vars.rx_gain_mode == DAQ_AGC_ON) { - phy_adjust_gain(clear, 512, 0, PHY_vars_UE_g[0]); - if (clear == 1) - clear = 0; - } - */ - - openair_daq_vars.do_synch=0; - - sync_getting_frame = 0; - sync_slot_cnt = 0; - } - sync_slot_cnt++; - } -#endif -} - - - - - - -//----------------------------------------------------------------------------- -/** MACPHY Thread */ -static void * openair_thread(void *param) { - //-----------------------------------------------------------------------------ddd - - //------------------------------ -#ifndef USER_MODE - struct sched_param p; -#endif // USER_MODE - - u8 next_slot, last_slot; - unsigned int time_in,time_out,i; - unsigned int aa,slot_offset, slot_offset_F; - int diff; - - LTE_DL_FRAME_PARMS *frame_parms = lte_frame_parms_g; - - RTIME rt_time_in, rt_time_out, rt_diff; - - int rc; - RTIME tv; - struct timespec ts; - - // run on CPU 1, which should be reserved only for this (by adding isolcpus=1 noirqbalance to the kernel options). Also use IsolCpusMaks=0x2 when loading rtai_hal - // rt_set_runnable_on_cpuid(pthread_self(),1); - rt_sleep(nano2count(NS_PER_SLOT)); - - - p.sched_priority = OPENAIR_THREAD_PRIORITY; - pthread_attr_setschedparam (&attr_threads[OPENAIR_THREAD_INDEX], &p); -#ifndef RTAI_ISNT_POSIX - pthread_attr_setschedpolicy (&attr_threads[OPENAIR_THREAD_INDEX], SCHED_FIFO); -#endif - - printk("[openair][SCHED][openair_thread] openair_thread started with id %x, fpu_flag = %x, cpuid = %d\n",(unsigned int)pthread_self(),pthread_self()->uses_fpu,rtai_cpuid()); - - if (openair_daq_vars.is_eNB == 1) { - msg("[openair][SCHED][openair_thread] Configuring openair_thread for primary clusterhead\n"); - } - else { - msg("[openair][SCHED][openair_thread] Configuring OPENAIR THREAD for regular node\n"); - } - -#ifdef OPENAIR1 - lte_sync_time_init(frame_parms); -#endif - - openair_daq_vars.sync_state=0; - - exit_openair = 0; - - sync_slot_cnt = 0; - sync_getting_frame = 0; - - // Inner thread endless loop - // exits on error or normally - - openair_daq_vars.sched_cnt = 0; - openair_daq_vars.instance_cnt = -1; - - for (i=0;i<number_of_cards;i++) - Zero_Buffer((void*)TX_DMA_BUFFER[i][0], - 4*SLOT_LENGTH_BYTES_NO_PREFIX); - - while (exit_openair == 0) { - - tv = rt_get_time(); - count2timespec(tv, &ts); - ts.tv_nsec += 100000; - - rc = pthread_mutex_timedlock(&openair_mutex,&ts); - if (rc==ETIMEDOUT) - msg("[SCHED][openair_thread] pthread_mutex_timedlock timed out, exiting\n"); - else if (rc != 0) - msg("[SCHED][openair_thread] ERROR pthread_mutex_lock\n"); - else { - //msg("[SCHED][openair_thread] Starting PHY processing for slot %d, frame %d\n",last_slot,mac_xface->frame); - //msg("[SCHED][openair_thread] Locked openair_mutex, instance_cnt=%d\n",openair_daq_vars.instance_cnt); - - while (openair_daq_vars.instance_cnt < 0) { - // wait for the irq handler to signal - // this also unlocks the mutex - // when signal is received, mutex is automatically locked again - pthread_cond_wait(&openair_cond,&openair_mutex); - } - /* - if (exit_openair==1) { - msg("Exiting openair_thread ... \n"); - break; - } - */ - //msg("[SCHED][openair_thread] unlocking openair_mutex, instance_cnt=%d\n",openair_daq_vars.instance_cnt); - if (pthread_mutex_unlock(&openair_mutex) !=0) - msg("[SCHED][openair_thread] ERROR unlocking openair_mutex\n"); - } - - next_slot = (openair_daq_vars.slot_count + 1 ) % LTE_SLOTS_PER_FRAME; - if (openair_daq_vars.slot_count==0) - last_slot = LTE_SLOTS_PER_FRAME-1; - else - last_slot = (openair_daq_vars.slot_count - 1 ) % LTE_SLOTS_PER_FRAME; - - //msg("[SCHED][Thread] Mode = %d (openair_NOT_SYNCHED=%d), slot_count = %d, instance_cnt = %d\n",openair_daq_vars.mode,openair_NOT_SYNCHED,openair_daq_vars.slot_count,openair_daq_vars.instance_cnt); - - if ((openair_daq_vars.mode != openair_NOT_SYNCHED) && (openair_daq_vars.node_running == 1)) { - time_in = openair_get_mbox(); - rt_time_in = rt_get_time_ns(); - -#ifdef DEBUG_PHY - //debug_msg("[SCHED][OPENAIR_THREAD] frame = %d, slot_count %d, last %d, next %d\n", mac_xface->frame, openair_daq_vars.slot_count, last_slot, next_slot); -#endif - -#ifdef OPENAIR1 - if (openair_daq_vars.is_eNB==1) { - if (PHY_vars_eNB_g && PHY_vars_eNB_g[0]) { - PHY_vars_eNB_g[0]->frame = openair_daq_vars.hw_frame; - phy_procedures_eNB_lte(last_slot,next_slot,PHY_vars_eNB_g[0],0); -#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); - slot_offset = (next_slot)* - (PHY_vars_eNB_g[0]->lte_frame_parms.samples_per_tti>>1); - - for (aa=0; aa<PHY_vars_eNB_g[0]->lte_frame_parms.nb_antennas_tx; aa++) { - if (PHY_vars_eNB_g[0]->lte_frame_parms.Ncp == 1) { - - /* - if ((openair_daq_vars.hw_frame%100) == 0) - msg("[SCHED][OPENAIR_THREAD] frame = %d, slot_offset_F %d, slot_offset %d, input %p, output %p, samples_per_tti %d\n", - openair_daq_vars.hw_frame, - slot_offset_F, - slot_offset, - &PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdataF[0][aa][slot_offset_F], - &PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][aa][slot_offset>>1], - PHY_vars_eNB_g[0]->lte_frame_parms.samples_per_tti); - */ - /* - for (i=0;i<6;i++) { - memset(&PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdataF[0][aa][slot_offset_F+i*PHY_vars_eNB_g[0]->lte_frame_parms.ofdm_symbol_size],0,PHY_vars_eNB_g[0]->lte_frame_parms.ofdm_symbol_size*sizeof(int)); - ((short*)(PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdataF[0][aa]))[(slot_offset_F+i*512+75)*2]=1024; - } - */ - /* - for (i=0;i<PHY_vars_eNB_g[0]->lte_frame_parms.ofdm_symbol_size;i++) - ((short*)(PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdataF[0][aa]))[(slot_offset_F+i)*2]=i; - */ - /* - for (i=0;i<PHY_vars_eNB_g[0]->lte_frame_parms.samples_per_tti>>1;i++) - ((char*)(PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][aa]))[(slot_offset+i)*2] = (char) 0; //(i/30); - */ - - PHY_ofdm_mod(&PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdataF[0][aa][slot_offset_F], // input -#ifdef BIT8_TX - &PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][aa][slot_offset>>1], // output -#else - &PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][aa][slot_offset], // output -#endif - PHY_vars_eNB_g[0]->lte_frame_parms.log2_symbol_size, // log2_fft_size - (PHY_vars_eNB_g[0]->lte_frame_parms.Ncp==1) ? 6 : 7, // number of symbols - PHY_vars_eNB_g[0]->lte_frame_parms.nb_prefix_samples, // number of prefix samples - PHY_vars_eNB_g[0]->lte_frame_parms.twiddle_ifft, // IFFT twiddle factors - PHY_vars_eNB_g[0]->lte_frame_parms.rev, // bit-reversal permutation - CYCLIC_PREFIX); - - if (((openair_daq_vars.hw_frame%1000)==0) && (next_slot==0) && (aa==0)) { - /* - for (i=0;i<511;i++) { - msg("twiddle_ifft(%d) = (%d, %d)\n", i, - PHY_vars_eNB_g[0]->lte_frame_parms.twiddle_ifft[4*i], - PHY_vars_eNB_g[0]->lte_frame_parms.twiddle_ifft[4*i+1]); - } - */ - for (i=0;i<512;i++) - msg("X(%d)=(%d,%d), ",i,((short*)(PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdataF[0][aa]))[(slot_offset_F+i)*2], - ((short*)(PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdataF[0][aa]))[(slot_offset_F+i)*2+1]); - msg("\n"); - for (i=0;i<640;i++) - msg("x(%d)=(%d,%d), ",i,((char*)(PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][aa]))[(slot_offset+i)*2], - ((char*)(PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][aa]))[(slot_offset+i)*2+1]); - msg("\n"); - //exit_openair=1; - } - - } - else { - msg("[SCHED][OPENAIR_THREAD] Normal prefix not implemented yet!!!\n"); - } - } -#endif //IFFT_FPGA - } - } - else { - if (PHY_vars_UE_g && PHY_vars_UE_g[0]) - phy_procedures_UE_lte(last_slot,next_slot,PHY_vars_UE_g[0],0,0); -#ifndef IFFT_FPGA - slot_offset_F = (next_slot)* - (PHY_vars_UE_g[0]->lte_frame_parms.ofdm_symbol_size)* - ((PHY_vars_UE_g[0]->lte_frame_parms.Ncp==1) ? 6 : 7); - slot_offset = (next_slot)* - (PHY_vars_UE_g[0]->lte_frame_parms.ofdm_symbol_size + PHY_vars_UE_g[0]->lte_frame_parms.nb_prefix_samples)* - ((PHY_vars_UE_g[0]->lte_frame_parms.Ncp==1) ? 6 : 7); - for (aa=0; aa<PHY_vars_UE_g[0]->lte_frame_parms.nb_antennas_tx; aa++) { - if (PHY_vars_UE_g[0]->lte_frame_parms.Ncp == 1) { - /* - debug_msg("[SCHED][OPENAIR_THREAD] frame = %d, slot_offset_F %d, slot_offset %d, input %p, output %p\n", - mac_xface->frame, - slot_offset_F, - slot_offset, - &PHY_vars_UE_g[0]->lte_ue_common_vars.txdataF[aa][slot_offset_F], - &PHY_vars_UE_g[0]->lte_ue_common_vars.txdata[aa][slot_offset>>1]); - */ - PHY_ofdm_mod(&PHY_vars_UE_g[0]->lte_ue_common_vars.txdataF[aa][slot_offset_F], // input -#ifdef BIT8_TX - &PHY_vars_UE_g[0]->lte_ue_common_vars.txdata[aa][slot_offset>>1], // output -#else - &PHY_vars_UE_g[0]->lte_ue_common_vars.txdata[aa][slot_offset], // output -#endif - PHY_vars_UE_g[0]->lte_frame_parms.log2_symbol_size, // log2_fft_size - (PHY_vars_UE_g[0]->lte_frame_parms.Ncp==1) ? 6 : 7, // number of symbols - PHY_vars_UE_g[0]->lte_frame_parms.nb_prefix_samples, // number of prefix samples - PHY_vars_UE_g[0]->lte_frame_parms.twiddle_ifft, // IFFT twiddle factors - PHY_vars_UE_g[0]->lte_frame_parms.rev, // bit-reversal permutation - CYCLIC_PREFIX); - } - else { - msg("[SCHED][OPENAIR_THREAD] Normal prefix not implemented yet!!!\n"); - } - } -#endif //IFFT_FPGA - } -#endif //OPENAIR1 - - time_out = openair_get_mbox(); - rt_time_out = rt_get_time_ns(); - - - diff = (((int) time_out) - ((int) time_in)) % ((int) 160); - rt_diff = rt_time_out-rt_time_in; - - /* - debug_msg("[SCHED][OPENAIR_THREAD] Frame %d: last_slot %d, macphy_scheduler time_in %d, time_out %d, diff %d, time_in %llu, time_out %llu, diff %llu\n", - mac_xface->frame, last_slot, - time_in,time_out,diff, - rt_time_in,rt_time_out,rt_diff); - */ - if (rt_diff > 500000) - msg("[SCHED][OPENAIR_THREAD] last_slot %d, macphy_scheduler time_in %d, time_out %d, diff %d, time_in %llu, time_out %llu, diff %llu\n", - last_slot, - time_in,time_out,diff, - rt_time_in,rt_time_out,rt_diff); - - - /* - if ((mac_xface->is_primary_cluster_head == 0) && (last_slot == 0)) { - if (openair_daq_vars.first_sync_call == 1) - openair_daq_vars.first_sync_call = 0; - } - */ - } // daq_mode != NOT_SYNCHED - - - else { // synchronization and get frame - - if ((openair_daq_vars.hw_frame%100==0) - && (openair_daq_vars.slot_count==0) - && (openair_daq_vars.mode != openair_SYNCHED)) { - msg("[SCHED][OPENAIR_THREAD] Frame %d: last_slot %d: calling openair_sync\n", - openair_daq_vars.hw_frame,openair_daq_vars.slot_count); - openair_daq_vars.do_synch=1; - } - openair_sync(); - - } - - // signal that PHY has finished by decreasing instance count - // don't forget to protect access with mutex - tv = rt_get_time(); - count2timespec(tv, &ts); - ts.tv_nsec += 100000; - - rc = pthread_mutex_timedlock(&openair_mutex,&ts); - if (rc==ETIMEDOUT) - msg("[SCHED][openair_thread] pthread_mutex_timedlock timed out, exiting\n"); - else if (rc != 0) - msg("[SCHED][openair_thread] ERROR pthread_mutex_lock\n"); - else { - openair_daq_vars.instance_cnt--; - //msg("[SCHED][openair_thread] Finished PHY processing for slot %d, frame %d\n",last_slot,mac_xface->frame); - // msg("[SCHED][openair_thread] unlocking openair_mutex, instance_cnt=%d\n",openair_daq_vars.instance_cnt); - if (pthread_mutex_unlock(&openair_mutex) !=0) - msg("[SCHED][openair_thread] ERROR unlocking openair_mutex\n"); - } - - } // end while (1) - - // report what happened - - msg ("[SCHED][OPENAIR_THREAD] Exited : openair_daq_vars.slot_count = %d, MODE = %d\n", openair_daq_vars.slot_count, openair_daq_vars.mode); - - // rt_task_delete(rt_whoami); - /* pthread_exit(NULL); */ -#ifdef SERIAL_IO - rt_spclose(COM1); -#endif - - pthread_mutex_destroy(&openair_mutex); - pthread_cond_destroy(&openair_cond); - - return(0); -} - - - -int slot_irq_handler(int irq, void *cookie) { - - unsigned int adac_cnt; - unsigned short irqval; - LTE_DL_FRAME_PARMS *frame_parms=lte_frame_parms_g; - int rc; - RTIME tv; - struct timespec ts; - u32 irqcmd; - static int busy=0; - - intr_in = 1; - intr_cnt++; - - if (oai_semaphore && inst_cnt_ptr && lxrt_task) { - rt_sem_wait(oai_semaphore); - //if ((intr_cnt2%2000)<10) rt_printk("intr_cnt %d, inst_cnt_ptr %p, inst_cnt %d\n",intr_cnt,inst_cnt_ptr,*inst_cnt_ptr); - if (*inst_cnt_ptr==0) { - rt_sem_signal(oai_semaphore); //now the mutex should have vaule 1 - if (busy==0) { - rt_printk("intr_cnt %d, worker thread busy!\n", intr_cnt); - busy = 1; - } //else no need to repeat this message - } - else { - (*inst_cnt_ptr)++; - //rt_printk("*inst_cnt_ptr %d\n",*inst_cnt_ptr); - rt_sem_signal(oai_semaphore); //now the mutex should have vaule 1 - rt_send_if(lxrt_task,intr_cnt); - if (busy==1) { - rt_printk("intr_cnt %d, resuming worker thread!\n", intr_cnt); - busy = 0; - } //else no need to repeat this message - } - intr_cnt2++; - } - - if (vid != XILINX_VENDOR) { //CBMIMO1 - - // check interrupt status register - pci_read_config_word(pdev[0],6 , &irqval); - - if ((irqval&8) != 0) { - - //msg("got interrupt for CBMIMO1, intr_cnt=%d, node_configured=%d\n",intr_cnt,openair_daq_vars.node_configured); - - // RESET PCI IRQ - openair_writel(pdev[0], FROM_GRLIB_CFG_GRPCI_EUR_CTRL_OFFSET, FROM_GRLIB_BOOT_HOK|FROM_GRLIB_PCI_IRQ_ACK); - openair_writel(pdev[0], FROM_GRLIB_CFG_GRPCI_EUR_CTRL_OFFSET, FROM_GRLIB_BOOT_HOK); - - if (openair_daq_vars.node_configured > 0) { - - adac_cnt = (*(unsigned int *)mbox); - - openair_daq_vars.slot_count=intr_cnt % LTE_SLOTS_PER_FRAME; - //openair_daq_vars.slot_count=adac_cnt>>3; - - //if ((adac_cnt>>3) == 0) - //if (((int) adac_cnt - (int) openair_daq_vars.last_adac_cnt)<0) // This is a new frame - if (openair_daq_vars.slot_count==0) - openair_daq_vars.hw_frame++; - - if (((openair_daq_vars.hw_frame %100) == 0) && (openair_daq_vars.hw_frame>0)) { - tv = rt_get_time_ns(); - msg("[SCHED][slot_irq_handler] time %llu, interrupt count %d, adac %d, last %d, HW Frame %d, slot %d\n", - tv,intr_cnt,adac_cnt,openair_daq_vars.last_adac_cnt,openair_daq_vars.hw_frame,openair_daq_vars.slot_count); - } - - openair_daq_vars.last_adac_cnt=adac_cnt; - - /* - if ((openair_daq_vars.hw_frame %100) == 0) - printk("[SCHED][slot_irq_handler] Current HW Frame %d, interrupt cnt %d\n",openair_daq_vars.hw_frame,intr_cnt); - */ - - - tv = rt_get_time(); - count2timespec(tv, &ts); - ts.tv_nsec += 100000; - - if (exit_openair==0) { - // Schedule openair_thread - - //first lock the mutex that protects the counter that indicates if PHY is still busy - //rc = pthread_mutex_lock (&openair_mutex); // lock before accessing shared resource - rc = pthread_mutex_timedlock (&openair_mutex,&ts); // lock before accessing shared resource - if (rc==ETIMEDOUT) { - msg("[SCHED][slot_irq_handler] pthread_mutex_timedlock timed out, exiting\n"); - //exit_openair = 1; - } - else if (rc != 0) { - msg("[SCHED][slot_irq_handler] ERROR pthread_mutex_lock, exiting\n"); - //exit_openair = 1; - } - else { - // we locked the mutex successfully, so now we can check its value - //msg("[SCHED][slot_irq_handler] Locked openair_mutex, instance_cnt=%d\n",openair_daq_vars.instance_cnt); - - if (openair_daq_vars.instance_cnt == 0) {// PHY is still busy - msg("[SCHED][slot_irq_handler] ERROR slot interrupt while processing, instance_cnt=%d\n", - openair_daq_vars.instance_cnt); - - // unlock the mutex - if (pthread_mutex_unlock (&openair_mutex) != 0) { - msg("[SCHED][slot_irq_handler] ERROR pthread_mutex_unlock\n"); - //exit_openair=1; - } - } - else { // schedule L2/L1H TX thread - openair_daq_vars.instance_cnt++; //now it should be 0 - - // Signal MAC_PHY Scheduler - /* - if ((openair_daq_vars.is_eNB==1) && - (PHY_vars_eNB_g[0]->frame<100)) - msg("[SCHED][slot_irq_handler] Signaling eNB MACPHY scheduler for slot %d\n",openair_daq_vars.slot_count); - else if ((openair_daq_vars.is_eNB==0) && - (PHY_vars_UE_g[0]->frame<100)) - msg("[SCHED][slot_irq_handler] Signaling UE MACPHY scheduler for slot %d\n",openair_daq_vars.slot_count); - */ - - // unlock the mutex - if (pthread_mutex_unlock (&openair_mutex) != 0) { - msg("[SCHED][slot_irq_handler] ERROR pthread_mutex_unlock\n"); - //exit_openair=1; - } - - if (pthread_cond_signal(&openair_cond) != 0) { - msg("[SCHED][slot_irq_handler] ERROR pthread_cond_signal\n");// schedule L2/L1H TX thread - //exit_openair = 1; - } - - } - } - } - } // node_configured > 0 - rt_ack_irq(irq); - rt_unmask_irq(irq); - rt_enable_irq(irq); - intr_in = 0; - return IRQ_HANDLED; - - } - else { // CBMIMO is not source of interrupt - - rt_pend_linux_irq(irq); - intr_in = 0; - return IRQ_NONE; - } - - // CBMIMO1 is not activated yet (no interrupts!) - rt_pend_linux_irq(irq); - intr_in = 0; - return IRQ_NONE; - } - else { //EXPRESS MIMO - - // msg("Got Exmimo PCIe interrupt ...\n"); - - irqval = ioread32(bar[0]); - - - if ((irqval&0x80) != 0) { - // clear PCIE interrupt bit (bit 7 of register 0x0) - iowrite32(irqval&0xffffff7f,bar[0]); - irqcmd = ioread32(bar[0]+0x4); - - - if (irqcmd == SLOT_INTERRUPT) { - // process_slot_interrupt(); - } - else if (irqcmd == PCI_PRINTK) { - // msg("Got PCIe interrupt for printk ...\n"); - pci_fifo_printk(); - - } - else if (irqcmd == GET_FRAME_DONE) { - msg("Got PCIe interrupt for GET_FRAME_DONE ...\n"); - openair_daq_vars.get_frame_done=1; - } - rt_ack_irq(irq); - rt_unmask_irq(irq); - rt_enable_irq(irq); - intr_in = 0; - return IRQ_HANDLED; - } - else { - // RESET PCI IRQ - rt_pend_linux_irq(irq); - intr_in = 0; - return IRQ_NONE; - } - } - -} - - - - -s32 openair_sched_init(void) { - - - int error_code; - - int* tmp; - - LTE_DL_FRAME_PARMS *frame_parms = lte_frame_parms_g; - - - openair_daq_vars.scheduler_interval_ns=NS_PER_SLOT; // initial guess - - openair_daq_vars.last_adac_cnt=-1; - - exit_openair=0; - - pthread_mutex_init(&openair_mutex,NULL); - - pthread_cond_init(&openair_cond,NULL); - - /* - if (openair_daq_vars.is_eNB==1){ - printk("[openair][SCHED][init] Configuring primary clusterhead\n"); - PHY_vars_eNB_g[0]->frame=0; - } - else { - PHY_vars_UE_g[0]->frame=0; - printk("[openair][SCHED][init] Configuring regular node\n"); - } - */ - openair_daq_vars.mode = openair_NOT_SYNCHED; - -#ifdef EMOS - error_code = rtf_create(CHANSOUNDER_FIFO_MINOR,CHANSOUNDER_FIFO_SIZE); - printk("[OPENAIR][SCHED][INIT] Created EMOS FIFO, error code %d\n",error_code); -#endif - - - - - pthread_attr_init (&attr_threads[OPENAIR_THREAD_INDEX]); - pthread_attr_setstacksize(&attr_threads[OPENAIR_THREAD_INDEX],OPENAIR_THREAD_STACK_SIZE); - - attr_threads[OPENAIR_THREAD_INDEX].priority = 1; - - openair_daq_vars.instance_cnt = -1; - - // Create openair_thread - error_code = pthread_create(&threads[OPENAIR_THREAD_INDEX], - &attr_threads[OPENAIR_THREAD_INDEX], - openair_thread, - (void *)0); - - - if (error_code!= 0) { - printk("[OPENAIR][SCHED][INIT] Could not allocate openair_thread, error %d\n",error_code); - return(error_code); - } - else { - printk("[OPENAIR][SCHED][INIT] Allocate openair_thread successful\n"); - } - - // Create interrupt service routine for PCI - - - - - - error_code = rtf_create(rx_sig_fifo, NB_ANTENNAS_RX*FRAME_LENGTH_BYTES); - printk("[openair][SCHED][INIT] Created rx_sig_fifo (%d bytes), error_code %d\n", - NB_ANTENNAS_RX*FRAME_LENGTH_BYTES, - error_code); - - - //if (mac_xface->is_cluster_head == 0) - //FK mac_xface->is_cluster_head not initialized at this stage - // error_code = init_dlsch_threads(); - - tmp = rt_malloc(sizeof(int)); - printk("[openair][SCHED][INIT] tmp= %p\n",tmp); - rt_free(tmp); - - return(error_code); - -} - -void openair_sched_cleanup() { - -#ifdef EMOS - int error_code; -#endif - exit_openair = 1; - openair_daq_vars.mode = openair_SCHED_EXIT; - -#ifdef EMOS - error_code = rtf_destroy(CHANSOUNDER_FIFO_MINOR); - printk("[OPENAIR][SCHED][CLEANUP] EMOS FIFO closed, error_code %d\n", error_code); -#endif - - //if (mac_xface->is_cluster_head == 0) - //FK: mac_xface->is_cluster_head not initialized at this stage - // cleanup_dlsch_threads(); - - if (openair_irq_enabled==1) { - rt_disable_irq(pdev[0]->irq); - rt_release_irq(pdev[0]->irq); - } - - printk("[openair][SCHED][CLEANUP] Done!\n"); - - -} - - -void openair_sched_exit(char *str) { - u8 i; - - msg("%s\n",str); - msg("[OPENAIR][SCHED] openair_sched_exit() called, preparing to exit ...\n"); - - exit_openair = 1; - openair_daq_vars.mode = openair_SCHED_EXIT; - for (i=0;i<number_of_cards;i++) - openair_dma(i,FROM_GRLIB_IRQ_FROM_PCI_IS_ACQ_DMA_STOP); - -} - - - -/*@}*/ - - diff --git a/openair1/SCHED/sched_lte_user.c b/openair1/SCHED/sched_lte_user.c deleted file mode 100644 index 07f8429dfb..0000000000 --- a/openair1/SCHED/sched_lte_user.c +++ /dev/null @@ -1,445 +0,0 @@ -/******************************************************************************* - - 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 sched_lte_fw2011.c -* \brief RTAI scheduler for LTE UE/eNB procedures (CBMIMO1 2011 FPGA firmware) -* \author R. Knopp, M. Guillaud, F. Kaltenberger -* \date 2011 -* \version 0.1 -* \company Eurecom -* \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr -* \note -* \warning -*/ -/* - * @{ - */ - -/* -* @addtogroup _physical_layer_ref_implementation_ -\section _process_scheduling_ Process Scheduling -This section deals with real-time process scheduling for PHY and synchronization with certain hardware targets (CBMIMO1). -*/ - -#ifndef USER_MODE -#define __NO_VERSION__ - -/* -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/version.h> -#include <linux/types.h> -#include <linux/netdevice.h> - -#include <asm/io.h> -#include <asm/bitops.h> - -#include <asm/uaccess.h> -#include <asm/segment.h> -#include <asm/page.h> -*/ - - -#ifdef RTAI_ISNT_POSIX -#include "rt_compat.h" -#endif /* RTAI_ISNT_POSIX */ - -#include "MAC_INTERFACE/extern.h" - -#ifdef CBMIMO1 -#include "ARCH/CBMIMO1/DEVICE_DRIVER/cbmimo1_device.h" -#include "ARCH/CBMIMO1/DEVICE_DRIVER/extern.h" -#include "ARCH/CBMIMO1/DEVICE_DRIVER/defs.h" -#endif // CBMIMO1 - -#ifdef RTAI_ENABLED -#include <rtai.h> -#include <rtai_posix.h> -#include <rtai_fifos.h> -#endif // - - -#include <linux/pci.h> - -#else -#include <stdio.h> -#include <stdlib.h> -#endif // /* USER_MODE */ - - -#include "PHY/types.h" -#include "PHY/defs.h" -#include "PHY/extern.h" -#include "defs.h" -#include "extern.h" - -#ifdef CBMIMO1 -#include "ARCH/CBMIMO1/DEVICE_DRIVER/from_grlib_softregs.h" -#endif //CBMIMO1 - -#ifdef SERIAL_IO -#include "rtai_serial.h" -#endif - -#ifdef EMOS -#include "phy_procedures_emos.h" -extern fifo_dump_emos_UE emos_dump_UE; -#endif - -/// Mutex for instance count on MACPHY scheduling -pthread_mutex_t openair_mutex; -/// Condition variable for MACPHY thread -pthread_cond_t openair_cond; -/// Threads -pthread_t threads[openair_SCHED_NB_THREADS]={NULL,NULL,NULL}; -/// Thread Attributes -pthread_attr_t attr_threads[openair_SCHED_NB_THREADS]; -/// RX Signal FIFO for Testing without hardware -#define RX_SIG_FIFO_NUMBER 59 -int rx_sig_fifo = RX_SIG_FIFO_NUMBER; -/// RX Control FIFO for testing without hardware -#define RF_CNTL_FIFO_NUMBER 60 -int rf_cntl_fifo = RF_CNTL_FIFO_NUMBER; - -#ifdef NOCARD_TEST - -/// RX Signal FIFO Mutex -pthread_mutex_t openair_rx_fifo_mutex; -/// RX Signal FIFO Condition variable -pthread_cond_t openair_rx_fifo_cond; - -/// Packet for RX Signal Control -RF_CNTL_PACKET rf_cntl_packet; -#endif //NOCARD_TEST - -/// Global exit variable (exit on error or manual stop via IOCTL) -int exit_openair = 0; - -extern int init_dlsch_threads(void); -extern void cleanup_dlsch_threads(void); - -extern int dlsch_instance_cnt[8]; -extern pthread_mutex_t dlsch_mutex[8]; -extern pthread_cond_t dlsch_cond[8]; - -#define NO_SYNC_TEST 1 - -#ifdef CBMIMO1 -#define NUMBER_OF_CHUNKS_PER_SLOT NUMBER_OF_OFDM_SYMBOLS_PER_SLOT -#define NUMBER_OF_CHUNKS_PER_FRAME (NUMBER_OF_CHUNKS_PER_SLOT * LTE_SLOTS_PER_FRAME) -#define SYNCH_WAIT_TIME 4000 // number of symbols between SYNCH retries -#define SYNCH_WAIT_TIME_RUNNING 100 // number of symbols between SYNCH retries -#define DRIFT_OFFSET 300 -#define NS_PER_SLOT 500000 -#define MAX_DRIFT_COMP 3000 -#endif // CBMIMO1 - -#define MAX_SCHED_CNT 50000000 - - -rtheap_t rt_heap; - -unsigned int sync_slot_cnt=0; -unsigned int sync_getting_frame = 0; - -//static int hw_frame = 0; -static int intr_cnt = 0; -int intr_cnt2 = 0; - -int intr_in = 0; - - -void openair1_restart(void) { - - int i; - - for (i=0;i<number_of_cards;i++) - openair_dma(i,FROM_GRLIB_IRQ_FROM_PCI_IS_ACQ_DMA_STOP); - // openair_daq_vars.tx_test=0; - openair_daq_vars.sync_state = 0; - if (openair_daq_vars.is_eNB==0) - PHY_vars_eNB_g[0]->frame = 0; - else - PHY_vars_UE_g[0]->frame = 0; - /* - if ((mac_xface->is_cluster_head) && (mac_xface->is_primary_cluster_head)) { - openair_daq_vars.mode = openair_SYNCHED_TO_MRSCH; - } - else { - openair_daq_vars.mode = openair_NOT_SYNCHED; - } - */ - -#ifdef OPENAIR2 - msg("[openair][SCHED][SYNCH] Clearing MAC Interface\n"); - //mac_resynch(); -#endif //OPENAIR2 - -} - -int slot_irq_handler(int irq, void *cookie) { - - unsigned int adac_cnt; - unsigned short irqval; - LTE_DL_FRAME_PARMS *frame_parms=lte_frame_parms_g; - int rc; - RTIME tv; - struct timespec ts; - u32 irqcmd; - static int busy=0; - unsigned int slot_interrupt = 0; - - intr_in = 1; - // intr_cnt++; - - - - if (vid != XILINX_VENDOR) { //CBMIMO1 - - // check interrupt status register - pci_read_config_word(pdev[0],6 , &irqval); - - if ((irqval&8) != 0) { - - intr_cnt++; - slot_interrupt = 1; - //msg("got interrupt for CBMIMO1, intr_cnt=%d, node_configured=%d\n",intr_cnt,openair_daq_vars.node_configured); - - // RESET PCI IRQ - openair_writel(pdev[0], FROM_GRLIB_CFG_GRPCI_EUR_CTRL_OFFSET, FROM_GRLIB_BOOT_HOK|FROM_GRLIB_PCI_IRQ_ACK); - openair_writel(pdev[0], FROM_GRLIB_CFG_GRPCI_EUR_CTRL_OFFSET, FROM_GRLIB_BOOT_HOK); - - - - rt_ack_irq(irq); - rt_unmask_irq(irq); - rt_enable_irq(irq); - intr_in = 0; - - } - else { // CBMIMO is not source of interrupt - - rt_pend_linux_irq(irq); - intr_in = 0; - return IRQ_NONE; - } - - if (oai_semaphore && inst_cnt_ptr && lxrt_task && (slot_interrupt == 1)) { - rt_sem_wait(oai_semaphore); - if ((intr_cnt2%2000)==0) rt_printk("***intr_cnt %d, intr_cnt2 %d, inst_cnt_ptr %p, inst_cnt %d\n",intr_cnt,intr_cnt2,inst_cnt_ptr,*inst_cnt_ptr); - if (*inst_cnt_ptr==0) { - rt_sem_signal(oai_semaphore); //now the mutex should have vaule 1 - if (busy==0) { - rt_printk("intr_cnt %d, worker thread busy!\n", intr_cnt); - busy = 1; - } //else no need to repeat this message - } - else { - (*inst_cnt_ptr)++; - //rt_printk("*inst_cnt_ptr %d\n",*inst_cnt_ptr); - rt_sem_signal(oai_semaphore); //now the mutex should have vaule 1 - rt_send_if(lxrt_task,intr_cnt); - if (busy==1) { - rt_printk("intr_cnt %d, resuming worker thread!\n", intr_cnt); - busy = 0; - } //else no need to repeat this message - } - intr_cnt2++; - } - } - else { //EXPRESS MIMO - - // msg("Got Exmimo PCIe interrupt ...\n"); - - irqval = ioread32(bar[0]); - - - if ((irqval&0x80) != 0) { - // clear PCIE interrupt bit (bit 7 of register 0x0) - iowrite32(irqval&0xffffff7f,bar[0]); - irqcmd = ioread32(bar[0]+0x4); - - - if (irqcmd == SLOT_INTERRUPT) { - // process_slot_interrupt(); - - intr_cnt++; - slot_interrupt = 1; - rt_ack_irq(irq); - rt_unmask_irq(irq); - rt_enable_irq(irq); - intr_in = 0; - if ((intr_cnt%2000)==0) rt_printk("intr_cnt %d\n",intr_cnt); - - } - else if (irqcmd == PCI_PRINTK) { - // msg("Got PCIe interrupt for printk ...\n"); - pci_fifo_printk(); - rt_ack_irq(irq); - rt_unmask_irq(irq); - rt_enable_irq(irq); - intr_in = 0; - return IRQ_HANDLED; - } - else if (irqcmd == GET_FRAME_DONE) { - msg("Got PCIe interrupt for GET_FRAME_DONE ...\n"); - openair_daq_vars.get_frame_done=1; - rt_ack_irq(irq); - rt_unmask_irq(irq); - rt_enable_irq(irq); - intr_in = 0; - return IRQ_HANDLED; - } - - } - else { - // RESET PCI IRQ - rt_printk("EXMIMO: got %x from control register (intr_cnt %d)\n",irqval,intr_cnt); - irqval = ioread32(bar[0]); - rt_printk("EXMIMO: retry got %x from control register (intr_cnt %d)\n",irqval,intr_cnt); - - rt_pend_linux_irq(irq); - intr_in = 0; - return IRQ_NONE; - } - } - - - - - - // clear PCIE interrupt bit (bit 7 of register 0x0) - - - return IRQ_HANDLED; - -} - - - - -s32 openair_sched_init(void) { - - - int error_code; - - int* tmp; - - LTE_DL_FRAME_PARMS *frame_parms = lte_frame_parms_g; - - - openair_daq_vars.scheduler_interval_ns=NS_PER_SLOT; // initial guess - - openair_daq_vars.last_adac_cnt=-1; - - exit_openair=0; - - //pthread_mutex_init(&openair_mutex,NULL); - - //pthread_cond_init(&openair_cond,NULL); - - /* - if (openair_daq_vars.is_eNB==1){ - printk("[openair][SCHED][init] Configuring primary clusterhead\n"); - PHY_vars_eNB_g[0]->frame=0; - } - else { - PHY_vars_UE_g[0]->frame=0; - printk("[openair][SCHED][init] Configuring regular node\n"); - } - */ - openair_daq_vars.mode = openair_NOT_SYNCHED; - -#ifdef EMOS - error_code = rtf_create(CHANSOUNDER_FIFO_MINOR,CHANSOUNDER_FIFO_SIZE); - printk("[OPENAIR][SCHED][INIT] Created EMOS FIFO, error code %d\n",error_code); -#endif - - openair_daq_vars.instance_cnt = -1; - - error_code = rtf_create(rx_sig_fifo, NB_ANTENNAS_RX*FRAME_LENGTH_BYTES); - printk("[openair][SCHED][INIT] Created rx_sig_fifo (%d bytes), error_code %d\n", - NB_ANTENNAS_RX*FRAME_LENGTH_BYTES, - error_code); - - tmp = rt_malloc(sizeof(int)); - printk("[openair][SCHED][INIT] tmp= %p\n",tmp); - rt_free(tmp); - - return(error_code); - -} - -void openair_sched_cleanup() { - -#ifdef EMOS - int error_code; -#endif - exit_openair = 1; - openair_daq_vars.mode = openair_SCHED_EXIT; - -#ifdef EMOS - error_code = rtf_destroy(CHANSOUNDER_FIFO_MINOR); - printk("[OPENAIR][SCHED][CLEANUP] EMOS FIFO closed, error_code %d\n", error_code); -#endif - - //if (mac_xface->is_cluster_head == 0) - //FK: mac_xface->is_cluster_head not initialized at this stage - // cleanup_dlsch_threads(); - - if (openair_irq_enabled==1) { - rt_disable_irq(pdev[0]->irq); - rt_release_irq(pdev[0]->irq); - } - - printk("[openair][SCHED][CLEANUP] Done!\n"); - - -} - - -void openair_sched_exit(char *str) { - u8 i; - - msg("%s\n",str); - msg("[OPENAIR][SCHED] openair_sched_exit() called, preparing to exit ...\n"); - - exit_openair = 1; - openair_daq_vars.mode = openair_SCHED_EXIT; - for (i=0;i<number_of_cards;i++) - openair_dma(i,FROM_GRLIB_IRQ_FROM_PCI_IS_ACQ_DMA_STOP); - -} - - - -/*@}*/ - - diff --git a/openair1/SIMULATION/LTE_PHY/Makefile b/openair1/SIMULATION/LTE_PHY/Makefile index b3b634302d..73e6a1dccc 100644 --- a/openair1/SIMULATION/LTE_PHY/Makefile +++ b/openair1/SIMULATION/LTE_PHY/Makefile @@ -9,7 +9,7 @@ OPENAIR1_TOP = $(OPENAIR1_DIR) OPENAIR2_TOP = $(OPENAIR2_DIR) OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS = -g -O -Wno-strict-aliasing -rdynamic -Wall -DPHYSIM -DNODE_RG -DUSER_MODE -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DPHY_CONTEXT=1 $(CPUFLAGS) -DMALLOC_CHECK_=1 # -Wno-packed-bitfield-compat +CFLAGS = -g -O2 -Wno-strict-aliasing -rdynamic -Wall -DPHYSIM -DNODE_RG -DUSER_MODE -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DPHY_CONTEXT=1 $(CPUFLAGS) -DMALLOC_CHECK_=1 # -Wno-packed-bitfield-compat # DCI Debug @@ -189,7 +189,7 @@ clean : rm -f *.o cleanall : clean - rm -f dlsim pbchsim pdcchsim ulsim pucchsim + rm -f dlsim pbchsim pdcchsim ulsim pucchsim mbmssim prachsim rm -f *.exe* showflags : diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 9cfc9df372..9ba5288ff2 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -196,7 +196,7 @@ int main(int argc, char **argv) { u16 Nid_cell=0; int eNB_id = 0, eNB_id_i = 1; - unsigned char mcs=0,mcs_i=mcs,dual_stream_UE = 0,awgn_flag=0,round,dci_flag=0; + unsigned char mcs=0,mcs_i=0,dual_stream_UE = 0,awgn_flag=0,round,dci_flag=0; unsigned char i_mod = 2; unsigned short NB_RB; unsigned char Ns,l,m; @@ -288,6 +288,7 @@ int main(int argc, char **argv) { printf("Detected cpu_freq %f GHz\n",cpu_freq_GHz); signal(SIGSEGV, handler); + signal(SIGABRT, handler); logInit(); @@ -301,6 +302,7 @@ int main(int argc, char **argv) { { case 'a': awgn_flag = 1; + channel_model = AWGN; break; case 'b': tdd_config=atoi(optarg); @@ -467,7 +469,7 @@ int main(int argc, char **argv) { openair_daq_vars.use_ia_receiver = 0; } if ((n_tx!=2) || (transmission_mode!=5)) { - msg("Unsupported nb of decoded users: %d user(s), %d user(s) to decode\n", n_tx, dual_stream_UE); + msg("IA receiver only supported for TM5!"); exit(-1); } break; @@ -597,13 +599,10 @@ int main(int argc, char **argv) { printf("SCM-A=%d, SCM-B=%d, SCM-C=%d, SCM-D=%d, EPA=%d, EVA=%d, ETU=%d, Rayleigh8=%d, Rayleigh1=%d, Rayleigh1_corr=%d, Rayleigh1_anticorr=%d, Rice1=%d, Rice8=%d\n", SCM_A, SCM_B, SCM_C, SCM_D, EPA, EVA, ETU, Rayleigh8, Rayleigh1, Rayleigh1_corr, Rayleigh1_anticorr, Rice1, Rice8); - if(awgn_flag==0) - sprintf(bler_fname,"second_bler_tx%d_mcs%d_chan%d.csv",transmission_mode,mcs,channel_model); - else - if(transmission_mode==5) - sprintf(bler_fname,"awgn_bler_tx%d_mcs%d_u%d.csv",transmission_mode,mcs,dual_stream_UE); - else - sprintf(bler_fname,"awgn_bler_tx%d_mcs%d.csv",transmission_mode,mcs); + if(transmission_mode==5) + sprintf(bler_fname,"bler_tx%d_chan%d_nrx%d_mcs%d_mcsi%d_u%d_imod%d.csv",transmission_mode,channel_model,n_rx,mcs,mcs_i,dual_stream_UE,i_mod); + else + sprintf(bler_fname,"bler_tx%d_chan%d_nrx%d_mcs%d.csv",transmission_mode,channel_model,n_rx,mcs); bler_fd = fopen(bler_fname,"w"); fprintf(bler_fd,"SNR; MCS; TBS; rate; err0; trials0; err1; trials1; err2; trials2; err3; trials3; dci_err\n"); @@ -616,6 +615,7 @@ int main(int argc, char **argv) { fprintf(csv_fd,"data_all%d=[",mcs); } + /* //sprintf(tikz_fname, "second_bler_tx%d_u2=%d_mcs%d_chan%d_nsimus%d.tex",transmission_mode,dual_stream_UE,mcs,channel_model,n_frames); sprintf(tikz_fname, "second_bler_tx%d_u2%d_mcs%d_chan%d_nsimus%d",transmission_mode,dual_stream_UE,mcs,channel_model,n_frames); tikz_fd = fopen(tikz_fname,"w"); @@ -710,6 +710,8 @@ int main(int argc, char **argv) { fprintf(tikz_fd,"\\addplot[color=yellow, mark=+] plot coordinates {"); break; } + */ + for (i=0;i<2;i++) { s_re[i] = malloc(FRAME_LENGTH_COMPLEX_SAMPLES*sizeof(double)); s_im[i] = malloc(FRAME_LENGTH_COMPLEX_SAMPLES*sizeof(double)); @@ -951,7 +953,7 @@ int main(int argc, char **argv) { dci_alloc[num_dci].rnti = n_rnti+k; dci_alloc[num_dci].format = format1; dump_dci(&PHY_vars_eNB->lte_frame_parms,&dci_alloc[num_dci]); - for(k=0;k<n_users;k++) { + printf("Generating dlsch params for user %d\n",k); generate_eNB_dlsch_params_from_dci(0, &DLSCH_alloc_pdu_1[0], @@ -964,7 +966,6 @@ int main(int argc, char **argv) { 0, P_RNTI, PHY_vars_eNB->eNB_UE_stats[0].DL_pmi_single); - } num_dci++; num_ue_spec_dci++; @@ -1086,7 +1087,7 @@ int main(int argc, char **argv) { dci_alloc[num_dci].format = format1A; dci_alloc[num_dci].nCCE = 0; dump_dci(&PHY_vars_eNB->lte_frame_parms,&dci_alloc[num_dci]); - for(k=0;k<n_users;k++) { + printf("Generating dlsch params for user %d\n",k); generate_eNB_dlsch_params_from_dci(0, &DLSCH_alloc_pdu_1[0], @@ -1099,7 +1100,6 @@ int main(int argc, char **argv) { 0, P_RNTI, PHY_vars_eNB->eNB_UE_stats[0].DL_pmi_single); - } num_common_dci++; num_dci++; @@ -1114,7 +1114,6 @@ int main(int argc, char **argv) { dci_alloc[num_dci].rnti = n_rnti+k; dci_alloc[num_dci].format = format1E_2A_M10PRB; dci_alloc[num_dci].nCCE = 4*k; - for(k=0;k<n_users;k++) { printf("Generating dlsch params for user %d\n",k); generate_eNB_dlsch_params_from_dci(0, &DLSCH_alloc_pdu2_1E[k], @@ -1127,7 +1126,6 @@ int main(int argc, char **argv) { 0, P_RNTI, PHY_vars_eNB->eNB_UE_stats[k].DL_pmi_single); - } dump_dci(&PHY_vars_eNB->lte_frame_parms,&dci_alloc[num_dci]); num_ue_spec_dci++; @@ -1173,7 +1171,7 @@ int main(int argc, char **argv) { input_buffer_length = PHY_vars_eNB->dlsch_eNB[k][0]->harq_processes[0]->TBS/8; input_buffer[k] = (unsigned char *)malloc(input_buffer_length+4); memset(input_buffer[k],0,input_buffer_length+4); - + if (input_trch_file==0) { for (i=0;i<input_buffer_length;i++) { input_buffer[k][i]= (unsigned char)(taus()&0xff); @@ -1196,12 +1194,23 @@ int main(int argc, char **argv) { } } } + + // this is for user 0 only + coded_bits_per_codeword = get_G(&PHY_vars_eNB->lte_frame_parms, + PHY_vars_eNB->dlsch_eNB[0][0]->nb_rb, + PHY_vars_eNB->dlsch_eNB[0][0]->rb_alloc, + get_Qm(PHY_vars_eNB->dlsch_eNB[0][0]->harq_processes[0]->mcs), + num_pdcch_symbols, + 0,subframe); + + uncoded_ber_bit = (short*) malloc(sizeof(short)*coded_bits_per_codeword); + + snr_step = input_snr_step; for (ch_realization=0;ch_realization<n_ch_rlz;ch_realization++){ if(abstx){ printf("**********************Channel Realization Index = %d **************************\n", ch_realization); saving_bler=1; - } for (SNR=snr0;SNR<snr1;SNR+=snr_step) { @@ -1446,46 +1455,34 @@ int main(int argc, char **argv) { } for (k=0;k<n_users;k++) { + coded_bits_per_codeword = get_G(&PHY_vars_eNB->lte_frame_parms, PHY_vars_eNB->dlsch_eNB[k][0]->nb_rb, PHY_vars_eNB->dlsch_eNB[k][0]->rb_alloc, get_Qm(PHY_vars_eNB->dlsch_eNB[k][0]->harq_processes[0]->mcs), num_pdcch_symbols, 0,subframe); - + #ifdef TBS_FIX // This is for MESH operation!!! tbs = (double)3*TBStable[get_I_TBS(PHY_vars_eNB->dlsch_eNB[k][0]->harq_processes[0]->mcs)][PHY_vars_eNB->dlsch_eNB[k][0]->nb_rb-1]/4; #else tbs = PHY_vars_eNB->dlsch_eNB[k][0]->harq_processes[0]->TBS; #endif - rate = (double)tbs/(double)coded_bits_per_codeword; - uncoded_ber_bit = (short*) malloc(2*coded_bits_per_codeword); - - if ((trials==0) && (round==0)) - printf("Rate = %f (%f bits/dim) (G %d, TBS %d, mod %d, pdcch_sym %d, ndi %d)\n", - rate,rate*get_Qm(PHY_vars_eNB->dlsch_eNB[k][0]->harq_processes[0]->mcs), + if ((SNR==snr0) && (trials==0) && (round==0)) + printf("User %d: Rate = %f (%f bits/dim) (G %d, TBS %d, mod %d, pdcch_sym %d, ndi %d)\n", + k,rate,rate*get_Qm(PHY_vars_eNB->dlsch_eNB[k][0]->harq_processes[0]->mcs), coded_bits_per_codeword, tbs, get_Qm(PHY_vars_eNB->dlsch_eNB[k][0]->harq_processes[0]->mcs), num_pdcch_symbols, PHY_vars_eNB->dlsch_eNB[0][0]->harq_processes[0]->Ndi); - - /* - // generate channel here - random_channel(eNB2UE); - // generate frequency response - freq_channel(eNB2UE,NB_RB); - // generate PMI from channel - */ - - // use the PMI from previous trial if (DLSCH_alloc_pdu2_1E[0].tpmi == 5) { PHY_vars_eNB->dlsch_eNB[0][0]->pmi_alloc = quantize_subband_pmi(&PHY_vars_UE->PHY_measurements,0); - PHY_vars_UE->dlsch_ue[0][0]->harq_processes[0]->pmi_alloc = quantize_subband_pmi(&PHY_vars_UE->PHY_measurements,0); + PHY_vars_UE->dlsch_ue[0][0]->pmi_alloc = quantize_subband_pmi(&PHY_vars_UE->PHY_measurements,0); if (n_users>1) PHY_vars_eNB->dlsch_eNB[1][0]->pmi_alloc = (PHY_vars_eNB->dlsch_eNB[0][0]->pmi_alloc ^ 0x1555); /* @@ -1496,6 +1493,8 @@ int main(int argc, char **argv) { } */ } + + start_meas(&PHY_vars_eNB->dlsch_encoding_stats); if (dlsch_encoding(input_buffer[k], &PHY_vars_eNB->lte_frame_parms, @@ -1508,7 +1507,7 @@ int main(int argc, char **argv) { )<0) exit(-1); stop_meas(&PHY_vars_eNB->dlsch_encoding_stats); - // printf("Did not Crash here 1\n"); + PHY_vars_eNB->dlsch_eNB[k][0]->rnti = (common_flag==0) ? n_rnti+k : SI_RNTI; start_meas(&sts); dlsch_scrambling(&PHY_vars_eNB->lte_frame_parms, @@ -1531,10 +1530,7 @@ int main(int argc, char **argv) { printf("%d : (%x)\n",i,PHY_vars_eNB->dlsch_eNB[k][0]->harq_processes[0]->c[s][i]); } } - // printf("Did not Crash here 2\n"); - // if (k==1) - // printf("AMP: %d\n",AMP); start_meas(&PHY_vars_eNB->dlsch_modulation_stats); re_allocated = dlsch_modulation(PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id], AMP, @@ -1543,10 +1539,10 @@ int main(int argc, char **argv) { num_pdcch_symbols, PHY_vars_eNB->dlsch_eNB[k][0]); stop_meas(&PHY_vars_eNB->dlsch_modulation_stats); - // printf("Did not Crash here 3\n"); + /* if (trials==0 && round==0) printf("RE count %d\n",re_allocated); - + */ if (num_layers>1) re_allocated = dlsch_modulation(PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id], 1024, @@ -2129,7 +2125,7 @@ int main(int argc, char **argv) { } } - //saving PMI incase of Transmission Mode > 5 + //saving PMI in case of Transmission Mode > 5 if(abstx){ if(saving_bler==0) @@ -2155,7 +2151,8 @@ int main(int argc, char **argv) { uncoded_ber/=coded_bits_per_codeword; avg_ber += uncoded_ber; - write_output("uncoded_ber_bit.m","uncoded_ber_bit",uncoded_ber_bit,coded_bits_per_codeword,1,0); + if (n_frames==1) + write_output("uncoded_ber_bit.m","uncoded_ber_bit",uncoded_ber_bit,coded_bits_per_codeword,1,0); /* printf("precoded CQI %d dB, opposite precoded CQI %d dB\n", @@ -2281,8 +2278,6 @@ int main(int argc, char **argv) { printf("DLSCH in error in round %d\n",round); } - //free(uncoded_ber_bit); - //uncoded_ber_bit = NULL; #ifdef XFORMS phy_scope_UE(form_ue, PHY_vars_UE, @@ -2438,8 +2433,8 @@ int main(int argc, char **argv) { fclose(bler_fd); - fprintf(tikz_fd,"};\n"); - fclose(tikz_fd); + //fprintf(tikz_fd,"};\n"); + //fclose(tikz_fd); if (input_trch_file==1) fclose(input_trch_fd); @@ -2449,8 +2444,13 @@ int main(int argc, char **argv) { fprintf(csv_fd,"];"); fclose(csv_fd); } - - + + free(uncoded_ber_bit); + uncoded_ber_bit = NULL; + for (k=0;k<n_users;k++) { + free(input_buffer[k]); + input_buffer[k]=NULL; + } printf("Freeing dlsch structures\n"); for (i=0;i<2;i++) { printf("eNB %d\n",i); diff --git a/targets/ARCH/EXMIMO/USERSPACE/OAI_FW_INIT/sdr_expressmimo2_v9 b/targets/ARCH/EXMIMO/USERSPACE/OAI_FW_INIT/sdr_expressmimo2_v9 index 72956d4866edfa5a514a5ed409eb0f12332168bc..2d44da8f2d6df49005778be6e2919dd487ffb1ce 100755 GIT binary patch delta 25102 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 CP|6tq delta 24883 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 diff --git a/targets/RTAI/USER/.runinfo b/targets/RTAI/USER/.runinfo index 230e162169..b69c5f60de 100644 --- a/targets/RTAI/USER/.runinfo +++ b/targets/RTAI/USER/.runinfo @@ -1,30 +1,34 @@ -synctest:lxrt+sem+mbx+msg:!./synctest ;sleep 1;popall:control_c -condtest:lxrt+sem+mbx+msg:!sudo ./condtest;sleep 1;popall:control_c -msg_test:lxrt+sem+mbx+msg:!sudo ./msg_test;sleep 1;popall:control_c -msg_many:lxrt+sem+mbx+msg:!sudo ./msg_test;sleep 1;popall:control_c -eNB:lxrt+sem+mbx+msg:!sudo ./synctest;sleep 1;popall:control_c +synctest:lxrt+sem+mbx+msg+fifos:!./synctest ;sleep 1;popall:control_c +condtest:lxrt+sem+mbx+msg+fifos:!sudo ./condtest;sleep 1;popall:control_c +msg_test:lxrt+sem+mbx+msg+fifos:!sudo ./msg_test;sleep 1;popall:control_c +msg_many:lxrt+sem+mbx+msg+fifos:!sudo ./msg_test;sleep 1;popall:control_c +eNB:lxrt+sem+mbx+msg+fifos:!sudo ./synctest;sleep 1;popall:control_c eNB_test:lxrt+sem+mbx+msg+smi:!sudo ./lte-softmodem -S -F enb2tx;sleep 1;popall:control_c -UE:lxrt+sem+mbx+msg:!sudo ./synctest -U -d -T 108;sleep 1;popall:control_c -UE0:lxrt+sem+mbx+msg:!sudo ./lte-softmodem -U -d -C 1907602944 -V;sleep 1;popall:control_c -UE0_smbv:lxrt+sem+mbx+msg:!sudo ./lte-softmodem -U -d -C 1907598252 -V;sleep 1;popall:control_c -UE850:lxrt+sem+mbx+msg:!sudo ./lte-softmodem -U -d -C 859498000 -F ex2_850;sleep 1;popall:control_c -eNB850:lxrt+sem+mbx+msg:!sudo ./lte-softmodem -d -C 859500000 -F ex2_850;sleep 1;popall:control_c -UE0noL2:lxrt+sem+mbx+msg:!sudo ./lte-softmodem -U -d -C 1907593460 -F ex2_2 --no-L2-connect;sleep 1;popall:control_c -UE0calib:lxrt+sem+mbx+msg:!sudo ./lte-softmodem -U -d -C 1912600000 --calib-ue-rx -70 ;sleep 1;popall:control_c -UE0calibmed:lxrt+sem+mbx+msg:!sudo ./lte-softmodem -U -d -C 1912600000 --calib-ue-rx-med -70 ;sleep 1;popall:control_c -UE0calibbyp:lxrt+sem+mbx+msg:!sudo ./lte-softmodem -U -d -C 1912600000 --calib-ue-rx-byp -70 ;sleep 1;popall:control_c -UE0prach:lxrt+sem+mbx+msg:!sudo ./lte-softmodem -U -d -C 1912606900 -F ue1 --debug-ue-prach;sleep 1;popall:control_c -UE1:lxrt+sem+mbx+msg:!sudo ./lte-softmodem -U -d -C 1907600000 -F ue1 ;sleep 1;popall:control_c -UE1prach:lxrt+sem+mbx+msg:!sudo ./lte-softmodem -U -d -C 1907600000 -F ue1 --debug-ue-prach;sleep 1;popall:control_c -UE1noL2:lxrt+sem+mbx+msg:!sudo ./lte-softmodem -U -d -C 1907600000 -F ue1 --no-L2-connect;sleep 1;popall:control_c -UE2:lxrt+sem+mbx+msg:!sudo ./lte-softmodem -U -d -C 1907600000 -F ue2;sleep 1;popall:control_c -UE2prach:lxrt+sem+mbx+msg:!sudo ./lte-softmodem -U -d -C 1907600000 -F ue2 --debug-ue-prach;sleep 1;popall:control_c -UE2noL2:lxrt+sem+mbx+msg:!sudo ./lte-softmodem -U -d -C 1907600000 -F ue2 --no-L2-connect;sleep 1;popall:control_c -eNB0:lxrt+sem+mbx+msg:!sudo ./lte-softmodem -C 1907600000 -d -V;sleep 1;popall:control_c -#eNB0:lxrt+sem+mbx+msg:!sudo ./lte-softmodem -C 1907598252 -d -V;sleep 1;popall:control_c -eNB1:lxrt+sem+mbx+msg:!sudo ./lte-softmodem -C 1907600000 -F ex2_2 -d;sleep 1;popall:control_c -eNB2:lxrt+sem+mbx+msg:!sudo ./lte-softmodem -C 1907600000 -F ue2 -d;sleep 1;popall:control_c -dot11:lxrt+sem+mbx+msg:!sudo ./dot11 -C 1907600000 -d;sleep 1;popall:control_c -dot11_tx_test: lxrt+sem+mbx+msg:!sudo ./dot11 -C 1907600000 -d -t;sleep 1;popall:control_c -eNB2_750:lxrt+sem+mbx+msg:!sudo ./synctest_eNB -C 746000000 -F enb1tx_750 -d;sleep 1;popall:control_c -eNB2_1900:lxrt+sem+mbx+msg:!sudo ./synctest_eNB -C 19076000000 -F enb1tx_1900 -d;sleep 1;popall:control_c +UE:lxrt+sem+mbx+msg+fifos:!sudo ./synctest -U -d -T 108;sleep 1;popall:control_c +#UE0:lxrt+sem+mbx+msg+fifos:!sudo ./lte-softmodem -U -d -C 1907602944 -V;sleep 1;popall:control_c +#EXMIMO2 card 1 +#UE0:lxrt+sem+mbx+msg+fifos:!sudo ./lte-softmodem -U -d -C 1907600480 -V;sleep 1;popall:control_c +#EXMIMO2 card 5 +UE0:lxrt+sem+mbx+msg+fifos:!sudo ./lte-softmodem -U -d -C 1907597440 -V;sleep 1;popall:control_c +UE0_smbv:lxrt+sem+mbx+msg+fifos:!sudo ./lte-softmodem -U -d -C 1907598252 -V;sleep 1;popall:control_c +UE850:lxrt+sem+mbx+msg+fifos:!sudo ./lte-softmodem -U -d -C 859498000 -F ex2_850;sleep 1;popall:control_c +eNB850:lxrt+sem+mbx+msg+fifos:!sudo ./lte-softmodem -d -C 859500000 -F ex2_850;sleep 1;popall:control_c +UE0noL2:lxrt+sem+mbx+msg+fifos:!sudo ./lte-softmodem -U -d -C 1907600480 --no-L2-connect;sleep 1;popall:control_c +UE0calib:lxrt+sem+mbx+msg+fifos:!sudo ./lte-softmodem -U -d -C 1912600000 --calib-ue-rx -70 ;sleep 1;popall:control_c +UE0calibmed:lxrt+sem+mbx+msg+fifos:!sudo ./lte-softmodem -U -d -C 1912600000 --calib-ue-rx-med -70 ;sleep 1;popall:control_c +UE0calibbyp:lxrt+sem+mbx+msg+fifos:!sudo ./lte-softmodem -U -d -C 1912600000 --calib-ue-rx-byp -70 ;sleep 1;popall:control_c +UE0prach:lxrt+sem+mbx+msg+fifos:!sudo ./lte-softmodem -U -d -C 1912606900 -F ue1 --debug-ue-prach;sleep 1;popall:control_c +UE1:lxrt+sem+mbx+msg+fifos:!sudo ./lte-softmodem -U -d -C 1907600000 -F ue1 ;sleep 1;popall:control_c +UE1prach:lxrt+sem+mbx+msg+fifos:!sudo ./lte-softmodem -U -d -C 1907600000 -F ue1 --debug-ue-prach;sleep 1;popall:control_c +UE1noL2:lxrt+sem+mbx+msg+fifos:!sudo ./lte-softmodem -U -d -C 1907600000 -F ue1 --no-L2-connect;sleep 1;popall:control_c +UE2:lxrt+sem+mbx+msg+fifos:!sudo ./lte-softmodem -U -d -C 1907600000 -F ue2;sleep 1;popall:control_c +UE2prach:lxrt+sem+mbx+msg+fifos:!sudo ./lte-softmodem -U -d -C 1907600000 -F ue2 --debug-ue-prach;sleep 1;popall:control_c +UE2noL2:lxrt+sem+mbx+msg+fifos:!sudo ./lte-softmodem -U -d -C 1907600000 -F ue2 --no-L2-connect;sleep 1;popall:control_c +eNB0:lxrt+sem+mbx+msg+fifos:!sudo ./lte-softmodem -C 1907600000 -d -V;sleep 1;popall:control_c +#eNB0:lxrt+sem+mbx+msg+fifos:!sudo ./lte-softmodem -C 1907598252 -d -V;sleep 1;popall:control_c +eNB1:lxrt+sem+mbx+msg+fifos:!sudo ./lte-softmodem -C 1907600000 -F ex2_2 -d;sleep 1;popall:control_c +eNB2:lxrt+sem+mbx+msg+fifos:!sudo ./lte-softmodem -C 1907600000 -F ue2 -d;sleep 1;popall:control_c +dot11:lxrt+sem+mbx+msg+fifos:!sudo ./dot11 -C 1907600000 -d;sleep 1;popall:control_c +dot11_tx_test: lxrt+sem+mbx+msg+fifos:!sudo ./dot11 -C 1907600000 -d -t;sleep 1;popall:control_c +eNB2_750:lxrt+sem+mbx+msg+fifos:!sudo ./synctest_eNB -C 746000000 -F enb1tx_750 -d;sleep 1;popall:control_c +eNB2_1900:lxrt+sem+mbx+msg+fifos:!sudo ./synctest_eNB -C 19076000000 -F enb1tx_1900 -d;sleep 1;popall:control_c diff --git a/targets/RTAI/USER/Makefile b/targets/RTAI/USER/Makefile index 8c4ea4e508..90ee228cb4 100644 --- a/targets/RTAI/USER/Makefile +++ b/targets/RTAI/USER/Makefile @@ -9,7 +9,7 @@ ifeq "$(GCCVERSION)" "4.6.1" CFLAGS += -Wno-packed-bitfield-compat endif -CFLAGS += -O +CFLAGS += -O2 CFLAGS += -DDRIVER2013 -I$(OPENAIR_TARGETS)/ARCH/EXMIMO/USERSPACE/LIB/ -I$(OPENAIR_TARGETS)/ARCH/EXMIMO/DEFS -DENABLE_VCD_FIFO SRC = synctest.c condtest.c lte-softmodem.c @@ -101,7 +101,7 @@ endif #CPUFLAGS = -mmmx -msse -msse2 -m32 -mssse3 -msse4.1 CPUFLAGS = -mmmx -msse -msse2 -mssse3 -msse4.1 #CFLAGS += -fno-common -mpreferred-stack-boundary=4 -CFLAGS += -Wall -fno-strict-aliasing -DPHYSIM -DUSER_MODE -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DPHY_CONTEXT=1 -g -ggdb -rdynamic $(CPUFLAGS) # -Wno-packed-bitfield-compat +CFLAGS += -Wall -fno-strict-aliasing -DPHYSIM -DUSER_MODE -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DPHY_CONTEXT=1 -rdynamic $(CPUFLAGS) # -Wno-packed-bitfield-compat CFLAGS += -DOPENAIR_LTE -DENABLE_FXP -DOPENAIR1 -DDLSCH_THREAD #-DULSCH_THREAD #only for CBMIMO1 @@ -119,7 +119,7 @@ CFLAGS += -DHARD_RT endif ifeq ($(EMOS),1) -CFLAGS += -DEMOS -DEMOS_CHANNEL +CFLAGS += -DEMOS #-DEMOS_CHANNEL LDFLAGS += -lgps endif @@ -247,7 +247,8 @@ run_eNB2: rtai-load eNB2 --verbose clean: - rm -rf $(OBJ) $(RTAI_OBJ) + rm -rf $(OBJ) $(RTAI_OBJ) + rm -f $(ASN1_MSG_INC)/asn1_msg.o cleanasn1: rm -f $(ASN1_MSG_OBJS1) @@ -265,6 +266,11 @@ cleancell: rm -f $(OPENAIR2_DIR)/NAS/SIMU_CELLULAR/*.o rm -f $(OPENAIR2_DIR)/NAS/SIMU_CELLULAR/*.d +cleanalmostall: clean + rm -f $(ASN1_MSG_OBJS1) + rm -rf condtest synctest lte-softmodem + rm -rf synctest_eNB synctest_UE + cleanall: clean cleanasn1 rm -rf condtest synctest lte-softmodem rm -rf synctest_eNB synctest_UE diff --git a/targets/RTAI/USER/lte-softmodem.c b/targets/RTAI/USER/lte-softmodem.c index 547bf955aa..cc4ed9778c 100644 --- a/targets/RTAI/USER/lte-softmodem.c +++ b/targets/RTAI/USER/lte-softmodem.c @@ -122,8 +122,9 @@ pthread_attr_t attr_dlsch_threads; struct sched_param sched_param_dlsch; #endif -pthread_t thread2; -pthread_t thread3; +pthread_t thread2; //xforms +pthread_t thread3; //emos + /* static int instance_cnt=-1; //0 means worker is busy, -1 means its free int instance_cnt_ptr_kern,*instance_cnt_ptr_user; @@ -231,6 +232,12 @@ void *scope_thread(void *arg) { char stats_buffer[16384]; //FILE *UE_stats, *eNB_stats; int len=0; + struct sched_param sched_param; + + 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) @@ -298,6 +305,13 @@ void *emos_thread (void *arg) struct gps_data_t *gps_data = NULL; struct gps_fix_t dummy_gps_data; + + struct sched_param sched_param; + + sched_param.sched_priority = sched_get_priority_max(SCHED_FIFO)-1; + sched_setscheduler(0, SCHED_FIFO,&sched_param); + + printf("EMOS thread has priority %d\n",sched_param.sched_priority); timer = time(NULL); now = localtime(&timer); @@ -320,6 +334,8 @@ void *emos_thread (void *arg) printf("[EMOS] Error sending command to GPS\n"); //exit(-1); } + else + printf("[EMOS] Opened GPS, gps_data=%p\n"); if (UE_flag==0) channel_buffer_size = sizeof(fifo_dump_emos_eNB); @@ -365,7 +381,7 @@ void *emos_thread (void *arg) continue; /* - if (eNB_flag==1) + 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); @@ -479,16 +495,17 @@ static void *eNB_thread(void *arg) else diff = mbox_target - mbox_current; - if (diff < (-6)) { - 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 (((slot%2==0) && (diff < (-14))) || ((slot%2==1) && (diff < (-7)))) { + // at the eNB, even slots have double as much time since most of the processing is done here and almost nothing in odd slots + LOG_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); @@ -713,7 +730,7 @@ static void *UE_thread(void *arg) else diff2 = mbox_target - mbox_current; - if (diff2 <(-5)) { + if (diff2 <(-7)) { LOG_D(HW,"UE Frame %d: missed slot, proceeding with next one (slot %d, hw_slot %d, diff %d)\n",frame, slot, hw_slot, diff2); if (frame>0) oai_exit=1; @@ -846,11 +863,13 @@ static void *UE_thread(void *arg) else { LOG_I(PHY,"[initial_sync] trying carrier off %d Hz\n",openair_daq_vars.freq_offset); for (i=0; i<4; i++) { - p_exmimo_config->rf.rf_freq_rx[i] = carrier_freq[i]+openair_daq_vars.freq_offset; - p_exmimo_config->rf.rf_freq_tx[i] = carrier_freq[i]+openair_daq_vars.freq_offset; + if (p_exmimo_config->rf.rf_freq_rx[i]) + p_exmimo_config->rf.rf_freq_rx[i] = carrier_freq[i]+openair_daq_vars.freq_offset; + if (p_exmimo_config->rf.rf_freq_tx[i]) + p_exmimo_config->rf.rf_freq_tx[i] = carrier_freq[i]+openair_daq_vars.freq_offset; } openair0_dump_config(card); - + rt_sleep_ns(FRAME_PERIOD); } } } @@ -907,7 +926,7 @@ int main(int argc, char **argv) { 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}; + u32 txgain[4] = {20,20,20,20}; u16 Nid_cell = 0; u8 cooperation_flag=0, transmission_mode=1, abstraction_flag=0; @@ -1106,7 +1125,7 @@ int main(int argc, char **argv) { case 5: case 6: frame_parms->nb_antennas_tx = 2; - frame_parms->nb_antennas_rx = 1; + frame_parms->nb_antennas_rx = 2; break; default: printf("Unsupported transmission mode %d\n",transmission_mode); @@ -1194,17 +1213,13 @@ int main(int argc, char **argv) { 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.rx_gain_mode = DAQ_AGC_ON; openair_daq_vars.auto_freq_correction = 0; - openair_daq_vars.use_ia_receiver = 1; + openair_daq_vars.use_ia_receiver = 0; // 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++) + rxgain[i] = 0; for (i=0;i<4;i++) { PHY_vars_UE_g[0]->rx_gain_max[i] = rxg_max[i]; @@ -1286,18 +1301,13 @@ int main(int argc, char **argv) { NB_INST=1; openair_daq_vars.ue_dl_rb_alloc=0x1fff; - openair_daq_vars.target_ue_dl_mcs=20; + openair_daq_vars.target_ue_dl_mcs=0; openair_daq_vars.ue_ul_nb_rb=6; - openair_daq_vars.target_ue_ul_mcs=12; + openair_daq_vars.target_ue_ul_mcs=6; // 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; - + for (i=0;i<4;i++) + rxgain[i]=10; // 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; @@ -1332,6 +1342,7 @@ int main(int argc, char **argv) { p_exmimo_config->framing.eNB_flag = 0; else p_exmimo_config->framing.eNB_flag = !UE_flag; + p_exmimo_config->framing.tdd_config = DUPLEXMODE_FDD + TXRXSWITCH_LSB; p_exmimo_config->framing.resampling_factor = 2; @@ -1360,14 +1371,18 @@ int main(int argc, char **argv) { p_exmimo_config->rf.rf_vcocal[ant] = rf_vcocal_850[ant]; p_exmimo_config->rf.rffe_band_mode[ant] = DD_TDD; } - else { + else if ((carrier_freq[ant] >= 1900000000) && (carrier_freq[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] = 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_txlow[ant] = 31; + p_exmimo_config->rf.rffe_gain_txhigh[ant] = 31; + p_exmimo_config->rf.rffe_gain_rxfinal[ant] = 31; p_exmimo_config->rf.rffe_gain_rxlow[ant] = 63; } @@ -1407,7 +1422,7 @@ int main(int argc, char **argv) { #endif #ifdef OPENAIR2 - init_pdcp_thread(!UE_flag); + init_pdcp_thread(); #endif number_of_cards = openair0_num_detected_cards; diff --git a/targets/RTAI/USER/sched_rx_pdsch.c b/targets/RTAI/USER/sched_rx_pdsch.c index 05c8070e9b..d951dc30a7 100644 --- a/targets/RTAI/USER/sched_rx_pdsch.c +++ b/targets/RTAI/USER/sched_rx_pdsch.c @@ -168,18 +168,6 @@ static void * rx_pdsch_thread(void *param) { phy_vars_ue->lte_ue_pdcch_vars[eNB_id]->num_pdcch_symbols, phy_vars_ue->frame,subframe); - /* - // msg("[MYEMOS] frame %d, las_slot %d, IA %d\n",phy_vars_ue->frame,last_slot,openair_daq_vars.use_ia_receiver); - if ((phy_vars_ue->frame%500 == 0) && (phy_vars_ue->frame>=500) && (last_slot%2 == 0) && (openair_daq_vars.use_ia_receiver == 0)) { - msg("[MYEMOS] frame %d, IA receiver ON, MCS %d, bitrate %d\n",phy_vars_ue->frame,phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->mcs,phy_vars_ue->bitrate[eNB_id]); - openair_daq_vars.use_ia_receiver = 1; - } - if ((phy_vars_ue->frame%1000 == 0) && (phy_vars_ue->frame>=500) && (last_slot%2 == 0) && (openair_daq_vars.use_ia_receiver == 1)) { - msg("[MYEMOS] frame %d, IA receiver OFF, MCS %d, bitrate %d\n",phy_vars_ue->frame,phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->mcs,phy_vars_ue->bitrate[eNB_id]); - openair_daq_vars.use_ia_receiver = 0; - } - */ - if ((phy_vars_ue->transmission_mode[eNB_id] == 5) && (phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->dl_power_off==0) && (openair_daq_vars.use_ia_receiver ==1)) { -- GitLab