FreeCalypso > hg > fc-magnetite
view src/cs/layer1/tm_cfile/l1tm_func.c @ 702:9394305d4ff5 default tip
etm_audio.c: fix off-by-one error in auw of FIR coefficients
This fix was already made in FC Tourmaline a while back, but it is also
the kind of bugfix that deserves to be backported to Magnetite and
Selenite as well.
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Mon, 31 Oct 2022 00:14:44 +0000 |
parents | b870b6a44d31 |
children |
line wrap: on
line source
/************* Revision Controle System Header ************* * GSM Layer 1 software * L1TM_FUNC.C * * Filename l1tm_func.c * Copyright 2003 (C) Texas Instruments * ************* Revision Controle System Header *************/ #include "l1_macro.h" #include "l1_confg.h" #if TESTMODE #define L1TM_FUNC_C #include <string.h> #include <math.h> #include "abb.h" #include "general.h" #include "l1_types.h" #include "sys_types.h" #include "l1_const.h" #include "l1_time.h" #include "l1_signa.h" #include "l1tm_defty.h" #if 0 //(CODE_VERSION != SIMULATION) // LoCosto-ism #include "pld.h" #endif #if (TRACE_TYPE==1) || (TRACE_TYPE==4) || (TRACE_TYPE==7) || (TRACE_TYPE==0) #include "rvt_gen.h" extern T_RVT_USER_ID tm_trace_user_id; #endif #if (AUDIO_TASK == 1) #include "l1audio_const.h" #include "l1audio_cust.h" #include "l1audio_defty.h" #endif #if (L1_GTT == 1) #include "l1gtt_const.h" #include "l1gtt_defty.h" #endif #if (L1_MP3 == 1) #include "l1mp3_defty.h" #endif #if (L1_MIDI == 1) #include "l1midi_defty.h" #endif #include "l1_defty.h" #include "cust_os.h" #include "l1_msgty.h" #include "l1_varex.h" #include "l1_proto.h" #include "mem.h" #if (CODE_VERSION != SIMULATION) #if (RF_FAM == 61) #include "tpudrv61.h" #include "l1_rf61.h" #include "l1tm_tpu61.h" #if (DRP_FW_EXT==1) #include "l1_drp_inc.h" #else #include "drp_drive.h" #endif #endif #if (RF_FAM == 60) #include "tpudrv60.h" #include "l1_rf60.h" #include "l1tm_tpu60.h" #include "drp_drive.h" #endif #if (RF_FAM==43) #include "tpudrv43.h" #include "l1_rf43.h" #include "l1tm_tpu43.h" #endif #if (RF_FAM == 35) #include "tpudrv35.h" #include "l1_rf35.h" #include "l1tm_tpu35.h" #endif #if (RF_FAM == 12) #include "tpudrv12.h" #include "l1_rf12.h" #include "l1tm_tpu12.h" #endif #if (RF_FAM == 10) #include "tpudrv10.h" #include "l1_rf10.h" #include "l1tm_tpu10.h" #endif #if (RF_FAM == 8) #include "tpudrv8.h" #include "l1_rf8.h" #include "l1tm_tpu8.h" #endif #if (RF_FAM == 2) #include "tpudrv2.h" #include "l1_rf2.h" #include "l1tm_tpu2.h" #endif #else #if (RF_FAM == 2) #include "l1_rf2.h" #endif #endif #include <assert.h> #include <string.h> #include "l1tm_msgty.h" #include "l1tm_signa.h" #include "l1tm_varex.h" #include "l1tm_ver.h" #if L1_GPRS #include "l1p_cons.h" #include "l1p_msgt.h" #include "l1p_deft.h" #include "l1p_vare.h" #include "l1p_sign.h" #endif #if ((L1_STEREOPATH == 1) && (OP_L1_STANDALONE == 1)) #include "sys_dma.h" #endif #if(L1_FF_MULTIBAND == 1) extern UWORD8 tm_band; #endif /*if (L1_FF_MULTIBAND == 1)*/ // Prototypes from external functions //------------------------------------ UWORD16 Convert_l1_radio_freq(SYS_UWORD16 radio_freq); void Cust_tm_rf_param_write (T_TM_RETURN *tm_return, WORD16 index, UWORD16 value); void Cust_tm_rf_param_read (T_TM_RETURN *tm_return, WORD16 index); void Cust_tm_rf_table_write (T_TM_RETURN *tm_return, WORD8 index, UWORD8 size, UWORD8 table[]); void Cust_tm_rf_table_read (T_TM_RETURN *tm_return, WORD8 index); void Cust_tm_rx_param_write (T_TM_RETURN *tm_return, WORD16 index, UWORD16 value); void Cust_tm_rx_param_read (T_TM_RETURN *tm_return, WORD16 index); void Cust_tm_tx_param_write (T_TM_RETURN *tm_return, WORD16 index, UWORD16 value, UWORD8 band); void Cust_tm_tx_param_read (T_TM_RETURN *tm_return, WORD16 index, UWORD8 band); void Cust_tm_tx_template_write (T_TM_RETURN *tm_return, WORD8 index, UWORD8 size, UWORD8 table[]); void Cust_tm_tx_template_read (T_TM_RETURN *tm_return, WORD8 index); void Cust_tm_special_param_write (T_TM_RETURN *tm_return, WORD16 index, UWORD16 value); void Cust_tm_special_param_read (T_TM_RETURN *tm_return, WORD16 index); void Cust_tm_special_table_write (T_TM_RETURN *tm_return, WORD8 index, UWORD8 size, UWORD8 table[]); void Cust_tm_special_table_read (T_TM_RETURN *tm_return, WORD8 index); void Cust_tm_special_enable (T_TM_RETURN *tm_return, WORD16 action); #if (CODE_VERSION != SIMULATION) void Cust_tm_tpu_table_write (T_TM_RETURN *tm_return, WORD8 index, UWORD8 size, UWORD8 table[]); void Cust_tm_tpu_table_read (T_TM_RETURN *tm_return, WORD8 index); #endif //------------------------------------ // Prototypes from external functions //------------------------------------ void Cust_tm_init (void); void l1tm_reset_rx_state (void); void l1tm_reset_rx_stats (void); #if L1_GPRS void l1pa_reset_cr_freq_list (void); #endif //------------------------------------ // Prototypes from internal functions //------------------------------------ void l1tm_initialize_var(void); UWORD16 l1tm_convert_arfcn2l1ch(UWORD16 arfcn, UWORD8 *error_flag); void l1tm_stats_read(T_TM_RETURN *tm_return, WORD16 type, UWORD16 bitmask); void tm_transmit(T_TM_RETURN *tm_ret); void l1tm_PRBS1_generate(UWORD16 *TM_ul_data); #if ((L1_STEREOPATH == 1) && (OP_L1_STANDALONE == 1)) void l1tm_stereopath_DMA_handler(SYS_UWORD16 dma_status); void l1tm_stereopath_fill_buffer(void* buffer_address); UWORD16 l1tm_stereopath_get_pattern(UWORD16 sampling_freq, UWORD16 sin_freq_left,UWORD16 sin_freq_right, UWORD8 data_type); #endif /***********************************************************************/ /* TESTMODE 3.X */ /***********************************************************************/ static UWORD8 tx_param_band=0; // used in tx_param_write/read; default is GSM900 // RF,(ANALOG)or other hardware dependent functions // - work done by tmrf.c functions for each product. // TestMode functions that modify the state variables // within the L1A - may need to allocate space // dynamically if this is the first time calling // these functions. // TestMode functions that start L1A state machines // may need to send L1A primitives to change L1A state. void l1tm_rf_param_write(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { tm_return->index = prim->u.tm_params.index; tm_return->size = 0; switch (prim->u.tm_params.index) { #if (FF_REPEATED_SACCH == 1) // Repeated SACCH mode case REPEATED_SACCH_ENA_FLAG: { l1_config.repeat_sacch_enable = prim->u.tm_params.value; #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif break; } #endif /* FF_REPEATED_SACCH */ #if (FF_REPEATED_DL_FACCH == 1) // Repeated FACCH mode case REPEATED_FACCHDL_ENA_FLAG: { l1_config.repeat_facch_dl_enable = prim->u.tm_params.value; #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif/*(ETM_PROTOCOL == 1)*/ break; } #endif /* FF_REPEATED_DL_FACCH == 1 */ case BCCH_ARFCN: { UWORD16 bcch_arfcn; UWORD8 error_flag; bcch_arfcn = l1tm_convert_arfcn2l1ch(prim->u.tm_params.value, &error_flag); if (error_flag) { #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_INVAL; #else tm_return->status = E_INVAL; #endif } else { l1_config.tmode.rf_params.bcch_arfcn = bcch_arfcn; // now change on the fly // no reason to check dedicated_active flag... // we just set these 2 globals for FB/SB/BCCH tests l1a_l1s_com.nsync.list[0].radio_freq = l1_config.tmode.rf_params.bcch_arfcn; l1a_l1s_com.Scell_info.radio_freq = l1_config.tmode.rf_params.bcch_arfcn; #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif } break; } case TCH_ARFCN: { T_CHN_SEL *chan_sel; UWORD16 tch_arfcn; UWORD8 error_flag; tch_arfcn = l1tm_convert_arfcn2l1ch(prim->u.tm_params.value, &error_flag); if (error_flag) #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_INVAL; #else tm_return->status = E_INVAL; #endif else { l1_config.tmode.rf_params.tch_arfcn = tch_arfcn; // now change on the fly if necessary if (l1_config.TestMode && l1tm.tmode_state.dedicated_active) { chan_sel = &(l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->chan_sel); chan_sel->rf_channel.single_rf.radio_freq = l1_config.tmode.rf_params.tch_arfcn; } #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif } break; } case MON_ARFCN: { UWORD16 mon_arfcn; UWORD8 error_flag; mon_arfcn = l1tm_convert_arfcn2l1ch(prim->u.tm_params.value, &error_flag); if (error_flag) #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_INVAL; #else tm_return->status = E_INVAL; #endif else { l1_config.tmode.rf_params.mon_arfcn = mon_arfcn; #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif } break; } #if L1_GPRS case PDTCH_ARFCN: { UWORD16 pdtch_arfcn; UWORD8 error_flag; pdtch_arfcn = l1tm_convert_arfcn2l1ch(prim->u.tm_params.value, &error_flag); if (error_flag) #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_INVAL; #else tm_return->status = E_INVAL; #endif else { l1_config.tmode.rf_params.pdtch_arfcn = pdtch_arfcn; #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif } break; } #endif case AFC_ENA_FLAG: { l1_config.afc_enable = prim->u.tm_params.value; #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif break; } case AFC_DAC_VALUE: { WORD16 afc_value = prim->u.tm_params.value; // 13-bit AFC DAC #if(RF_FAM != 61) if (afc_value<-4096 || afc_value>4095) #else if (afc_value<-8192 || afc_value>8191) #endif { #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_INVAL; #else tm_return->status = E_INVAL; #endif break; } if (!l1_config.afc_enable) { // write AFC value to AFC DAC ASAP!! AFC DAC will be updated by any RX // or TX test. l1s.afc = afc_value; } #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif break; } #if L1_GPRS case MULTISLOT_CLASS: { UWORD8 multislot_class; multislot_class = prim->u.tm_params.value; if ((multislot_class < 1) || (multislot_class > 12)) #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_INVAL; #else tm_return->status = E_INVAL; #endif else { l1_config.tmode.rf_params.multislot_class = multislot_class; #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif } break; } #endif // end of L1_GPRS default: { Cust_tm_rf_param_write(tm_return, prim->u.tm_params.index, prim->u.tm_params.value); break; } } // end switch } UWORD16 l1tm_convert_arfcn2l1ch(UWORD16 arfcn, UWORD8 *error_flag) #if (L1_FF_MULTIBAND == 0) { /* Here, before we store the channel numbers to the l1_config structure, we convert from ETSI to TI channel numbering system. The GGT ALWAYS expects the ETSI numbering system as input and output. We need to do the OPPOSITE of what is done in convert_l1_arfcn() in tpudrvX.c *************************************** *** convert arfcn's from ETSI to TI *** *************************************** ** ** ** ETSI TI ** ** 0 GSM 174 ** ** 1 - 124 GSM 1 - 124 ** ** 975 - 1023 E-GSM 125 - 173 ** ** 512 - 885 DCS 174 - 548 ** ** ** *************************************** */ *error_flag = 0; switch (l1_config.std.id) { case GSM: case DCS1800: case PCS1900: case GSM850: break; case DUAL: if ((arfcn >= 512) && (arfcn <= 885)) arfcn -= 337; else if (arfcn > 124) *error_flag = 1; // invalid arfcn break; case DUALEXT: if (arfcn == 0) arfcn = 174; else if ((arfcn >= 975) && (arfcn <= 1023)) arfcn -= 850; else if ((arfcn >= 512) && (arfcn <= 885)) arfcn -= 337; else if ((arfcn >= 1) && (arfcn <= 124)); else *error_flag = 1; // invalide arfcn break; case DUAL_US: // GSM850:128-251 PCS1900:512-810 if ((arfcn >= 128) && (arfcn <= 251)) arfcn -= 127; else if ((arfcn >= 512) && (arfcn <= 810)) arfcn -= 387; else *error_flag = 1; // invalid arfcn break; default: *error_flag = 1; // invalid std.id break; } // end switch return arfcn; } #else // L1_FF_MULTIBAND = 1 below { *error_flag=0; if(tm_band == RF_PCS1900) { arfcn = arfcn + 512; } return(arfcn); #if 0 UWORD16 l1_radio_freq = 0; UWORD8 effective_band_id = 0; *error_flag = 1; for (effective_band_id = 0; effective_band_id < RF_NB_SUBBANDS; effective_band_id ++) { if( multiband_conversion_data[effective_band_id].physical_band_id == tm_band) { if( (arfcn - multiband_conversion_data[effective_band_id].first_tpu_radio_freq) < multiband_conversion_data[effective_band_id].nbmax_carrier) { l1_radio_freq = arfcn - multiband_conversion_data[effective_band_id].first_tpu_radio_freq + multiband_conversion_data[effective_band_id].first_radio_freq; *error_flag = 0; return(l1_radio_freq); } } } return(l1_radio_freq); #endif } #endif // #if (L1_FF_MULTIBAND == 0) else void l1tm_rf_param_read(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { volatile UWORD16 value; tm_return->index = prim->u.tm_params.index; switch (prim->u.tm_params.index) { #if (FF_REPEATED_SACCH == 1 ) /* Repeated SACCH mode */ case REPEATED_SACCH_ENA_FLAG: { value = l1_config.repeat_sacch_enable; break; } #endif /* FF_REPEATED_SACCH */ #if FF_REPEATED_DL_FACCH // Repeated FACCH mode case REPEATED_FACCHDL_ENA_FLAG: { value = l1_config.repeat_facch_dl_enable; break; } #endif /* FF_REPEATED_DL_FACCH */ case BCCH_ARFCN: { // return ETSI value for channel number value = Convert_l1_radio_freq(l1_config.tmode.rf_params.bcch_arfcn); break; } case TCH_ARFCN: { // return ETSI value for channel number value = Convert_l1_radio_freq(l1_config.tmode.rf_params.tch_arfcn); break; } case MON_ARFCN: { // return ETSI value for channel number value = Convert_l1_radio_freq(l1_config.tmode.rf_params.mon_arfcn); break; } #if L1_GPRS case PDTCH_ARFCN: { // return ETSI value for channel number value = Convert_l1_radio_freq(l1_config.tmode.rf_params.pdtch_arfcn); break; } #endif case AFC_ENA_FLAG: { value = l1_config.afc_enable; break; } case AFC_DAC_VALUE: { value = l1s.afc; // returned as F13.3 break; } #if L1_GPRS case MULTISLOT_CLASS: { value = l1_config.tmode.rf_params.multislot_class; break; } #endif default: { Cust_tm_rf_param_read(tm_return, prim->u.tm_params.index); return; } } // end switch memcpy(tm_return->result, (UWORD8 *)&value, 2); tm_return->size = 2; #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif } void l1tm_rf_table_write(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { Cust_tm_rf_table_write(tm_return, prim->u.tm_table.index, prim->str_len_in_bytes - 1, // subtract 8-bit index prim->u.tm_table.table); } void l1tm_rf_table_read(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { Cust_tm_rf_table_read(tm_return, prim->u.tm_table.index); } void l1tm_rx_param_write(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { tm_return->index = prim->u.tm_params.index; tm_return->size = 0; switch (prim->u.tm_params.index) { case RX_AGC_GAIN: { WORD8 gain = prim->u.tm_params.value; // It is up to the user to write a valid gain, // one that falls within the range of gains in the current RF // AGC gain can only be controlled in 2dB steps as the bottom bit (bit zero) // corresponds to the lna_off bit l1_config.tmode.rx_params.agc = gain & ~0x01; l1_config.tmode.rx_params.lna_off = gain & 0x01; #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif break; } case RX_TIMESLOT: { if (prim->u.tm_params.value > 7) { #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_INVAL; #else tm_return->status = E_INVAL; #endif break; } l1_config.tmode.rx_params.slot_num = prim->u.tm_params.value; if (l1_config.TestMode && l1tm.tmode_state.dedicated_active) { // currently CANNOT change RX slot on the fly! } #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif break; } case RX_PM_ENABLE: { l1_config.tmode.rx_params.pm_enable = prim->u.tm_params.value; #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif break; } #if L1_GPRS case RX_GPRS_SLOTS: { // At least one DL TS needs to be allocated if (!prim->u.tm_params.value) #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_INVAL; #else tm_return->status = E_INVAL; #endif else { l1_config.tmode.rx_params.timeslot_alloc = prim->u.tm_params.value; #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif } break; } case RX_GPRS_CODING: { UWORD8 coding_scheme; coding_scheme = prim->u.tm_params.value; if ((coding_scheme < 1) || (coding_scheme > 6) || (coding_scheme == 3)) #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_INVAL; #else tm_return->status = E_INVAL; #endif else { l1_config.tmode.rx_params.coding_scheme = prim->u.tm_params.value; #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif } break; } #endif case RX_AGC_ENA_FLAG: { l1_config.agc_enable = prim->u.tm_params.value; #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif break; } default: { Cust_tm_rx_param_write(tm_return, prim->u.tm_params.index, prim->u.tm_params.value); break; } } // end switch } void l1tm_rx_param_read(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { volatile UWORD16 value; tm_return->index = prim->u.tm_params.index; switch (prim->u.tm_params.index) { case RX_AGC_GAIN: { value = l1_config.tmode.rx_params.agc | l1_config.tmode.rx_params.lna_off; break; } case RX_TIMESLOT: { value = l1_config.tmode.rx_params.slot_num; break; } case RX_AGC_ENA_FLAG: { value = l1_config.agc_enable; break; } case RX_PM_ENABLE: { value = l1_config.tmode.rx_params.pm_enable; break; } #if L1_GPRS case RX_GPRS_SLOTS: { value = l1_config.tmode.rx_params.timeslot_alloc; break; } case RX_GPRS_CODING: { value = l1_config.tmode.rx_params.coding_scheme; break; } #endif default: { Cust_tm_rx_param_read(tm_return, prim->u.tm_params.index); return; } } // end switch memcpy(tm_return->result, (UWORD8 *)&value, 2); tm_return->size = 2; #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif } void l1tm_tx_param_write(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { tm_return->index = prim->u.tm_params.index; tm_return->size = 0; switch (prim->u.tm_params.index) { case TX_PWR_LEVEL: { UWORD8 temp_txpwr, temp_band; if (prim->u.tm_params.value < 100) // GSM900 { temp_txpwr = prim->u.tm_params.value; temp_band = 0; } else if (prim->u.tm_params.value < 200) // DCS1800 { temp_txpwr = prim->u.tm_params.value - 100; temp_band = 1; } else if (prim->u.tm_params.value < 300) // PCS1900 { temp_txpwr = prim->u.tm_params.value - 200; temp_band = 2; } else // force invalid values to return -ETM_INVAL or E_INVAL { temp_txpwr = 50; temp_band = 10; } // Note that the pwr level is only checked for being within the range [0..31] // because all pwr levels should be testable. // For subfunctions [TX_APC_DAC..TX_DELAY_DOWN]: // temp_txpwr + 0 ==> GSM900 // temp_txpwr + 100 ==> DCS1800 // temp_txpwr + 200 ==> PCS1900 // Changing tx pwr level on the fly while in continuous mode is not supported. if (temp_txpwr > 31 || temp_band > 2 || l1_config.tmode.rf_params.tmode_continuous == TM_CONTINUOUS) { #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_INVAL; #else tm_return->status = E_INVAL; #endif break; } l1_config.tmode.tx_params.txpwr = temp_txpwr; tx_param_band = temp_band; // if in TX mode, change txpwr on the fly if ((l1_config.TestMode) && (l1tm.tmode_state.dedicated_active) && (l1_config.tmode.rf_params.down_up & TMODE_UPLINK)) { // this causes 'direct' changing of TXPWR, which is OK in TestMode l1a_l1s_com.dedic_set.aset->new_target_txpwr = l1s.applied_txpwr = l1_config.tmode.tx_params.txpwr; } #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif break; } case TX_TIMING_ADVANCE: { l1_config.tmode.tx_params.timing_advance = prim->u.tm_params.value; if (l1_config.TestMode && l1tm.tmode_state.dedicated_active) { // direct changing of Timing Advance l1a_l1s_com.dedic_set.aset->new_timing_advance = l1_config.tmode.tx_params.timing_advance; // new TA to take effect immediately l1a_l1s_com.dedic_set.aset->timing_advance = l1a_l1s_com.dedic_set.aset->new_timing_advance; } #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif break; } case TX_PWR_SKIP: { l1_config.tmode.tx_params.txpwr_skip = prim->u.tm_params.value; #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif break; } #if L1_GPRS case TX_GPRS_POWER0: case TX_GPRS_POWER1: case TX_GPRS_POWER2: case TX_GPRS_POWER3: case TX_GPRS_POWER4: case TX_GPRS_POWER5: case TX_GPRS_POWER6: case TX_GPRS_POWER7: { l1_config.tmode.tx_params.txpwr_gprs[prim->u.tm_params.index - TX_GPRS_POWER0] = prim->u.tm_params.value; #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif break; } case TX_GPRS_SLOTS: { l1_config.tmode.tx_params.timeslot_alloc = prim->u.tm_params.value; #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif break; } case TX_GPRS_CODING: { UWORD8 coding_scheme; coding_scheme = prim->u.tm_params.value; if ((coding_scheme < 2) || (coding_scheme > 6) || (coding_scheme == 3)) #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_INVAL; #else tm_return->status = E_INVAL; #endif else { l1_config.tmode.tx_params.coding_scheme = prim->u.tm_params.value; #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif } break; } #endif default: { Cust_tm_tx_param_write(tm_return, prim->u.tm_params.index, prim->u.tm_params.value, tx_param_band); break; } } // end switch } void l1tm_tx_param_read(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { tm_return->index = prim->u.tm_params.index; Cust_tm_tx_param_read(tm_return, prim->u.tm_params.index, tx_param_band); } void l1tm_tx_template_write(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { Cust_tm_tx_template_write(tm_return, prim->u.tm_table.index, prim->str_len_in_bytes - 1, // subtract 8-bit index prim->u.tm_table.table); } void l1tm_tx_template_read(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { Cust_tm_tx_template_read(tm_return, prim->u.tm_table.index); } /* TCS211 function missing in LoCosto, reconstructed from disassembly */ void l1tm_mode_set(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { switch (prim->u.tm_params.index) { case 0: l1_config.TestMode = 0; tm_return->status = E_OK; break; case 1: l1_config.TestMode = 1; l1_config.tx_pwr_code = 1; l1_config.pwr_mngt = 0; tm_return->status = E_OK; Cust_tm_init(); l1tm_initialize_var(); break; default: tm_return->status = E_INVAL; } tm_return->index = 0; tm_return->size = 0; } /* TCS211 function missing in LoCosto, reconstructed from disassembly */ void l1tm_version_get(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { UWORD16 revision; extern T_RF rf; tm_return->index = prim->u.tm_params.index; switch (prim->u.tm_params.index) { /* "meat" of this switch statement taken from LoCosto etm_tm3core.c */ case BBCHIP_MODULE_REV: revision = CHIPSET; break; case CHIPID_MODULE_REV: revision = *( (volatile UWORD16 *) (MEM_JTAGID_PART)); break; case CHIPVER_MODULE_REV: revision = *( (volatile UWORD16 *) (MEM_JTAGID_VER)); break; case DSPSW_MODULE_REV: revision = l1s.version.dsp_code_version; break; case ANALOGCHIP_MODULE_REV: revision = ((ANLG_PG << 7) | ANLG_FAM); break; case LAYER1_MODULE_REV: revision = l1s.version.mcu_tcs_official; break; case RFDRIVER_MODULE_REV: revision = rf.rf_revision; break; case TM_API_MODULE_REV: revision = TMAPIVERSION; break; case L1_TM_CORE_MODULE_REV: revision = l1s.version.mcu_tm_version; break; case DSP_MODULE_REV: revision = DSP; break; case RF_MODULE_REV: revision = ((RF_PA << 10) | (RF_PG << 7) | RF_FAM); break; default: tm_return->status = E_BADINDEX; tm_return->size = 0; return; } memcpy(tm_return->result, &revision, sizeof revision); tm_return->size = sizeof revision; tm_return->status = E_OK; } /* TCS211 function missing in LoCosto, reconstructed from disassembly */ void l1tm_mem_write(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { UWORD8 *mem_ptr; UWORD8 num_of_bytes; UWORD16 i; mem_ptr = (UWORD8 *) prim->u.mem_write.address; num_of_bytes = prim->str_len_in_bytes - 4; for (i = 0; i < num_of_bytes; i++) mem_ptr[i] = prim->u.mem_write.table[i]; tm_return->size = 0; tm_return->index = 0; tm_return->status = E_OK; } /* TCS211 function missing in LoCosto, reconstructed from disassembly */ void l1tm_mem_read(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { tm_return->index = 0; if (prim->u.mem_read.length > TM_PAYLOAD_UPLINK_SIZE_MAX - 4) { tm_return->size = 0; tm_return->status = E_BADSIZE; return; } memcpy(tm_return->result, &prim->u.mem_read.length, 4); memcpy(tm_return->result + 4, (UWORD8 *) prim->u.mem_read.src, prim->u.mem_read.length); tm_return->size = prim->u.mem_read.length + 4; tm_return->status = E_OK; } /* TCS211 function missing in LoCosto, reconstructed from disassembly */ void l1tm_codec_write(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { UWORD16 page, reg; page = (prim->u.tm_params.index >> 5) & 1; reg = prim->u.tm_params.index & 0x1F; if (!l1_config.TestMode) { tm_return->status = E_TESTMODE; goto out; } if (page >= 2 || reg >= 32) { tm_return->status = E_INVAL; goto out; } ABB_Write_Register_on_page(page + 1, reg << 1, prim->u.tm_params.value & 0x3FF); tm_return->status = E_OK; out: tm_return->index = 0; tm_return->size = 0; } /* TCS211 function missing in LoCosto, reconstructed from disassembly */ void l1tm_codec_read(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { UWORD16 page, reg; UWORD16 value; page = (prim->u.tm_params.index >> 5) & 1; reg = prim->u.tm_params.index & 0x1F; value = ABB_Read_Register_on_page(page + 1, reg << 1); memcpy(tm_return->result, &value, 2); tm_return->size = 2; tm_return->status = E_OK; tm_return->index = 0; } /* TCS211 function missing in LoCosto, reconstructed from disassembly */ void l1tm_misc_param_write(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { tm_return->index = prim->u.tm_params.index; tm_return->size = 0; switch (prim->u.tm_params.index) { case ADC_ENA_FLAG: l1_config.adc_enable = prim->u.tm_params.value; break; default: Cust_tm_misc_param_write(tm_return, prim->u.tm_params.index, prim->u.tm_params.value); return; } tm_return->status = E_OK; } /* TCS211 function missing in LoCosto, reconstructed from disassembly */ void l1tm_misc_param_read(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { UWORD16 value; tm_return->index = prim->u.tm_params.index; switch (prim->u.tm_params.index) { case ADC_ENA_FLAG: value = l1_config.adc_enable; break; case CURRENT_TM_MODE: value = l1_config.TestMode; break; default: Cust_tm_misc_param_read(tm_return, prim->u.tm_params.index); return; } memcpy(tm_return->result, &value, 2); tm_return->size = 2; tm_return->status = E_OK; } /* TCS211 function missing in LoCosto, reconstructed from disassembly */ void l1tm_misc_enable(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { Cust_tm_misc_enable(tm_return, prim->u.tm_params.index); } void l1tm_special_param_write(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { Cust_tm_special_param_write(tm_return, prim->u.tm_params.index, prim->u.tm_params.value); } void l1tm_special_param_read(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { Cust_tm_special_param_read(tm_return, prim->u.tm_params.index); } void l1tm_special_table_write(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { Cust_tm_special_table_write(tm_return, prim->u.tm_table.index, prim->str_len_in_bytes - 1, prim->u.tm_table.table); } void l1tm_special_table_read(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { Cust_tm_special_table_read(tm_return, prim->u.tm_table.index); } void l1tm_special_enable(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { Cust_tm_special_enable(tm_return, prim->u.tm_params.index); } /* TCS211 function missing in LoCosto, reconstructed from disassembly */ void l1tm_initialize(T_TM_RETURN *tm_return) { Cust_tm_init(); tm_return->status = E_OK; tm_return->size = 0; tm_return->index = 0; } /* TCS211 function missing in LoCosto, reconstructed from disassembly */ void l1tm_ffs(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { tm_return->size = tm_ffs(tm_return->result, 32, prim->u.ffs.packet, prim->str_len_in_bytes); tm_return->status = E_OK; tm_return->index = 0; } /*-------------------------------------------------------*/ /* l1tm_initialize_var() */ /*-------------------------------------------------------*/ /* Parameters : */ /* ------------- */ /* Return : */ /* ------------- */ /* Description : */ /* ------------- */ /* This routine is used to switch to TestMode by re- */ /* initializing the l1a, l1s and l1a_l1s_com global */ /* structures. Re-initialization is kept at a minimum. */ /*-------------------------------------------------------*/ void l1tm_initialize_var(void) { UWORD32 i; UWORD8 task_id; // L1S tasks management... //----------------------------------------- for(task_id=0; task_id<NBR_DL_L1S_TASKS; task_id++) { l1s.task_status[task_id].new_status = NOT_PENDING; l1s.task_status[task_id].current_status = INACTIVE; } l1s.frame_count = 0; l1s.forbid_meas = 0; // MFTAB management variables... //----------------------------------------- l1s.afrm = 0; l1s_clear_mftab(l1s.mftab.frmlst); // Flag registers for RF task controle... //----------------------------------------- l1s.tpu_ctrl_reg = 0; l1s.dsp_ctrl_reg = 0; //++++++++++++++++++++++++++++++++++++++++++ // Reset "l1a" structure. //++++++++++++++++++++++++++++++++++++++++++ // Downlink tasks management... // Uplink tasks management... // Measurement tasks management... //----------------------------------------- for(i=0; i<NBR_L1A_PROCESSES; i++) { l1a.l1a_en_meas[i] = 0; l1a.state[i] = 0; // RESET state. } // Flag for forward/delete message management. //--------------------------------------------- l1a.l1_msg_forwarded = 0; //++++++++++++++++++++++++++++++++++++++++++ // Reset "l1a_l1s_com" structure. //++++++++++++++++++++++++++++++++++++++++++ l1a_l1s_com.l1a_activity_flag = TRUE; l1a_l1s_com.time_to_next_l1s_task = 0; // sleep management configuration //=============================== l1s.pw_mgr.mode_authorized = NO_SLEEP; // L1S scheduler... //==================== // L1S tasks management... //----------------------------------------- for(i=0; i<NBR_DL_L1S_TASKS; i++) { l1a_l1s_com.task_param[i] = SEMAPHORE_RESET; l1a_l1s_com.l1s_en_task[i] = TASK_DISABLED; } // Measurement tasks management... //----------------------------------------- l1a_l1s_com.meas_param = 0; l1a_l1s_com.l1s_en_meas = 0; #if L1_GPRS // Set DSP scheduler mode l1a_l1s_com.dsp_scheduler_mode = GSM_SCHEDULER; // Packet measurement: Reset of the frequency list. //------------------------------------------------- l1pa_reset_cr_freq_list(); // Initialize active list used in Neighbour Measurement Transfer Process l1pa_l1ps_com.cres_freq_list.alist = &(l1pa_l1ps_com.cres_freq_list.list[0]); l1pa_l1ps_com.transfer.semaphore = TRUE; l1pa_l1ps_com.transfer.aset = &(l1pa_l1ps_com.transfer.set[0]); l1pa_l1ps_com.transfer.fset[0] = &(l1pa_l1ps_com.transfer.set[1]); l1pa_l1ps_com.transfer.fset[1] = &(l1pa_l1ps_com.transfer.set[2]); for(i=0;i<3;i++) { l1pa_l1ps_com.transfer.set[i].SignalCode = 0; l1pa_l1ps_com.transfer.set[i].dl_tbf_synchro_timeslot = 0; l1pa_l1ps_com.transfer.set[i].dl_tbf_synchro_timeslot = 0; l1pa_l1ps_com.transfer.set[i].transfer_synchro_timeslot = 0; l1pa_l1ps_com.transfer.set[i].allocated_tbf = NO_TBF; l1pa_l1ps_com.transfer.set[i].assignment_command = NO_TBF; l1pa_l1ps_com.transfer.set[i].multislot_class = 0; l1pa_l1ps_com.transfer.set[i].packet_ta.ta = 255; l1pa_l1ps_com.transfer.set[i].packet_ta.ta_index = 255; l1pa_l1ps_com.transfer.set[i].packet_ta.ta_tn = 255; l1pa_l1ps_com.transfer.set[i].tsc = 0; l1pa_l1ps_com.transfer.set[i].freq_param.chan_sel.h = 0; l1pa_l1ps_com.transfer.set[i].freq_param.chan_sel. rf_channel.single_rf.radio_freq = 0; l1pa_l1ps_com.transfer.set[i].tbf_sti.present = FALSE; l1pa_l1ps_com.transfer.set[i].mac_mode = 0; l1pa_l1ps_com.transfer.set[i].ul_tbf_alloc->tfi = 255; l1pa_l1ps_com.transfer.set[i].dl_tbf_alloc.tfi = 255; l1pa_l1ps_com.transfer.set[i].dl_pwr_ctl.p0 = 255; l1pa_l1ps_com.transfer.set[i].dl_pwr_ctl.bts_pwr_ctl_mode = 0; l1pa_l1ps_com.transfer.set[i].dl_pwr_ctl.pr_mode = 0; } #endif // Init global test mode variables l1tm.tmode_state.dedicated_active = 0; #if L1_GPRS l1tm.tmode_state.packet_transfer_active = FALSE; #endif // PRBS seed initialization with a random pattern l1tm.tmode_prbs.prbs1_seed = 0x5613; } void l1tm_rf_enable(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { unsigned SignalCode =0; unsigned size = 0; //omaps00090550 xSignalHeaderRec *msg; UWORD8 send_prim = FALSE; // Flag to send TestMode primitive... // Do not send primitive is the default; change it if necessary UWORD8 band; tm_return->index = 0; // don't include index in header #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif // Function only valid in TEST mode if (l1_config.TestMode == 0) { #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_L1TESTMODE; #else tm_return->status = E_TESTMODE; #endif } else { // Reset all statistics l1tm_reset_rx_stats(); // Reset receive state counters, unless already in dedicated mode if (!l1tm.tmode_state.dedicated_active) l1tm_reset_rx_state(); // Reset monitor task l1_config.tmode.rf_params.mon_report = 0; l1_config.tmode.rf_params.mon_tasks = 0; switch (prim->u.tm_params.index) { // Stop all RX and TX operations case STOP_ALL: { SignalCode = TMODE_STOP_RX_TX; size = sizeof(T_TMODE_STOP_RX_TX); l1tm.tmode_state.dedicated_active = 0; #if (RF_FAM == 61) // Reset the APC back to Automatic Mode l1ddsp_apc_set_automatic_mode(); #endif #if (RF_FAM == 35) pll_tuning.enable=0; #endif // Reset down_up flag only if not in continuous mode. If in continuous mode, down_up // will be reset after the proper TPU scenario is loaded. if (l1_config.tmode.rf_params.tmode_continuous != TM_CONTINUOUS) l1_config.tmode.rf_params.down_up = 0; send_prim = TRUE; break; } // RX with or without network synchronization first case RX_TCH: { // if already in UL-only if (l1tm.tmode_state.dedicated_active && l1_config.tmode.rf_params.down_up == TMODE_UPLINK) { // cannot start to RX while already TXing #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_AGAIN; #else tm_return->status = E_AGAIN; #endif } else { l1_config.tmode.rf_params.down_up = TMODE_DOWNLINK; SignalCode = TMODE_IMMED_ASSIGN_REQ; size = sizeof(T_TMODE_IMMED_ASSIGN_REQ); send_prim = TRUE; } break; } // TX NB's or AB's on TCH with or without network synch. first case TX_TCH: { // Normal burst TX if (l1_config.tmode.tx_params.burst_type == 0) { // if already in DL-only, add UL if (l1tm.tmode_state.dedicated_active && l1_config.tmode.rf_params.down_up == TMODE_DOWNLINK) { l1_config.tmode.rf_params.down_up = (TMODE_DOWNLINK | TMODE_UPLINK); } else { l1_config.tmode.rf_params.down_up = TMODE_UPLINK; SignalCode = TMODE_IMMED_ASSIGN_REQ; size = sizeof(T_TMODE_IMMED_ASSIGN_REQ); send_prim = TRUE; } } // AB TX else if (l1_config.tmode.tx_params.burst_type == 1) { // cannot start RACH while already in dedicated mode if (l1tm.tmode_state.dedicated_active) { #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_AGAIN; #else tm_return->status = E_AGAIN; #endif } else { SignalCode = TMODE_RA_START; size = sizeof(TMODE_RA_START); send_prim = TRUE; } } break; } // RX & TX on TCH with or without network synch. first case RX_TX_TCH: { // if NB TX if (l1_config.tmode.tx_params.burst_type == 0) { // if already in DL-only, add UL if (l1tm.tmode_state.dedicated_active && l1_config.tmode.rf_params.down_up == TMODE_DOWNLINK) { l1_config.tmode.rf_params.down_up = (TMODE_DOWNLINK | TMODE_UPLINK); } // else if already in UL-only else if (l1tm.tmode_state.dedicated_active && l1_config.tmode.rf_params.down_up == TMODE_UPLINK) { // cannot start to RX while already TXing #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_AGAIN; #else tm_return->status = E_AGAIN; #endif } else { l1_config.tmode.rf_params.down_up = (TMODE_DOWNLINK | TMODE_UPLINK); SignalCode = TMODE_IMMED_ASSIGN_REQ; size = sizeof(T_TMODE_IMMED_ASSIGN_REQ); send_prim = TRUE; } } // else if AB TX else if (l1_config.tmode.tx_params.burst_type == 1) { // Cannot TX RACH and RX simultaneously #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_AGAIN; #else tm_return->status = E_AGAIN; #endif } break; } // Continuous (all timeslots) reception on TCH case RX_TCH_CONT: { // if already in UL, DL or UL+DL if (l1tm.tmode_state.dedicated_active && l1_config.tmode.rf_params.down_up != 0) { // cannot start to continously RX while already TXing or RXing #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_AGAIN; #else tm_return->status = E_AGAIN; #endif } else { l1_config.tmode.rf_params.tmode_continuous = TM_START_RX_CONTINUOUS; l1_config.tmode.rf_params.down_up = TMODE_DOWNLINK; SignalCode = TMODE_IMMED_ASSIGN_REQ; size = sizeof(T_TMODE_IMMED_ASSIGN_REQ); send_prim = TRUE; } break; } // continuous (all timeslots) transmission case TX_TCH_CONT: { // PCS 1900 not supported yet. #if (L1_FF_MULTIBAND == 0) band = ((l1_config.tmode.rf_params.tch_arfcn >= 512) && (l1_config.tmode.rf_params.tch_arfcn <= 885)); #else band = ( ((l1_config.tmode.rf_params.tch_arfcn >= 512) && (l1_config.tmode.rf_params.tch_arfcn <= 885)) || ((l1_config.tmode.rf_params.tch_arfcn >= 1024) && (l1_config.tmode.rf_params.tch_arfcn <= 1322)) ); #endif // if already in UL, DL or UL+DL if ((l1tm.tmode_state.dedicated_active && l1_config.tmode.rf_params.down_up != 0) || (band == 0 && (l1_config.tmode.tx_params.txpwr < (5 + l1_config.tmode.tx_params.txpwr_skip))) || (band == 1 && (l1_config.tmode.tx_params.txpwr < (0 + l1_config.tmode.tx_params.txpwr_skip)))) { // cannot start to continously TX while already TXing or RXing // or while adc reading are enabled #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_INVAL; #else tm_return->status = E_INVAL; #endif } else { #if (RF_FAM == 61) // Set APC in Manual Mode l1ddsp_apc_set_manual_mode(); #endif l1_config.tmode.rf_params.tmode_continuous = TM_START_TX_CONTINUOUS; l1_config.tmode.rf_params.down_up = TMODE_UPLINK; SignalCode = TMODE_IMMED_ASSIGN_REQ; size = sizeof(T_TMODE_IMMED_ASSIGN_REQ); send_prim = TRUE; } break; } // Continuous BCCH case BCCH_LOOP: { SignalCode = TMODE_SCELL_NBCCH_REQ; size = sizeof(TMODE_SCELL_NBCCH_REQ); send_prim = TRUE; break; } // Continuous SB case SB_LOOP: { SignalCode = TMODE_SB_REQ; size = sizeof(T_TMODE_SB_REQ); send_prim = TRUE; break; } // Continuous FB1 case FB1_LOOP: { SignalCode = TMODE_FB1_REQ; size = sizeof(T_TMODE_FB1_REQ); send_prim = TRUE; break; } // Continuous FB0 case FB0_LOOP: { SignalCode = TMODE_FB0_REQ; size = sizeof(T_TMODE_FB0_REQ); send_prim = TRUE; break; } // TX + RX + MON on TCH case RX_TX_MON_TCH: // Stats collected from TCH Channel. case RX_TX_MON: // Stats collected from MON Channel (except rxlev). { // Normal burst uplink if (l1_config.tmode.tx_params.burst_type == 0) { // If already in dedicated mode, return error if (l1tm.tmode_state.dedicated_active) { #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_AGAIN; #else tm_return->status = E_AGAIN; #endif } else { l1_config.tmode.rf_params.down_up = (TMODE_DOWNLINK | TMODE_UPLINK); l1_config.tmode.rf_params.mon_report = ((prim->u.tm_params.index & 0x08) >> 3); l1_config.tmode.rf_params.mon_tasks = 1; // enable MON tasks SignalCode = TMODE_IMMED_ASSIGN_REQ; size = sizeof(T_TMODE_IMMED_ASSIGN_REQ); send_prim = TRUE; } } // else if Access burst uplink else if (l1_config.tmode.tx_params.burst_type == 1) { // Cannot TX RACH and RX simultaneously #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_AGAIN; #else tm_return->status = E_AGAIN; #endif } break; } case SINGLE_PM: { SignalCode = TMODE_RXLEV_REQ; size = sizeof(T_TMODE_RXLEV_REQ); send_prim = TRUE; break; } #if L1_GPRS // RX & TX on PDTCH with or without network synch. first case RX_TX_PDTCH: { UWORD8 bit_map = 0x80; // set uplink + downlink if (l1_config.tmode.tx_params.timeslot_alloc) l1_config.tmode.rf_params.down_up = TMODE_DOWNLINK | TMODE_UPLINK; else l1_config.tmode.rf_params.down_up = TMODE_DOWNLINK; while (bit_map) { if (bit_map & l1_config.tmode.stats_config.stat_gprs_slots) l1tm.tmode_stats.nb_dl_pdtch_slots ++; bit_map>>=1; } SignalCode = TMODE_PDTCH_ASSIGN_REQ; size = sizeof(T_TMODE_PDTCH_ASSIGN_REQ); send_prim = TRUE; break; } #endif #if L1_GPRS // RX & TX on PDTCH, FB on monitor arfcn case RX_TX_PDTCH_MON: { // set uplink + downlink if (l1_config.tmode.tx_params.timeslot_alloc) l1_config.tmode.rf_params.down_up = TMODE_DOWNLINK | TMODE_UPLINK; else l1_config.tmode.rf_params.down_up = TMODE_DOWNLINK; l1_config.tmode.rf_params.mon_report = 1; // collect stats from MON channel l1_config.tmode.rf_params.mon_tasks = 1; // enable MON tasks SignalCode = TMODE_PDTCH_ASSIGN_REQ; size = sizeof(T_TMODE_PDTCH_ASSIGN_REQ); send_prim = TRUE; break; } #endif #if (RF_FAM == 35) case RX_PLL_TUNING: { // if already in UL-only if (l1tm.tmode_state.dedicated_active && l1_config.tmode.rf_params.down_up == TMODE_UPLINK) { // cannot start to RX while already TXing #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_AGAIN; #else tm_return->status = E_AGAIN; #endif } else { pll_tuning.data[5] = 0; pll_tuning.index = 0; pll_tuning.enable = 1; l1_config.tmode.rf_params.down_up = TMODE_DOWNLINK; SignalCode = TMODE_IMMED_ASSIGN_REQ; size = sizeof(T_TMODE_IMMED_ASSIGN_REQ); send_prim = TRUE; } break; } #endif default: { #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_INVAL; #else tm_return->status = E_BADINDEX; #endif break; } } //end switch } // end of else if (send_prim == TRUE) { // Allocate result message. msg = os_alloc_sig(size); DEBUGMSG(status,NU_ALLOC_ERR) msg->SignalCode = SignalCode; os_send_sig(msg, L1C1_QUEUE); DEBUGMSG(status,NU_SEND_QUEUE_ERR) } // always return a 0 in the result[], even if error tm_return->result[0] = 0; tm_return->size = 1; } void l1tm_stats_config_write(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { tm_return->index = prim->u.tm_params.index; tm_return->size = 0; switch (prim->u.tm_params.index) { case LOOPS: { l1_config.tmode.stats_config.num_loops = prim->u.tm_params.value; #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif break; } case AUTO_RESULT_LOOPS: { l1_config.tmode.stats_config.auto_result_loops = prim->u.tm_params.value; #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif break; } case AUTO_RESET_LOOPS: { l1_config.tmode.stats_config.auto_reset_loops = prim->u.tm_params.value; #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif break; } case STAT_TYPE: { l1_config.tmode.stats_config.stat_type = prim->u.tm_params.value; #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif break; } case STAT_BITMASK: { l1_config.tmode.stats_config.stat_bitmask = prim->u.tm_params.value; #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif break; } #if L1_GPRS case STAT_GPRS_SLOTS: { UWORD8 allocation, value; value = prim->u.tm_params.value; // Check for mismatch between DL TS allocation and stats bitmap allocation = value ^ l1_config.tmode.rx_params.timeslot_alloc; if (value & allocation) #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_INVAL; #else tm_return->status = E_INVAL; #endif else { l1_config.tmode.stats_config.stat_gprs_slots = value; #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif } break; } #endif default: { #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_INVAL; #else tm_return->status = E_BADINDEX; #endif break; } } // end switch } void l1tm_stats_config_read(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { volatile UWORD16 value; tm_return->index = prim->u.tm_params.index; switch (prim->u.tm_params.index) { case LOOPS: { value = l1_config.tmode.stats_config.num_loops; break; } case AUTO_RESULT_LOOPS: { value = l1_config.tmode.stats_config.auto_result_loops; break; } case AUTO_RESET_LOOPS: { value = l1_config.tmode.stats_config.auto_reset_loops; break; } case STAT_TYPE: { value = l1_config.tmode.stats_config.stat_type; break; } case STAT_BITMASK: { value = l1_config.tmode.stats_config.stat_bitmask; break; } #if L1_GPRS case STAT_GPRS_SLOTS: { value = l1_config.tmode.stats_config.stat_gprs_slots; break; } #endif default: { #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_INVAL; #else tm_return->status = E_BADINDEX; #endif tm_return->size = 0; return; } } // end switch memcpy(tm_return->result, (UWORD8 *) &value, 2); tm_return->size = 2; #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif } void l1tm_statistics(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { l1tm_stats_read(tm_return, prim->u.tm_params.index, prim->u.tm_params.value); } #if L1_GPRS void l1tm_rlc_uplink(UWORD8 tx, API *ul_data) { // Cast the ul_data_buffer typedef struct { API a_ul_data[4][29]; } T_A_UL_DATA; T_A_UL_DATA *ptr = (T_A_UL_DATA*) ul_data; UWORD8 i,j; for (j=0; j<tx; j++) { ptr->a_ul_data[j][0] = l1_config.tmode.tx_params.coding_scheme; for (i=0;i<l1_config.tmode.tx_params.rlc_buffer_size;i++) ptr->a_ul_data[j][i+1] = l1_config.tmode.tx_params.rlc_buffer[i]; } } #endif void l1tm_stats_read(T_TM_RETURN *tm_return, WORD16 type, UWORD16 bitmask) { extern T_L1A_L1S_COM l1a_l1s_com; extern T_L1S_GLOBAL l1s; volatile UWORD32 utemp = bitmask, temp_U32; volatile WORD32 temp = type; volatile WORD32 value_signed_int; volatile UWORD32 value_unsigned_int; volatile UWORD16 value_unsigned_short; UWORD8 j, offset=0; // offset is index of tm_return->result[] UWORD16 rssi, len; WORD32 count; WORD32 runs = l1tm.tmode_stats.loop_count; /* * FreeCalypso TCS211 reconstruction: the following automatic var * is for the BLER code we have conditioned out below. */ #if 0 //L1_GPRS volatile UWORD16 value_array_unsigned_short[4]; #endif // Put type and bitmask in the front of tm_return->result[]. // Use volatile vars for proper operation of memcpy(). memcpy(&tm_return->result[offset], (UWORD8 *) &temp, 2); offset+=2; memcpy(&tm_return->result[offset], (UWORD8 *) &utemp, 2); offset+=2; switch (type) { // Accumulated receive burst stats case ACCUMULATED_RX_STATS: { // all stats saved when collected from TCH if (l1tm.tmode_state.dedicated_active && (l1_config.tmode.rf_params.mon_report == 0)) count = l1tm.tmode_stats.loop_count; #if L1_GPRS else if (l1tm.tmode_state.packet_transfer_active && (l1_config.tmode.rf_params.mon_report == 0)) { // loop_count contains the number of blocks // Stats (PM, TOA, SNR, ANGLE) are accumulated over all frames and all time slots count = l1tm.tmode_stats.loop_count * l1tm.tmode_stats.nb_dl_pdtch_slots * 4; // the count of runs vs. successes is accumulated over all time slots per block runs = l1tm.tmode_stats.loop_count * l1tm.tmode_stats.nb_dl_pdtch_slots; } #endif else count = l1tm.tmode_stats.flag_count; // only PASS stats saved if (bitmask & RSSI) // rxlev: RSSI SF12.4 eventually (currently F7.1) { len = sizeof(l1tm.tmode_stats.rssi_fifo) / sizeof(l1tm.tmode_stats.rssi_fifo[0]); rssi = 0; for (j=0; j<len; j++) rssi += l1tm.tmode_stats.rssi_fifo[j]; rssi /= len; // F7.1 memcpy(&tm_return->result[offset], (UWORD8 *) &rssi, 2); offset+=2; } // pm: DSP MEAN power measurement UF10.6 if (bitmask & DSP_PM) { if (count) value_unsigned_short = l1tm.tmode_stats.pm_sum / count; else value_unsigned_short = 0; memcpy(&tm_return->result[offset], (UWORD8 *) &value_unsigned_short, 2); offset+=2; } // angle mean if (bitmask & ANGLE_MEAN) { if (count) // non-zero value_signed_int = l1tm.tmode_stats.angle_sum / count; else value_signed_int = 0; memcpy(&tm_return->result[offset], (UWORD8 *) &value_signed_int, 4); offset+=4; } // angle variance if (bitmask & ANGLE_VAR) { // VAR[X] = E[X^2] - (E[X])^2 if (count) // non-zero { temp_U32 = l1tm.tmode_stats.angle_sum / count; value_unsigned_int = l1tm.tmode_stats.angle_sq_sum / count - (temp_U32)*(temp_U32); } else value_unsigned_int = 0; memcpy(&tm_return->result[offset], (UWORD8 *) &value_unsigned_int, 4); offset+=4; } // angle minimum if (bitmask & ANGLE_MIN) { value_signed_int = l1tm.tmode_stats.angle_min; memcpy(&tm_return->result[offset], (UWORD8 *) &value_signed_int, 4); offset+=4; } // angle maximum if (bitmask & ANGLE_MAX) { value_signed_int = l1tm.tmode_stats.angle_max; memcpy(&tm_return->result[offset], (UWORD8 *) &value_signed_int, 4); offset+=4; } // SNR mean if (bitmask & SNR_MEAN) { if (count) // non-zero value_unsigned_int = l1tm.tmode_stats.snr_sum / count; else value_unsigned_int = 0; memcpy(&tm_return->result[offset], (UWORD8 *) &value_unsigned_int, 4); offset+=4; } // SNR variance if (bitmask & SNR_VAR) { if (count) // non-zero { temp_U32 = l1tm.tmode_stats.snr_sum / count; value_unsigned_int = l1tm.tmode_stats.snr_sq_sum / count - temp_U32 * temp_U32; } else value_unsigned_int = 0; memcpy(&tm_return->result[offset], (UWORD8 *) &value_unsigned_int, 4); offset+=4; } // TOA mean if (bitmask & TOA_MEAN) { if (count) // non-zero value_unsigned_int = l1tm.tmode_stats.toa_sum / count; else value_unsigned_int = 0; memcpy(&tm_return->result[offset], (UWORD8 *) &value_unsigned_int, 4); offset+=4; } // TOA variance if (bitmask & TOA_VAR) { if (count) // non-zero { temp_U32 = l1tm.tmode_stats.toa_sum / count; value_unsigned_int = l1tm.tmode_stats.toa_sq_sum / count - temp_U32 * temp_U32; } else value_unsigned_int = 0; memcpy(&tm_return->result[offset], (UWORD8 *) &value_unsigned_int, 4); offset+=4; } // Frame # mod 26*51 if (bitmask & FRAME_NUMBER) { value_unsigned_int = l1s.actual_time.fn; memcpy(&tm_return->result[offset], (UWORD8 *) &value_unsigned_int, 4); offset+=4; } // Tot # of runs executed so far if (bitmask & RUNS) { memcpy(&tm_return->result[offset], (UWORD8 *) &runs, 4); offset+=4; } // Tot # of successes so far if (bitmask & SUCCESSES) { memcpy(&tm_return->result[offset], (UWORD8 *) &l1tm.tmode_stats.flag_count, 4); offset+=4; } // BSIC if (bitmask & BSIC) { value_unsigned_short = l1tm.tmode_stats.bsic; memcpy(&tm_return->result[offset], (UWORD8 *) &value_unsigned_short, 2); offset+=2; } /* * FreeCalypso TCS211 reconstruction: suspected LoCosto-ism, * removing in order to pass compilation. */ #if 0 //L1_GPRS if (bitmask & BLER) { UWORD8 j; if (count) // non-zero { float bler, remain_part; UWORD8 int_part, bitmap_remain; int i; //compute bler for each block for (j=0; j<4; j++) { bler = ((float) (l1tm.tmode_stats.bler_crc[j] * 100)) / ((float) l1tm.tmode_stats.bler_total_blocks); //conversion from floating to fixed format int_part = (UWORD8) bler; remain_part = bler - (float) int_part; bitmap_remain = 0; i=5; while (i >= 0) { bitmap_remain |= (UWORD8) (remain_part *2) << i; if (((UWORD8) (remain_part *2)) >= 1) remain_part = (remain_part * 2) - 1; else remain_part = (remain_part * 2); i--; } // Reporting the percentage of blocks in error (F10.6) value_array_unsigned_short[j] = bitmap_remain | (int_part << 6); } } // Reporting a BLER of 100, if no computation has been done else { for (j=0; j<4; j++) value_array_unsigned_short[j] = 100 << 6; } memcpy(&tm_return->result[offset], (UWORD8 *) &value_array_unsigned_short[0], 8); offset+=8; } #endif #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif break; } // Most recent receive burst stats case MOST_RECENT_RX_STATS: { // rxlev: RSSI SF12.4 eventually (F7.1 currently) if (bitmask & RSSI) { value_unsigned_short = l1tm.tmode_stats.rssi_recent; memcpy(&tm_return->result[offset], (UWORD8 *) &value_unsigned_short, 2); offset+=2; } // pm: most recent DSP power measurement UF10.6 if (bitmask & DSP_PM) { memcpy(&tm_return->result[offset], &l1tm.tmode_stats.pm_recent, 2); offset+=2; } // most recent ANGLE value if (bitmask & ANGLE_MEAN) { value_signed_int = l1tm.tmode_stats.angle_recent; memcpy(&tm_return->result[offset], (UWORD8 *) &value_signed_int, 4); offset+=4; } // doesn't make sense. if (bitmask & ANGLE_VAR) { } // doesn't make sense. if (bitmask & ANGLE_MIN) { } // doesn't make sense. if (bitmask & ANGLE_MAX) { } // most recent SNR value if (bitmask & SNR_MEAN) { value_unsigned_int = l1tm.tmode_stats.snr_recent; memcpy(&tm_return->result[offset], (UWORD8 *) &value_unsigned_int, 4); offset+=4; } // doesn't make sense. if (bitmask & SNR_VAR) { } // most recent TOA value if (bitmask & TOA_MEAN) { value_unsigned_int = l1tm.tmode_stats.toa_recent; memcpy(&tm_return->result[offset], (UWORD8 *) &value_unsigned_int, 4); offset+=4; } // doesn't make sense. if (bitmask & TOA_VAR) { } // Frame # mod 26*51 if (bitmask & FRAME_NUMBER) { value_unsigned_int = l1s.actual_time.fn; memcpy(&tm_return->result[offset], (UWORD8 *) &value_unsigned_int, 4); offset+=4; } // must be '1' if (bitmask & RUNS) { } // most recent Success flag if (bitmask & SUCCESSES) { memcpy(&tm_return->result[offset], (UWORD8 *)&l1tm.tmode_stats.flag_recent, 4); offset+=4; } // BSIC if (bitmask & BSIC) { value_unsigned_short = l1tm.tmode_stats.bsic; memcpy(&tm_return->result[offset], (UWORD8 *) &value_unsigned_short, 2); offset+=2; } #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_OK; #else tm_return->status = E_OK; #endif break; } default: { #if (ETM_PROTOCOL == 1) tm_return->status = -ETM_INVAL; #else tm_return->status = E_BADINDEX; #endif break; } } // end switch tm_return->size = offset; tm_return->index = 0; // don't include index in header } /*-------------------------------------------------------*/ /* l1tm_fill_burst() */ /*-------------------------------------------------------*/ /* */ /* Description: Prepare bursts for transmission in case */ /* ------------ of UL test */ /* */ /* Simulation of IQ Swap does the following mapping: */ /* */ /* 00 -> 01 */ /* 01 -> 00 */ /* 10 -> 11 */ /* 11 -> 10 */ /* */ /*-------------------------------------------------------*/ #if (L1_FF_MULTIBAND == 1) extern const WORD8 rf_subband2band[]; #endif void l1tm_fill_burst (UWORD16 pattern, UWORD16 *TM_ul_data) { UWORD32 i; UWORD8 swap_iq, swap_flag; UWORD16 gb_front, gb_end, tb_front, tb_end, even_bits, odd_bits; #if (L1_FF_MULTIBAND == 1) UWORD8 physical_band_id; #endif UWORD8 tsc_bits_in_first_word; UWORD16 tsc_front_mask,tsc_end_mask; extern T_RF rf; // training sequences list...... UWORD32 tsc[8]= { 0x00970897, 0x00B778B7, 0x010EE90E, 0x011ED11E, 0x006B906B, 0x013AC13A, 0x029F629F, 0x03BC4BBC }; #if (L1_FF_MULTIBAND == 0) if(((l1_config.std.id == DUAL) || (l1_config.std.id == DUALEXT) || (l1_config.std.id == DUAL_US)) && (l1_config.tmode.rf_params.tch_arfcn >= l1_config.std.first_radio_freq_band2)) { swap_iq = l1_config.std.swap_iq_band2; } else { swap_iq = l1_config.std.swap_iq_band1; } #else // L1_FF_MULTIBAND = 1 below physical_band_id = rf_subband2band[rf_convert_rffreq_to_l1subband(l1_config.tmode.rf_params.tch_arfcn)]; swap_iq = rf_band[physical_band_id].swap_iq; #endif // #if (L1_FF_MULTIBAND == 0) else // Swap IQ definitions... // 0=No Swap, 1=Swap RX only, 2=Swap TX only, 3=Swap RX and TX if (swap_iq & 0x2) { swap_flag = 1; } else { swap_flag = 0; } //=========================================== // define uplink patterns //=========================================== if (pattern == 0) // 0's pattern = 0x0000; else if (pattern == 1) // 1's pattern = 0xffff; else if (pattern == 2) // 01's pattern = 0x5555; // first replicate pattern through all buffer if ((pattern == 3) || (pattern == 4)) { // fill the uplink burst with PRBS1 l1tm_PRBS1_generate(TM_ul_data); } else if ((pattern != 12) && (pattern != 13)) { for (i=0;i<=15;i++) TM_ul_data[i] = (pattern << 6); } //=========================================== // create front-end guard and tail bits masks //=========================================== // guard bits mask gb_front = 0xFFC0 << (10 - rf.tx.guard_bits); // max. of 10, min. of 2 guard bits allowed // check if guard bits > 7 if (rf.tx.guard_bits > 7) { // tail bits mask tb_front = ~((UWORD16)(0xE000 << (10 - rf.tx.guard_bits))) & 0xFFC0; // tail bits placed in TM_ul_data[1] //oamps00090550 // add tail bits to uplink data TM_ul_data[1] = TM_ul_data[1] & tb_front; // add guard bits to uplink data TM_ul_data[0] = gb_front; } else { // tail bits mask tb_front = ~((UWORD16)(0xE000 >> rf.tx.guard_bits) )& 0xFFC0; // 3 tail bits // add tail bits to uplink data TM_ul_data[0] = (TM_ul_data[0] | gb_front) & tb_front; } //=========================================== // create back-end guard and tail bits masks //=========================================== // guard bits mask gb_end = (0xFFC0 >> (10 - (12 - rf.tx.guard_bits))) & 0xFFC0; // max. of 10, min. of 2 guard bits allowed // check if guard bits < 5 if (rf.tx.guard_bits < 5) { //tail bits mask tb_end = ~(UWORD16)((0x01C0 >> (rf.tx.guard_bits - 2))) & 0xFFC0; // tail bits placed in TM_ul_data[14] // add tail bits to uplink data TM_ul_data[14] = TM_ul_data[14] & tb_end; // add guard bits to uplink data TM_ul_data[15] = gb_end; } else { // tail bits mask tb_end = ~(UWORD16)((0x01C0 << (12 - rf.tx.guard_bits))) & 0xFFC0; // 3 tail bits // add tail bits to uplink data TM_ul_data[15] = (TM_ul_data[15] | gb_end) & tb_end; } //=========================================== // Insert the training sequence pattern .The location of TSC bits will // vary according to the value of guard bits used. //=========================================== if ((pattern == 13)||(pattern==3)) { // TM_ul_data[6] = (TM_ul_data[6] & 0xFE00) | ( (UWORD8) ((tsc[l1_config.tmode.tx_params.tsc]>>24) << 6 ) ); // tsc bits 1-2 // TM_ul_data[7] = (TM_ul_data[7] & 0x0000) | ( (UWORD8) ((tsc[l1_config.tmode.tx_params.tsc]>>14) << 6 ) ); // tsc bits 3-12 // TM_ul_data[8] = (TM_ul_data[8] & 0x0000) | ( (UWORD8) ((tsc[l1_config.tmode.tx_params.tsc]>>4 ) << 6 ) ); // tsc bits 13-22 // TM_ul_data[9] = (TM_ul_data[9] & 0x07C0) | ( (UWORD8) ((tsc[l1_config.tmode.tx_params.tsc]>>0 ) << 12) ); // tsc bits 23-26 if (rf.tx.guard_bits <4) // TSC will be in [6],[7],[8] { tsc_bits_in_first_word = 9-rf.tx.guard_bits; // 7 bits when guard is 2, 6 bit when guard is 3 tsc_front_mask = ((0xFFC0) << tsc_bits_in_first_word); // insert zeros from right //tsc_bits_in_last_word = 26 -10 -tsc_bits_in_first_word = (16-tsc_bits_in_first_word) tsc_end_mask = (((0xFFC0) >> (16-tsc_bits_in_first_word)) & 0xFFC0); //insert zeros from left TM_ul_data[6] = (TM_ul_data[6] & tsc_front_mask) | ( ((UWORD16) ((tsc[l1_config.tmode.tx_params.tsc]>>(26-tsc_bits_in_first_word)) << 6 )) & (~tsc_front_mask) ); TM_ul_data[7] = (TM_ul_data[7] & 0x0000) | ( ((UWORD16) ((tsc[l1_config.tmode.tx_params.tsc]<<(tsc_bits_in_first_word+6))>>16)) & (0xFFC0)); //next 10 bits of TSC TM_ul_data[8] = (TM_ul_data[8] & tsc_end_mask) | ( ((UWORD16) ((tsc[l1_config.tmode.tx_params.tsc] << (tsc_bits_in_first_word+6+10))>>16) )& (~tsc_end_mask)); } else if ((rf.tx.guard_bits >=4) && (rf.tx.guard_bits <9) )// TSC will be in [6],[7],[8],[9] { tsc_bits_in_first_word = 9-rf.tx.guard_bits; // 5 bits when guard is 4, 1 bit when guard is 8 tsc_front_mask = ((0xFFC0) << tsc_bits_in_first_word); // insert zeros from right //tsc_bits_in_last_word = 26 -10 -10 -tsc_bits_in_first_word = (6-tsc_bits_in_first_word) tsc_end_mask = (((0xFFC0) >> (6-tsc_bits_in_first_word)) & 0xFFC0); //insert zeros from left TM_ul_data[6] = (TM_ul_data[6] & tsc_front_mask) | ( ((UWORD16) ((tsc[l1_config.tmode.tx_params.tsc]>>(26-tsc_bits_in_first_word)) << 6 )) & (~tsc_front_mask) ); TM_ul_data[7] = (TM_ul_data[7] & 0x0000) | ( ((UWORD16) ((tsc[l1_config.tmode.tx_params.tsc]<<(tsc_bits_in_first_word+6))>>16)) & (0xFFC0) ); //next 10 bits of TSC TM_ul_data[8] = (TM_ul_data[8] & 0x0000) | ( ((UWORD16) ((tsc[l1_config.tmode.tx_params.tsc]<<(tsc_bits_in_first_word+6+10))>>16)) & (0xFFC0) ); //next 10 bits of TSC TM_ul_data[9] = (TM_ul_data[9] & tsc_end_mask) | ( ((UWORD16) ((tsc[l1_config.tmode.tx_params.tsc] << (tsc_bits_in_first_word+6+10+10))>>16) ) & (~tsc_end_mask)); } else //(rf.tx.guard_bits>=9) : TSC will be in [7],[8],[9], { tsc_bits_in_first_word = 19-rf.tx.guard_bits; // 10 bits when guard is 9, 9 bits when guard is 10 tsc_front_mask = ((0xFFC0) << tsc_bits_in_first_word); // insert zeros from right //tsc_bits_in_last_word = 26 -10 -tsc_bits_in_first_word = (16-tsc_bits_in_first_word) tsc_end_mask = (((0xFFC0) >> (16-tsc_bits_in_first_word)) & 0xFFC0); //insert zeros from left TM_ul_data[7] = (TM_ul_data[7] & tsc_front_mask) | ( ((UWORD16) ((tsc[l1_config.tmode.tx_params.tsc]>>(26-tsc_bits_in_first_word)) << 6 )) & (~tsc_front_mask) ); TM_ul_data[8] = (TM_ul_data[8] & 0x0000) | ( ((UWORD16) ((tsc[l1_config.tmode.tx_params.tsc]<<(tsc_bits_in_first_word+6))>>16)) & (0xFFC0) ); //next 10 bits of TSC TM_ul_data[9] = (TM_ul_data[9] & tsc_end_mask) | ( ((UWORD16) ((tsc[l1_config.tmode.tx_params.tsc] << (tsc_bits_in_first_word+6+10))>>16)) & (~tsc_end_mask)); } } // swap uplink data if IQ swap if(swap_flag) { for (i=0;i<=15;i++) { even_bits = TM_ul_data[i] & 0xAA80; // keep bits in even positions odd_bits = ~(TM_ul_data[i]) & 0x5540; // keep and complement bits in odd positions TM_ul_data[i] = even_bits | odd_bits; // swapped uplink data } } } void l1a_tmode_send_ul_msg(T_TM_RETURN *tm_ret) { tm_transmit(tm_ret); } /******************************************************************************* * * void tm_receive(void *inbuf, int size) * * Purpose : Parses TestMode data and copies it directly into TESTMODE_PRIM. * It forwards primitive to L1, except in the case of tm_init() which * gets executed in the CST. * * Arguments: In : command * Out: * * Returns : void * ******************************************************************************/ void tm_receive(UWORD8 *inbuf, UWORD16 size) { UWORD8 cksum, cid, error = 0; BOOL msg_used=FALSE; #if (ETM_PROTOCOL == 1) UWORD8 mid = 0; #endif UWORD8 *pmsg; xSignalHeaderRec *msg; msg = os_alloc_sig(sizeof(T_TESTMODE_PRIM)); msg->SignalCode = TESTMODE_PRIM; // pmsg will be used to fill up the TestMode primitive with th // data, in consecutive order according to the definition of T_TESTMODE_PRIM. pmsg = (UWORD8 *)((T_TESTMODE_PRIM *)(msg->SigP)); #if (ETM_PROTOCOL == 1) // Use of ETM protocol #if (OP_L1_STANDALONE == 1) // Check MID *pmsg++ = mid = *inbuf++; if ((mid != ETM_RF) && (mid != ETM_CORE)) // check if coming from ETM RF or ETM CORE DLL error = -ETM_PACKET; #elif (OP_L1_STANDALONE == 0) *pmsg++ = mid = ETM_RF; #endif // Copy CID/FID *pmsg++ = cid = *inbuf++; #if (OP_L1_STANDALONE == 1) // Copy data payload size (size minus MID byte and checksum byte) size -= 2; #endif *pmsg++ = --size; // Size of TM payload -1 for cid/fid // Validate data payload size: check if longer than size of testmode // primitive minus cid, str_len_in_bytes, and two holes FIXME: This is a // really bad way of doing it! if (size > sizeof(T_TESTMODE_PRIM) - 4) error = -ETM_PACKET; // The CID have been received. The data that follows are part of a // unique struct within the union of T_TESTMODE_PRIM, so we now // need to align at a 32-bit word boundary. *pmsg++ = 0; // In a SSA integration the cksum is done in the etm_receive function #if (OP_L1_STANDALONE == 1) if (!error) { cksum = mid; cksum ^= cid; while (size--) { cksum ^= *inbuf; *pmsg++ = *inbuf++; } if (cksum != *inbuf) error = -ETM_PACKET; } #elif (OP_L1_STANDALONE == 0) // Copy payload without cid/fid while (size--) { *pmsg++ = *inbuf++; } #endif // At this point, all the data have been parsed and copied into // the TestMode primitive. Now we send the primitive to L1. if (!error) { os_send_sig(msg, L1C1_QUEUE); msg_used=TRUE; } else { UWORD8 mymsg[4]; // on error, return short error message; cid, error, checksum mymsg[0] = mid; mymsg[1] = cid; // the payload fid mymsg[2] = error; // status mymsg[3] = cid ^ error; // checksum #if (TRACE_TYPE==0) || (TRACE_TYPE==1) || (TRACE_TYPE==4) || (TRACE_TYPE==7) rvt_send_trace_cpy((T_RVT_BUFFER) mymsg, tm_trace_user_id, 4, RVT_BINARY_FORMAT); #endif } #else // end of (ETM_PROTOCOL ==1) // Copy CID *pmsg++ = cid = *inbuf++; // Copy data payload size (size minus CID byte and checksum byte) size -= 2; *pmsg++ = size; // Validate data payload size: check if longer than size of testmode // primitive minus cid, str_len_in_bytes, and two holes FIXME: This is a // really bad way of doing it! if (size > sizeof(T_TESTMODE_PRIM) - 4) error = E_PACKET; // The CID have been received. The data that follows are part of a // unique struct within the union of T_TESTMODE_PRIM, so we now // need to align at a 32-bit word boundary. pmsg += 2; if (!error) { cksum = cid; while (size--) { cksum ^= *inbuf; *pmsg++ = *inbuf++; } if (cksum != *inbuf) error = E_CHECKSUM; } // At this point, all the data have been parsed and copied into // the TestMode primitive. Now we send the primitive to L1. if (!error) { os_send_sig(msg, L1C1_QUEUE); msg_used=TRUE; } else { UWORD8 mymsg[3]; // on error, return short error message; error, cid/fid, checksum mymsg[0] = cid; mymsg[1] = error; mymsg[2] = cid ^ error; // checksum #if (TRACE_TYPE==1) || (TRACE_TYPE==4) || (TRACE_TYPE==7) || (TRACE_TYPE==0) rvt_send_trace_cpy((T_RVT_BUFFER) mymsg, tm_trace_user_id,3, RVT_BINARY_FORMAT); #endif } #endif // end of (ETM_PROTOCOL ==0) // if the message allocated is not sent to L1A, it has to be deallocated if(msg_used==FALSE) os_free_sig(msg); } void tm_transmit(T_TM_RETURN *tm_ret) { UWORD8 size, cksum; UWORD8 *pbuf, *ptmret; UWORD8 buf[TM_PAYLOAD_UPLINK_SIZE_MAX + TM_UPLINK_PACKET_OVERHEAD]; pbuf = &buf[0]; // move the header #if (ETM_PROTOCOL == 1) *pbuf++ = tm_ret->mid; cksum = tm_ret->mid; *pbuf++ = tm_ret->status; cksum ^= tm_ret->status; *pbuf++ = tm_ret->cid; cksum ^= tm_ret->cid; // Include index if not equal to zero, and if not an error // Exception: in TX_TEMPLATE_READ we always include the index. if ((tm_ret->status == -ETM_OK) && (tm_ret->index || tm_ret->cid == TX_TEMPLATE_READ)){ *pbuf++ = tm_ret->index; cksum ^= tm_ret->index; } #else *pbuf++ = tm_ret->cid; *pbuf++ = tm_ret->status; cksum = tm_ret->cid ^ tm_ret->status; // Include index if not equal to zero, and if not an error // Exception: in TX_TEMPLATE_READ we always include the index. if ((tm_ret->status == E_OK) && (tm_ret->index || tm_ret->cid == TX_TEMPLATE_READ)){ *pbuf++ = tm_ret->index; cksum ^= tm_ret->index; } #endif ptmret = (UWORD8 *) &tm_ret->result[0]; size = tm_ret->size; while (size--) { *pbuf++ = *ptmret; cksum ^= *ptmret++; } // move the checksum and append it to buf *pbuf++ = cksum; #if (TRACE_TYPE==1) || (TRACE_TYPE==4) || (TRACE_TYPE==7) || (TRACE_TYPE==0) rvt_send_trace_cpy(buf, tm_trace_user_id, pbuf - buf, RVT_BINARY_FORMAT); #endif } #if ((L1_STEREOPATH == 1) && (CODE_VERSION == NOT_SIMULATION) && (OP_L1_STANDALONE == 1)) /******************************************************************************* * * UWORD16 l1tm_stereopath_get_pattern(UWORD16 sampling_freq, UWORD16 sin_freq_left,UWORD16 sin_freq_right, UWORD8 data_type) * * Purpose : this function is use to get a complete period of a sinusoide depending on * the sinusoide freq (L+R), the sampling freq and the type of samples (S8,S16,S32) * * Arguments: sampling_freq : sampling frequency * sin_freq_left : frequency of the left channel sinusoide * sin_freq_right : frequency of the right channel sinusoide * data_type : type of samples * * Returns : number of elements in the pattern * ******************************************************************************/ UWORD16 l1tm_stereopath_get_pattern(UWORD16 sampling_freq, UWORD16 sin_freq_left,UWORD16 sin_freq_right, UWORD8 data_type) { float max_sin_period; float my_time; UWORD16 i; // get the lowest frequency to get the biggest period if (sin_freq_left > sin_freq_right) { max_sin_period = 1 / (float) sin_freq_right; } else { max_sin_period = 1 / (float) sin_freq_left; } my_time = 0; i = 0; if (data_type == AUDIO_SP_DATA_S8) { WORD8* my_ptr; // cast the steropath_pattern to a pointer on 8 bits samples my_ptr = (WORD8*) l1tm.stereopath.stereopath_pattern; // fill the pattern while the biggest period is not reached while (my_time < max_sin_period) { my_ptr[i++] = 0x7F * sin(2*3.1416*my_time*sin_freq_left); my_ptr[i++] = 0x7F * sin(2*3.1416*my_time*sin_freq_right); my_time = i/2/((float) sampling_freq); } } else // S16 { WORD16* my_ptr; // cast the steropath_pattern to a pointer on 16 bits samples my_ptr = (WORD16*) l1tm.stereopath.stereopath_pattern; // fill the pattern while the biggest period is not reached while (my_time < max_sin_period) { my_ptr[i++] = 0x7FFF * sin(2*3.1416*my_time*sin_freq_left); my_ptr[i++] = 0x7FFF * sin(2*3.1416*my_time*sin_freq_right); my_time = i/2/((float) sampling_freq); } } return (i); } /******************************************************************************* * * void l1tm_stereopath_fill_buffer(void* buffer_address) * * Purpose : this function is use to fill a buffer with a predefined pattern * * Arguments: buffer_address : address of the buffer to fill * * Returns : none * ******************************************************************************/ void l1tm_stereopath_fill_buffer(void* buffer_address) { static UWORD16 my_counter = 0; UWORD16 copied_samples; UWORD16 i; if (l1a_l1s_com.stereopath_drv_task.parameters.data_type == AUDIO_SP_DATA_S8) { WORD8* start_address; WORD8* my_ptr; // l1tm.stereopath.stereopath_buffer_number is a variable used to know which half of the buffer we have to fill if (l1tm.stereopath.stereopath_buffer_number == 0) { // first half start_address = (WORD8*) buffer_address; l1tm.stereopath.stereopath_buffer_number = 1; } else { // second half, add the frame number to get the half buffer address start_address = ((WORD8*) buffer_address) + l1a_l1s_com.stereopath_drv_task.parameters.frame_number; l1tm.stereopath.stereopath_buffer_number = 0; } // copied_samples is the number of samples copied to the half buffer copied_samples = 0; // cast the steropath_pattern to a pointer on 8 bits samples my_ptr = (WORD8*) l1tm.stereopath.stereopath_pattern; if (l1a_l1s_com.stereopath_drv_task.parameters.frame_number > l1tm.stereopath.stereopath_nb_samples) { // size of the half buffer to fill is bigger than the predefined pattern // start to fill the buffer with the end of the not complete previous pattern (from current_sample to the last one) memcpy(start_address,my_ptr+l1tm.stereopath.stereopath_current_sample,l1tm.stereopath.stereopath_nb_samples-l1tm.stereopath.stereopath_current_sample); copied_samples = l1tm.stereopath.stereopath_nb_samples-l1tm.stereopath.stereopath_current_sample; // while there is still enough place in the buffer to copy a complete pattern ... while (copied_samples<l1a_l1s_com.stereopath_drv_task.parameters.frame_number-l1tm.stereopath.stereopath_nb_samples) { // ... copy a complete pattern memcpy(start_address+copied_samples,my_ptr,l1tm.stereopath.stereopath_nb_samples); copied_samples += l1tm.stereopath.stereopath_nb_samples; } // fill the rest of the buffer with a part of the pattern memcpy(start_address+copied_samples,my_ptr,l1a_l1s_com.stereopath_drv_task.parameters.frame_number-copied_samples); // save the last pattern sample copied in the buffer for next time (to get a continuous sound) l1tm.stereopath.stereopath_current_sample = l1a_l1s_com.stereopath_drv_task.parameters.frame_number-copied_samples; } else { // size of the half buffer to fill is smaller than the predefined pattern // fill the buffer with a part of the pattern memcpy(start_address,my_ptr+l1tm.stereopath.stereopath_current_sample,l1a_l1s_com.stereopath_drv_task.parameters.frame_number); // save the last pattern sample copied in the buffer for next time (to get a continuous sound) l1tm.stereopath.stereopath_current_sample += l1a_l1s_com.stereopath_drv_task.parameters.frame_number; if (l1tm.stereopath.stereopath_current_sample > l1tm.stereopath.stereopath_nb_samples) { l1tm.stereopath.stereopath_current_sample -= l1tm.stereopath.stereopath_nb_samples; } } } else // S16 { WORD16* start_address; WORD16* my_ptr; // l1tm.stereopath.stereopath_buffer_number is a variable used to know which half of the buffer we have to fill if (l1tm.stereopath.stereopath_buffer_number == 0) { // first half start_address = (WORD16*) buffer_address; l1tm.stereopath.stereopath_buffer_number = 1; } else { // second half, add the frame number to get the half buffer address start_address = ((WORD16*) buffer_address) + l1a_l1s_com.stereopath_drv_task.parameters.frame_number; l1tm.stereopath.stereopath_buffer_number = 0; } // copied_samples is the number of samples copied to the half buffer copied_samples = 0; // cast the steropath_pattern to a pointer on 16 bits samples my_ptr = (WORD16*) l1tm.stereopath.stereopath_pattern; if (l1a_l1s_com.stereopath_drv_task.parameters.frame_number > l1tm.stereopath.stereopath_nb_samples) { // size of the half buffer to fill is bigger than the predefined pattern // start to fill the buffer with the end of the not complete previous pattern (from current_sample to the last one) memcpy(start_address, my_ptr+l1tm.stereopath.stereopath_current_sample,(l1tm.stereopath.stereopath_nb_samples-l1tm.stereopath.stereopath_current_sample)*2); copied_samples = l1tm.stereopath.stereopath_nb_samples-l1tm.stereopath.stereopath_current_sample; // while there is still enough place in the buffer to copy a complete pattern ... while (copied_samples<l1a_l1s_com.stereopath_drv_task.parameters.frame_number-l1tm.stereopath.stereopath_nb_samples) { // ... copy a complete pattern memcpy(start_address+copied_samples,my_ptr,l1tm.stereopath.stereopath_nb_samples*2); copied_samples += l1tm.stereopath.stereopath_nb_samples; } // fill the rest of the buffer with a part of the pattern memcpy(start_address+copied_samples,my_ptr,(l1a_l1s_com.stereopath_drv_task.parameters.frame_number-copied_samples)*2); // save the last pattern sample copied in the buffer for next time (to get a continuous sound) l1tm.stereopath.stereopath_current_sample = l1a_l1s_com.stereopath_drv_task.parameters.frame_number-copied_samples; } else { // size of the half buffer to fill is smaller than the predefined pattern // fill the buffer with a part of the pattern memcpy(start_address,my_ptr+l1tm.stereopath.stereopath_current_sample,l1a_l1s_com.stereopath_drv_task.parameters.frame_number); l1tm.stereopath.stereopath_current_sample += l1a_l1s_com.stereopath_drv_task.parameters.frame_number; // save the last pattern sample copied in the buffer for next time (to get a continuous sound) if (l1tm.stereopath.stereopath_current_sample > l1tm.stereopath.stereopath_nb_samples) { l1tm.stereopath.stereopath_current_sample -= l1tm.stereopath.stereopath_nb_samples; } } } } /******************************************************************************* * * void l1tm_stereopath_DMA_handler(SYS_UWORD16 dma_status) * * Purpose : this function is the stereopath DMA interrupt handler * * Arguments: dma_status : type of interrupt * * Returns : none * ******************************************************************************/ void l1tm_stereopath_DMA_handler(SYS_UWORD16 dma_status) { // stereopath DMA handler, check which type of interrupt it is if (F_DMA_COMPARE_CHANNEL_IT_STATUS_BLOCK(dma_status)) { l1tm.stereopath.stereopath_block++; // Block --> fill a new buffer l1tm_stereopath_fill_buffer((void*) l1a_l1s_com.stereopath_drv_task.parameters.source_buffer_address); } if (F_DMA_COMPARE_CHANNEL_IT_STATUS_HALF_BLOCK(dma_status)) { l1tm.stereopath.stereopath_half_block++; // Half Block --> fill a new buffer l1tm_stereopath_fill_buffer((void*) l1a_l1s_com.stereopath_drv_task.parameters.source_buffer_address); } if (F_DMA_COMPARE_CHANNEL_IT_STATUS_TIME_OUT_SRC(dma_status)) l1tm.stereopath.stereopath_source_timeout++; if (F_DMA_COMPARE_CHANNEL_IT_STATUS_TIME_OUT_DST(dma_status)) l1tm.stereopath.stereopath_dest_timeout++; if (F_DMA_COMPARE_CHANNEL_IT_STATUS_DROP(dma_status)) l1tm.stereopath.stereopath_drop++; if (F_DMA_COMPARE_CHANNEL_IT_STATUS_FRAME(dma_status)) l1tm.stereopath.stereopath_frame++; } #endif #if (CODE_VERSION != SIMULATION) void l1tm_tpu_table_write(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { Cust_tm_tpu_table_write(tm_return, prim->u.tm_table.index, prim->str_len_in_bytes - 1, // subtract 8-bit index prim->u.tm_table.table); } void l1tm_tpu_table_read(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return) { Cust_tm_tpu_table_read(tm_return, prim->u.tm_table.index); } #endif // (CODE_VERSION != SIMULATION) /*------------------------------------------------------------------*/ /* l1tm_PRBS1_generate() */ /*------------------------------------------------------------------*/ /* */ /* Parameters : UWORD16 *TM_ul_data */ /* ------------- */ /* point to the uplink burts table to be filled */ /* with the PRBS 1 of bits */ /* */ /* Return : Void */ /* ------------- */ /* */ /* Description : */ /* ------------- */ /* This algorithm generates a Pseudo Random Bit Sequence */ /* using a method called method "Primitive Polynomial Modulo 2" */ /* For a sequence length of (2^15-1) we a polynomial of order 15 */ /* is used, the coefficients are [ 15, 1, 0 ] */ /* The basic idea is to generate the new bit by XORing all the */ /* coefficients of the polynomial except coeff 0 */ /* i.e newbit = ( B15 XOR B1 ) */ /* The following notation must be used for the bit numbering: */ /* _______________________________________________________ */ /*|B16|B15|B14|B13|B12|B11|B10|B9|B8|B7|B6|B5|B4|B3|B2|B1| */ /*------------------------------------------------------------------*/ /* */ /* each word of the uplink buffer needs to be filled by new 10 bits */ /*------------------------------------------------------------------*/ void l1tm_PRBS1_generate(UWORD16 *TM_ul_data) { #define B15_MASK 0x4000 #define B1_MASK 0x0001 #define MASK_16BITS 0xFFFF UWORD16 newbit =0x0000; UWORD8 index ,word; //generate 16 words to fill Uplink table for (word=0;word<16;word++) { // generate new 10 bits from the sequence for (index =0; index< 10;index++) { // generate new bit , using the "Primitive Polynomial Modulo 2 " method with coeff. ( 15, 1, 0 ) //XOR bit 15 with bit 1. newbit = (((l1tm.tmode_prbs.prbs1_seed& B15_MASK)>>14)^(l1tm.tmode_prbs.prbs1_seed & B1_MASK)); // insert new bit in the sequence. l1tm.tmode_prbs.prbs1_seed = (l1tm.tmode_prbs.prbs1_seed << 1) | newbit; } TM_ul_data[word]=(UWORD16)((l1tm.tmode_prbs.prbs1_seed&MASK_16BITS)<<6); } } #endif // TESTMODE