FreeCalypso > hg > fc-magnetite
view src/g23m-gprs/grlc/grlc_ruf.c @ 347:78d1df0b8487
aci2: AT%CBC and AT@CHARGE implemented
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 16 Dec 2017 00:37:43 +0000 |
parents | 219afcfc6250 |
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 RU of | entity GRLC. +----------------------------------------------------------------------------- */ #ifndef GRLC_RUF_C #define GRLC_RUF_C #endif #define ENTITY_GRLC /*==== INCLUDES =============================================================*/ #include <stdio.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" #include "grlc.h" /* to get the global entity definitions */ #include "grlc_f.h" #include "grlc_tms.h" #include "grlc_rds.h" #include "grlc_ruf.h" #include <string.h> #include "cl_rlcmac.h" /*==== CONST ================================================================*/ /*==== LOCAL VARS ===========================================================*/ /*==== PRIVATE FUNCTIONS ====================================================*/ /*==== PUBLIC FUNCTIONS =====================================================*/ /* +------------------------------------------------------------------------------ | Function : ru_init +------------------------------------------------------------------------------ | Description : The function ru_init() set init values in null state. | | Parameters : dummy - description of parameter dummy | +------------------------------------------------------------------------------ */ GLOBAL void ru_init ( void ) { UBYTE i; UBYTE j; TRACE_FUNCTION( "ru_init" ); INIT_STATE(RU,RU_NULL); /* * UBYTE */ grlc_data->ru.nts = 0xFF; grlc_data->ru.nts_max = 0xFF; grlc_data->ru.ti = 0xFF; grlc_data->ru.next_prim = 0xFF; grlc_data->ru.active_prim = 0xFF; grlc_data->ru.vs = 0xFF; grlc_data->ru.va = 0xFF; grlc_data->ru.bsn_ret = 0xFF; grlc_data->ru.last_si_block = 0xFF; grlc_data->ru.cv = 0xFF; grlc_data->ru.N3104 = 0xFF; grlc_data->ru.N3104_MAX = 0xFF; grlc_data->ru.block_status = 0xFF; grlc_data->ru.poll_tn = 0xFF; grlc_data->ru.count_cv_0 = 0xFF; grlc_data->ru.nr_nacked_blks = 0xFF; grlc_data->ru.pdu_cnt = 0xFF; grlc_data->ru.pdu_sent = 0xFF; grlc_data->ru.pdu_rem = 0xFF; grlc_data->ru.pdu_boundaries = 0xFF; grlc_data->ru.write_pos_index = 0xFF; /* * USHORT */ grlc_data->ru.rlc_data_size = 0xFFFF; grlc_data->ru.sdu_len = 0xFFFF; grlc_data->ru.sdu_off = 0xFFFF; grlc_data->ru.rlc_octet_cnt = 0xFFFF; grlc_data->ru.tbc = 0xFFFF; grlc_data->ru.cnt_ts = 0xFFFF; /* * BOOL */ grlc_data->ru.tlli_cs_type = FALSE; grlc_data->ru.cd_active = TRUE; grlc_data->ru.first_usf = FALSE; grlc_data->ru.release_tbf = FALSE; #if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH grlc_data->ru.tbf_re_est = FALSE; #endif /* * Type */ grlc_data->ru.cs_type = CS_ZERO; /* * structs */ grlc_data->ru.pl_retrans_current.cnt = 0xFF; memset(grlc_data->ru.pl_retrans_current.blk, 0xFF, 4); /* * array */ for (i=0;i<WIN_SIZE;i++) grlc_data->ru.vb[i & WIN_MOD] = VB_INVALID; /* * global structs */ for (i=0;i<NEXT_POLL_ARRAY_SIZE;i++) { /* * set free list */ grlc_data->next_poll_array[i].next = i+1; grlc_data->next_poll_array[i].fn = 0xFFFFFFFF; grlc_data->next_poll_array[i].cnt = 0; for(j=0; j< POLL_TYPE_ARRAY_SIZE; j++) grlc_data->next_poll_array[i].poll_type[j] = CGRLC_POLL_NONE; } /* * last free entry points to 0xff */ grlc_data->next_poll_array[NEXT_POLL_ARRAY_SIZE-1].next = 0xFF; /* * indicates invalid paramters */ grlc_data->poll_start_free = 0; grlc_data->poll_start_tbf = 0xFF; } /* ru_init() */ /* +------------------------------------------------------------------------------ | Function : ru_within_window +------------------------------------------------------------------------------ | Description : The function ru_within_window() checks if the bsn_i value is | between high_value_i and low_value_i(modulo operating). | The return value is result. | | | Parameters : bsn_i - chech this value | high_value_i - right side of the window | low_value_i - left side of the window | +------------------------------------------------------------------------------ */ GLOBAL BOOL ru_within_window ( UBYTE bsn_i, UBYTE high_value_i,UBYTE low_value_i ) { BOOL result = FALSE; TRACE_FUNCTION( "ru_within_window" ); if( ( high_value_i >= low_value_i ) AND /* vs >= va */ ( bsn_i > low_value_i ) AND /* ssn > va */ ( bsn_i <= high_value_i ) /* vs >= ssn */ ) { result = TRUE; } else if( ( high_value_i < low_value_i ) /* va > vs */ AND ( ( ( bsn_i > low_value_i ) AND /* ssn > va */ ( bsn_i > high_value_i )) OR /* ssn > vs */ ( ( bsn_i < low_value_i ) AND /* ssn > va */ ( bsn_i <= high_value_i )) /* ssn <= vs */ ) ) { result = TRUE; } /* if(!result) { TRACE_EVENT_P3("BSN not in range: low=%d bsn=%d high=%d", low_value_i,bsn_i,high_value_i); } */ return result; } /* ru_within_window() */ /* +------------------------------------------------------------------------------ | Function : ru_recalc_rlc_oct_cnt +------------------------------------------------------------------------------ | Description : The function ru_recalc_rlc_oct_cnt() the number of octetcs | during the TBF. It is needed for starting the countdown procedure | | Parameters : dummy - description of parameter dummy | +------------------------------------------------------------------------------ */ GLOBAL USHORT ru_recalc_rlc_oct_cnt ( void ) { USHORT result; UBYTE next_cnt; UBYTE prev_cnt; UBYTE rem_pdu_bound; ULONG rest_of_pdu; UBYTE last_pdu_bound; TRACE_FUNCTION( "ru_recalc_rlc_oct_cnt" ); grlc_data->ru.next_prim = grlc_data->prim_queue[grlc_data->ru.active_prim].next; result = grlc_data->ru.sdu_len; next_cnt = grlc_data->ru.next_prim; if(grlc_data->ru.sdu_len) grlc_data->ru.pdu_rem = 1; /*init calculate nr of pdu boundaries*/ rest_of_pdu = grlc_data->ru.sdu_len%grlc_data->ru.rlc_data_size; if((rest_of_pdu EQ 0) AND ((next_cnt EQ 0xFF) OR /* either no primitive in queue */ grlc_data->prim_queue[next_cnt].start_new_tbf)) /* or next primitive belongs to new tbf */ rem_pdu_bound = 0; /*fills excatly in cv=0*/ else if(rest_of_pdu EQ 0) rem_pdu_bound = 2; /*fills exxalty, more pdus rerq, therefore 2 bounds*/ else rem_pdu_bound = 1; /*normal case*/ last_pdu_bound = rem_pdu_bound; #ifdef _SIMULATION_ TRACE_EVENT_P4("pdu_len=%d,rest_of_pdu=%d,rem_pdu_bound=%d,last_pdu_bound=%d", grlc_data->ru.sdu_len, rest_of_pdu, rem_pdu_bound, last_pdu_bound ); #endif /* #ifdef _SIMULATION_ */ prev_cnt = grlc_data->ru.active_prim; while((next_cnt < PRIM_QUEUE_SIZE_TOTAL) AND (grlc_data->prim_queue[next_cnt].start_new_tbf EQ 0) ) { ULONG sdu_len; result += grlc_data->prim_queue[next_cnt].prim_ptr->sdu.l_buf/8; sdu_len = grlc_data->prim_queue[next_cnt].prim_ptr->sdu.l_buf/8; grlc_data->prim_queue[next_cnt].previous = prev_cnt; grlc_data->prim_queue[next_cnt].cv_status = FALSE; grlc_data->prim_queue[next_cnt].rlc_status = FALSE; grlc_data->prim_queue[next_cnt].last_bsn = 0xFF; prev_cnt = next_cnt; next_cnt = grlc_data->prim_queue[next_cnt].next; grlc_data->ru.pdu_rem++; /*init calculate nr of pdu boundaries*/ rest_of_pdu = ((sdu_len+last_pdu_bound+rest_of_pdu)%grlc_data->ru.rlc_data_size); if((rest_of_pdu EQ 0) AND ((next_cnt EQ 0xFF) OR grlc_data->prim_queue[next_cnt].start_new_tbf)) { rem_pdu_bound += 0; /*fills excatly in cv=0*/ last_pdu_bound = 0; } else if(rest_of_pdu EQ 0) { rem_pdu_bound += 2; /*fills exxalty, more pdus rerq, therefore 2 bounds*/ last_pdu_bound = 2; } else { rem_pdu_bound += 1; /*normal case*/ last_pdu_bound = 1; } #ifdef _SIMULATION_ TRACE_EVENT_P4("pdu_len=%d,rest_of_pdu=%d,rem_pdu_bound=%d,last_pdu_bound=%d", sdu_len, rest_of_pdu, rem_pdu_bound, last_pdu_bound ); #endif /* #ifdef _SIMULATION_ */ } grlc_data->ru.pdu_cnt = grlc_data->ru.pdu_rem+grlc_data->ru.pdu_sent; grlc_data->ru.pdu_boundaries = rem_pdu_bound; #ifdef _SIMULATION_ TRACE_EVENT_P4("pdu_cnt=%d,pdu_sent=%d,pdu_rem=%d,needed pdu_boundaries=%d", grlc_data->ru.pdu_cnt, grlc_data->ru.pdu_sent, grlc_data->ru.pdu_rem, grlc_data->ru.pdu_boundaries ); #endif /* #ifdef _SIMULATION_ */ grlc_data->tbf_ctrl[grlc_data->ul_index].pdu_cnt = grlc_data->ru.pdu_cnt; return result; } /* ru_recalc_rlc_oct_cnt() */ /* +------------------------------------------------------------------------------ | Function : ru_get_next_sdu +------------------------------------------------------------------------------ | Description : The function ru_get_next_sdu() gets the next GRLC_DATA_REQ from | the queue. | | Parameters : dummy - description of parameter dummy | +------------------------------------------------------------------------------ */ GLOBAL void ru_get_next_sdu ( void ) { TRACE_FUNCTION( "ru_get_next_sdu" ); grlc_data->ru.pdu_rem--; grlc_data->ru.pdu_sent++; grlc_data->prim_queue[grlc_data->ru.active_prim].last_bsn = grlc_data->ru.vs; if((grlc_data->prim_queue[grlc_data->ru.next_prim].start_new_tbf EQ 0) AND grlc_data->ru.next_prim NEQ 0xFF) { grlc_data->ru.active_prim = grlc_data->prim_queue[grlc_data->ru.active_prim].next; grlc_data->ru.sdu_len = grlc_data->prim_queue[grlc_data->ru.active_prim].prim_ptr->sdu.l_buf/8; grlc_data->ru.sdu_off = grlc_data->prim_queue[grlc_data->ru.active_prim].prim_ptr->sdu.o_buf/8; grlc_data->prim_queue[grlc_data->ru.active_prim].rlc_status = TRUE; grlc_data->ru.next_prim = grlc_data->prim_queue[grlc_data->ru.active_prim].next; } else { grlc_data->ru.sdu_len = 0; grlc_data->ru.sdu_off = 0; } #ifdef _SIMULATION_ TRACE_EVENT_P3("pdu_cnt=%d,pdu_sent=%d,pdu_rem=%d", grlc_data->ru.pdu_cnt, grlc_data->ru.pdu_sent, grlc_data->ru.pdu_rem ); #endif /* #ifdef _SIMULATION_ */ } /* ru_get_next_sdu() */ /* +------------------------------------------------------------------------------ | Function : ru_calc_rlc_data_size +------------------------------------------------------------------------------ | Description : The function ru_calc_rlc_data_size() calculates the Data size of | an RLC data block without header and TLLI. The size is described | in bytes. | | Parameters : cs_type_i - Coding scheme, determines the size of an RLC data block | +------------------------------------------------------------------------------ */ GLOBAL USHORT ru_calc_rlc_data_size ( T_CODING_SCHEME cs_type_i, UBYTE ti_bit_i ) { USHORT result=0; UBYTE tlli_size; TRACE_FUNCTION( "ru_calc_rlc_data_size" ); /* * check if tlli must be included in RLC data blocks */ if (ti_bit_i EQ 0) tlli_size = 0; else { tlli_size = TLLI_SIZE; if(!(grlc_data->ru.tlli_cs_type)) cs_type_i = CS_1; #ifdef REL99 if(grlc_data->pfi_support) { tlli_size++; } #endif } switch( cs_type_i) { case CS_1: result = 20; break; case CS_2: result = 30; break; case CS_3: result = 36; break; case CS_4: result = 50; break; default: if (!result) { TRACE_EVENT_P2("Unknown coding scheme, tsize=%d, t_cs=%d", tlli_size, grlc_data->ru.tlli_cs_type); result = 20; /* Going by CS1 coding scheme by default */ } break; } result -= tlli_size; return result; } /* ru_calc_rlc_data_size() */ /* +------------------------------------------------------------------------------ | Function : ru_set_block_status +------------------------------------------------------------------------------ | Description : The function ru_set_block_status() sets the block status. | | Parameters : cs_type_i - Coding scheme, determines the block status | +------------------------------------------------------------------------------ */ GLOBAL USHORT ru_set_block_status ( T_CODING_SCHEME cs_type_i ) { USHORT result=0; TRACE_FUNCTION( "ru_set_block_status" ); if(!(grlc_data->ru.tlli_cs_type) AND grlc_data->ru.ti) cs_type_i = CS_1; switch( cs_type_i) { case CS_1: result = 2; break; case CS_2: result = 4; break; case CS_3: result = 5; break; case CS_4: result = 6; break; default: TRACE_EVENT_P3("Unknown CS cstype=%d t_cs=%d, ti=%d",cs_type_i, grlc_data->ru.tlli_cs_type, grlc_data->ru.ti); break; } return result; } /* ru_set_block_status() */ /* +------------------------------------------------------------------------------ | Function : ru_get_cs_type +------------------------------------------------------------------------------ | Description : The function ru_get_cs_type() returns the coding scheme | for the requeseted block status. | | Parameters : bs_i - requested block status | +------------------------------------------------------------------------------ */ GLOBAL T_CODING_SCHEME ru_get_cs_type ( USHORT bs_i ) { T_CODING_SCHEME result= CS_ZERO; ; TRACE_FUNCTION( "ru_get_cs_type" ); switch( bs_i) { case 2: result = CS_1; break; case 4: result = CS_2; break; case 5: result = CS_3; break; case 6: result = CS_4; break; default: TRACE_ERROR("unknown block status"); break; } return result; } /* ru_get_cs_type() */ /* +------------------------------------------------------------------------------ | Function : ru_tbf_init +------------------------------------------------------------------------------ | Description : The function ru_tbf_init() sets the parameters at tbf assignment | | Parameters : dummy - description of parameter dummy | +------------------------------------------------------------------------------ */ GLOBAL void ru_tbf_init ( void ) { UBYTE i; TRACE_FUNCTION( "ru_tbf_init" ); grlc_data->ru.rlc_mode = grlc_data->uplink_tbf.rlc_mode; grlc_data->ru.nts = grlc_data->uplink_tbf.nts; grlc_data->ru.nts_max = grlc_data->uplink_tbf.nts; grlc_data->ru.va = 0; grlc_data->ul_tn_mask = grlc_data->uplink_tbf.ts_mask; #if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH grlc_data->ru.tbf_re_est = FALSE; #endif /* * initate l1 queue parameters */ grlc_data->ru.write_pos_index = 0; for(i=0; i<MAX_UL_TN;i++) grlc_data->ru.ul_data[i].block_status = 0; if(grlc_data->ru.rlc_mode EQ CGRLC_RLC_MODE_ACK) { /* * parameters only used in acknowledged mode */ grlc_data->ru.bsn_ret = 0; grlc_data->ru.last_si_block = 0; grlc_data->ru.N3104_MAX = 3 * (grlc_data->uplink_tbf.bs_cv_max + 3 ) * grlc_data->ru.nts_max; grlc_data->ru.nr_nacked_blks = 0; grlc_data->ru.ti = grlc_data->uplink_tbf.ti; } else if(grlc_data->ru.rlc_mode EQ CGRLC_RLC_MODE_UACK) { /* * parameters only used in unacknowledged mode */ grlc_data->ru.count_cv_0 = 0; /* * tlli is not send within data blocks */ grlc_data->ru.ti = 0; } /* * read the first pdu */ grlc_data->ru.active_prim = grlc_data->prim_start_tbf; grlc_data->prim_queue[grlc_data->prim_start_tbf].previous = 0xFF; grlc_data->ru.next_prim = grlc_data->prim_queue[grlc_data->ru.active_prim].next; grlc_data->prim_queue[grlc_data->prim_start_tbf].cv_status = FALSE; grlc_data->prim_queue[grlc_data->prim_start_tbf].last_bsn = 0xFF; grlc_data->ru.vs = 0; grlc_data->ru.cv = 55; /* * USHORT */ grlc_data->ru.sdu_len = grlc_data->prim_queue[grlc_data->ru.active_prim].prim_ptr->sdu.l_buf/8; grlc_data->ru.sdu_off = grlc_data->prim_queue[grlc_data->ru.active_prim].prim_ptr->sdu.o_buf/8; grlc_data->prim_queue[grlc_data->ru.active_prim].rlc_status = TRUE; grlc_data->ru.pdu_sent = 0; grlc_data->ru.cnt_ts = 0; /* * ULONG */ grlc_data->missed_poll_fn = 1; /* * BOOL */ grlc_data->ru.tlli_cs_type = grlc_data->uplink_tbf.tlli_cs_type; grlc_data->ru.cd_active = FALSE; grlc_data->ru.reorg_l1_needed = FALSE; grlc_data->ru.v_next_tbf_params = FALSE; grlc_data->ul_tfi_changed = FALSE; grlc_data->ru.release_tbf = FALSE; /* * Type */ grlc_data->ru.cs_type = grlc_data->uplink_tbf.cs_type; grlc_data->ru.last_bsn = LAST_BSN_NOT_BULIT; /* * struct */ if(grlc_data->uplink_tbf.mac_mode EQ CGRLC_MAC_MODE_DA) { /* * Start t3164, when starting time is elapsed. * Only if contention resolution is needed and not fixed alloc is used. */ grlc_data->ru.first_usf = TRUE; } grlc_data->ru.rlc_data_size = ru_calc_rlc_data_size(grlc_data->ru.cs_type, grlc_data->ru.ti); grlc_data->ru.block_status = ru_set_block_status(grlc_data->ru.cs_type); /* * handle close ended TBF */ if (grlc_data->uplink_tbf.rlc_db_granted ) { ULONG rlc_oct_cnt ; UBYTE next = grlc_data->prim_queue[grlc_data->prim_start_tbf].next; rlc_oct_cnt = (grlc_data->prim_queue[grlc_data->prim_start_tbf].prim_ptr->sdu.l_buf/8)+1; grlc_data->uplink_tbf.rlc_db_granted *= grlc_data->ru.rlc_data_size; while( (next < PRIM_QUEUE_SIZE) AND (!grlc_data->prim_queue[next].start_new_tbf) AND ((rlc_oct_cnt+(grlc_data->prim_queue[next].prim_ptr->sdu.l_buf/8)+1) < grlc_data->uplink_tbf.rlc_db_granted)) { rlc_oct_cnt += (grlc_data->prim_queue[next].prim_ptr->sdu.l_buf/8)+1; next = grlc_data->prim_queue[next].next; } if(next < PRIM_QUEUE_SIZE) grlc_data->prim_queue[next].start_new_tbf = 1; TRACE_EVENT_P4("close ended TBF: rlc_g=%ld rlc_oct =%ld data_size=%d next=%d" ,grlc_data->uplink_tbf.rlc_db_granted ,rlc_oct_cnt ,grlc_data->ru.rlc_data_size ,next); } grlc_data->ru.rlc_octet_cnt = ru_recalc_rlc_oct_cnt(); /*rlc data size needed*/ grlc_data->ru.pl_retrans_current.cnt = 0; /* TRACE PARAMS*/ grlc_data->ul_index = 0; grlc_data->tbf_ctrl[grlc_data->ul_index].tbf_type = TBF_TYPE_UL; grlc_data->tbf_ctrl[grlc_data->ul_index].tfi = grlc_data->ul_tfi; grlc_data->tbf_ctrl[grlc_data->ul_index].rlc_oct_cnt = 0; grlc_data->tbf_ctrl[grlc_data->ul_index].ret_bsn = 0; grlc_data->tbf_ctrl[grlc_data->ul_index].ack_cnt = 0; grlc_data->tbf_ctrl[grlc_data->ul_index].fbi = 0; } /* ru_tbf_init() */ /* +------------------------------------------------------------------------------ | Function : ru_set_T3198 +------------------------------------------------------------------------------ | Description : The function ru_set_T3198() starts the timer T3198 of the rlc | data block with bsn as input parameter. The timer is handled in | BS_CV_MAX block periods. | | Parameters : bsn_i - bsn value of the data block | +------------------------------------------------------------------------------ */ GLOBAL void ru_set_T3198 ( UBYTE bsn_i ) { USHORT block_periods; TRACE_FUNCTION( "ru_set_T3198" ); block_periods = MAXIMUM(1,grlc_data->uplink_tbf.bs_cv_max); /* * set timer T3198 , * the framenumber is set, at which the block is set to negative acknowledged */ grlc_data->ru.rlc_data[bsn_i & WIN_MOD].T3198 = grlc_decode_tbf_start_rel(grlc_data->ul_fn, --block_periods); #ifdef _SIMULATION_ TRACE_EVENT_P4("SET T3198: bsn %d t3198=%ld c_fn=%ld bs_cv_max=%d" ,bsn_i ,grlc_data->ru.rlc_data[bsn_i & WIN_MOD].T3198 ,grlc_data->ul_fn ,grlc_data->uplink_tbf.bs_cv_max); #endif } /* ru_set_T3198() */ /* +------------------------------------------------------------------------------ | Function : ru_send_mac_data_req +------------------------------------------------------------------------------ | Description : The function ru_send_mac_data_req() sends the data block with | bsn_i. The claculated block is matched in the PL buffer | (and MAC_DATA_REQ primitive, if SIMULATION is defined). | | Parameters : bsn_i - bsn value of the next to sent data block | +------------------------------------------------------------------------------ */ GLOBAL void ru_send_mac_data_req ( UBYTE bsn_i ) { UBYTE li_cnt; UBYTE data_cnt; UBYTE i; USHORT l_tlli; UBYTE len; USHORT off; UBYTE index; UBYTE *ptr_temp; TRACE_FUNCTION( "ru_send_mac_data_req" ); #ifdef _SIMULATION_ TRACE_EVENT_P2("BSN=%d mac_header=%x ",bsn_i, grlc_data->ru.rlc_data[bsn_i & WIN_MOD].header.mac); #endif /* #ifdef _SIMULATION_ */ { memset(&grlc_data->ru.ul_data[grlc_data->ru.write_pos_index], 0, sizeof(T_ul_data)); grlc_data->ru.ul_data[grlc_data->ru.write_pos_index].block_status = grlc_data->ru.rlc_data[bsn_i & WIN_MOD].block_status; ptr_temp = (UBYTE *) (grlc_data->ru.ul_data[grlc_data->ru.write_pos_index].ul_block); /* * set MAC Header */ ptr_temp[0] = grlc_data->ru.rlc_data[bsn_i & WIN_MOD].header.mac; ptr_temp[1] = (grlc_data->ul_tfi << 1 | grlc_data->ru.rlc_data[bsn_i & WIN_MOD].header.ti); ptr_temp[2] = (bsn_i << 1 | grlc_data->ru.rlc_data[bsn_i & WIN_MOD].header.e_bit); /*lint !e415*/ /* * set Length Indicator field(s) if present */ li_cnt = grlc_data->ru.rlc_data[bsn_i & WIN_MOD].header.li_cnt; for(i=3; i<(3+li_cnt);i++) ptr_temp[i] = grlc_data->ru.rlc_data[bsn_i & WIN_MOD].header.li_me[i-3]; /*lint !e661 !e662*/ /* * set TLLI field, if present */ if(grlc_data->ru.rlc_data[bsn_i & WIN_MOD].header.ti) { grlc_set_tlli( &l_tlli, &off, &(ptr_temp[3+li_cnt]), grlc_data->uplink_tbf.tlli ); l_tlli /= 8; /* handled in bytes */ #ifdef REL99 if (grlc_data->pfi_support) { ptr_temp[1] |= 0x40; ptr_temp[3+li_cnt+l_tlli] =(grlc_data->pfi_value << 1) | 0x01;/*04.60 7.1.2.6(initial pfi)*/ /*E bit = 1*/ l_tlli++; } #endif } else l_tlli = 0; /* * copy LLC DATA */ index = 0; data_cnt = grlc_data->ru.rlc_data[bsn_i & WIN_MOD].data_cnt; for(i=0;i<data_cnt;i++) { len = grlc_data->ru.rlc_data[bsn_i & WIN_MOD].data[i].l_buf / 8; off = grlc_data->ru.rlc_data[bsn_i & WIN_MOD].data[i].o_buf / 8; if(!grlc_test_mode_active()) { /* * get regular data */ memcpy(&(ptr_temp[3+li_cnt+l_tlli+index]), (grlc_data->ru.rlc_data[bsn_i & WIN_MOD].data[i].ptr_data->buf + off), len); /*lint !e797*/ } else { /* * test mode active, get test data */ if(grlc_data->testmode.mode EQ CGRLC_TEST_RANDOM) { /* * CGRLC_TEST_RANDOM */ if (!grlc_data->testmode.no_data_calculation) { /* * First call in this block */ grlc_prbs(COMPUTE_DATA, len, grlc_data->testmode.ptr_test_data); grlc_data->testmode.no_data_calculation = 1; } if (grlc_data->ru.nts EQ 1) { /* * this block is finished, allow prbs data calculation aigain */ grlc_data->testmode.no_data_calculation = 0; } /* * copy the prbs in */ memcpy(&(ptr_temp[3+li_cnt+l_tlli+index]), grlc_data->testmode.ptr_test_data, len); /*lint !e797*/ } else { /* * CGRLC_LOOP */ /* * If the downlink TBF is established on more than one timeslot, the MS shall transmit in * the second uplink timeslot (if present) RLC/MAC blocks received on the second downlink * timeslot, and shall transmit in the third uplink timeslot (if present) RLC/MAC blocks * received in the third downlink timeslot and so on. * It is assumed that while transmitting L1 will transmit data blocks in the sequence * in which it has received blocks from GRLC. */ if (grlc_data->downlink_tbf.nts > 1) { if (grlc_data->ru.write_pos_index EQ 0) { memcpy(&(ptr_temp[3+li_cnt+l_tlli+index]),grlc_data->testmode.rec_data[0].payload,len); TRACE_EVENT_P4("bsn =%d ready for send, cs_type=%ld, e_bit=%d, tn=%d" ,bsn_i ,grlc_data->ru.ul_data[grlc_data->ru.write_pos_index].block_status ,grlc_data->testmode.rec_data[0].e_bit ,grlc_data->ru.write_pos_index); } else { memcpy(&(ptr_temp[3+li_cnt+l_tlli+index]),grlc_data->testmode.rec_data[1].payload,len); TRACE_EVENT_P4("bsn =%d ready for send, cs_type=%ld, e_bit=%d, tn=%d" ,bsn_i ,grlc_data->ru.ul_data[grlc_data->ru.write_pos_index].block_status ,grlc_data->testmode.rec_data[1].e_bit ,grlc_data->ru.write_pos_index); } } else { memcpy(&(ptr_temp[3+li_cnt+l_tlli+index]),grlc_data->testmode.rec_data[0].payload,len); TRACE_EVENT_P3("bsn =%d ready for send, cs_type=%ld, e_bit=%d" ,bsn_i ,grlc_data->ru.ul_data[grlc_data->ru.write_pos_index].block_status ,grlc_data->testmode.rec_data[0].e_bit); } } } index += len; } if((grlc_data->ru.rlc_data[bsn_i & WIN_MOD].header.mac & 0x3C) EQ 0) /* countdown value is equal 0*/ { /* * fill rest of last block with 2B */ USHORT rlc_data_size; rlc_data_size = ru_calc_rlc_data_size( ru_get_cs_type(grlc_data->ru.rlc_data[bsn_i & WIN_MOD].block_status) , grlc_data->ru.rlc_data[bsn_i & WIN_MOD].header.ti); len = rlc_data_size-index-li_cnt; memset(&(ptr_temp[3+li_cnt+l_tlli+index]), 0x2B, len); /*lint !e797*/ } #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[grlc_data->ru.write_pos_index]), sizeof(T_ul_data)); /*lint !e797*/ PSEND(hCommL1,mac_data_req); } TRACE_EVENT_P1("wpi %d",grlc_data->ru.write_pos_index); #else /* #ifdef _SIMULATION_ */ { TRACE_MEMORY_PRIM ( hCommGRLC, hCommL1, MAC_DATA_REQ, &grlc_data->ru.ul_data[grlc_data->ru.write_pos_index], sizeof(T_ul_data) ); } #endif /* #ifdef _SIMULATION_ */ grlc_data->ru.write_pos_index++; /* * indicates the PL, there is no more block */ grlc_data->ru.ul_data[grlc_data->ru.write_pos_index].block_status = 0; } grlc_data->ru.pl_retrans_current.blk[grlc_data->ru.pl_retrans_current.cnt] = bsn_i; grlc_data->ru.pl_retrans_current.cnt++; grlc_data->ru.nts--; grlc_data->ru.vb[bsn_i & WIN_MOD] = VB_PENDING_ACK; } /* ru_send_mac_data_req() */ /* +------------------------------------------------------------------------------ | Function : ru_set_prim_queue +------------------------------------------------------------------------------ | Description : The function ru_set_prim_queue() updates the primitive queue. | If the countdown procedure is started, all LLC PDUs which belongs | to the current tbf are signed with cv_status as true. In this case | these LLC PDUs can´t reorginized an more LLC PDU can sent during | his TBF. Additionally received LLC PDUs are sent in a new TBF. | If the countdown procedure is stopped (i.e. change of cpding | scheme) then this functions resets the cv_status to False. | | Parameters : cd_state_i - if true, the countdown procedue is started, else | it is stopped | +------------------------------------------------------------------------------ */ GLOBAL void ru_set_prim_queue ( BOOL cd_state_i ) { UBYTE next; TRACE_FUNCTION( "ru_set_prim_queue" ); next = grlc_data->ru.next_prim; grlc_data->prim_queue[grlc_data->ru.active_prim].cv_status = cd_state_i; while( (grlc_data->prim_queue[next].start_new_tbf EQ 0) AND (next NEQ 0xFF) ) { grlc_data->prim_queue[next].cv_status = cd_state_i; next = grlc_data->prim_queue[next].next; } } /* ru_set_prim_queue() */ /* +------------------------------------------------------------------------------ | Function : ru_countdown_procedure +------------------------------------------------------------------------------ | Description : The function ru_countdown_procedure() calculates the countdown | value. After Contention resoultion is succesfully completed or | at changing of the Coding scheme(indicateded in packet | uplink ack/nack or packet timeslot reconfigure), the countdown | value must be recalculated. | | Parameters : dummy - description of parameter dummy | +------------------------------------------------------------------------------ */ GLOBAL UBYTE ru_countdown_procedure ( UBYTE ret_blocks ) { USHORT x; UBYTE result; TRACE_FUNCTION( "ru_countdown_procedure" ); /* * ret_blocks is the number of blocks which has to retransmit * formular for cv calculation: x = round((TBC-bsn´-1)/nts) * here tbc = (TBC-bsn) so that * x = round((tbc-1)/nts) * nr of pdu bundaries is also considered for calculating tbc */ #ifdef _SIMULATION_ TRACE_EVENT_P3("bs_cv_max=%d rlc_oct_cnt=%d data_size=%d",grlc_data->uplink_tbf.bs_cv_max,grlc_data->ru.rlc_octet_cnt,grlc_data->ru.rlc_data_size); #endif /* #ifdef _SIMULATION_ */ if(grlc_data->testmode.mode EQ CGRLC_LOOP) { TRACE_EVENT("testmode B: cv value=15"); return (15); } grlc_data->ru.tbc = (grlc_data->ru.rlc_octet_cnt+grlc_data->ru.pdu_boundaries) / grlc_data->ru.rlc_data_size; if( (grlc_data->ru.rlc_octet_cnt+grlc_data->ru.pdu_boundaries) % grlc_data->ru.rlc_data_size) /*round upwards*/ grlc_data->ru.tbc++; x = (grlc_data->ru.tbc -1 + ret_blocks) / grlc_data->ru.nts_max; if( (grlc_data->ru.tbc -1 + ret_blocks ) % grlc_data->ru.nts_max) /*round upwards*/ x++; if(x > grlc_data->uplink_tbf.bs_cv_max) { result = 15; if(grlc_data->ru.cd_active) { grlc_data->ru.cd_active = FALSE; ru_set_prim_queue(grlc_data->ru.cd_active); } } else { result = (UBYTE)x; if(!grlc_data->ru.cd_active AND ((grlc_data->ru.state NEQ RU_WAIT_FOR_FIRST_CALL_ACK) OR (grlc_data->ru.state NEQ RU_WAIT_FOR_FIRST_CALL_UACK))) { grlc_data->ru.cd_active = TRUE; ru_set_prim_queue(grlc_data->ru.cd_active); } } return result; } /* ru_countdown_procedure() */ /* +------------------------------------------------------------------------------ | Function : ru_update_vb +------------------------------------------------------------------------------ | Description : The function ru_update_vb() refreshs the VB array field after | receiving a packet uplink ack/nack. | | Parameters : dummy - description of parameter dummy | +------------------------------------------------------------------------------ */ GLOBAL void ru_update_vb ( void ) { MCAST(d_ul_ack,D_GRLC_UL_ACK); UBYTE bsn, ssn, i; TRACE_FUNCTION( "ru_update_vb" ); ssn = d_ul_ack->gprs_ul_ack_nack_info.ack_nack_des.ssn; /* * Check if ssn is valid */ if(!ru_within_window(ssn,grlc_data->ru.vs,grlc_data->ru.va)) { TRACE_EVENT_P4( "SSN OUTSIDE WINDOW: ssn=%d, vs=%d, va=%d f_ack_ind=%d", ssn, grlc_data->ru.vs, grlc_data->ru.va, d_ul_ack->gprs_ul_ack_nack_info.ack_nack_des.f_ack_ind); return; } grlc_data->ru.nr_nacked_blks = 0; for(i = 1; i <= WIN_SIZE; i++) { bsn = (ssn - i) & 0x7F; /*mod 128*/ if(d_ul_ack->gprs_ul_ack_nack_info.ack_nack_des.rbb[WIN_SIZE-i]) { if(grlc_data->ru.vb[bsn & WIN_MOD] NEQ VB_ACKED) { grlc_data->ru.vb[bsn & WIN_MOD] = VB_ACKED; } } else if(grlc_check_if_tbf_start_is_elapsed ( grlc_data->ru.rlc_data[bsn & WIN_MOD].T3198, grlc_data->ul_fn)) { /* * timeout T3198 */ grlc_data->ru.vb[bsn & WIN_MOD] = VB_NACKED; grlc_data->ru.nr_nacked_blks++; } else { TRACE_EVENT_P3("BSN =%d not acked. T3198=%ld not expired (c_fn=%ld). vb not modified" ,bsn ,grlc_data->ru.rlc_data[bsn & WIN_MOD].T3198 ,grlc_data->ul_fn); } if (bsn EQ grlc_data->ru.va) i = WIN_SIZE+1; /* break cobdition*/ } } /* ru_update_vb() */ /* +------------------------------------------------------------------------------ | Function : ru_calc_rlc_data_block +------------------------------------------------------------------------------ | Description : The funcion ru_calc_rlc_data_block() builds a complete RLC | data block. | | Parameters : bsn_i - bsn value of the calculated RLC data block | +------------------------------------------------------------------------------ */ GLOBAL void ru_calc_rlc_data_block ( UBYTE bsn_i ) { USHORT rlc_len; UBYTE li_cnt, data_cnt; TRACE_FUNCTION( "ru_calc_rlc_data_block" ); /* * calculate the countdown value, no retransmission */ grlc_data->ru.cv = ru_countdown_procedure(0); grlc_data->ru.rlc_data[bsn_i & WIN_MOD].block_status = grlc_data->ru.block_status; /* * set MAC header */ grlc_data->ru.rlc_data[bsn_i & WIN_MOD].header.mac = (grlc_data->ru.cv << 2 | grlc_data->r_bit ); /* * set RLC header values */ grlc_data->ru.rlc_data[bsn_i & WIN_MOD].header.ti = grlc_data->ru.ti; /* * data handling */ rlc_len = grlc_data->ru.rlc_data_size; data_cnt = 0; li_cnt = 0; if(grlc_data->testmode.mode EQ CGRLC_LOOP) { grlc_data->ru.sdu_len = 7777; /* random value */ grlc_data->ru.sdu_off = 0; rlc_len = 50; grlc_data->ru.rlc_octet_cnt = 7777; /* to be in line with sdu_len*/ TRACE_EVENT("testmode B: get data from received downlink"); } while ( (grlc_data->ru.sdu_len < rlc_len) AND (grlc_data->ru.sdu_len > 0) ) { /* * end of pdu in block reached */ grlc_data->ru.rlc_data[bsn_i & WIN_MOD].header.li_me[li_cnt]= (UBYTE) grlc_data->ru.sdu_len; grlc_data->ru.rlc_data[bsn_i & WIN_MOD].header.li_me[li_cnt] <<= 2; grlc_data->ru.rlc_data[bsn_i & WIN_MOD].data[li_cnt].ptr_data = &(grlc_data->prim_queue[grlc_data->ru.active_prim].prim_ptr->sdu); grlc_data->ru.rlc_data[bsn_i & WIN_MOD].data[li_cnt].l_buf = grlc_data->ru.sdu_len * 8; grlc_data->ru.rlc_data[bsn_i & WIN_MOD].data[li_cnt].o_buf = grlc_data->ru.sdu_off * 8; rlc_len -= grlc_data->ru.sdu_len + 1; grlc_data->ru.rlc_octet_cnt -= grlc_data->ru.sdu_len; grlc_data->ru.sdu_len -= grlc_data->ru.rlc_data[bsn_i & WIN_MOD].data[li_cnt].l_buf/8; grlc_data->ru.sdu_off += grlc_data->ru.rlc_data[bsn_i & WIN_MOD].data[li_cnt].l_buf/8; ru_get_next_sdu(); if((grlc_data->ru.sdu_len > 0) AND rlc_len) { /* * one more sdu in queue */ grlc_data->ru.rlc_data[bsn_i & WIN_MOD].header.li_me[li_cnt] |= 0x02; } else { /* * no more sdu in queue */ grlc_data->ru.rlc_data[bsn_i & WIN_MOD].header.li_me[li_cnt] |= 0x01; } data_cnt++; li_cnt++; if(li_cnt > NR_OF_PDUS_PER_RLCMAC_BLOCK) { TRACE_EVENT_P2("li_cnt=%d NR_OF_PDUS_PER_RLCMAC_BLOCK=%d",li_cnt,NR_OF_PDUS_PER_RLCMAC_BLOCK); TRACE_ERROR("ru li_cnt bigger than RD_LI_CNT_MAX (=8)"); TRACE_ASSERT( li_cnt > NR_OF_PDUS_PER_RLCMAC_BLOCK ); return; } } if((grlc_data->ru.sdu_len EQ rlc_len) AND (grlc_data->ru.sdu_len > 0) AND (grlc_data->ru.cv EQ 0)) { /* * end of pdu; rest of pdu match exactly into the rest of a rlc data block, last uplink block */ grlc_data->ru.rlc_data[bsn_i & WIN_MOD].data[li_cnt].ptr_data = &(grlc_data->prim_queue[grlc_data->ru.active_prim].prim_ptr->sdu); /*lint !e661*/ grlc_data->ru.rlc_data[bsn_i & WIN_MOD].data[li_cnt].l_buf = grlc_data->ru.sdu_len *8; /*lint !e661*/ grlc_data->ru.rlc_data[bsn_i & WIN_MOD].data[li_cnt].o_buf = grlc_data->ru.sdu_off *8; /*lint !e661*/ data_cnt++; grlc_data->ru.rlc_octet_cnt -= rlc_len; ru_get_next_sdu(); } else if((grlc_data->ru.sdu_len EQ rlc_len) AND (grlc_data->ru.sdu_len > 0)) { /* * end of pdu; rest of pdu match exactly into the rest of a rlc data block, * split into two blocks, len set to zero, indicates that the end of pdu is not reached */ grlc_data->ru.rlc_data[bsn_i & WIN_MOD].header.li_me[li_cnt] = 0x01; /*lint !e661*/ grlc_data->ru.rlc_data[bsn_i & WIN_MOD].data[li_cnt].ptr_data = &(grlc_data->prim_queue[grlc_data->ru.active_prim].prim_ptr->sdu); /*lint !e661*/ grlc_data->ru.rlc_data[bsn_i & WIN_MOD].data[li_cnt].l_buf = (grlc_data->ru.sdu_len-1) *8; /*lint !e661*/ grlc_data->ru.rlc_data[bsn_i & WIN_MOD].data[li_cnt].o_buf = grlc_data->ru.sdu_off *8; /*lint !e661*/ data_cnt++; li_cnt++; rlc_len--; grlc_data->ru.sdu_len -= rlc_len; grlc_data->ru.sdu_off += rlc_len; grlc_data->ru.rlc_octet_cnt -= rlc_len; if(li_cnt > NR_OF_PDUS_PER_RLCMAC_BLOCK) { TRACE_EVENT_P2("li_cnt=%d NR_OF_PDUS_PER_RLCMAC_BLOCK=%d",li_cnt,NR_OF_PDUS_PER_RLCMAC_BLOCK); TRACE_ERROR("ru2 li_cnt bigger than RD_LI_CNT_MAX (=8)"); TRACE_ASSERT( li_cnt > NR_OF_PDUS_PER_RLCMAC_BLOCK ); return; } } else if( (grlc_data->ru.sdu_len > 0) AND rlc_len) { /* * only a part of the sdu matches into the rlc data block */ if(grlc_data->testmode.mode EQ CGRLC_LOOP) { grlc_data->ru.rlc_data[bsn_i & WIN_MOD].data[li_cnt].ptr_data = NULL; /*lint !e661*/ TRACE_EVENT("set data ptr for testmode B to NULL"); } else { grlc_data->ru.rlc_data[bsn_i & WIN_MOD].data[li_cnt].ptr_data = &(grlc_data->prim_queue[grlc_data->ru.active_prim].prim_ptr->sdu); /*lint !e661*/ } grlc_data->ru.rlc_data[bsn_i & WIN_MOD].data[li_cnt].l_buf = rlc_len * 8; /*lint !e661*/ grlc_data->ru.rlc_data[bsn_i & WIN_MOD].data[li_cnt].o_buf = grlc_data->ru.sdu_off * 8; /*lint !e661*/ data_cnt++; grlc_data->ru.sdu_len -= rlc_len; grlc_data->ru.sdu_off += rlc_len; grlc_data->ru.rlc_octet_cnt -= rlc_len; } /* * LI fied parameters are set */ if(grlc_data->testmode.mode EQ CGRLC_LOOP) { grlc_data->ru.rlc_data[bsn_i & WIN_MOD].header.e_bit = grlc_data->testmode.rec_data[0].e_bit; } else if(li_cnt) { grlc_data->ru.rlc_data[bsn_i & WIN_MOD].header.e_bit = 0; grlc_data->ru.rlc_data[bsn_i & WIN_MOD].header.li_me[li_cnt-1] |= 0x01; grlc_data->ru.pdu_boundaries -= li_cnt; #ifdef _SIMULATION_ TRACE_EVENT_P2("li_cnt=%d,remaining pdu boundaries=%d", li_cnt, grlc_data->ru.pdu_boundaries); #endif /* #ifdef _SIMULATION_ */ } else { grlc_data->ru.rlc_data[bsn_i & WIN_MOD].header.e_bit = 1; } grlc_data->ru.rlc_data[bsn_i & WIN_MOD].header.li_cnt = li_cnt; grlc_data->ru.rlc_data[bsn_i & WIN_MOD].data_cnt = data_cnt; } /* ru_calc_rlc_data_block() */ /* +------------------------------------------------------------------------------ | Function : ru_handle_n3102 +------------------------------------------------------------------------------ | Description : The function ru_handle_n3102() handles the counter N3102. | If the input parameter ia PAN_INC, then the counter is | incremented. If the input parameter ia PAN_DEC, then the | counter is decremented. | | Parameters : pan_cnt_i - determines, if the counter is either in- or | decremented | +------------------------------------------------------------------------------ */ GLOBAL void ru_handle_n3102 ( T_PAN_CNT pan_cnt_i ) { TRACE_FUNCTION( "ru_handle_n3102" ); if((grlc_data->N3102 NEQ 0xFF) AND grlc_data->pan_struct.inc AND grlc_data->pan_struct.dec AND grlc_data->pan_struct.pmax) { switch( pan_cnt_i ) { case PAN_INC: grlc_data->N3102 += grlc_data->pan_struct.inc; grlc_data->N3102 = MINIMUM(grlc_data->N3102,grlc_data->pan_struct.pmax); /*TRACE_EVENT_P4( "INC N3102: inc=%d, dec=%d, pan_max=%d n3102=%d", grlc_data->pan_struct.inc, grlc_data->pan_struct.dec, pgrlc_data->pan_struct.pmax, grlc_data->N3102 );*/ break; case PAN_DEC: if( grlc_data->N3102 > grlc_data->pan_struct.dec ) { grlc_data->N3102 -= grlc_data->pan_struct.dec; TRACE_EVENT_P4( "DEC1 N3102: inc=%d, dec=%d, pan_max=%d n3102=%d", grlc_data->pan_struct.inc, grlc_data->pan_struct.dec, grlc_data->pan_struct.pmax, grlc_data->N3102 ); sig_ru_tm_error_ra(); } else { grlc_data->N3102 = 0; TRACE_EVENT_P4( "DEC2 N3102: inc=%d, dec=%d, pan_max=%d n3102=%d", grlc_data->pan_struct.inc, grlc_data->pan_struct.dec, grlc_data->pan_struct.pmax, grlc_data->N3102); sig_ru_tm_error_ra(); } break; default: TRACE_ERROR("unknown type for pan_cnt_i"); break; } } else if(pan_cnt_i EQ PAN_DEC) { TRACE_EVENT( "IGNORE N3102" ); sig_ru_tm_error_ra(); } } /* ru_handle_n3102() */ /* +------------------------------------------------------------------------------ | Function : ru_calc_va +------------------------------------------------------------------------------ | Description : The function ru_calc_va() claculates the block, that was | negatively acknowledged and must be retransmitted in the next | uplink block. | | Parameters : dummy - description of parameter dummy | +------------------------------------------------------------------------------ */ GLOBAL UBYTE ru_calc_va ( void ) { UBYTE result; TRACE_FUNCTION( "ru_calc_va" ); result = (grlc_data->ru.va) & 0x7F /*mod 128*/; while( (grlc_data->ru.vb[result & WIN_MOD] EQ VB_ACKED) AND (result NEQ grlc_data->ru.vs)) { result = (result+1) & 0x7F /*mod 128*/; } return result; } /* ru_calc_va() */ /* +------------------------------------------------------------------------------ | Function : ru_set_next_bsn_ret() +------------------------------------------------------------------------------ | Description : The function ru_set_next_bsn_ret sets the next valid bsn, | which shall be transmitted as next retransmission | | Parameters : - description of parameter dummy | +------------------------------------------------------------------------------ */ GLOBAL UBYTE ru_set_next_bsn_ret ( void) { UBYTE new_bsn_ret; TRACE_FUNCTION( "ru_set_next_bsn_ret" ); new_bsn_ret = (grlc_data->ru.bsn_ret+1) & 0x7F; while( (grlc_data->ru.vb[new_bsn_ret & WIN_MOD] NEQ VB_PENDING_ACK) AND (grlc_data->ru.vb[new_bsn_ret & WIN_MOD] NEQ VB_NACKED) AND new_bsn_ret NEQ grlc_data->ru.vs ) { new_bsn_ret = (new_bsn_ret+1) & 0x7F; } if( new_bsn_ret EQ grlc_data->ru.vs ) { grlc_data->ru.nr_nacked_blks = 0 ; new_bsn_ret = grlc_data->ru.va; } return new_bsn_ret; } /* ru_set_next_bsn_ret() */ /* +------------------------------------------------------------------------------ | Function : ru_ret_bsn +------------------------------------------------------------------------------ | Description : The function ru_ret_bsn() is called in RU_REL_ACK. In this state | all RLC data blocks are transmitted, but not acknowledged. If | more uplink PDCHs are available(i.e. the PL reads valid USF | flags), then the blocks which currently where not acked are | retransmitted. The bsn value of the next block is controled by | bsn_ret. | | Parameters : dummy | +------------------------------------------------------------------------------ */ GLOBAL void ru_ret_bsn ( void ) { TRACE_FUNCTION( "ru_ret_bsn" ); /* TRACE_EVENT_P3("BSN RET: bsn=%d, cv=%d vb=%d" ,grlc_data->ru.bsn_ret ,grlc_data->ru.rlc_data[grlc_data->ru.bsn_ret & WIN_MOD].header.cv ,grlc_data->ru.vb[grlc_data->ru.bsn_ret & WIN_MOD]); */ ru_send_mac_data_req(grlc_data->ru.bsn_ret); grlc_data->ru.bsn_ret = ru_set_next_bsn_ret(); } /* ru_ret_bsn() */ /* +------------------------------------------------------------------------------ | Function : ru_change_of_cs +------------------------------------------------------------------------------ | Description : The function ru_change_of_cs() handles the change of the coding | scheme. Folling values must be recalculated. | 1. rlc_data_len | 2. rlc_octet_cnt | | Parameters : cs_type_i - new coding scheme | +------------------------------------------------------------------------------ */ GLOBAL void ru_change_of_cs ( T_CODING_SCHEME cs_type_i ) { TRACE_FUNCTION( "ru_change_of_cs" ); grlc_data->ru.rlc_data_size = ru_calc_rlc_data_size(cs_type_i,grlc_data->ru.ti); grlc_data->ru.block_status = ru_set_block_status(grlc_data->ru.cs_type); if(grlc_data->ru.last_bsn NEQ LAST_BSN_IS_SENT) { grlc_data->ru.rlc_octet_cnt = ru_recalc_rlc_oct_cnt(); grlc_data->ru.reorg_l1_needed = TRUE; } else { TRACE_EVENT_P3("No REORG dueto CS change requried: rlc_cnt=%ld l_bsn=%d cv=%d" ,grlc_data->ru.rlc_octet_cnt ,grlc_data->ru.last_bsn ,grlc_data->ru.cv); } } /* ru_change_of_cs() */ /* +------------------------------------------------------------------------------ | Function : ru_contention_resolution +------------------------------------------------------------------------------ | Description : The function ru_contention_resolution() checks at one phase | access after receiving a packet uplink ack/nack message the | contention resolution TLLI. | | Parameters : dummy - description of parameter dummy | +------------------------------------------------------------------------------ */ GLOBAL BOOL ru_contention_resolution ( void ) { MCAST(d_ul_ack,D_GRLC_UL_ACK); BOOL result = FALSE; TRACE_FUNCTION( "ru_contention_resolution" ); if((grlc_data->ru.ti) AND (d_ul_ack->gprs_ul_ack_nack_info.v_cr_tlli) ) { ULONG tlli; /* * TLLI received and Contention resolution not yet processed */ tlli = grlc_buffer2ulong( &d_ul_ack->gprs_ul_ack_nack_info.cr_tlli ); if(tlli EQ grlc_data->uplink_tbf.tlli) result = TRUE; grlc_data->ru.N3104 = 0; vsi_t_stop(GRLC_handle,T3166); if(result) { /* * correct TLLI received, contention resolution succesful */ grlc_data->ru.ti = 0; grlc_data->ru.rlc_data_size = ru_calc_rlc_data_size(grlc_data->ru.cs_type,grlc_data->ru.ti); grlc_data->ru.block_status = ru_set_block_status(grlc_data->ru.cs_type); /* * needed, because nr of pdu boundaries could be change */ grlc_data->ru.rlc_octet_cnt = ru_recalc_rlc_oct_cnt(); sig_ru_tm_cs(); result = FALSE; grlc_data->ru.reorg_l1_needed = TRUE; } else { /* * wrong TLLI received, contention resolution failed, TBF will be aborted */ result = TRUE; TRACE_ERROR( "TLLI error occured" ); sig_ru_tm_error_ra(); } } else if(grlc_data->ru.ti EQ 0) result = FALSE; return result; } /* ru_contention_resolution() */ /* +------------------------------------------------------------------------------ | Function : ru_delete_prims +------------------------------------------------------------------------------ | Description : The function ru_delete_prims() deletes LLC PDUs from the | primitive queue which are positivlely acknowledged(indirectly | by the highest bsn value in the rrb field included in the | packet uplink ack/nack). | | Parameters : last_bsn_i - all primitives including last_bsn_i are deleted. | +------------------------------------------------------------------------------ */ GLOBAL void ru_delete_prims ( UBYTE last_bsn_i ) { UBYTE cnt=0, prim_type=CGRLC_PRIM_TYPE_OTHER; BOOL all_null_frames = TRUE; TRACE_FUNCTION( "ru_delete_prims" ); /* * check if last_bsn_i is outside window */ while( (grlc_data->prim_start_tbf < PRIM_QUEUE_SIZE_TOTAL) AND (grlc_data->prim_queue[grlc_data->prim_start_tbf].last_bsn NEQ 0xFF) AND (ru_within_window( last_bsn_i, grlc_data->ru.vs, grlc_data->prim_queue[grlc_data->prim_start_tbf].last_bsn))) { cnt++; if( (prim_type NEQ CGRLC_PRIM_TYPE_GMM) AND (grlc_data->prim_queue[grlc_data->prim_start_tbf].prim_ptr->cause EQ GRLC_DTACS_MOBILITY_MANAGEMENT) ) { prim_type = CGRLC_PRIM_TYPE_GMM; } if( (all_null_frames EQ TRUE) AND (grlc_data->prim_queue[grlc_data->prim_start_tbf].prim_ptr->cause NEQ GRLC_DTACS_CELL_NOTIFI_NULL_FRAME) ) { /* This variable is set to FALSE in case there is at least ont not NULL frame */ all_null_frames = FALSE; } sig_ru_tm_prim_delete(); } if(cnt) { if( grlc_data->ready_timer.handling EQ READY_TIMER_HANDLING_ENABLED AND all_null_frames EQ FALSE AND grlc_data->ready_timer.value NEQ CGRLC_STANDBY ) { if (grlc_data->ready_timer.value NEQ CGRLC_DEACTIVATED) { /* The Ready Timer will be restarted in case of at least one not NULL frame and valid value (<>0 and <> 0xFFFFFFFF) */ vsi_t_start(GRLC_handle,T3314, grlc_data->ready_timer.value ); } grlc_enter_ready_state( ); } if( grlc_data->ready_timer.handling EQ READY_TIMER_HANDLING_DISABLED OR ( grlc_data->ready_timer.handling EQ READY_TIMER_HANDLING_ENABLED AND prim_type EQ CGRLC_PRIM_TYPE_GMM ) ) { PALLOC(cgrlc_trigger_ind,CGRLC_TRIGGER_IND); /* T_CGRLC_TRIGGER_IND */ cgrlc_trigger_ind->prim_type = prim_type; PSEND(hCommGMM,cgrlc_trigger_ind); } } #ifdef _SIMULATION_ TRACE_EVENT_P5("%d PRIMS deleted: last_bsn=%d vs=%d prim_start_tbf=%d, prim_cnt=%d ", cnt,last_bsn_i,grlc_data->ru.vs,grlc_data->prim_start_tbf,grlc_data->grlc_data_req_cnt); TRACE_EVENT_P3("pdu_cnt=%d,pdu_sent=%d,pdu_rem=%d", grlc_data->ru.pdu_cnt, grlc_data->ru.pdu_sent, grlc_data->ru.pdu_rem ); #endif /* #ifdef _SIMULATION_ */ } /* ru_delete_prims() */ /* +------------------------------------------------------------------------------ | Function : ru_handle_n3104 +------------------------------------------------------------------------------ | Description : The function ru_handle_n3104() controls the counter N3104. If | the counter reaches it maximum value, then the tbf is released. | The counter is ignored, if the contention resolution is | successfully completed. Evry time at receiption a packet uplink | ack/nack without including TLLI the counter is incremented. | | Parameters : dummy - description of parameter dummy | +------------------------------------------------------------------------------ */ GLOBAL BOOL ru_handle_n3104 ( void) { UBYTE result = FALSE; TRACE_FUNCTION( "ru_handle_n3104" ); if(grlc_data->ru.ti) { grlc_data->ru.N3104 = (UBYTE)grlc_data->ru.cnt_ts; if(grlc_data->ru.N3104 EQ grlc_data->ru.N3104_MAX) { result = TRUE; vsi_t_stop(GRLC_handle,T3166); } } return result; } /* ru_handle_n3104() */ /* +------------------------------------------------------------------------------ | Function : ru_send_control_block +------------------------------------------------------------------------------ | Description : The function ru_send_control_block() sends a control block | instead of RLC data block | | Parameters : dummy - description of parameter dummy | +------------------------------------------------------------------------------ */ GLOBAL void ru_send_control_block ( void ) { UBYTE index; TRACE_FUNCTION( "ru_send_control_block" ); #ifdef _SIMULATION_ memset( &grlc_data->ru.ul_data[grlc_data->ru.write_pos_index], 0, sizeof( T_ul_data ) ); #endif /* #ifdef _SIMULATION_ */ grlc_data->ru.ul_data[grlc_data->ru.write_pos_index].block_status = 2; index = tm_cpy_ctrl_blk_to_buffer ( ( UBYTE* )grlc_data->ru.ul_data[grlc_data->ru.write_pos_index].ul_block ); #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[grlc_data->ru.write_pos_index]), sizeof(T_ul_data)); PSEND(hCommL1,mac_data_req); } TRACE_EVENT_P1("wpi %d",grlc_data->ru.write_pos_index); #else /* #ifdef _SIMULATION_ */ { TRACE_MEMORY_PRIM ( hCommGRLC, hCommL1, MAC_DATA_REQ, &grlc_data->ru.ul_data[grlc_data->ru.write_pos_index], sizeof(T_ul_data) ); } #endif /* #ifdef _SIMULATION_ */ { UBYTE* ul_block = ( UBYTE* )grlc_data->ru.ul_data[grlc_data->ru.write_pos_index].ul_block; TRACE_BINDUMP( hCommGRLC, TC_USER4, cl_rlcmac_get_msg_name ( ( UBYTE )( ul_block[1] >> 2 ), RLC_MAC_ROUTE_UL ), ul_block, MAX_L2_FRAME_SIZE ); /*lint !e569*/ } grlc_data->ru.write_pos_index++; grlc_data->ru.ul_data[grlc_data->ru.write_pos_index].block_status = 0; grlc_data->ru.pl_retrans_current.blk[grlc_data->ru.pl_retrans_current.cnt] = index + OFFSET_CTRL_BLOCK_IDX; grlc_data->ru.pl_retrans_current.cnt++; grlc_data->ru.nts--; } /* ru_send_control_block() */ /* +------------------------------------------------------------------------------ | Function : ru_stall_ind +------------------------------------------------------------------------------ | Description : The function ru_stall_ind() handles the stall indication. | If stall indication occurs, the the window is retransmitted if | uplink PDCHs are available. | | Parameters : dummy - description of parameter dummy | +------------------------------------------------------------------------------ */ GLOBAL void ru_stall_ind ( void) { TRACE_FUNCTION( "ru_stall_ind" ); /* set the si bit */ grlc_data->ru.rlc_data[grlc_data->ru.last_si_block & WIN_MOD].header.mac |= 0x02; /* send block with set si bit */ ru_send_mac_data_req(grlc_data->ru.last_si_block); /* reset the si bit */ grlc_data->ru.rlc_data[grlc_data->ru.last_si_block & WIN_MOD].header.mac &= 0xFD; grlc_data->ru.last_si_block = (grlc_data->ru.last_si_block+1) & 0x7F; if(grlc_data->ru.last_si_block EQ grlc_data->ru.vs) grlc_data->ru.last_si_block = grlc_data->ru.va ; } /* ru_stall_ind() */ /* +------------------------------------------------------------------------------ | Function : ru_new_data +------------------------------------------------------------------------------ | Description : The function ru_new_data() calculates the next in sequence data | and transmits it. | | Parameters : dummy - description of parameter dummy | +------------------------------------------------------------------------------ */ GLOBAL void ru_new_data ( void) { TRACE_FUNCTION( "ru_new_data" ); ru_calc_rlc_data_block(grlc_data->ru.vs); ru_send_mac_data_req(grlc_data->ru.vs); grlc_data->ru.rlc_data[grlc_data->ru.vs & WIN_MOD].cnt_pl_trans = 0; /*first try to transmit*/ grlc_data->ru.vs = (grlc_data->ru.vs+1) & 0x7F /*mod 128*/; } /* ru_new_data() */ /* +------------------------------------------------------------------------------ | Function : ru_reorg_l1 +------------------------------------------------------------------------------ | Description : The function ru_reorg_l1() recalculates data blocks which are | passed to l1 but wasn´t sent due to usf only after succesfull | contention resolution or change of coding scheme. | | Parameters : sent_blks_i - description of parameter dummy | +------------------------------------------------------------------------------ */ GLOBAL void ru_reorg_l1 ( UBYTE sent_blks_i ) { UBYTE cnt_reog_blks; /* number of reorged blks */ UBYTE reorged_blks = 0; /*counts the number of modified blocks*/ UBYTE i, bsn; TRACE_FUNCTION( "ru_reorg_l1" ); cnt_reog_blks = grlc_data->ru.nts_max - sent_blks_i; for (i=0; i < cnt_reog_blks; i++) { UBYTE index; index = grlc_data->ru.pl_retrans_current.cnt - 1 - i; bsn = grlc_data->ru.pl_retrans_current.blk[index]; if(bsn <= BSN_MAX) { #ifdef _SIMULATION_ TRACE_EVENT_P1("bsn %d",bsn); #endif if(!grlc_data->ru.rlc_data[bsn & WIN_MOD].cnt_pl_trans) {/* not transmitted over physical link */ UBYTE cnt_data_parts; reorged_blks++; grlc_data->ru.vs--; grlc_data->ru.vs = grlc_data->ru.vs & 0x7F; cnt_data_parts = grlc_data->ru.rlc_data[bsn & WIN_MOD].data_cnt - 1; grlc_data->ru.sdu_len += (grlc_data->ru.rlc_data[bsn & WIN_MOD].data[cnt_data_parts].l_buf/8); grlc_data->ru.sdu_off = (grlc_data->ru.rlc_data[bsn & WIN_MOD].data[cnt_data_parts].o_buf/8); grlc_data->ru.rlc_octet_cnt += (grlc_data->ru.rlc_data[bsn & WIN_MOD].data[cnt_data_parts].l_buf/8); if(cnt_data_parts) grlc_data->ru.sdu_len = 0; /* pdu bound in block*/ while(cnt_data_parts--) { grlc_data->ru.sdu_len += (grlc_data->ru.rlc_data[bsn & WIN_MOD].data[cnt_data_parts].l_buf/8); grlc_data->ru.sdu_off = grlc_data->ru.rlc_data[bsn & WIN_MOD].data[cnt_data_parts].o_buf/8; grlc_data->ru.rlc_octet_cnt += (grlc_data->ru.rlc_data[bsn & WIN_MOD].data[cnt_data_parts].l_buf/8); grlc_data->ru.next_prim = grlc_data->ru.active_prim; grlc_data->ru.active_prim = grlc_data->prim_queue[grlc_data->ru.active_prim].previous; grlc_data->prim_queue[grlc_data->ru.active_prim].last_bsn = grlc_data->prim_queue[grlc_data->ru.next_prim].last_bsn; TRACE_EVENT("parts of pdu present"); } /* * handle pdu parametes */ if((grlc_data->ru.rlc_data[bsn & WIN_MOD].header.mac & 0x3C) EQ 0) /* countdown value is equal 0*/ { grlc_data->ru.pdu_rem += grlc_data->ru.rlc_data[bsn & WIN_MOD].data_cnt; grlc_data->ru.pdu_sent -= grlc_data->ru.rlc_data[bsn & WIN_MOD].data_cnt; } else if(grlc_data->ru.rlc_data[bsn & WIN_MOD].header.li_cnt AND ((grlc_data->ru.rlc_data[bsn & WIN_MOD].header.li_me[grlc_data->ru.rlc_data[bsn & WIN_MOD].header.li_cnt-1] & 0xFC) EQ 0)) { grlc_data->ru.pdu_rem += grlc_data->ru.rlc_data[bsn & WIN_MOD].data_cnt; grlc_data->ru.pdu_sent -= grlc_data->ru.rlc_data[bsn & WIN_MOD].data_cnt; } else { grlc_data->ru.pdu_rem += grlc_data->ru.rlc_data[bsn & WIN_MOD].header.li_cnt; grlc_data->ru.pdu_sent -= grlc_data->ru.rlc_data[bsn & WIN_MOD].header.li_cnt; } if(grlc_data->ru.state EQ RU_REL_ACK) { SET_STATE(RU,RU_ACK); } else if(grlc_data->ru.state EQ RU_REL_UACK) { SET_STATE(RU,RU_UACK); } /* * Stop Countdown procedure, if bsn was the first block with CV NEQ 15 */ if(grlc_data->ru.cd_active AND (grlc_data->ru.rlc_data[((--bsn) & 0x7F) & WIN_MOD].header.mac & 0x3C) EQ 15) { TRACE_EVENT_P4("stop CNT DWN during reorg bsn-1 =%d bs_cv_max=%d,ru.cv=%d rlc_oc_ctn=%ld" ,((bsn--) & 0x7F) ,grlc_data->uplink_tbf.bs_cv_max ,grlc_data->ru.cv ,grlc_data->ru.rlc_octet_cnt); grlc_data->ru.cd_active = FALSE; ru_set_prim_queue(grlc_data->ru.cd_active); } } else { /* * block was once transmitted over physical link */ reorged_blks++; /* TRACE_EVENT("block was transmitted over pl link, do not modify"); */ } } else { TRACE_EVENT("CTRL BLK in L1 queue: reorg not needed"); } } if(reorged_blks) { grlc_data->ru.write_pos_index -= reorged_blks; grlc_data->ru.pl_retrans_current.cnt -= reorged_blks; memset(&grlc_data->ru.pl_retrans_current.blk[grlc_data->ru.pl_retrans_current.cnt], 0xFF, reorged_blks); } ru_recalc_rlc_oct_cnt(); } /* ru_reorg_l1() */ /* +------------------------------------------------------------------------------ | Function : ru_del_prim_in_uack_mode +------------------------------------------------------------------------------ | Description : The function ru_del_prim_in_uack_mode() deletes primitvies in | rlc unackknowledged mode | | Parameters : dummy - description of parameter dummy | +------------------------------------------------------------------------------ */ GLOBAL void ru_del_prim_in_uack_mode ( UBYTE rlc_blocks_sent_i) { UBYTE highest_bsn = BSN_MAX + 1; /* this represents the highest bsn sent on air */ UBYTE counter = 0; TRACE_FUNCTION( "ru_del_prim_in_uack_mode" ); for(counter = rlc_blocks_sent_i;counter > 0;counter--) { highest_bsn = grlc_data->ru.pl_retrans_current.blk[counter-1]; if( highest_bsn < (BSN_MAX + 1) ) { /* data block has been transmitted on air, valid bsn found. */ highest_bsn=(highest_bsn+1) & BSN_MAX; if(grlc_data->ru.cv NEQ 0) { ru_delete_prims(highest_bsn); } else if((grlc_data->ru.cv EQ 0) AND (grlc_data->ru.count_cv_0 EQ 4)) { ru_delete_prims(highest_bsn); } break; } /* if highest_bsn is greater than BSN_MAX then it is a control block. we should check in * next radio block */ } } /* ru_del_prim_in_uack_mode() */ /* +------------------------------------------------------------------------------ | Function : ru_handle_timers +------------------------------------------------------------------------------ | Description : The function ru_handle_timers handles the following timers: | T3164, T3166, T3180, T3182, T3198 | | Parameters : dummy - description of parameter dummy | +------------------------------------------------------------------------------ */ GLOBAL void ru_handle_timers ( UBYTE rlc_blocks_sent_i) { UBYTE i; TRACE_FUNCTION( "ru_handle_timers" ); /* * start timter T3198, l1 has transmitted a block */ for(i=0 ; i < rlc_blocks_sent_i;i++) { if (grlc_data->ru.pl_retrans_current.blk[i] <= BSN_MAX ) ru_set_T3198(grlc_data->ru.pl_retrans_current.blk[i]); } /* * first usf is read: stop T3164; wait for first ack/nack: start T3166 */ if( rlc_blocks_sent_i AND grlc_data->ru.first_usf) { vsi_t_stop(GRLC_handle,T3164); grlc_data->ru.first_usf = FALSE; grlc_data->t3164_to_cnt = 0; } if(grlc_data->ru.ti AND rlc_blocks_sent_i AND (!grlc_data->ru.cnt_ts)) { /* * Only started in phase access when first data block was sent * in case of fixed allocation, after sending the first rlc data block * T3166 must be started(Wait for the first acknowledge). */ vsi_t_start(GRLC_handle,T3166,T3166_VALUE); } /* * start T3182 if at stall indication or * start T3182 if final data block was sent or * restart T3180 if a data block was sent, only in dynamic allocation */ if (rlc_blocks_sent_i AND grlc_data->uplink_tbf.mac_mode EQ CGRLC_MAC_MODE_DA) { vsi_t_stop(GRLC_handle,T3180); vsi_t_start(GRLC_handle,T3180,T3180_VALUE); } if( grlc_data->ru.last_bsn EQ LAST_BSN_STALL_CONDITION AND (grlc_t_status( T3182 ) EQ 0)) { vsi_t_start(GRLC_handle,T3182,T3182_VALUE); TRACE_EVENT_P6("SI:T3182 is started: vs=%d va=%d dl_fn=%ld rlc_bs=%d bsn[0]=%d bsn[1]=%d" ,grlc_data->ru.vs ,grlc_data->ru.va ,grlc_data->dl_fn ,rlc_blocks_sent_i ,grlc_data->ru.pl_retrans_current.blk[0] ,grlc_data->ru.pl_retrans_current.blk[1]); } else if( (grlc_data->ru.last_bsn EQ LAST_BSN_IS_SENT) AND (grlc_t_status( T3182 ) EQ 0) /* timer is not running */ AND (!grlc_data->ru.nr_nacked_blks)) { vsi_t_start(GRLC_handle,T3182,T3182_VALUE); TRACE_EVENT_P3("T3182 started : vs=%d va=%d last_bsn=%d " ,grlc_data->ru.vs ,grlc_data->ru.va ,grlc_data->ru.last_bsn); } /* else { TRACE_EVENT_P6("NO TIMER START: vs=%d va=%d last_bsn=%d t3182=%ld t3180=%d rlc_blocks_sent_i=%d" ,grlc_data->ru.vs ,grlc_data->ru.va ,grlc_data->ru.last_bsn ,grlc_t_status( T3182 ) ,grlc_t_status( T3180 ) ,rlc_blocks_sent_i); } */ } /* ru_handle_timers() */ /* +------------------------------------------------------------------------------ | Function : ru_handle_nts +------------------------------------------------------------------------------ | Description : The function ru_handle_nts recalutates the parameter | grlc_data->ru.nts in case of layer 1 queue reorganisation | | Parameters : dummy - description of parameter dummy | +------------------------------------------------------------------------------ */ GLOBAL void ru_handle_nts (UBYTE rlc_blocks_sent_i) { UBYTE i; TRACE_FUNCTION( "ru_handle_nts" ); if( grlc_data->testmode.mode EQ CGRLC_LOOP AND (rlc_blocks_sent_i < grlc_data->ru.nts_max) ) { TRACE_EVENT_P2("TESTMODE B REORG L1: blk_sent = %d nts=nts_max=%d",rlc_blocks_sent_i,grlc_data->ru.nts_max); grlc_data->ru.reorg_l1_needed = TRUE; } grlc_data->ru.nts = rlc_blocks_sent_i; /* * check whether there is a reorganisation of the tansmit queue needed * due to pending control blocks */ if( tm_get_num_ctrl_blck( ) NEQ 0 ) { grlc_data->ru.reorg_l1_needed = TRUE; } if( grlc_data->ru.reorg_l1_needed AND (rlc_blocks_sent_i < grlc_data->ru.nts_max ) AND grlc_data->ru.pl_retrans_current.cnt AND grlc_data->ru.pl_retrans_current.blk[0] NEQ 0xFF) /* dummy blocks in queue*/ { ru_reorg_l1(rlc_blocks_sent_i); grlc_data->ru.nts = grlc_data->ru.nts_max; } else if (!grlc_data->ru.pl_retrans_current.cnt) { /* no data block in queue, put max nuber in queue*/ grlc_data->ru.nts = grlc_data->ru.nts_max; } /********otherwise check if a positive acknowledged block is queue**********/ else { for(i=0; i < grlc_data->ru.pl_retrans_current.cnt;i++) { if(grlc_data->ru.pl_retrans_current.blk[i] <= BSN_MAX AND (grlc_data->ru.vb[grlc_data->ru.pl_retrans_current.blk[i] & WIN_MOD] EQ VB_ACKED)) { grlc_data->ru.nts = (grlc_data->ru.nts_max -i); grlc_data->ru.pl_retrans_current.cnt -= (grlc_data->ru.nts - rlc_blocks_sent_i); memset(&grlc_data->ru.pl_retrans_current.blk[i], 0xFF, grlc_data->ru.nts); grlc_data->ru.write_pos_index -= grlc_data->ru.nts - rlc_blocks_sent_i; break; } } } /***********************check if a bsn_ret block is in queue*****************/ for(i=0; i < grlc_data->ru.pl_retrans_current.cnt;i++) { if(grlc_data->ru.pl_retrans_current.blk[i] EQ grlc_data->ru.bsn_ret) { grlc_data->ru.bsn_ret = ru_set_next_bsn_ret(); } } /****************************************************************************/ grlc_data->ru.reorg_l1_needed = FALSE; } /* ru_handle_nts() */ /* +------------------------------------------------------------------------------ | Function : ru_check_pl_ret +------------------------------------------------------------------------------ | Description : handles the restart of timer T3198, and first call of RU | (to stop T3164) | | Parameters : rlc_blocks_sent_i - number of needed blocks by PL(is equal to | the number of sent blocks in the previous radio block) | +------------------------------------------------------------------------------ */ GLOBAL void ru_check_pl_ret ( UBYTE rlc_blocks_sent_i) { UBYTE i; UBYTE bsn; TRACE_FUNCTION( "ru_check_pl_ret" ); /* * handle the sent blocks */ for(i=0;i<rlc_blocks_sent_i;i++) { bsn = grlc_data->ru.pl_retrans_current.blk[i]; /* * chek if the range is OK */ if( bsn <= BSN_MAX ) /* data block was sent */ { /* * trace parametes: 1. retranmission counter, byte counter */ grlc_data->ru.rlc_data[bsn & WIN_MOD].cnt_pl_trans++; if(grlc_data->ru.rlc_data[bsn & WIN_MOD].cnt_pl_trans > 1) grlc_data->tbf_ctrl[grlc_data->ul_index].ret_bsn++; else { UBYTE j; for(j=0;j<grlc_data->ru.rlc_data[bsn & WIN_MOD].data_cnt;j++) grlc_data->tbf_ctrl[grlc_data->ul_index].rlc_oct_cnt +=grlc_data->ru.rlc_data[bsn & WIN_MOD].data[j].l_buf/8; } /* * a retransmitted block was sent */ if(bsn EQ grlc_data->ru.bsn_ret) { grlc_data->ru.bsn_ret = ru_set_next_bsn_ret(); } /* * last bsn is sent */ if((grlc_data->ru.rlc_data[bsn & WIN_MOD].header.mac & 0x3C) EQ 0) /* countdown value is equal 0*/ { grlc_data->ru.last_bsn = LAST_BSN_IS_SENT; } else if(bsn EQ ((grlc_data->ru.va+WIN_SIZE-1) & 0x7F) AND (grlc_data->ru.last_bsn NEQ LAST_BSN_STALL_CONDITION)) { /* * stall indication detected */ grlc_data->ru.last_bsn = LAST_BSN_STALL_CONDITION; TRACE_EVENT_P6("NEXT DATA STALL INDICATION bsn=%d va=%d vs=%d cnt_ts=%d last_bsn=%ld dl_fn=%ld" ,bsn ,grlc_data->ru.va ,grlc_data->ru.vs ,grlc_data->ru.cnt_ts ,grlc_data->ru.last_bsn ,grlc_data->dl_fn); } } else if( bsn >= OFFSET_CTRL_BLOCK_IDX AND bsn < 0xFF ) /* control block was sent */ { sig_ru_tm_ctrl_blk_sent( (UBYTE)( bsn - OFFSET_CTRL_BLOCK_IDX ) ); } else if (bsn EQ 0xFF) { /* nothing to do : dummy block sent*/ } else /*invalid block was sent, should not appear */ { TRACE_ERROR("INVALID bsn range neither data or control block"); TRACE_EVENT("INVALID bsn range neither data or control block"); TRACE_EVENT_P1("bsn = %d ", bsn); } } ru_handle_timers(rlc_blocks_sent_i); /******************delete sent blocks from pl_retrans_current**************/ memcpy(grlc_data->ru.pl_retrans_current.blk, &grlc_data->ru.pl_retrans_current.blk[rlc_blocks_sent_i], (grlc_data->ru.nts_max - rlc_blocks_sent_i)); grlc_data->ru.pl_retrans_current.cnt -= rlc_blocks_sent_i; grlc_data->ru.cnt_ts += rlc_blocks_sent_i; } /* ru_check_pl_ret() */ /* +------------------------------------------------------------------------------ | Function : ru_send_ul_dummy_block +------------------------------------------------------------------------------ | Description : The function ru_send_ul_dummy_block() sends a uplink dummy | control block instead of RLC data block | | Parameters : dummy - description of parameter dummy | +------------------------------------------------------------------------------ */ GLOBAL void ru_send_ul_dummy_block ( void ) { MCAST (ul_dummy,U_GRLC_UL_DUMMY); TRACE_FUNCTION( "ru_send_ul_dummy_block" ); memset(&grlc_data->ru.ul_data[grlc_data->ru.write_pos_index], 0, sizeof(T_ul_data)); grlc_data->ru.ul_data[grlc_data->ru.write_pos_index].block_status = 2; /* * set uplink dummy block */ ul_dummy->msg_type = U_GRLC_UL_DUMMY_c; grlc_set_buf_tlli( &ul_dummy->tlli_value, grlc_data->uplink_tbf.tlli ); grlc_encode_ul_ctrl_block( ( UBYTE* ) grlc_data->ru.ul_data[grlc_data->ru.write_pos_index].ul_block, ( UBYTE* )ul_dummy ); #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[grlc_data->ru.write_pos_index]), sizeof(T_ul_data)); PSEND(hCommL1,mac_data_req); } TRACE_EVENT_P1("wpi %d",grlc_data->ru.write_pos_index); #else /* #ifdef _SIMULATION_ */ { TRACE_MEMORY_PRIM ( hCommGRLC, hCommL1, MAC_DATA_REQ, &grlc_data->ru.ul_data[grlc_data->ru.write_pos_index], sizeof(T_ul_data) ); } #endif /* #ifdef _SIMULATION_ */ { UBYTE* ul_block = ( UBYTE* )grlc_data->ru.ul_data[grlc_data->ru.write_pos_index].ul_block; TRACE_BINDUMP( hCommGRLC, TC_USER5, cl_rlcmac_get_msg_name ( ( UBYTE )( ul_block[1] >> 2 ), RLC_MAC_ROUTE_UL ), ul_block, MAX_L2_FRAME_SIZE ); /*lint !e569*/ } grlc_data->ru.write_pos_index++; grlc_data->ru.ul_data[grlc_data->ru.write_pos_index].block_status = 0; grlc_data->ru.pl_retrans_current.blk[grlc_data->ru.pl_retrans_current.cnt] = 255; grlc_data->ru.pl_retrans_current.cnt++; grlc_data->ru.nts--; } /* ru_send_ul_dummy_block() */ /* +------------------------------------------------------------------------------ | Function : ru_handle_stall_ind +------------------------------------------------------------------------------ | Description : The function ru_handle_stall_ind() checks, if there was a stall | condition, and if it is canceled. | | Parameters : dummy - description of parameter dummy | +------------------------------------------------------------------------------ */ GLOBAL void ru_handle_stall_ind ( void ) { TRACE_FUNCTION( "ru_handle_stall_ind" ); if(grlc_data->ru.last_bsn EQ LAST_BSN_STALL_CONDITION) { if(!(grlc_data->ru.vs EQ ((grlc_data->ru.va + WIN_SIZE) & 0x7F))) {/*stall condition eliminated*/ grlc_data->ru.reorg_l1_needed = TRUE; /* remove stalled blocks from data queue */ vsi_t_stop(GRLC_handle,T3182); ru_handle_n3102(PAN_INC); if(grlc_data->ru.rlc_mode EQ CGRLC_RLC_MODE_UACK) { /*resume with data transfer after stall indication in rlc unacknowledged problem*/ grlc_data->ru.last_bsn = LAST_BSN_RESUME_UACK_MODE_AFTER_SI; } else { grlc_data->ru.last_bsn = LAST_BSN_NOT_BULIT; } } } else { ru_handle_n3102(PAN_INC); grlc_data->ru.last_si_block = grlc_data->ru.va; } } /* ru_handle_stall_ind() */ /* +------------------------------------------------------------------------------ | Function : ru_handle_tbf_start_in_ptm +------------------------------------------------------------------------------ | Description : The function ru_handle_tbf_start_in_ptm() modifies the parameters | for the tbf at reaching the starting time | | Parameters : rlc_blocks_sent_i - number of blocks sent in current in radio block | return value is set, if only nts is decrased and not all blocks are sent | +------------------------------------------------------------------------------ */ GLOBAL void ru_handle_tbf_start_in_ptm ( UBYTE rlc_blocks_sent_i ) { UBYTE ctrl_blk_active_idx; BOOL realloc_prr_allowed = FALSE; TRACE_FUNCTION( "ru_handle_tbf_start_in_ptm" ); /* * reassignment of uplink and tbf starting time elapsed, received either with packet uplink assignment * or packet timeslot reconfigure */ if(grlc_data->ul_tfi_changed) { if((rlc_blocks_sent_i < grlc_data->ru.nts_max) AND /* nr of locks which are not sent */ (grlc_data->ru.cs_type EQ grlc_data->ru.next_tbf_params.cs_type) AND /* coding scheme has not changed */ (grlc_data->ru.nts_max <= grlc_data->ru.next_tbf_params.nts)) /* nts increased or equal */ { UBYTE i, bsn[4],cnt; /* * change the tfi for blocks which are in l1 queue */ cnt = grlc_data->ru.pl_retrans_current.cnt; bsn[0] = grlc_data->ru.pl_retrans_current.blk[0]; bsn[1] = grlc_data->ru.pl_retrans_current.blk[1]; grlc_data->ru.pl_retrans_current.cnt = 0; for (i = 0; i< cnt;i++) { if(bsn[i] <= BSN_MAX) { grlc_data->ru.write_pos_index--; ru_send_mac_data_req(bsn[i]); TRACE_EVENT_P1("bsn %d modified while tfi is changed",bsn[i]); } else { TRACE_EVENT_P1("bsn %d :TFI FOR CTRL BLOCK CHANGED. no modification",bsn[i]); } } } grlc_data->ul_tfi_changed = FALSE; } grlc_data->ru.tlli_cs_type = grlc_data->ru.next_tbf_params.tlli_cs_type; if(grlc_data->ru.cs_type NEQ grlc_data->ru.next_tbf_params.cs_type) { TRACE_EVENT_P2("UL assign: CS changed from %d to %d ",grlc_data->ru.cs_type,grlc_data->ru.next_tbf_params.cs_type); grlc_data->ru.cs_type = grlc_data->ru.next_tbf_params.cs_type; ru_change_of_cs(grlc_data->ru.cs_type); } if(grlc_data->ru.nts_max < grlc_data->ru.next_tbf_params.nts) { TRACE_EVENT_P6("nts increased from %d to %d, tfi=%d,cnt_ts=%d,vs=%d,va=%d", grlc_data->ru.nts_max, grlc_data->ru.next_tbf_params.nts, grlc_data->ul_tfi, grlc_data->ru.cnt_ts, grlc_data->ru.vs, grlc_data->ru.va); grlc_data->ru.nts = (grlc_data->ru.next_tbf_params.nts - grlc_data->ru.nts_max); grlc_data->ru.nts_max = grlc_data->ru.next_tbf_params.nts; while( grlc_data->ru.nts AND tm_get_num_ctrl_blck( ) NEQ 0 AND ru_ctrl_blk_selection_allowed() ) { /* * next uplink block is a control block, * check if countdown procedure is statred or not */ ru_send_control_block( ); } while(grlc_data->ru.nts) { ctrl_blk_active_idx = ru_peek_for_ctrl_blk(); if ((ctrl_blk_active_idx EQ 0xFF) OR realloc_prr_allowed EQ TRUE) /*No control block , form data block*/ { while(grlc_data->ru.nts AND grlc_data->ru.sdu_len) { ru_new_data(); } while(grlc_data->ru.nts) { ru_ret_bsn(); } realloc_prr_allowed = FALSE; break; } else { TRACE_EVENT_P1("reallocation of llc pdu (index)=%d",ctrl_blk_active_idx); /* if already one PRR in L1 Buffer , replace it with new PRR */ if (grlc_data->ru.pl_retrans_current.blk[0] EQ (BLK_INDEX_TM + OFFSET_CTRL_BLOCK_IDX)) { grlc_data->ru.write_pos_index--; grlc_data->ru.pl_retrans_current.cnt--; grlc_data->ru.nts++; TRACE_EVENT("prr in l1 buffer queue,replace with new prr"); } sig_ru_tm_end_of_pdu(ctrl_blk_active_idx); ru_send_control_block(); realloc_prr_allowed = TRUE; } } if(grlc_data->ru.cv EQ 0 AND grlc_data->ru.rlc_mode EQ CGRLC_RLC_MODE_ACK ) { SET_STATE(RU,RU_REL_ACK); } else if(grlc_data->ru.rlc_mode EQ CGRLC_RLC_MODE_ACK) { SET_STATE(RU,RU_ACK); } else if(grlc_data->ru.cv EQ 0 AND grlc_data->ru.rlc_mode EQ CGRLC_RLC_MODE_UACK ) { SET_STATE(RU,RU_REL_UACK); } else if(grlc_data->ru.rlc_mode EQ CGRLC_RLC_MODE_UACK) { SET_STATE(RU,RU_UACK); } else { TRACE_EVENT_P2("RLC MODE ??? cv=%d rlc_mode=%d",grlc_data->ru.cv,grlc_data->ru.rlc_mode); } } else if(grlc_data->ru.nts_max > grlc_data->ru.next_tbf_params.nts) { /* Reorg layer 1 */ ru_reorg_l1((UBYTE)(rlc_blocks_sent_i)); TRACE_EVENT_P7("nts decrased from %d to %d tfi=%d,cnt_ts=%d,va=%d,vs=%d blk_s=%d ", grlc_data->ru.nts_max, grlc_data->ru.next_tbf_params.nts, grlc_data->ul_tfi, grlc_data->ru.cnt_ts, grlc_data->ru.va, grlc_data->ru.vs, rlc_blocks_sent_i); grlc_data->ru.nts_max = grlc_data->ru.next_tbf_params.nts; } else { TRACE_EVENT_P6("ul tbf reassignment with tfi=%d,cnt_ts=%d,va=%d,vs=%d,nts_max=%d tbf_st_time=%ld", grlc_data->ul_tfi, grlc_data->ru.cnt_ts, grlc_data->ru.va, grlc_data->ru.vs, grlc_data->ru.nts_max, grlc_data->ul_tbf_start_time); } grlc_data->ru.v_next_tbf_params = FALSE; } /* ru_handle_tbf_start_in_ptm() */ /* +------------------------------------------------------------------------------ | Function : ru_switch_ul_buffer +------------------------------------------------------------------------------ | Description : The function ru_switch_ul_buffer () .... | | Parameters : - | +------------------------------------------------------------------------------ */ GLOBAL void ru_switch_ul_buffer ( UBYTE rlc_blocks_sent_i ) { UBYTE i; TRACE_FUNCTION( "ru_switch_ul_buffer " ); /* * switch uplink buffer, it means, rlc blocks which are not sent * by PL are switched to the top of the ul buffer */ if (rlc_blocks_sent_i) { i = rlc_blocks_sent_i; while((i < MAX_UL_TN) AND (grlc_data->ru.ul_data[i].block_status NEQ 0)) { grlc_data->ru.ul_data[i - rlc_blocks_sent_i] = grlc_data->ru.ul_data[i]; i++; } grlc_data->ru.write_pos_index -= rlc_blocks_sent_i; } } /* ru_switch_ul_buffer () */ /* +------------------------------------------------------------------------------ | Function : ru_cgrlc_st_time_ind +------------------------------------------------------------------------------ | Description : The function ru_cgrlc_st_time_ind () informs higher layers | that the starting time is elapsed | | Parameters : - | +------------------------------------------------------------------------------ */ GLOBAL void ru_cgrlc_st_time_ind ( void ) { PALLOC(cgrlc_starting_time_ind,CGRLC_STARTING_TIME_IND); /* T_CGRLC_STARTING_TIME_IND */ TRACE_FUNCTION( "ru_cgrlc_st_time_ind " ); cgrlc_starting_time_ind->tbf_mode = CGRLC_TBF_MODE_UL; cgrlc_starting_time_ind->tfi = grlc_data->ul_tfi; PSEND(hCommGRR,cgrlc_starting_time_ind); grlc_data->ul_tn_mask = grlc_data->uplink_tbf.ts_mask; } /* ru_cgrlc_st_time_ind () */ /* +------------------------------------------------------------------------------ | Function : ru_ctrl_blk_selection_allowed +------------------------------------------------------------------------------ | Description : This function gets called from sig_gff_ru_mac_ready_ind handler | and also from the function which handles ul reassignment | (ru_handle_tbf_start_in_ptm). In mac ready indicate handler | this is calld only when ru is in rel_ack state. | This function returns true or false according to the following | table. The table applies for uack mode also. | When this function returns true, then control block should be | selected for transmission by RU. | When it returns False, then control block is selected by RD. | | ru_rel_ack state rd_rel_ack - TRUE | ru_ack rd_ack - TRUE | ru_ack rd_rel_ack - TRUE | ru_rel_ack rd_ack - FALSE | ru_ack NO DL TBF(rd_null) - TRUE | ru_rel_ack NO DL TBF(rd_null) - TRUE | | This function should be called only in PTM. | | Parameters : None +------------------------------------------------------------------------------ */ GLOBAL BOOL ru_ctrl_blk_selection_allowed() { BOOL ru_in_release_mode = FALSE, ctrl_blk_allowed = TRUE, dl_release_started = TRUE; if(grlc_data->tbf_type EQ TBF_TYPE_CONC) { /* In ru_send_pca stete, ctrl blocks are not sent. No need to * check for that here. */ if((GET_STATE(RU) EQ RU_REL_ACK) OR (GET_STATE(RU) EQ RU_REL_UACK)) { ru_in_release_mode = TRUE; } sig_ru_rd_get_downlink_release_state(&dl_release_started); /* rd_rel_state would be true if fbi=1 has been received * in downlink. */ if(ru_in_release_mode AND (dl_release_started EQ FALSE) ) { ctrl_blk_allowed = FALSE; } } return ctrl_blk_allowed; } /* +------------------------------------------------------------------------------ | Function : ru_peek_for_ctrl_blk +------------------------------------------------------------------------------ | Description : The function would peek to see if there is reallocation set, | then it returns TRUE, so that PRR can be constructed. | Also if the rlc block has more than one llc pdu with re-allocation | set , then prr os sent for the latest llc pdu. | Parameters : None. | +------------------------------------------------------------------------------ */ #ifndef CF_FAST_EXEC GLOBAL UBYTE ru_peek_for_ctrl_blk() { BOOL ctrlblk_found = FALSE; USHORT rlc_len; USHORT sdu_len; UBYTE active_prim,next_prim,active_prr_idx = 0xFF; TRACE_FUNCTION( "ru_peek_for_ctrl_blk" ); sdu_len = grlc_data->ru.sdu_len; active_prim = grlc_data->ru.active_prim; next_prim = grlc_data->ru.next_prim; rlc_len = grlc_data->ru.rlc_data_size; while ( (sdu_len < rlc_len) AND (sdu_len > 0) ) { rlc_len -= sdu_len + 1; /* 1 is for length indicator */ if (!grlc_data->ru.cd_active) { ctrlblk_found = ru_peek_next_sdu(&sdu_len,&active_prim,&next_prim); active_prr_idx = ctrlblk_found ? active_prim:0xFF; } else { #ifdef _SIMULATION_ TRACE_EVENT("countdown in progress and extended tbf not supported,cant build PRR"); #endif return active_prr_idx; } } return (ctrlblk_found ? active_prr_idx : 0xFF); }/*ru_peek_for_ctrl_blk*/ #endif /* CF_FAST_EXEC */ /* +------------------------------------------------------------------------------ | Function : ru_peek_next_sdu +------------------------------------------------------------------------------ | Description : The function would peek to see if there is reallocation set, | for the current llc PDU. | | Parameters : None. | +------------------------------------------------------------------------------ */ #ifndef CF_FAST_EXEC GLOBAL BOOL ru_peek_next_sdu(USHORT *sdu_len,UBYTE *active_prim,UBYTE *next_prim) { BOOL prr_build = FALSE; TRACE_FUNCTION( "ru_peek_next_sdu"); if( *next_prim NEQ 0xFF AND (grlc_data->prim_queue[*next_prim].start_new_tbf EQ 0)) { *active_prim = grlc_data->prim_queue[*active_prim].next; /* This signal allows TM to initiate resource re-allocation * if required */ prr_build = grlc_data->prim_queue[*active_prim].re_allocation; *sdu_len = grlc_data->prim_queue[*active_prim].prim_ptr->sdu.l_buf/8; *next_prim = grlc_data->prim_queue[*active_prim].next; } else { *sdu_len = 0; } return prr_build; }/*ru_peek_next_sdu*/ #endif /* CF_FAST_EXEC */