FreeCalypso > hg > fc-tourmaline
view src/g23m-gprs/grlc/grlc_tmf.c @ 303:f76436d19a7a default tip
!GPRS config: fix long-standing AT+COPS chance hanging bug
There has been a long-standing bug in FreeCalypso going back years:
sometimes in the AT command bring-up sequence of an ACI-only MS,
the AT+COPS command would produce only a power scan followed by
cessation of protocol stack activity (only L1 ADC traces), instead
of the expected network search sequence. This behaviour was seen
in different FC firmware versions going back to Citrine, and seemed
to follow some law of chance, not reliably repeatable.
This bug has been tracked down and found to be specific to !GPRS
configuration, stemming from our TCS2/TCS3 hybrid and reconstruction
of !GPRS support that was bitrotten in TCS3.2/LoCosto version.
ACI module psa_mms.c, needed only for !GPRS, was missing in the TCS3
version and had to be pulled from TCS2 - but as it turns out,
there is a new field in the MMR_REG_REQ primitive that needs to be
set correctly, and that psa_mms.c module is the place where this
initialization needed to be added.
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Thu, 08 Jun 2023 08:23:37 +0000 |
parents | fa8dc04885d8 |
children |
line wrap: on
line source
/* +----------------------------------------------------------------------------- | Project : GPRS (8441) | Modul : GRLC +----------------------------------------------------------------------------- | Copyright 2002 Texas Instruments Berlin, AG | All rights reserved. | | This file is confidential and a trade secret of Texas | Instruments Berlin, AG | The receipt of or possession of this file does not convey | any rights to reproduce or disclose its contents or to | manufacture, use, or sell anything it may describe, in | whole, or in part, without the specific written consent of | Texas Instruments Berlin, AG. +----------------------------------------------------------------------------- | Purpose : This module implements local functions for service TC of | entity GRLC. +----------------------------------------------------------------------------- */ #ifndef GRLC_TMF_C #define GRLC_TMF_C #endif #define ENTITY_GRLC /*==== INCLUDES =============================================================*/ #include <stdio.h> #include <string.h> #include "typedefs.h" /* to get Condat data types */ #include "vsi.h" /* to get a lot of macros */ #include "macdef.h" #include "gprs.h" #include "gsm.h" /* to get a lot of macros */ #include "ccdapi.h" /* to get CCD API */ #include "cnf_grlc.h" /* to get cnf-definitions */ #include "mon_grlc.h" /* to get mon-definitions */ #include "prim.h" /* to get the definitions of used SAP and directions */ #include "message.h" /* to get air message definitions */ #include "grlc.h" /* to get the global entity definitions */ #include "grlc_f.h" /* to get Process GRLC global function definitions */ #include "grlc_tmf.h" /* to get Service TM global function definitions */ #include "grlc_tms.h" /* to get Service TM inter signal definitions */ #include "grlc_rus.h" /* to get interface to service RU */ #include "grlc_rds.h" /* to get interface to service RD */ #include "grlc_gffs.h" #include "grlc_meass.h" #include "grlc_tpcs.h" #include "cl_rlcmac.h" /*==== CONST ================================================================*/ /* * used in tm_compare_prim */ #define SAME_RLC_MODE 0 #define DIFFERENT_RLC_MODE 1 #define PRIO_LOWER 0 #define PRIO_SAME 1 #define PRIO_HIGHER 2 #define THROUGHPUT_LOWER 0 #define THROUGHPUT_SAME 1 #define THROUGHPUT_HIGHER 2 #ifdef REL99 #define SAME_PFI 0 #define DIFF_PFI 1 #endif /*==== DIAGNOSTICS ==========================================================*/ /*==== LOCAL VARS ===========================================================*/ /*==== PRIVATE FUNCTIONS ====================================================*/ LOCAL void tm_close_gaps_in_ctrl_blk_seq( UBYTE index ); /*==== PUBLIC FUNCTIONS =====================================================*/ /* +------------------------------------------------------------------------------ | Function : tm_access_allowed +------------------------------------------------------------------------------ | Description : The function tm_access_allowed() this function checks wheather | access is allowed or not. The return is TRUE if access | is allowed. | | Parameters : radio_prrio - radio priority for current primitive | +------------------------------------------------------------------------------ */ GLOBAL BOOL tm_access_allowed ( UBYTE radio_prio ) { BOOL result = FALSE; TRACE_FUNCTION( "tm_access_allowed" ); switch(grlc_data->uplink_tbf.ac_class) { case CGRLC_PCCCH_AC_ALLOWED: result = TRUE; break; case CGRLC_PCCCH_AC_NOT_ALLOWED: TRACE_EVENT(" grlc ACCESS NOT ALLOWED PBCCH:"); break; case CGRLC_CCCH_AC_NOT_ALLOWED: TRACE_EVENT("grlc ACCESS NOT ALLOWED CCCH"); break; default: if ( (radio_prio+3) <= grlc_data->uplink_tbf.ac_class) result = TRUE; else TRACE_EVENT_P2("Radio prio to low : pdu_rp=%d net_rp=%d",radio_prio,grlc_data->uplink_tbf.ac_class); break; } return(result); } /* tm_access_allowed() */ /* +------------------------------------------------------------------------------ | Function : tm_build_chan_req_des +------------------------------------------------------------------------------ | Description : The function builds a channel request description. It is called | during re-allocation or during uplink allocation on | a dowlink TBF. | | Parameters : out_i - Function have to write the channel request description | at this address | p_ptr_i - Pointer to primitive which causes the channel request | description | +------------------------------------------------------------------------------ */ GLOBAL void tm_build_chan_req_des ( T_chan_req_des * out_i,T_PRIM_QUEUE * p_ptr_i ) { UBYTE next; TRACE_FUNCTION( "tm_build_chan_req_des" ); grlc_data->uplink_tbf.ti = 0; /* no contention resolution needed */ out_i->peak_thr_class = p_ptr_i->prim_ptr->grlc_qos.peak; out_i->radio_prio = p_ptr_i->prim_ptr->radio_prio; /* * set RLC-Mode and LLC-Mode */ out_i->llc_pdu_type = LLC_NOT_ACK; /* that means not acknowledged */ if(p_ptr_i->prim_type EQ CGRLC_LLC_PRIM_TYPE_DATA_REQ) { /* CGRLC_LLC_PRIM_TYPE_DATA_REQ */ out_i->rlc_mode = RLC_ACK_MODE; /* that means RLC mode acknowledged */ } else { /* CGRLC_LLC_PRIM_TYPE_UNITDATA_REQ */ out_i->rlc_mode = RLC_UNACK_MODE; /* that means RLC mode not acknowledged */ } next = p_ptr_i->next; out_i->rlc_octet_cnt = p_ptr_i->prim_ptr->sdu.l_buf/8 +1; while (next < PRIM_QUEUE_SIZE_TOTAL) { out_i->rlc_octet_cnt += grlc_data->prim_queue[next].prim_ptr->sdu.l_buf/8 +1; next = grlc_data->prim_queue[next].next; } if (grlc_data->testmode.mode EQ CGRLC_LOOP) { out_i->rlc_octet_cnt = 0; TRACE_EVENT("open-ended tbf for testmode B requested"); } return; } /* tm_build_chan_req_des */ /* +------------------------------------------------------------------------------ | Function : tm_send_tbf_rel +------------------------------------------------------------------------------ | Description : The function tm_send_tbf_rel() builds CGRLC_TBF_REL_IND | and send it. | | Parameters : TBP-Type - that have to be deleted | +------------------------------------------------------------------------------ */ GLOBAL void tm_send_tbf_rel ( T_TBF_TYPE tbf_i ) { PALLOC(cgrlc_tbf_rel_ind,CGRLC_TBF_REL_IND); TRACE_FUNCTION( "tm_send_tbf_rel" ); if(grlc_data->uplink_tbf.ti) cgrlc_tbf_rel_ind->tbf_rel_cause = CGRLC_TBF_REL_CR_FAILED; else if (grlc_data->N3102 EQ 0) /* tbf error with cell reselction*/ cgrlc_tbf_rel_ind->tbf_rel_cause = CGRLC_TBF_REL_WITH_CELL_RESELECT; else cgrlc_tbf_rel_ind->tbf_rel_cause = CGRLC_TBF_REL_NORMAL; /* Find condition for abnormal release */ grlc_data->uplink_tbf.ti = 0; /* * indicate if testmode or tbf_type is released */ if((tbf_i NEQ TBF_TYPE_DL) AND /* Testmode released only in case of uplink tbf release*/ (grlc_test_mode_active())) { if (grlc_data->testmode.mode EQ CGRLC_TEST_RANDOM) { MFREE(grlc_data->testmode.ptr_test_data); grlc_data->testmode.ptr_test_data = NULL; } grlc_data->testmode.mode = CGRLC_TEST_MODE_RELEASE; cgrlc_tbf_rel_ind->tbf_rel_cause = CGRLC_TBF_REL_NORMAL; } #if defined REL99 AND defined TI_PS_FF_TI_PS_FF_TBF_EST_PACCH if (tbf_i EQ TBF_TYPE_TP_ACCESS AND grlc_data->tm.pacch_prr_pca_sent) /*PRR/PCA sent as POLL (tbf on pacch)*/ { vsi_t_stop(GRLC_handle,T3168); cgrlc_tbf_rel_ind->tbf_mode = CGRLC_TBF_MODE_UL; grlc_data->tm.pacch_prr_pca_sent = FALSE; sig_tm_gff_ul_deactivate(); } else #endif if (tbf_i EQ TBF_TYPE_UL) { cgrlc_tbf_rel_ind->tbf_mode = CGRLC_TBF_MODE_UL; grlc_data->rel_type |= REL_TYPE_UL; sig_tm_gff_ul_deactivate(); } else if (tbf_i EQ TBF_TYPE_DL) { cgrlc_tbf_rel_ind->tbf_mode = CGRLC_TBF_MODE_DL; grlc_data->rel_type |= REL_TYPE_DL; sig_tm_gff_dl_deactivate(); cgrlc_tbf_rel_ind->dl_trans_id = grlc_data->downlink_tbf.trans_id; } else { cgrlc_tbf_rel_ind->tbf_mode = CGRLC_TBF_MODE_DL_UL; grlc_data->rel_type = REL_TYPE_DL_UL; cgrlc_tbf_rel_ind->dl_trans_id = grlc_data->downlink_tbf.trans_id; sig_tm_gff_ul_deactivate(); sig_tm_gff_dl_deactivate(); } /* * \ tbf_i | UL DL CONC * \ | * \ | * \ | * tbf_type \ | * -----------+----------- * NULL | x x x * UL | x - x * DL | - x x * CONC | - - x * * x means, that no more TBF is existing * - means, that a TBF is still existing */ if( tbf_i EQ TBF_TYPE_CONC OR grlc_data->tbf_type EQ TBF_TYPE_NULL OR grlc_data->tbf_type EQ tbf_i ) { cgrlc_tbf_rel_ind->v_c_value = TRUE; meas_grlc_c_get_c_value( &cgrlc_tbf_rel_ind->c_value ); meas_c_restart( ); } else { cgrlc_tbf_rel_ind->v_c_value = FALSE; } #if defined (_TARGET_) switch(cgrlc_tbf_rel_ind->tbf_mode) { case CGRLC_TBF_MODE_UL: #if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH case CGRLC_TBF_MODE_2PA: #endif TRACE_EVENT_P4("UL_TBF_REL:nr_of_crc_errors= %ld ul_call_errors=%ld dl_call_errors=%ld rel_type=%d", grlc_data->nr_of_crc_errors, grlc_data->ul_call_errors, grlc_data->dl_call_errors, grlc_data->rel_type); break; case CGRLC_TBF_MODE_DL: TRACE_EVENT_P4("DL_TBF_REL:nr_of_crc_errors= %ld ul_call_errors=%ld dl_call_errors=%ld rel_type=%d", grlc_data->nr_of_crc_errors, grlc_data->ul_call_errors, grlc_data->dl_call_errors, grlc_data->rel_type); break; case CGRLC_TBF_MODE_DL_UL: TRACE_EVENT_P4("UL/DL_TBF_REL:nr_of_crc_errors= %ld ul_call_errors=%ld dl_call_errors=%ld rel_type=%d", grlc_data->nr_of_crc_errors, grlc_data->ul_call_errors, grlc_data->dl_call_errors, grlc_data->rel_type); break; case CGRLC_TBF_MODE_TMA: case CGRLC_TBF_MODE_TMB: TRACE_EVENT_P3 ("Testmode TBF_REL:nr_of_crc_errors= %ld ul_call_errors=%ld dl_call_errors=%ld", grlc_data->nr_of_crc_errors, grlc_data->ul_call_errors, grlc_data->dl_call_errors); break; } if(grlc_data->ul_call_errors OR grlc_data->dl_call_errors) { TRACE_EVENT_P6("ul_fn_err=%ld,%ld,%ld//dl_fn_err=%ld,%ld,%ld", grlc_data->ul_fn_errors[0], grlc_data->ul_fn_errors[1], grlc_data->ul_fn_errors[2], grlc_data->dl_fn_errors[0], grlc_data->dl_fn_errors[1], grlc_data->dl_fn_errors[2]); grlc_data->ul_call_errors = 0; grlc_data->dl_call_errors = 0; } grlc_data->nr_of_crc_errors = 0; #endif /* defined (_TARGET_) */ PSEND(hCommGRR,cgrlc_tbf_rel_ind); } /* tm_send_tbf_rel() */ /* +------------------------------------------------------------------------------ | Function : tm_abort_tbf +------------------------------------------------------------------------------ | Description : The function tm_abort_tbf() stops a TBF. | | Parameters : tbf_i - TBF type to abort | +------------------------------------------------------------------------------ */ GLOBAL void tm_abort_tbf ( T_TBF_TYPE tbf_i ) { /*SZML-TC/056*/ TRACE_FUNCTION( "tm_abort_tbf" ); switch( tbf_i ) { case TBF_TYPE_NULL: TRACE_EVENT("NULL TBF active: check if tbf starting time is running"); /*SZML-TC/093*/ break; #if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH case TBF_TYPE_TP_ACCESS: tm_send_tbf_rel(tbf_i); tm_deactivate_tbf(tbf_i); break; #endif case TBF_TYPE_UL: tm_send_tbf_rel(tbf_i); sig_tm_ru_abrel(1, FALSE); tm_deactivate_tbf(tbf_i); break; case TBF_TYPE_DL: tm_send_tbf_rel(tbf_i); sig_tm_rd_abrel(1,FALSE); tm_deactivate_tbf(tbf_i); break; case TBF_TYPE_CONC: tm_send_tbf_rel(tbf_i); sig_tm_ru_abrel(1, FALSE); sig_tm_rd_abrel(1,FALSE); tm_deactivate_tbf(tbf_i); break; default: TRACE_ERROR ( "tm_abort_tbf: TBF type is invalid" ); break; } } /* tm_abort_tbf() */ /* +------------------------------------------------------------------------------ | Function : tm_ini_realloc +------------------------------------------------------------------------------ | Description : The function tm_ini_realloc() do all action that are necessary | to start a Resource Re-Allocation Procedure. | | Parameters : void | +------------------------------------------------------------------------------ */ GLOBAL void tm_ini_realloc ( UBYTE start_of_new_tbf_i ) { TRACE_FUNCTION( "tm_ini_realloc" ); grlc_data->tm.start_of_new_tbf = start_of_new_tbf_i ; /*SZML-TC/058*/ } /* tm_ini_realloc() */ /* +------------------------------------------------------------------------------ | Function : tm_build_res_req +------------------------------------------------------------------------------ | Description : The function tm_build_res_req() builds Packet Resource Request. | | Parameters : reason_i - the reason for building that packet resouce | reallocation | +------------------------------------------------------------------------------ */ GLOBAL void tm_build_res_req (T_U_GRLC_RESOURCE_REQ *ptr2res_req, T_REASON_BUILD reason_i) { TRACE_FUNCTION( "tm_build_res_req" ); memset(ptr2res_req,0,sizeof(T_U_GRLC_RESOURCE_REQ) ); /* processing of messsage type */ ptr2res_req->msg_type = U_GRLC_RESOURCE_REQ_c; /* processing of change mark */ if( grlc_data->tm.change_mark EQ NOT_SET ) { ptr2res_req->v_ma_ch_mark = 0; } else { ptr2res_req->v_ma_ch_mark = 1; ptr2res_req->ma_ch_mark = grlc_data->tm.change_mark; } if(reason_i EQ R_FIX_RE_ALLOC) { /* 1 - processing of ACCESS_TYPE */ ptr2res_req->v_access_type = 0; /* 2 - processing of global TFI and TLLI */ ptr2res_req->flag = 0; ptr2res_req->v_glob_tfi = 1; ptr2res_req->glob_tfi.flag = 0; ptr2res_req->glob_tfi.v_ul_tfi = 1; ptr2res_req->glob_tfi.ul_tfi = grlc_data->ul_tfi; /* 3 - processing of radio access capabilities */ ptr2res_req->v_ra_cap = FALSE; /* 4 - processing of channel request description */ tm_build_chan_req_des(&ptr2res_req->chan_req_des, &grlc_data->prim_queue[grlc_data->prim_start_tbf]); } else if(reason_i EQ R_RE_ALLOC) { /* 1 - processing of ACCESS_TYPE */ ptr2res_req->v_access_type = 0; /* 2 - processing of global TFI and TLLI */ ptr2res_req->flag = 1; ptr2res_req->v_glob_tfi = 0; ptr2res_req->v_tlli_value = 1; grlc_set_buf_tlli( &ptr2res_req->tlli_value, grlc_data->uplink_tbf.tlli ); /* 3 - processing of radio access capabilities */ ptr2res_req->v_ra_cap = FALSE; /* 4 - processing of channel request description */ tm_build_chan_req_des(&ptr2res_req->chan_req_des, &grlc_data->prim_queue[grlc_data->tm.start_of_new_tbf]); } else if(reason_i EQ R_BUILD_2PHASE_ACCESS) { /* 1 - processing of ACCESS_TYPE */ ptr2res_req->v_access_type = 1; ptr2res_req->access_type = TWO_PHASE; /* 2 - processing of global TFI and TLLI */ ptr2res_req->flag = 1; ptr2res_req->v_glob_tfi = 0; ptr2res_req->v_tlli_value = 1; grlc_set_buf_tlli( &ptr2res_req->tlli_value, grlc_data->uplink_tbf.tlli ); /* 3 - processing of radio access capabilities */ if( rr_csf_get_radio_access_capability( &ptr2res_req->ra_cap ) EQ 0 ) { ptr2res_req->v_ra_cap = TRUE; } else { ptr2res_req->v_ra_cap = FALSE; TRACE_ERROR( "tm_build_res_req: radio access capabilities invalid" ); } /* 4 - processing of channel request description */ tm_build_chan_req_des((T_chan_req_des *)(&ptr2res_req->chan_req_des), &grlc_data->prim_queue[grlc_data->prim_start_tbf] ); } /* 5 - processing of signal variance */ ptr2res_req->signvar = meas_sv_get_value( ); ptr2res_req->v_signvar = TRUE; /* 6 - processing of relative interference levels */ meas_int_get_rel_i_level( &ptr2res_req->ilev ); /* 7 - processing of C value */ ptr2res_req->c_value = meas_grlc_c_get_value( ); #ifdef REL99 ptr2res_req->v_release_99_str_grlc_prr = TRUE; /* Workaround to avoid definition of EGPRS measurements info * in grr.aim file. This will reduce the size of ccddata.lib */ ptr2res_req->release_99_str_grlc_prr.flag = 0; ptr2res_req->release_99_str_grlc_prr.flag2 = 0; /* Flag PFI, shall only include if PFI and BSS R99 */ if (grlc_data->nw_rel AND grlc_data->pfi_support) { ptr2res_req->release_99_str_grlc_prr.v_pfi = 1; if ( reason_i EQ R_RE_ALLOC ) { ptr2res_req->release_99_str_grlc_prr.pfi = grlc_data->prim_queue[grlc_data->tm.start_of_new_tbf].prim_ptr->pkt_flow_id[0]; } else { ptr2res_req->release_99_str_grlc_prr.pfi = grlc_data->pfi_value; } } else { ptr2res_req->release_99_str_grlc_prr.v_pfi = 0; } ptr2res_req->release_99_str_grlc_prr.add_ms_rac = 0; ptr2res_req->release_99_str_grlc_prr.retrans_of_prr = 0; #endif } /* tm_build_res_req() */ /* +------------------------------------------------------------------------------ | Function : tm_init_prim +------------------------------------------------------------------------------ | Description : The function tm_init_prim() initializes the primitive queue. | Parameters : void | +------------------------------------------------------------------------------ */ GLOBAL void tm_init_prim ( void ) { UBYTE i; TRACE_FUNCTION( "tm_init_prim" ); /* LLC PRIM QUEUE*/ for (i=0;i<PRIM_QUEUE_SIZE;i++) { /* * set next to the following entry */ grlc_data->prim_queue[i].next = i+1; /* * and initialize the not used primitive entry */ grlc_data->prim_queue[i].prim_ptr = NULL; grlc_data->prim_queue[i].prim_type = CGRLC_LLC_PRIM_TYPE_NULL; grlc_data->prim_queue[i].cv_status = FALSE; grlc_data->prim_queue[i].rlc_status = FALSE; grlc_data->prim_queue[i].re_allocation = FALSE; grlc_data->prim_queue[i].start_new_tbf = FALSE; grlc_data->prim_queue[i].last_bsn = 0xff; } /* * last free entry points to 0xff */ grlc_data->prim_queue[PRIM_QUEUE_SIZE-1].next = 0xff; /* * index 0 is the first free entry */ grlc_data->prim_start_free = 0; /* * becauce there are no primitives in the tbf prim_start_tbf points to 0xff */ grlc_data->prim_start_tbf = 0xff; /* * init because there are no primitives there is also no user data */ grlc_data->prim_user_data = 0; /* init gmm prim queue*/ for (i=PRIM_QUEUE_SIZE; i<(PRIM_QUEUE_SIZE_TOTAL);i++) { grlc_data->prim_queue[i].next = i+1; grlc_data->prim_queue[i].prim_ptr = NULL; grlc_data->prim_queue[i].prim_type = CGRLC_LLC_PRIM_TYPE_NULL; grlc_data->prim_queue[i].cv_status = FALSE; grlc_data->prim_queue[i].rlc_status = FALSE; grlc_data->prim_queue[i].re_allocation = FALSE; grlc_data->prim_queue[i].start_new_tbf = FALSE; grlc_data->prim_queue[i].last_bsn = 0xff; } grlc_data->gmm_procedure_is_running = FALSE; grlc_data->prim_queue[PRIM_QUEUE_SIZE_TOTAL-1].next = 0xff; } /* tm_init_prim() */ /* +------------------------------------------------------------------------------ | Function : tm_start_access +------------------------------------------------------------------------------ | Description : The function tm_start_access() prepares the TC data structure | for a packet access procedure. | | Parameters : void | +------------------------------------------------------------------------------ */ GLOBAL void tm_start_access ( void ) { USHORT rlc_octetts; TRACE_FUNCTION( "tm_start_access" ); /* * mark that first packet access in process */ grlc_data->tm.n_res_req = 0; #if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH grlc_data->tm.pacch_prr_pca_sent = FALSE; #endif grlc_data->tm.n_acc_req_procedures++; if(grlc_data->prim_start_tbf < PRIM_QUEUE_SIZE_TOTAL) { grlc_data->uplink_tbf.prio = grlc_data->prim_queue[grlc_data->prim_start_tbf].prim_ptr->radio_prio; /* save prio for packet access request building */ rlc_octetts = grlc_data->prim_queue[grlc_data->prim_start_tbf].prim_ptr->sdu.l_buf/8 +1; #ifdef REL99 if (grlc_data->pfi_support) { /* pfi will take 1 byte*/ grlc_data->uplink_tbf.nr_blocks = ( rlc_octetts / 15 ) + 1; grlc_data->pfi_value = grlc_data->prim_queue[grlc_data->prim_start_tbf].prim_ptr->pkt_flow_id[0]; } else #endif { /* last "+1" we need complete bytes/octetts */ grlc_data->uplink_tbf.nr_blocks = ( rlc_octetts / 16 ) + 1; } /*TRACE_EVENT_P1("tm_start_access: nr_block: %d", grlc_data->uplink_tbf.nr_blocks);*/ /* 16 because 23(CS_1 length) -3(blockheader) -4(TLLI) = 16 octetts */ /* last "+1" we need complete blocks */ if(grlc_data->prim_queue[grlc_data->prim_start_tbf].prim_type EQ CGRLC_LLC_PRIM_TYPE_UNITDATA_REQ ) { grlc_data->uplink_tbf.rlc_mode = CGRLC_RLC_MODE_UACK; grlc_data->uplink_tbf.ti = 0; /* mark that contention resolution is not requested */ } else { grlc_data->uplink_tbf.rlc_mode = CGRLC_RLC_MODE_ACK; grlc_data->uplink_tbf.ti = 1; /* mark that contention resulution is not yet done */ } /* * estimate access_type */ if(grlc_data->prim_queue[grlc_data->prim_start_tbf].prim_type EQ CGRLC_LLC_PRIM_TYPE_UNITDATA_REQ ) { grlc_data->uplink_tbf.access_type = CGRLC_AT_TWO_PHASE; } else if(grlc_data->uplink_tbf.access_type EQ CGRLC_AT_CELL_UPDATE) { TRACE_EVENT("CU WILL BE PERFORMED"); } else { switch(grlc_data->prim_queue[grlc_data->prim_start_tbf].prim_ptr->cause) { case GRLC_DTACS_DEF: if(grlc_data->uplink_tbf.nr_blocks <= 8) { grlc_data->uplink_tbf.access_type = CGRLC_AT_SHORT_ACCESS; } else { grlc_data->uplink_tbf.access_type = CGRLC_AT_ONE_PHASE; } break; case GRLC_DTACS_PAGE_RESPONSE: grlc_data->uplink_tbf.access_type = CGRLC_AT_PAGE_RESPONSE; break; case GRLC_DTACS_MOBILITY_MANAGEMENT: grlc_data->uplink_tbf.access_type = CGRLC_AT_MM_PROCEDURE; break; case GRLC_DTACS_EMPTY_FRAME: case GRLC_DTACS_CELL_NOTIFI_NULL_FRAME: grlc_data->uplink_tbf.access_type = CGRLC_AT_CELL_UPDATE; TRACE_EVENT("EMPTY FRAME for CU, but not requested by GMM"); break; default: grlc_data->uplink_tbf.access_type = CGRLC_AT_NULL; break; } } } else { TRACE_ERROR("NO PRIM IN QUEUE in tm_start_access"); } } /* tm_start_access() */ /* +------------------------------------------------------------------------------ | Function : tm_data_req +------------------------------------------------------------------------------ | Description : The function tm_data_req() starts the process of queueing | a primitive received from LLC | | Parameters : prime_tpye_i - primitiven type (PRIME_TYPE_UNITDATA or | PRIME_TYPE_DATA) | ptr2prim_i - address of the primitive to handle | | +------------------------------------------------------------------------------ */ GLOBAL void tm_data_req ( T_PRIM_TYPE prim_tpye_i, T_GRLC_DATA_REQ * ptr2prim_i) { UBYTE free_entry_count , position , new_prim ; T_COMPARE_PRIM compare_result = C_PRIM_CONTINUE; BOOL new_qos = FALSE; TRACE_FUNCTION( "tm_data_req" ); /* * get the index of next free prim queue entry */ free_entry_count = tm_prim_queue_get_free_count(); if (free_entry_count) { /* get first free entry from free list */ new_prim = grlc_prim_get_first (&grlc_data->prim_start_free); #ifdef REL99 /*SM currenlty give 0xFF , in case network does not assign PFI */ if (ptr2prim_i->pkt_flow_id[0] EQ 0xFF) { ptr2prim_i->pkt_flow_id[0] = 0; } #endif grlc_data->prim_queue[new_prim ].prim_type = prim_tpye_i; grlc_data->prim_queue[new_prim ].prim_ptr = ptr2prim_i; position = grlc_data->prim_start_tbf; do { if(position < PRIM_QUEUE_SIZE_TOTAL) /* this "if" make sure only valid llc_pdu are used in comparision */ { compare_result = tm_compare_prim(new_prim ,position ,&new_qos); /* * position for new prim is found ! */ if(compare_result NEQ C_PRIM_CONTINUE) break; position = grlc_data->prim_queue[position ].next; } else { /* first prim in queue */ compare_result = C_PRIM_NEW_TBF; break; } } while (1); switch( compare_result ) { case C_PRIM_NEW_TBF: grlc_data->prim_queue[new_prim ].start_new_tbf = 1; break; case C_PRIM_REALLOC_START: { T_U_GRLC_RESOURCE_REQ resource_req;/*lint !e813*/ tm_ini_realloc(new_prim); tm_build_res_req( &resource_req, R_RE_ALLOC ); tm_store_ctrl_blk( CGRLC_BLK_OWNER_TM, ( void* )&resource_req ); if (grlc_data->prim_queue[position].next NEQ 0xff)/*sec 8.1.1.1.2 para 10*/ { grlc_data->prim_queue[grlc_data->prim_queue[position].next].re_allocation = 1; } } break; case C_PRIM_REALLOC_SHORT: { T_U_GRLC_RESOURCE_REQ resource_req; /*lint !e813*/ tm_ini_realloc(new_prim); tm_build_res_req( &resource_req, R_FIX_RE_ALLOC ); tm_store_ctrl_blk( CGRLC_BLK_OWNER_TM, ( void* )&resource_req ); } break; case C_PRIM_REALLOC_MARK: grlc_data->prim_queue[new_prim ].re_allocation = 1; break; case C_PRIM_RLC_MODE_CHANGE: /*sec 8.1.1.1.2 para 5*/ grlc_data->prim_queue[new_prim].start_new_tbf = 1; grlc_data->prim_queue[grlc_data->prim_queue[position].next].start_new_tbf = 1; break; } if(position < PRIM_QUEUE_SIZE_TOTAL) { position = grlc_data->prim_queue[position].next; } /*This new QOS is for lower priority */ if ( (position EQ 0xff) AND (new_qos EQ TRUE)) { grlc_data->prim_queue[new_prim].re_allocation = 1;/*8.1.1.1.2 para 10*/ TRACE_EVENT_P2("reallocation set for llc pdu = %d ,priority =%d",new_prim,ptr2prim_i->radio_prio); } grlc_prim_put(&grlc_data->prim_start_tbf,new_prim ,position ); /* * update amount of buffered user data */ grlc_data->prim_user_data += BYTELEN(ptr2prim_i->sdu.l_buf); /* * and check if the queue is now full */ free_entry_count--; if( (free_entry_count == 0) || (grlc_data->prim_user_data > grlc_data->tm.max_grlc_user_data ) ) { grlc_data->tm.send_grlc_ready_ind = PRIM_QUEUE_FULL; } } else { TRACE_ERROR("Data-Request, but prim_queue full"); /* * This is an error of LLC. * Therefore here is no special handling of this case */ PFREE(ptr2prim_i); } } /* tm_data_req() */ /* +------------------------------------------------------------------------------ | Function : tm_grlc_init +------------------------------------------------------------------------------ | Description : The function tm_grlc_init() initialize the TC data structure. | | Parameters : void | +------------------------------------------------------------------------------ */ GLOBAL void tm_grlc_init ( void ) { UBYTE i; TRACE_FUNCTION( "tm_grlc_init" ); /* * set some values */ grlc_data->tm.disable_class = CGRLC_DISABLE_CLASS_CR; grlc_data->tbf_type = TBF_TYPE_NULL; grlc_data->rel_type = REL_TYPE_NULL; grlc_data->tm.start_of_new_tbf = 0xff; grlc_data->tm.send_grlc_ready_ind = SEND_A_GRLC_READY_IND; grlc_data->tm.n_acc_req_procedures = 0; grlc_data->tm.n_res_req = 0; #if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH grlc_data->tm.pacch_prr_pca_sent = FALSE; #endif /* initialize the relevant data for uplink control block */ grlc_data->tm.ul_ctrl_blk.seq[0] = MAX_CTRL_BLK_NUM; for( i = 0; i < MAX_CTRL_BLK_NUM; i++ ) { grlc_data->tm.ul_ctrl_blk.blk[i].state = BLK_STATE_NONE; grlc_data->tm.ul_ctrl_blk.blk[i].owner = CGRLC_BLK_OWNER_NONE; } /* * Initialise service name (uses define SERVICE_NAME_* in GRLC.H); */ INIT_STATE(TM,TM_ACCESS_DISABLED); /* * initialize primitive queue */ tm_init_prim(); } /* tm_grlc_init() */ /* +------------------------------------------------------------------------------ | Function : tm_prim_queue_get_free_count +------------------------------------------------------------------------------ | Description : This function returns the number of free | entries in the primitive queue. | | Parameters : void | +------------------------------------------------------------------------------ */ GLOBAL UBYTE tm_prim_queue_get_free_count ( void ) { UBYTE i = grlc_data->prim_start_free; UBYTE result = 0,j; TRACE_FUNCTION( "tm_prim_queue_get_free_count" ); for(j=0;j<PRIM_QUEUE_SIZE_TOTAL;j++) { if (i NEQ 0xff) { result++; i = grlc_data->prim_queue[i].next; } else { break; } } if((grlc_data->grlc_data_req_cnt + result NEQ PRIM_QUEUE_SIZE )AND !grlc_data->gmm_procedure_is_running) { TRACE_EVENT_P4("PST=%d PSF=%d PDU=%d FREE_CNT=%d: tm_prim_queue_get_free_count CHECK it" ,grlc_data->prim_start_tbf ,grlc_data->prim_start_free ,grlc_data->grlc_data_req_cnt ,result); } return(result); } /* tm_prim_queue_get_free_count() */ /* +------------------------------------------------------------------------------ | Function : tm_compare_prim +------------------------------------------------------------------------------ | Description : The function tm_compare_prim() check wheather the pdu have to | set at tis position or not. They function also estimate | how to set this primitive (with new TBF, immediately | re-allocation or re-allocation at next PDU-boundary) | | Parameters : new_prim_i - index of the new-primitive entry in prim_queue[] | position_i - index of the preceding entry of the possible | position of the new primitive +------------------------------------------------------------------------------ */ GLOBAL T_COMPARE_PRIM tm_compare_prim ( UBYTE new_prim_i, UBYTE position_i, BOOL *new_qos) { BOOL rlc_mode; UBYTE new_prio = PRIO_HIGHER; UBYTE new_throughput = THROUGHPUT_HIGHER; #ifdef REL99 UBYTE new_pfi = SAME_PFI; #endif UBYTE pre_prim_index, post_prim_index, new_prim_index; T_GRLC_UNITDATA_REQ * pre_prim_ptr, * new_prim_ptr, * post_prim_ptr; T_COMPARE_PRIM result; TRACE_FUNCTION( "tm_compare_prim" ); /* * set all variables */ pre_prim_index = position_i; post_prim_index = grlc_data->prim_queue[position_i].next; new_prim_index = new_prim_i; /* * GRLC_UNITDATA_REQ and T_GRLC_UNITDATA_REQ have the same layout!! */ pre_prim_ptr = (T_GRLC_UNITDATA_REQ *) grlc_data->prim_queue[pre_prim_index].prim_ptr; post_prim_ptr = (T_GRLC_UNITDATA_REQ *) grlc_data->prim_queue[post_prim_index].prim_ptr; new_prim_ptr = (T_GRLC_UNITDATA_REQ *) grlc_data->prim_queue[new_prim_index].prim_ptr; if(post_prim_index NEQ 0xff) { #ifdef REL99 if (grlc_data->pfi_support AND (post_prim_ptr->pkt_flow_id[0] NEQ new_prim_ptr->pkt_flow_id[0]) ) { new_pfi = DIFF_PFI; } #endif /* * last position in queue; the values at position 0xff in the prim_queue are invalid * therefore they are here not set */ if(post_prim_ptr->radio_prio < new_prim_ptr->radio_prio ) { new_prio = PRIO_LOWER; } else if(post_prim_ptr->radio_prio EQ new_prim_ptr->radio_prio ) { new_prio = PRIO_SAME; } if(post_prim_ptr->grlc_qos.peak > new_prim_ptr->grlc_qos.peak ) { new_throughput = THROUGHPUT_LOWER; } else if(post_prim_ptr->grlc_qos.peak EQ new_prim_ptr->grlc_qos.peak ) { new_throughput = THROUGHPUT_SAME; } } /* TRACE_EVENT_P2("np=%d np=%d",new_prio,new_throughput);*/ /* * evalute - wheather the primitive have to put at this position or not * compare with "following primitive" */ if(post_prim_index EQ 0xff) { /* * because this is the last entry in prim_queue this * primitive have to put at this position */ result = C_PRIM_PUT; } else { if (grlc_data->prim_queue[post_prim_index].rlc_status) { /* * it is forbidden to change position of * primitives already in transmission */ result = C_PRIM_CONTINUE; } else if (grlc_data->prim_queue[post_prim_index].cv_status) {/* * it is forbidden to change position of primitives * included in countdown procedure */ result = C_PRIM_CONTINUE; } #ifdef REL99 else if (new_pfi EQ DIFF_PFI) { result = C_PRIM_PUT; } #endif else if ( new_prio EQ PRIO_HIGHER) { result = C_PRIM_PUT; } else if ( (new_prio EQ PRIO_SAME) AND (new_throughput EQ THROUGHPUT_HIGHER) ) { result = C_PRIM_PUT; } else { result = C_PRIM_CONTINUE; } } /* * evalute - type of "put" * compare with "preceding primitive" */ /*TRACE_EVENT_P3("np=%d np=%d result=%d",new_prio,new_throughput,result);*/ if(result EQ C_PRIM_PUT) { /* * set variables */ if(pre_prim_ptr->radio_prio < new_prim_ptr->radio_prio ) { new_prio = PRIO_LOWER; *new_qos = TRUE; } else if(pre_prim_ptr->radio_prio EQ new_prim_ptr->radio_prio ) { new_prio = PRIO_SAME; } else { new_prio = PRIO_HIGHER; } if(pre_prim_ptr->grlc_qos.peak > new_prim_ptr->grlc_qos.peak ) { new_throughput = THROUGHPUT_LOWER; } else if(pre_prim_ptr->grlc_qos.peak EQ new_prim_ptr->grlc_qos.peak ) { new_throughput = THROUGHPUT_SAME; } else { new_throughput = THROUGHPUT_HIGHER; } #ifdef REL99 if (grlc_data->pfi_support AND (pre_prim_ptr->pkt_flow_id[0] NEQ new_prim_ptr->pkt_flow_id[0]) ) { new_pfi = DIFF_PFI; } else { new_pfi = SAME_PFI; } #endif if ( grlc_data->prim_queue[pre_prim_index].prim_type EQ grlc_data->prim_queue[new_prim_index].prim_type) { rlc_mode = SAME_RLC_MODE; } else { rlc_mode = DIFFERENT_RLC_MODE; } /* * evalution */ /* TRACE_EVENT_P4("result=%d,rlc_mode=%d,prio=%d,peak=%d",result,rlc_mode,new_prio,new_throughput);*/ if(rlc_mode EQ DIFFERENT_RLC_MODE) { if (new_prio EQ PRIO_HIGHER AND post_prim_index NEQ 0xFF) { result = C_PRIM_RLC_MODE_CHANGE; } else { result = C_PRIM_NEW_TBF; } } else if (grlc_data->prim_queue[pre_prim_index].cv_status) { /* * if count-down-procedure has started for this pdu, * re-allocation is forbitten */ result = C_PRIM_NEW_TBF; } #ifdef REL99 else if ( grlc_data->pfi_support AND grlc_data->prim_queue[pre_prim_index].rlc_status AND new_pfi EQ DIFF_PFI ) { result = C_PRIM_REALLOC_START; TRACE_EVENT_P3("C_PRIM_REALLOC_START: npfi = %d, rlc_st = %d pre_prim_i=%d" ,new_prim_ptr->pkt_flow_id[0] ,grlc_data->prim_queue[pre_prim_index].rlc_status ,pre_prim_index); } #endif else if( (grlc_data->prim_queue[pre_prim_index].rlc_status) AND ((new_prio EQ PRIO_HIGHER ) OR ((new_throughput EQ THROUGHPUT_HIGHER ) AND (new_prio EQ PRIO_SAME )) ) ) { /* * C_PRIM_REALLOC_START only if the "pre-pdu" * is in transmission */ TRACE_EVENT_P4("C_PRIM_REALLOC_START: ntp=%d np=%d rlc_st=%d pre_prim_i=%d" ,new_throughput ,new_prio ,grlc_data->prim_queue[pre_prim_index].rlc_status ,pre_prim_index); result = C_PRIM_REALLOC_START; } else if( (new_prio EQ PRIO_LOWER ) OR ((new_throughput EQ THROUGHPUT_LOWER ) AND (new_prio EQ PRIO_SAME )) ) { result = C_PRIM_REALLOC_MARK; TRACE_EVENT_P4("C_PRIM_REALLOC_MARK: ntp=%d np=%d rlc_st=%d pre_prim_i=%d" ,new_throughput ,new_prio ,grlc_data->prim_queue[pre_prim_index].rlc_status ,pre_prim_index); } else if (grlc_data->uplink_tbf.ac_class >= CGRLC_PCCCH_AC_NOT_ALLOWED AND /* if pbcch is present */ grlc_data->uplink_tbf.access_type EQ CGRLC_AT_SHORT_ACCESS AND /* last acess type */ grlc_data->tbf_type NEQ TBF_TYPE_DL) /* not required if acess is over existing downlink tbf*/ { /* if prevoious access type is short access, ms should send packet resource request*/ result = C_PRIM_REALLOC_SHORT; grlc_data->uplink_tbf.access_type = CGRLC_AT_ONE_PHASE; TRACE_EVENT_P4("C_PRIM_REALLOC_SHORT: ntp=%d np=%d rlc_st=%d pre_prim_i=%d" ,new_throughput ,new_prio ,grlc_data->prim_queue[pre_prim_index].rlc_status ,pre_prim_index); } } /* TRACE_EVENT_P4("np=%d np=%d rlc_mode=%d result=%d",new_prio,new_throughput,rlc_mode,result);*/ return(result); } /* tm_compare_prim() */ /* +------------------------------------------------------------------------------ | Function : tm_send_grlc_ready_ind +------------------------------------------------------------------------------ | Description : This function sends the GRLC_READY_IND | | Parameters : | +------------------------------------------------------------------------------ */ LOCAL void tm_send_grlc_ready_ind ( void ) { if(grlc_data->gmm_procedure_is_running) { PALLOC(grlc_suspend_ready_ind, GRLC_SUSPEND_READY_IND); PSEND(hCommLLC, grlc_suspend_ready_ind); } else { PALLOC(grlc_ready_ind, GRLC_READY_IND); PSEND(hCommLLC, grlc_ready_ind); } } /* tm_send_grlc_ready_ind() */ /* +------------------------------------------------------------------------------ | Function : tm_handle_grlc_ready_ind +------------------------------------------------------------------------------ | Description : This function handles the sending of the GRLC_READY_IND. Call | to this function in any of the following cases: | | - a GRLC_DATA_REQ was received | - a GRLC_UNITDATA_REQ was received | - a queued prim is deleted | - the TM state is changed from TM_ACCESS_DISABLED or | TM_ACCESS_PREPARED to another | | Parameters : none +------------------------------------------------------------------------------ */ GLOBAL void tm_handle_grlc_ready_ind ( void ) { UBYTE state = GET_STATE( TM ); TRACE_FUNCTION( "tm_handle_grlc_ready_ind" ); if( state EQ TM_ACCESS_DISABLED OR state EQ TM_ACCESS_PREPARED ) { TRACE_EVENT("TM_ACCESS_DISABLED/TM_ACCESS_PREPARED no ready ind"); return; } switch (grlc_data->tm.send_grlc_ready_ind) { case SEND_A_GRLC_READY_IND: tm_send_grlc_ready_ind(); grlc_data->tm.send_grlc_ready_ind = WAIT_FOR_LLC_DATA_REQ; break; case PRIM_QUEUE_FULL: /* * Check if we have now enough space */ TRACE_EVENT_P3("PRIM_QUEUE_FULL prim_start_tbf=%d prim_start_free=%ld user_data=%ld", grlc_data->prim_start_tbf, grlc_data->prim_start_free, grlc_data->prim_user_data); if ( (tm_prim_queue_get_free_count() > 0) AND (grlc_data->prim_user_data <= grlc_data->tm.max_grlc_user_data) ) { TRACE_EVENT("NOT PRIM_QUEUE_FULL !!!"); tm_send_grlc_ready_ind(); grlc_data->tm.send_grlc_ready_ind = WAIT_FOR_LLC_DATA_REQ; } break; case WAIT_FOR_LLC_DATA_REQ: /* NO BREAK */ default: /* Nothing to do */ break; } } /* tm_handle_grlc_ready_ind() */ /* +------------------------------------------------------------------------------ | Function : tm_handle_error_ra +------------------------------------------------------------------------------ | Description : The function tm_handle_error_ra() handles actions related | to errors that leads to randam access procedure | | Parameters : void | +------------------------------------------------------------------------------ */ GLOBAL void tm_handle_error_ra ( void ) { TRACE_FUNCTION( "tm_handle_error_ra" ); /* * - called in case of contention resulution failed in RU * - t3168 expires contention resulution failed in 2P-Access * - If the mobile station has been assigned more PDCHs than it supports according * to its MS multislot class, the mobile station shall reinitiate the packet access * procedure unless it has already been repeated 4 times. In that * case, TBF failure has occurred. */ /* * Kill TBF if running */ TRACE_EVENT_P3("ERROR_RA: nacc: %d prim_start_tbf:%d t3164_cnt=%d" ,grlc_data->tm.n_acc_req_procedures ,grlc_data->prim_start_tbf ,grlc_data->t3164_to_cnt); if(grlc_data->tbf_type NEQ CGRLC_TBF_MODE_NULL) { SET_STATE(TM,TM_WAIT_4_PIM); } else { SET_STATE(TM,TM_PIM); sig_tm_ru_reset_poll_array(); } tm_abort_tbf(grlc_data->tbf_type); grlc_data->tm.n_res_req = 0; /* reset counter of resource requests during access */ if (grlc_data->N3102 EQ 0) { } else if((grlc_data->tm.n_acc_req_procedures < 5) AND (grlc_data->t3164_to_cnt < 4)) { } else { grlc_data->t3164_to_cnt = 0; grlc_data->tm.n_acc_req_procedures = 0; tm_cgrlc_status_ind(CGRLC_TBF_ESTABLISHMENT_FAILURE); grlc_delete_prim(); tm_handle_grlc_ready_ind(); } } /* tm_handle_error_ra() */ /* +------------------------------------------------------------------------------ | Function : tm_activate_tbf +------------------------------------------------------------------------------ | Description : The function tm_activate_tbf() set the assigned TBF | into the data structures | | Parameters : tbf_type_i - type of TBF to deactivate | +------------------------------------------------------------------------------ */ GLOBAL void tm_activate_tbf ( T_TBF_TYPE tbf_type_i ) { TRACE_FUNCTION( "tm_activate_tbf" ); /* * Reset of n_acc_req_procedures because of the fact that number of * access procedures during pacet access procedures must not considered in * a error with random access occured during running TBF. */ /* grlc_data->tm.n_acc_req_procedures = 0;*/ switch( tbf_type_i ) { case TBF_TYPE_UL: switch( grlc_data->tbf_type ) { case TBF_TYPE_DL: grlc_data->tbf_type = TBF_TYPE_CONC; break; case TBF_TYPE_NULL: #if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH case TBF_TYPE_TP_ACCESS: #endif grlc_data->tbf_type = TBF_TYPE_UL; break; default: break; } break; case TBF_TYPE_DL: switch( grlc_data->tbf_type ) { case TBF_TYPE_UL: grlc_data->tbf_type = TBF_TYPE_CONC; break; case TBF_TYPE_NULL: grlc_data->tbf_type = TBF_TYPE_DL; break; default: break; } break; case TBF_TYPE_CONC: switch( grlc_data->tbf_type ) { case TBF_TYPE_UL: case TBF_TYPE_DL: case TBF_TYPE_CONC: grlc_data->tbf_type = TBF_TYPE_CONC; break; default: { TRACE_ERROR("FATAL ERROR: tm_activate_tbf called with wrong tbf_type"); } break; } break; #if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH case TBF_TYPE_TP_ACCESS: switch( grlc_data->tbf_type ) { case TBF_TYPE_NULL: grlc_data->tbf_type = TBF_TYPE_TP_ACCESS; break; default: { TRACE_ERROR("FATAL ERROR: tm_activate_tbf called with wrong tbf_type"); } break; } break; #endif default: { TRACE_ERROR("FATAL ERROR: tm_activate_tbf called with wrong tbf_type"); } break; } /* switch (tbf_type_i) */ } /* tm_activate_tbf() */ /* +------------------------------------------------------------------------------ | Function : tm_deactivate_tbf +------------------------------------------------------------------------------ | Description : The function tm_deactivate_tbf() removes a TBF logical from TM | end estimates how to continue. | | Parameters : void | +------------------------------------------------------------------------------ */ GLOBAL void tm_deactivate_tbf ( T_TBF_TYPE tbf_i ) { TRACE_FUNCTION( "tm_deactivate_tbf" ); switch( grlc_data->tbf_type ) { case TBF_TYPE_CONC: switch( tbf_i ) { case TBF_TYPE_UL: grlc_data->tbf_type = TBF_TYPE_DL; break; case TBF_TYPE_DL: grlc_data->tbf_type = TBF_TYPE_UL; break; case TBF_TYPE_CONC: grlc_data->tbf_type = TBF_TYPE_NULL; break; } break; case TBF_TYPE_DL: case TBF_TYPE_UL: if(grlc_data->tbf_type EQ tbf_i) { grlc_data->tbf_type = TBF_TYPE_NULL; } else { TRACE_ERROR("requested release tbf type does not exist"); TRACE_EVENT_P2("SNH: requested release tbf type does not exist tbf_i =%d tbf_ty=%d",tbf_i,grlc_data->tbf_type); } break; #if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH case TBF_TYPE_TP_ACCESS: grlc_data->tbf_type = TBF_TYPE_NULL; break; #endif default: break; } } /* tm_deactivate_tbf() */ /* +------------------------------------------------------------------------------ | Function : tm_delete_prim_queue +------------------------------------------------------------------------------ | Description : delete all pdus in the queue | | Parameters : void | +------------------------------------------------------------------------------ */ GLOBAL void tm_delete_prim_queue( void) { TRACE_FUNCTION( "tm_delete_prim_queue" ); do { grlc_delete_prim(); } while( (grlc_data->prim_start_tbf < PRIM_QUEUE_SIZE_TOTAL) AND !grlc_data->prim_queue[grlc_data->prim_start_tbf].start_new_tbf ); tm_handle_grlc_ready_ind(); } /* tm_delete_prim_queue */ /* +------------------------------------------------------------------------------ | Function : tm_queue_test_mode_prim() +------------------------------------------------------------------------------ | Description : The function puts a number of primitives | in the primitive queue | | Parameters : pdu_num_i - number of primitives to queue | +------------------------------------------------------------------------------ */ GLOBAL void tm_queue_test_mode_prim( UBYTE pdu_num_i ) { UBYTE i = 0; TRACE_FUNCTION( "tm_queue_test_mode_prim" ); for (i=0; i<pdu_num_i; i++) { PALLOC_SDU(grlc_unitdata_req,GRLC_UNITDATA_REQ,(195*8)); grlc_unitdata_req->sapi = GRLC_SAPI_TEST_MODE; grlc_unitdata_req->tlli = grlc_data->uplink_tbf.tlli; memset(&grlc_unitdata_req->grlc_qos,0,sizeof(T_GRLC_grlc_qos)); grlc_unitdata_req->radio_prio=2; grlc_unitdata_req->sdu.l_buf= 195*8; grlc_unitdata_req->sdu.o_buf=0; memset(grlc_unitdata_req->sdu.buf,0x0f,195); /*lint !e419*/ PSEND(hCommGRLC,grlc_unitdata_req); } } /* tm_queue_test_mode_prim */ /* +------------------------------------------------------------------------------ | Function : tm_close_gaps_in_ctrl_blk_seq +------------------------------------------------------------------------------ | Description : The function tm_close_gaps_in_ctrl_blk_seq reorders the queue | holding the order which is used to identify the next control | block to sent. | | Parameters : index - at this index the reordering starts | +------------------------------------------------------------------------------ */ LOCAL void tm_close_gaps_in_ctrl_blk_seq ( UBYTE index ) { TRACE_FUNCTION( "tm_close_gaps_in_ctrl_blk_seq" ); while( index < MAX_CTRL_BLK_NUM AND grlc_data->tm.ul_ctrl_blk.seq[index] NEQ MAX_CTRL_BLK_NUM ) { grlc_data->tm.ul_ctrl_blk.seq[index-1] = grlc_data->tm.ul_ctrl_blk.seq[index]; index++; } grlc_data->tm.ul_ctrl_blk.seq[index-1] = MAX_CTRL_BLK_NUM; } /* tm_close_gaps_in_ctrl_blk_seq() */ /* +------------------------------------------------------------------------------ | Function : tm_store_ctrl_blk +------------------------------------------------------------------------------ | Description : | | Parameters : | +------------------------------------------------------------------------------ */ GLOBAL BOOL tm_store_ctrl_blk ( T_BLK_OWNER blk_owner, void *blk_struct ) { UBYTE i; /* used for counting */ BOOL result = FALSE; /* indicates whether control block is */ /* stored successfully or not */ T_BLK_INDEX blk_index; /* index to the control block buffer */ TRACE_FUNCTION( "tm_store_ctrl_msg" ); /* * we have to find a free buffer for the control block which is * indicated by the index to the control block buffer */ blk_index = MAX_CTRL_BLK_NUM; switch( blk_owner ) { case( CGRLC_BLK_OWNER_CTRL ): if( grlc_data->tm.ul_ctrl_blk.blk[BLK_INDEX_CTRL].state EQ BLK_STATE_NONE ) { blk_index = BLK_INDEX_CTRL; } break; case( CGRLC_BLK_OWNER_CS ): if( grlc_data->tm.ul_ctrl_blk.blk[BLK_INDEX_CS].state EQ BLK_STATE_NONE ) { blk_index = BLK_INDEX_CS; } break; case( CGRLC_BLK_OWNER_TM ): if( grlc_data->tm.ul_ctrl_blk.blk[BLK_INDEX_TM].state EQ BLK_STATE_NONE ) { blk_index = BLK_INDEX_TM; } break; case( CGRLC_BLK_OWNER_MEAS ): blk_index = BLK_INDEX_MEAS; while( blk_index < MAX_CTRL_BLK_NUM AND grlc_data->tm.ul_ctrl_blk.blk[blk_index].state NEQ BLK_STATE_NONE ) { blk_index++; } break; default: /* do nothing */ break; } /* * check whether the control block buffer is free, */ if( blk_index < MAX_CTRL_BLK_NUM ) { /* * check the queue holding the order which is used to identify the next * control block to send */ i = 0; while( i < MAX_CTRL_BLK_NUM AND grlc_data->tm.ul_ctrl_blk.seq[i] NEQ MAX_CTRL_BLK_NUM ) { i++; } /* * check whether there is a free entry in the order queue, * in case the check fails, there is something wrong with the concept */ if( i < MAX_CTRL_BLK_NUM ) { /* * store the control block data and state in the queues */ if(blk_owner EQ CGRLC_BLK_OWNER_TM) { grlc_encode_ul_ctrl_block ( ( UBYTE* )&grlc_data->tm.ul_ctrl_blk.blk[blk_index].data[0], ( UBYTE* )blk_struct ); } else { /* * encoded control message received by higher layers */ memcpy(( UBYTE* )&grlc_data->tm.ul_ctrl_blk.blk[blk_index].data[0],( UBYTE* )blk_struct,BYTE_UL_CTRL_BLOCK); } grlc_data->tm.ul_ctrl_blk.blk[blk_index].state = BLK_STATE_ALLOCATED; grlc_data->tm.ul_ctrl_blk.blk[blk_index].owner = blk_owner; grlc_data->tm.ul_ctrl_blk.seq[i] = blk_index; if( i < MAX_CTRL_BLK_NUM - 1 ) { grlc_data->tm.ul_ctrl_blk.seq[i+1] = MAX_CTRL_BLK_NUM; } result = TRUE; } else { TRACE_ERROR( "tm_store_ctrl_blk: no free entry in queue found" ); } } if( result EQ FALSE ) { if( blk_owner EQ CGRLC_BLK_OWNER_MEAS ) { TRACE_EVENT( "tm_store_ctrl_blk: no table entry allocated" ); } else { TRACE_ERROR( "tm_store_ctrl_blk: no table entry allocated" ); } } return( result ); } /* tm_store_ctrl_blk() */ /* +------------------------------------------------------------------------------ | Function : tm_cancel_ctrl_blk +------------------------------------------------------------------------------ | Description : | | Parameters : | +------------------------------------------------------------------------------ */ GLOBAL BOOL tm_cancel_ctrl_blk ( T_BLK_OWNER blk_owner ) { BOOL result = FALSE; UBYTE i = 0; UBYTE blk_index = grlc_data->tm.ul_ctrl_blk.seq[i]; TRACE_FUNCTION( "tm_cancel_ctrl_blk" ); while( blk_index NEQ MAX_CTRL_BLK_NUM AND result EQ FALSE ) { if( grlc_data->tm.ul_ctrl_blk.blk[blk_index].owner EQ blk_owner AND grlc_data->tm.ul_ctrl_blk.blk[blk_index].state EQ BLK_STATE_ALLOCATED ) { /* * mark the entry in the queue as free */ grlc_data->tm.ul_ctrl_blk.blk[blk_index].state = BLK_STATE_NONE; grlc_data->tm.ul_ctrl_blk.blk[blk_index].owner = CGRLC_BLK_OWNER_NONE; tm_close_gaps_in_ctrl_blk_seq( (UBYTE)( i + 1 ) ); result = TRUE; } i++; if( i < MAX_CTRL_BLK_NUM ) { blk_index = grlc_data->tm.ul_ctrl_blk.seq[i]; } else { blk_index = MAX_CTRL_BLK_NUM; } } if( result EQ FALSE ) { TRACE_EVENT( "tm_cancel_ctrl_blk: no block found" ); } return( result ); } /* tm_cancel_ctrl_blk() */ /* +------------------------------------------------------------------------------ | Function : tm_set_start_ctrl_blk +------------------------------------------------------------------------------ | Description : | | Parameters : | +------------------------------------------------------------------------------ */ GLOBAL UBYTE* tm_set_start_ctrl_blk ( UBYTE *index ) { UBYTE i = 0; T_BLK_INDEX blk_index = MAX_CTRL_BLK_NUM; TRACE_FUNCTION( "tm_set_start_ctrl_blk" ); while( i < MAX_CTRL_BLK_NUM AND grlc_data->tm.ul_ctrl_blk.seq[i] NEQ MAX_CTRL_BLK_NUM AND blk_index EQ MAX_CTRL_BLK_NUM ) { blk_index = grlc_data->tm.ul_ctrl_blk.seq[i]; if( grlc_data->tm.ul_ctrl_blk.blk[blk_index].state EQ BLK_STATE_ALLOCATED ) { grlc_data->tm.ul_ctrl_blk.blk[blk_index].state = BLK_STATE_SENT_REQ; /* * the control block was encoded without having correct information * about the value of the R bit. So we have to set the correct value now. */ grlc_data->tm.ul_ctrl_blk.blk[blk_index].data[0] = 0x40 | grlc_data->r_bit; } else { blk_index = MAX_CTRL_BLK_NUM; } i++; } *index = blk_index; return( blk_index EQ MAX_CTRL_BLK_NUM ? NULL : grlc_data->tm.ul_ctrl_blk.blk[blk_index].data ); } /* tm_set_start_ctrl_blk() */ /* +------------------------------------------------------------------------------ | Function : tm_set_stop_ctrl_blk +------------------------------------------------------------------------------ | Description : | | Parameters : | +------------------------------------------------------------------------------ */ GLOBAL T_BLK_INDEX tm_set_stop_ctrl_blk ( BOOL is_tx_success, T_BLK_OWNER srch_owner, T_BLK_INDEX start_index ) { T_BLK_INDEX blk_index = grlc_data->tm.ul_ctrl_blk.seq[start_index]; T_BLK_INDEX nxt_index; TRACE_FUNCTION( "tm_set_stop_ctrl_blk" ); if( blk_index < MAX_CTRL_BLK_NUM ) { T_BLK_OWNER blk_owner = grlc_data->tm.ul_ctrl_blk.blk[blk_index].owner; if( srch_owner EQ CGRLC_BLK_OWNER_NONE OR srch_owner EQ blk_owner ) { /* * mark the entry in the queue as free */ grlc_data->tm.ul_ctrl_blk.blk[blk_index].state = BLK_STATE_NONE; grlc_data->tm.ul_ctrl_blk.blk[blk_index].owner = CGRLC_BLK_OWNER_NONE; tm_close_gaps_in_ctrl_blk_seq( 1 ); nxt_index = start_index; } else { nxt_index = start_index + 1; } } else { nxt_index = MAX_CTRL_BLK_NUM; } return( nxt_index ); } /* tm_set_stop_ctrl_blk() */ /* +------------------------------------------------------------------------------ | Function : tm_set_stop_tm_ctrl_blk +------------------------------------------------------------------------------ | Description : | | Parameters : | +------------------------------------------------------------------------------ */ GLOBAL void tm_set_stop_tm_ctrl_blk ( void ) { T_BLK_INDEX start_index = 0; TRACE_FUNCTION( "tm_set_stop_tm_ctrl_blk" ); while ( ( start_index = tm_set_stop_ctrl_blk( FALSE, CGRLC_BLK_OWNER_TM, start_index ) ) NEQ MAX_CTRL_BLK_NUM ){}; } /* tm_set_stop_tm_ctrl_blk() */ /* +------------------------------------------------------------------------------ | Function : tm_set_stop_all_ctrl_blk +------------------------------------------------------------------------------ | Description : | | Parameters : | +------------------------------------------------------------------------------ */ GLOBAL void tm_set_stop_all_ctrl_blk ( void ) { T_BLK_INDEX start_index = 0; TRACE_FUNCTION( "tm_set_stop_all_ctrl_blk" ); while ( ( start_index = tm_set_stop_ctrl_blk( FALSE, CGRLC_BLK_OWNER_NONE, start_index ) ) NEQ MAX_CTRL_BLK_NUM ){}; } /* tm_set_stop_all_ctrl_blk() */ /* +------------------------------------------------------------------------------ | Function : tm_get_gmm_prim_queue +------------------------------------------------------------------------------ | Description : The function tm_get_gmm_prim_queue () .... | | Parameters : void | +------------------------------------------------------------------------------ */ GLOBAL void tm_get_gmm_prim_queue ( void ) { UBYTE i; TRACE_FUNCTION( "tm_get_gmm_prim_queue " ); /* init gmm prim queue*/ TRACE_EVENT_P4("GET GMM QUEUE: BEFORE ps=%d, pf=%d,sps=%d,spf=%d", grlc_data->prim_start_tbf, grlc_data->prim_start_free, grlc_data->save_prim_start_tbf, grlc_data->save_prim_start_free); /* * Delte all GMM primitives in current llc queue, which are on the top. */ while((grlc_data->prim_start_tbf >= PRIM_QUEUE_SIZE) AND (grlc_data->prim_start_tbf < PRIM_QUEUE_SIZE_TOTAL)) { grlc_delete_prim(); } grlc_data->gmm_procedure_is_running = TRUE; if(grlc_data->prim_start_free EQ 0xFF) { TRACE_ERROR("PRIM_QUEUE FULL: RAU MAY BE SENT, NEXT DATA PRIM WILL BE DELETED "); } for (i=PRIM_QUEUE_SIZE; i<(PRIM_QUEUE_SIZE_TOTAL);i++) { grlc_data->prim_queue[i].next = i+1; grlc_data->prim_queue[i].prim_ptr = NULL; grlc_data->prim_queue[i].prim_type = CGRLC_LLC_PRIM_TYPE_NULL; grlc_data->prim_queue[i].cv_status = FALSE; grlc_data->prim_queue[i].rlc_status = FALSE; grlc_data->prim_queue[i].re_allocation = FALSE; grlc_data->prim_queue[i].start_new_tbf = FALSE; grlc_data->prim_queue[i].last_bsn = 0xff; } grlc_data->prim_queue[PRIM_QUEUE_SIZE_TOTAL-1].next = 0xff; grlc_data->save_prim_start_tbf = grlc_data->prim_start_tbf; grlc_data->save_prim_start_free = grlc_data->prim_start_free; grlc_data->prim_start_tbf = 0xFF; grlc_data->prim_start_free = PRIM_QUEUE_SIZE; grlc_data->prim_user_data = 0; grlc_data->tm.send_grlc_ready_ind = SEND_A_GRLC_READY_IND; TRACE_EVENT_P4("GET GMM QUEUE: AFTER ps=%d, pf=%d,sps=%d,spf=%d", grlc_data->prim_start_tbf, grlc_data->prim_start_free, grlc_data->save_prim_start_tbf, grlc_data->save_prim_start_free); } /* tm_get_gmm_prim_queue */ /* +------------------------------------------------------------------------------ | Function : tm_get_llc_prim_queue +------------------------------------------------------------------------------ | Description : The function tm_get_llc_prim_queue () .... | | Parameters : void | +------------------------------------------------------------------------------ */ GLOBAL void tm_get_llc_prim_queue ( void ) { UBYTE i; TRACE_FUNCTION( "tm_get_llc_prim_queue " ); TRACE_EVENT_P4("GET LLC QUEUE: BEFORE ps=%d, pf=%d,sps=%d,spf=%d", grlc_data->prim_start_tbf, grlc_data->prim_start_free, grlc_data->save_prim_start_tbf, grlc_data->save_prim_start_free); if(grlc_data->prim_start_tbf < PRIM_QUEUE_SIZE_TOTAL) { /*finish gmm data and than resume with llc data*/ i = grlc_data->prim_start_tbf; while(grlc_data->prim_queue[i].next NEQ 0xFF) { i = grlc_data->prim_queue[i].next; } grlc_data->prim_queue[i].next = grlc_data->save_prim_start_tbf; grlc_data->prim_queue[i].start_new_tbf = TRUE; } else { grlc_data->prim_start_tbf = grlc_data->save_prim_start_tbf; } grlc_data->prim_start_free = grlc_data->save_prim_start_free; grlc_data->gmm_procedure_is_running = FALSE; grlc_data->prim_user_data = 0; i = grlc_data->prim_start_tbf; while(i NEQ 0xFF) { grlc_data->prim_user_data += BYTELEN(grlc_data->prim_queue[i].prim_ptr->sdu.l_buf); i = grlc_data->prim_queue[i].next; } TRACE_EVENT_P4("GET LLC QUEUE: AFTER ps=%d, pf=%d,sps=%d,spf=%d", grlc_data->prim_start_tbf, grlc_data->prim_start_free, grlc_data->save_prim_start_tbf, grlc_data->save_prim_start_free); } /* tm_get_llc_prim_queue */ /* +------------------------------------------------------------------------------ | Function : tm_ul_tbf_ind +------------------------------------------------------------------------------ | Description : The function tm_ul_tbf_ind () .... | | Parameters : void | +------------------------------------------------------------------------------ */ GLOBAL void tm_ul_tbf_ind ( void ) { TRACE_FUNCTION( "tm_ul_tbf_ind " ); switch(grlc_data->tbf_type) { case TBF_TYPE_NULL: if( grlc_data->prim_start_tbf < PRIM_QUEUE_SIZE_TOTAL ) { PALLOC(cgrlc_ul_tbf_ind,CGRLC_UL_TBF_IND); /*T_CGRLC_UL_TBF_IND*/ tm_start_access(); cgrlc_ul_tbf_ind->access_type = grlc_data->uplink_tbf.access_type; cgrlc_ul_tbf_ind->ra_prio = grlc_data->uplink_tbf.prio; cgrlc_ul_tbf_ind->nr_blocks = grlc_data->uplink_tbf.nr_blocks; cgrlc_ul_tbf_ind->llc_prim_type = grlc_data->prim_queue[grlc_data->prim_start_tbf].prim_type; cgrlc_ul_tbf_ind->rlc_oct_cnt = grlc_data->prim_queue[grlc_data->prim_start_tbf].prim_ptr->sdu.l_buf/8 +1; cgrlc_ul_tbf_ind->peak = grlc_data->prim_queue[grlc_data->prim_start_tbf].prim_ptr->grlc_qos.peak; #if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH cgrlc_ul_tbf_ind->tbf_est_pacch = FALSE; #endif SET_STATE( TM, TM_PAM ); PSEND(hCommGRR,cgrlc_ul_tbf_ind); } else { /* * inform higher layers that no tbf is requested */ PALLOC(cgrlc_ul_tbf_ind,CGRLC_UL_TBF_IND); /*T_CGRLC_UL_TBF_IND*/ cgrlc_ul_tbf_ind->access_type = CGRLC_AT_NULL; cgrlc_ul_tbf_ind->ra_prio = 0xEE; cgrlc_ul_tbf_ind->nr_blocks = 0xEE; cgrlc_ul_tbf_ind->llc_prim_type = 0xEE; cgrlc_ul_tbf_ind->peak = 0xEE; #if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH cgrlc_ul_tbf_ind->tbf_est_pacch = FALSE; #endif PSEND(hCommGRR,cgrlc_ul_tbf_ind); /* * delete control message queue */ tm_set_stop_all_ctrl_blk(); } tm_handle_grlc_ready_ind( ); break; case TBF_TYPE_DL: if( (grlc_data->prim_start_tbf < PRIM_QUEUE_SIZE_TOTAL) AND (!grlc_data->tm.n_res_req)) { tm_start_access(); tm_build_chan_req_des(&grlc_data->chan_req_des, &grlc_data->prim_queue[grlc_data->prim_start_tbf]); sig_tm_rd_ul_req(); grlc_data->tm.n_res_req++; } break; case TBF_TYPE_CONC: case TBF_TYPE_UL: break; default: TRACE_ERROR("unknown tbf type during uplink access"); break; } } /* tm_ul_tbf_ind */ /* +------------------------------------------------------------------------------ | Function : tm_tfi_handling +------------------------------------------------------------------------------ | Description : The function tm_tfi_handling () handles modified tfi´s in | case of starting time | | Parameters : start_fn_present: indicates if a starting time is present | tbf_type : type of the current tbf | ul_tfi : new assignend uplink tfi | dl_tfi : new assignend downlink tfi | +------------------------------------------------------------------------------ */ GLOBAL void tm_tfi_handling (ULONG tbf_start,UBYTE tbf_type, UBYTE ul_tfi, UBYTE dl_tfi) { TRACE_FUNCTION( "tm_tfi_handling " ); /*TRACE_EVENT_P6("TFI CHANGE: =tbf_type = %d\n fn= %ld \n new_Utfi=%d old_Utfi=%d \n new_Dtfi=%d old_Dtfi=%d" ,tbf_type ,tbf_start ,ul_tfi ,grlc_data->ul_tfi ,dl_tfi ,grlc_data->dl_tfi); */ switch( tbf_type ) { case CGRLC_TBF_MODE_UL: if((tbf_start NEQ CGRLC_STARTING_TIME_NOT_PRESENT) AND (ul_tfi NEQ grlc_data->ul_tfi)) /*lint !e650*/ { if(grlc_data->tfi_change EQ TFI_CHANGE_NULL) grlc_data->tfi_change = TFI_CHANGE_UL; else if(grlc_data->tfi_change EQ TFI_CHANGE_DL) grlc_data->tfi_change = TFI_CHANGE_ALL; grlc_data->start_fn_ul_tfi = ul_tfi; grlc_data->ul_tbf_start_time = tbf_start; TRACE_EVENT_P3("GRLC UL TFI CHANGE AFTER ST. TIME = %ld new_tfi=%d old_tfi=%d" ,tbf_start ,ul_tfi ,grlc_data->ul_tfi); } else { if(grlc_data->tfi_change EQ TFI_CHANGE_UL) grlc_data->tfi_change = TFI_CHANGE_NULL; else if(grlc_data->tfi_change EQ TFI_CHANGE_ALL) grlc_data->tfi_change = TFI_CHANGE_DL; grlc_data->ul_tfi = ul_tfi; grlc_data->start_fn_ul_tfi = 0xFF; grlc_data->ul_tbf_start_time = CGRLC_STARTING_TIME_NOT_PRESENT; } #if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH sig_tm_gff_ul_activate(GFF_ACTIVE); #else sig_tm_gff_ul_activate(); #endif break; case CGRLC_TBF_MODE_DL: if((tbf_start NEQ CGRLC_STARTING_TIME_NOT_PRESENT) AND (dl_tfi NEQ grlc_data->dl_tfi)) /*lint !e650*/ { if(grlc_data->tfi_change EQ TFI_CHANGE_NULL) grlc_data->tfi_change = TFI_CHANGE_DL; else if(grlc_data->tfi_change EQ TFI_CHANGE_UL) grlc_data->tfi_change = TFI_CHANGE_ALL; grlc_data->start_fn_dl_tfi = dl_tfi; grlc_data->dl_tbf_start_time = tbf_start; TRACE_EVENT_P3("GRLC DL TFI CHANGE AFTER ST. TIME =%ld new_tfi=%d old_tfi=%d" ,tbf_start ,dl_tfi ,grlc_data->dl_tfi); } else { if(grlc_data->tfi_change EQ TFI_CHANGE_DL) grlc_data->tfi_change = TFI_CHANGE_NULL; else if(grlc_data->tfi_change EQ TFI_CHANGE_ALL) grlc_data->tfi_change = TFI_CHANGE_UL; grlc_data->dl_tfi = dl_tfi; grlc_data->start_fn_dl_tfi = 0xFF; grlc_data->dl_tbf_start_time = CGRLC_STARTING_TIME_NOT_PRESENT; } sig_tm_gff_dl_activate(); break; #if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH case CGRLC_TBF_MODE_2PA: sig_tm_gff_ul_activate(GFF_TWO_PHASE); break; #endif } /*TRACE_EVENT_P1("TFI_CHANGE = %d",grlc_data->tfi_change );*/ } /* tm_tfi_handling () */ /* +------------------------------------------------------------------------------ | Function : tm_cgrlc_status_ind +------------------------------------------------------------------------------ | Description : Handles the primitive CGRLC_STATUS_IND | | Parameters : cause - status cause, gmm is informed | +------------------------------------------------------------------------------ */ GLOBAL void tm_cgrlc_status_ind ( UBYTE cause ) { PALLOC(cgrlc_status_ind,CGRLC_STATUS_IND); TRACE_FUNCTION( "tm_cgrlc_status_ind" ); cgrlc_status_ind->failure = cause; PSEND(hCommGMM,cgrlc_status_ind); TRACE_EVENT_P1("error cause = %ld",cause); }/* tm_cgrlc_status_ind*/ /* +------------------------------------------------------------------------------ | Function : tm_handle_polling_bit +------------------------------------------------------------------------------ | Description : Handles the the polling in the immediate assignment (uplink or | downlink) | | Parameters : st_fn - starting time | tn - timeslot | +------------------------------------------------------------------------------ */ GLOBAL void tm_handle_polling_bit ( ULONG st_fn, UBYTE tn ) { TRACE_FUNCTION( "tm_handle_polling_bit" ); grlc_data->next_poll_fn = st_fn; grlc_data->ul_poll_pos_index = 0; if(grlc_data->burst_type EQ 0) { grlc_send_access_burst( tn ); } else { grlc_send_normal_burst(grlc_set_packet_ctrl_ack(), NULL, tn); } }/* tm_handle_polling_bit */ /* +------------------------------------------------------------------------------ | Function : tm_store_fa_bitmap +------------------------------------------------------------------------------ | Description : This function stores the allocation bitmap in | case of fixed allocation | | Parameters : ptr2_fix_alloc - ptr to the fixed allocation struct | +------------------------------------------------------------------------------ */ GLOBAL void tm_store_fa_bitmap (T_CGRLC_fix_alloc_struct * ptr2_fix_alloc) { UBYTE i,j; USHORT ul_res_sum = 0; T_FA_ALLOC * ptr_fa_ctrl; TRACE_FUNCTION( "tm_store_fa_bitmap" ); /* * calculate uplink resources allocation */ for(i=0;i<ptr2_fix_alloc->bitmap_len;i++) { if(ptr2_fix_alloc->bitmap_array[i]) { UBYTE mask = 0x80; for(j=0; j<=7; j++) { if(ptr2_fix_alloc->bitmap_array[i] & mask) ul_res_sum++; mask>>=1; } } } /* * set fa_ctrl */ if(grlc_data->uplink_tbf.fa_manag.fa_type EQ FA_NO_CURRENT) { grlc_data->uplink_tbf.fa_manag.fa_type = FA_NO_NEXT; ptr_fa_ctrl = &grlc_data->uplink_tbf.fa_manag.current_alloc; ptr_fa_ctrl->alloc_start_fn = grlc_data->ul_tbf_start_time; ptr_fa_ctrl->alloc_end_fn = ptr2_fix_alloc->end_fn; } else { grlc_data->uplink_tbf.fa_manag.fa_type = FA_BITMAP; ptr_fa_ctrl = &grlc_data->uplink_tbf.fa_manag.next_alloc; ptr_fa_ctrl->alloc_start_fn = grlc_data->ul_tbf_start_time; /* * check conflict of end of current alloc and start of next alloc */ if( grlc_check_dist(grlc_data->uplink_tbf.fa_manag.current_alloc.alloc_end_fn, grlc_data->uplink_tbf.fa_manag.next_alloc.alloc_start_fn,10000)) { ULONG delta_fn; UBYTE idle_frames; UBYTE iden_radio_blocks; UBYTE ts_delet; delta_fn = grlc_data->uplink_tbf.fa_manag.current_alloc.alloc_end_fn - grlc_data->uplink_tbf.fa_manag.next_alloc.alloc_start_fn; idle_frames = (UBYTE)((delta_fn / 52) *4 + delta_fn % 4); iden_radio_blocks = (UBYTE)((delta_fn - idle_frames) / 4 + 1); /* * remove shared allocation from current allocation */ ts_delet = 0; for(i=0;i<iden_radio_blocks;i++) { UBYTE pos; pos = grlc_data->uplink_tbf.fa_manag.current_alloc.alloc.bitmap_len - i; /* * calculate number of timeslots for current frame and delete them from resources */ if(grlc_data->uplink_tbf.fa_manag.current_alloc.alloc.bitmap_array[pos]) { UBYTE mask = 0x80; for(j=0; j<=7; j++) { if(ptr2_fix_alloc->bitmap_array[i] & mask) ts_delet++; mask>>=1; } } grlc_data->uplink_tbf.fa_manag.current_alloc.alloc.bitmap_array[pos] = 0; } grlc_data->uplink_tbf.fa_manag.current_alloc.ul_res_sum -= ts_delet; grlc_data->uplink_tbf.fa_manag.ul_res_sum -= ts_delet; grlc_data->uplink_tbf.fa_manag.current_alloc.alloc.bitmap_len -= iden_radio_blocks; grlc_data->uplink_tbf.fa_manag.current_alloc.alloc_end_fn = grlc_data->uplink_tbf.fa_manag.current_alloc.alloc_end_fn - delta_fn; } } grlc_data->uplink_tbf.fa_manag.ul_res_sum += ul_res_sum; ptr_fa_ctrl->ul_res_sum = ul_res_sum; /* * store end of fixed allocation */ ptr_fa_ctrl->alloc_end_fn = ptr2_fix_alloc->end_fn; tm_handle_final_alloc (ptr2_fix_alloc->final_alloc); } /* tm_store_fa_bitmap() */ /* +------------------------------------------------------------------------------ | Function : tm_handle_final_alloc +------------------------------------------------------------------------------ | Description : This function handles the final allocation bit. | | Parameters : - | +------------------------------------------------------------------------------ */ GLOBAL void tm_handle_final_alloc (UBYTE final_allocation) { UBYTE next; T_RLC_VALUES rlc_val; USHORT rlc_data_size=0; TRACE_FUNCTION( "tm_handle_final_alloc" ); switch(grlc_data->uplink_tbf.cs_type) { case CS_1: rlc_data_size = 20; break; case CS_2: rlc_data_size = 30; break; case CS_3: rlc_data_size = 36; break; case CS_4: rlc_data_size = 50; break; default: break; } if(grlc_data->prim_start_tbf < PRIM_QUEUE_SIZE_TOTAL AND grlc_data->prim_queue[grlc_data->prim_start_tbf].rlc_status EQ FALSE ) { next = grlc_data->prim_queue[grlc_data->prim_start_tbf].next; } else { next = grlc_data->prim_start_tbf; TRACE_EVENT_P3("PST=%d PSF=%d PDU=%d: tm_handle_final_alloc" ,grlc_data->prim_start_tbf ,grlc_data->prim_start_free ,grlc_data->grlc_data_req_cnt); } grlc_get_sdu_len_and_used_ts( &rlc_val); grlc_data->uplink_tbf.fa_manag.tbf_oct_cnt = rlc_val.sdu_len; grlc_data->uplink_tbf.fa_manag.ul_res_used = rlc_val.cnt_ts; grlc_data->uplink_tbf.fa_manag.ul_res_remain = grlc_data->uplink_tbf.fa_manag.ul_res_sum - grlc_data->uplink_tbf.fa_manag.ul_res_used; grlc_data->uplink_tbf.fa_manag.tbf_oct_cap_remain = grlc_data->uplink_tbf.fa_manag.ul_res_remain * rlc_data_size; if(final_allocation) { /* * last allocation of the tbf, it must end at the end of tbf. * check if more data is in prim queue than available uplink resources. * NO: nothing to do * YES: reorganize prim queue(set start_new_tbf) and inform RU */ while((grlc_data->prim_queue[next].start_new_tbf EQ 0) AND (next NEQ 0xFF) ) { if(grlc_data->uplink_tbf.fa_manag.tbf_oct_cap_remain < (grlc_data->uplink_tbf.fa_manag.tbf_oct_cnt + grlc_data->prim_queue[next].prim_ptr->sdu.l_buf/8 + 1)) { /* * find the end of the tbf. */ grlc_data->prim_queue[next].start_new_tbf = 1; sig_tm_ru_queue_status(); return; } grlc_data->uplink_tbf.fa_manag.tbf_oct_cnt += grlc_data->prim_queue[next].prim_ptr->sdu.l_buf/8; grlc_data->uplink_tbf.fa_manag.tbf_oct_cnt++; /* for pdu boundaries */ next = grlc_data->prim_queue[next].next; } } else { /* * not the last allocation */ while((grlc_data->prim_queue[next].start_new_tbf EQ 0) AND (next NEQ 0xFF) ) { grlc_data->uplink_tbf.fa_manag.tbf_oct_cnt += grlc_data->prim_queue[next].prim_ptr->sdu.l_buf/8; grlc_data->uplink_tbf.fa_manag.tbf_oct_cnt++; /* for pdu boundaries */ next = grlc_data->prim_queue[next].next; } } } /* tm_handle_final_alloc() */ /* +------------------------------------------------------------------------------ | Function : tm_set_fa_bitmap +------------------------------------------------------------------------------ | Description : sets fixed allocation bitmap for requested allocation after | receiving a repeat allocation with ts_override | | Parameters : void | +------------------------------------------------------------------------------ */ GLOBAL USHORT tm_set_fa_bitmap( UBYTE ts_mask, T_FA_ALLOC* ptr_alloc) { UBYTE i,j; USHORT tx_slots; TRACE_FUNCTION( "tm_set_fa_bitmap" ); if (ts_mask) { /* * add new time slots to current allocation */ tx_slots = 0; for(i=0;i<grlc_data->uplink_tbf.fa_manag.current_alloc.alloc.bitmap_len;i++) { ptr_alloc->alloc.bitmap_array[i] = grlc_data->uplink_tbf.fa_manag.current_alloc.alloc.bitmap_array[i] | ts_mask; if(ptr_alloc->alloc.bitmap_array[i]) { UBYTE mask = 0x80; for(j=0; j<=7; j++) { if(ptr_alloc->alloc.bitmap_array[i] & mask) tx_slots++; mask>>=1; } } } } else { /* * no new timeslot allocated */ tx_slots = grlc_data->uplink_tbf.fa_manag.current_alloc.ul_res_sum; } return (tx_slots); } /* tm_set_fa_bitmap() */ /* +------------------------------------------------------------------------------ | Function : tm_handle_test_mode_cnf +------------------------------------------------------------------------------ | Description : | | Parameters : | +------------------------------------------------------------------------------ */ GLOBAL void tm_handle_test_mode_cnf ( BOOL v_test_mode_cnf ) { TRACE_FUNCTION( "tm_handle_test_mode_cnf" ); if( v_test_mode_cnf EQ TRUE ) { PALLOC( cgrlc_test_mode_cnf, CGRLC_TEST_MODE_CNF ); grlc_data->testmode.mode = CGRLC_NO_TEST_MODE; PSEND( hCommGMM, cgrlc_test_mode_cnf ); tm_delete_prim_queue(); /*inform grr that testmode is finished*/ { PALLOC(cgrlc_test_mode_ind,CGRLC_TEST_MODE_IND); /*T_CGRLC_TEST_MODE_IND*/ cgrlc_test_mode_ind->test_mode_flag = CGRLC_NO_TEST_MODE; PSEND(hCommGRR,cgrlc_test_mode_ind); } } } /* tm_handle_test_mode_cnf() */ /* +------------------------------------------------------------------------------ | Function : tm_prcs_pwr_ctrl +------------------------------------------------------------------------------ | Description : | | Parameters : | +------------------------------------------------------------------------------ */ GLOBAL void tm_prcs_pwr_ctrl ( T_CGRLC_pwr_ctrl *pwr_ctrl ) { TRACE_FUNCTION( "tm_prcs_pwr_ctrl" ); if( pwr_ctrl->v_pwr_ctrl_param ) { tpc_set_pwr_ctrl_param( &pwr_ctrl->pwr_ctrl_param ); } if( pwr_ctrl->v_glbl_pwr_ctrl_param ) { tpc_set_glbl_pwr_ctrl_param( &pwr_ctrl->glbl_pwr_ctrl_param ); } if( pwr_ctrl->v_freq_param ) { grlc_data->tm.freq_param = pwr_ctrl->freq_param; } if( pwr_ctrl->v_c_value ) { meas_grlc_c_set_c_value( &pwr_ctrl->c_value ); } sig_tm_tpc_update_pch( ); { PALLOC( pwr_ctrl_cnf, CGRLC_PWR_CTRL_CNF ); PSEND( hCommGRR, pwr_ctrl_cnf ); } } /* tm_prcs_pwr_ctrl() */ #if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH GLOBAL void tm_send_msg_directly_to_l1_queue (UBYTE * unencoded_msg) { TRACE_FUNCTION( "tm_send_msg_directly_to_l1_queue" ); /* Call function that formats ARAC message */ memset(&grlc_data->ru.ul_data[0], 0, sizeof(T_ul_data)); grlc_data->ru.ul_data[0].block_status = 2; grlc_encode_ul_ctrl_block(( UBYTE* ) grlc_data->ru.ul_data[0].ul_block, ( UBYTE* )unencoded_msg ); #ifdef _SIMULATION_ { PALLOC(mac_data_req,MAC_DATA_REQ); memset(&(mac_data_req->ul_data), 0, sizeof(T_ul_data)); memcpy(&(mac_data_req->ul_data), &(grlc_data->ru.ul_data[0]), sizeof(T_ul_data)); PSEND(hCommL1,mac_data_req); } #else /* No need to copy again */ #endif /* ! _SIMULATION_ */ grlc_data->ru.ul_data[1].block_status = 0; return; } GLOBAL void tm_send_prr_2p_ptm ( void ) { T_U_GRLC_RESOURCE_REQ resource_req; TRACE_FUNCTION( "tm_send_prr_2p_ptm" ); tm_build_res_req( &resource_req, R_BUILD_2PHASE_ACCESS); tm_send_msg_directly_to_l1_queue((UBYTE *)&resource_req); return; } #endif