FreeCalypso > hg > fc-tourmaline
diff src/g23m-gprs/grlc/grlc_rdf.c @ 1:fa8dc04885d8
src/g23m-*: import from Magnetite
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 16 Oct 2020 06:25:50 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/g23m-gprs/grlc/grlc_rdf.c Fri Oct 16 06:25:50 2020 +0000 @@ -0,0 +1,1307 @@ +/* ++----------------------------------------------------------------------------- +| 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 RD of +| entity GRLC. ++----------------------------------------------------------------------------- +*/ + +#ifndef GRLC_RDF_C +#define GRLC_RDF_C +#endif + +#define ENTITY_GRLC + +/*==== INCLUDES =============================================================*/ + +#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_tms.h" +#include <string.h> /* memcpy */ +#include "grlc_f.h" +#include "grlc_rdf.h" +#include "grlc_meass.h" + +/*==== CONST ================================================================*/ + +/*==== LOCAL VARS ===========================================================*/ + +/*==== PRIVATE FUNCTIONS ====================================================*/ + +/*==== PUBLIC FUNCTIONS =====================================================*/ + + +/* ++------------------------------------------------------------------------------ +| Function : rd_init ++------------------------------------------------------------------------------ +| Description : The function rd_init() .... +| +| Parameters : dummy - description of parameter dummy +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void rd_init ( void ) +{ + TRACE_FUNCTION( "rd_init" ); + + /* + * UBYTE + */ + grlc_data->rd.vq = 0xFF; + grlc_data->rd.vr = 0xFF; + grlc_data->rd.li_cnt = 0xFF; + grlc_data->rd.rlc_data_len = 0xFF; + grlc_data->rd.f_ack_ind = 0xFF; + grlc_data->rd.ssn = 0xFF; + + /* + * USHORT + */ + grlc_data->rd.pdu_len = 0xFFFF; + /* + * BOOL + */ + grlc_data->rd.pdu_complete = TRUE; + grlc_data->rd.channel_req = FALSE; + grlc_data->rd.ch_req_in_ack_prog = FALSE; + grlc_data->rd.inSequence = TRUE; + /* + * struct + */ + grlc_data->rd.ptr_grlc = NULL; + grlc_data->rd.next_poll_block = NEXT_POLL_BLOCK_NONE; + + INIT_STATE(RD,RD_NULL); + +} /* rd_init() */ + + + + + +/* ++------------------------------------------------------------------------------ +| Function : rd_tbf_init ++------------------------------------------------------------------------------ +| Description : The function rd_tbf_init() .... +| +| Parameters : dummy - description of parameter dummy +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void rd_tbf_init ( void ) +{ + TRACE_FUNCTION( "rd_tbf_init" ); + + /* + * UBYTE + */ + grlc_data->rd.vq = 0; + grlc_data->rd.vr = 0; + grlc_data->rd.li_cnt = 0; + grlc_data->rd.ssn = 0; + grlc_data->rd.last_bsn = 0xFF; + grlc_data->rd.bsn_pdu_start = 0xFF; /*set to zero at receiving the first data block*/ + grlc_data->rd.cnt_sent_f_ack = 0; + grlc_data->rd.f_ack_ind = 0; + grlc_data->dl_tn_mask = grlc_data->downlink_tbf.ts_mask; + + /* + * USHORT + */ + grlc_data->rd.pdu_len = 0; + + /* + * BOOL + */ + grlc_data->rd.release_tbf = FALSE; + grlc_data->rd.pdu_complete = TRUE; + grlc_data->rd.ch_req_in_ack_prog = FALSE; + grlc_data->rd.v_next_tbf_params = FALSE; + grlc_data->rd.ignore_pdu = FALSE; + + + grlc_data->rd.fn_p_tbf_rel = 0xFFFFFFFF; + /* + * struct + */ + grlc_data->rd.rlc_mode = grlc_data->downlink_tbf.rlc_mode; + grlc_data->rd.cs_type = CS_ZERO; + /* + * arrays + */ + + memset(grlc_data->rd.data_array, 0 , WIN_SIZE * sizeof(grlc_data->rd.data_array[0]) ); + memset(grlc_data->rd.vn , VN_INVALID, WIN_SIZE * sizeof(grlc_data->rd.vn[0]) ); + memset(grlc_data->rd.li , 0 , RD_LI_CNT_MAX * sizeof(grlc_data->rd.li[0]) ); + memset(grlc_data->rd.m , 0 , RD_LI_CNT_MAX ); + +} /* rd_tbf_init() */ + + + +/* ++------------------------------------------------------------------------------ +| Function : rd_read_li_m_of_block ++------------------------------------------------------------------------------ +| Description : The function rd_read_li_m_of_block() .... +| +| Parameters : dummy - description of parameter dummy +| ++------------------------------------------------------------------------------ +*/ +GLOBAL BOOL rd_read_li_m_of_block ( UBYTE * ptr_data_i, UBYTE e_bit_i ) +{ + USHORT len_sum; + BOOL result; + + TRACE_FUNCTION( "rd_read_li_m_of_block" ); + + len_sum = 0; + grlc_data->rd.li_cnt = 0; + + while(!(e_bit_i)) + { + grlc_data->rd.li[grlc_data->rd.li_cnt] = + (ptr_data_i[grlc_data->rd.li_cnt] & 0xFC) >> 2; + grlc_data->rd.m [grlc_data->rd.li_cnt] = + (ptr_data_i[grlc_data->rd.li_cnt] & 0x02) >> 1; + e_bit_i = (ptr_data_i[grlc_data->rd.li_cnt] & 0x01); + len_sum += grlc_data->rd.li[grlc_data->rd.li_cnt]; + if((e_bit_i EQ 0) + AND (!grlc_data->rd.m [grlc_data->rd.li_cnt])) + { + /*SZML-RD/001*/ + return FALSE; + } + else if(!(grlc_data->rd.li[grlc_data->rd.li_cnt]) + AND (grlc_data->rd.m [grlc_data->rd.li_cnt])) + { + TRACE_ERROR("dl block with li=0 and m=1: NOT ALLOWED"); + return FALSE; + } + grlc_data->rd.li_cnt++; + } + + if(grlc_data->rd.li_cnt > RD_LI_CNT_MAX) + { + TRACE_EVENT_P2("li_cnt=%d RD_LI_CNT_MAX=%d",grlc_data->rd.li_cnt,RD_LI_CNT_MAX); + TRACE_ERROR("rd li_cnt bigger than RD_LI_CNT_MAX (=8)"); + TRACE_ASSERT( grlc_data->rd.li_cnt > RD_LI_CNT_MAX ); + return FALSE; + } + + /* + * check if sum of LIs is longer than a rlc data block len + */ + len_sum += grlc_data->rd.li_cnt; + if( (len_sum > grlc_data->rd.rlc_data_len) + OR + ((len_sum EQ grlc_data->rd.rlc_data_len) AND (grlc_data->rd.m [grlc_data->rd.li_cnt-1])) ) + result = FALSE; + else + result = TRUE; + + return result; + +} /* rd_read_li_m_of_block() */ + + + +/* ++------------------------------------------------------------------------------ +| Function : rd_out_grlc_data_ind ++------------------------------------------------------------------------------ +| Description : The function rd_out_grlc_data_ind() .... +| +| Parameters : dummy - description of parameter dummy +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void rd_out_grlc_data_ind( void ) +{ + T_GRLC_DATA_IND *prim_ptr; + TRACE_FUNCTION( "rd_out_grlc_data_ind" ); + + if(grlc_data->rd.ignore_pdu OR + grlc_test_mode_active()) + { + /* + * this pdu is not passed to LLC because MAX_LLC_PDU_SIZE was exceed or testmode is active + */ + grlc_data->rd.ignore_pdu = FALSE; + + TRACE_EVENT_P4("TARGET PDU END reached at will be ignored: len=%ld, bsn=pdu_start=%d vr = %d testmode=%d " + ,grlc_data->rd.pdu_len + ,grlc_data->rd.bsn_pdu_start + ,grlc_data->rd.vr + ,grlc_test_mode_active()); + + rd_free_desc_list_partions(); + return; + } + + if(grlc_data->rd.rlc_mode EQ CGRLC_RLC_MODE_ACK) + { + PALLOC_DESC (grlc_data_ind, GRLC_DATA_IND);//lint !e413 + prim_ptr = grlc_data_ind; + } + else + { + PALLOC_DESC (grlc_unitdata_ind, GRLC_UNITDATA_IND);//lint !e413 + prim_ptr = (T_GRLC_DATA_IND*)grlc_unitdata_ind; + } + + memcpy( prim_ptr, + &grlc_data->rd.grlc_data_ind, + sizeof(T_GRLC_DATA_IND) ); + PSEND(hCommLLC, prim_ptr); + + grlc_data->rd.grlc_data_ind.desc_list.first = NULL; + grlc_data->rd.pdu_complete = TRUE; + grlc_data->tbf_ctrl[grlc_data->dl_index].rlc_oct_cnt += grlc_data->rd.pdu_len; + grlc_data->tbf_ctrl[grlc_data->dl_index].pdu_cnt++; + +} /* rd_out_grlc_data_ind() */ + +#ifdef _SIMULATION_ + +/* ++------------------------------------------------------------------------------ +| Function : rd_out_grlc_data_ind_test ++------------------------------------------------------------------------------ +| Description : The function rd_out_grlc_data_ind_test() .... +| +| Parameters : dummy - description of parameter dummy +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void rd_out_grlc_data_ind_test( void ) +{ + T_NEXT_ARRAY *ptr_next_array = NULL; + T_NEXT_ARRAY *ptr_help = NULL; + UBYTE *ptr_pos = NULL,cnt=0; + USHORT sdu_len_in_bits; + T_GRLC_DATA_IND_TEST *prim_ptr = NULL; + + TRACE_FUNCTION( "rd_out_grlc_data_ind_test" ); + + + if(grlc_data->rd.ignore_pdu OR + grlc_test_mode_active()) + { + /* + * this pdu is not passed to LLC because MAX_LLC_PDU_SIZE was exceed or testmode is active + */ + grlc_data->rd.ignore_pdu = FALSE; + + TRACE_EVENT_P4("SIMULATION PDU END reached at will be ignored: len=%ld, bsn=pdu_start=%d vr = %d testmode=%d" + ,grlc_data->rd.pdu_len + ,grlc_data->rd.bsn_pdu_start + ,grlc_data->rd.vr + ,grlc_test_mode_active()); + rd_free_desc_list_partions(); + return; + } + sdu_len_in_bits = grlc_data->rd.pdu_len * 8; + + if(grlc_data->rd.rlc_mode EQ CGRLC_RLC_MODE_ACK) + { + PALLOC_SDU (grlc_data_ind_test, GRLC_DATA_IND_TEST, sdu_len_in_bits); + prim_ptr = grlc_data_ind_test; + } + else + { + PALLOC_SDU (grlc_unitdata_ind_test, GRLC_UNITDATA_IND_TEST, sdu_len_in_bits); + prim_ptr = (T_GRLC_DATA_IND_TEST*)grlc_unitdata_ind_test; + } + { + /* + * copy from description list to test primitive + */ + prim_ptr->tlli = grlc_data->downlink_tbf.tlli; + prim_ptr->sdu.l_buf = grlc_data->rd.pdu_len * 8; + prim_ptr->sdu.o_buf = 0; + ptr_next_array = + (T_NEXT_ARRAY*)grlc_data->rd.grlc_data_ind.desc_list.first; + ptr_pos = prim_ptr->sdu.buf; + cnt=0; + do + { + cnt++; + memcpy(ptr_pos, + ptr_next_array->data, + ptr_next_array->len ); + ptr_pos = &ptr_pos[ptr_next_array->len]; + ptr_next_array = (T_NEXT_ARRAY*)ptr_next_array->next; + } + while(ptr_next_array NEQ NULL); + PSEND(hCommLLC, prim_ptr); + TRACE_EVENT_P1("SEND PARTIONS =%d",cnt); + + } + + grlc_data->tbf_ctrl[grlc_data->dl_index].rlc_oct_cnt += grlc_data->rd.pdu_len; + grlc_data->tbf_ctrl[grlc_data->dl_index].pdu_cnt++; + + + /* delete blocks which are sent to LLC: only possible in test environment + * usally, deleting of the description list is task of LLC + */ + rd_free_desc_list_partions(); + +} /* rd_out_grlc_data_ind_test() */ + +#endif /* _SIMULATION_ */ + + + + +/* ++------------------------------------------------------------------------------ +| Function : rd_send_grlc_data_ind ++------------------------------------------------------------------------------ +| Description : The function rd_send_grlc_data_ind() .... +| +| Parameters : dummy - description of parameter dummy +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void rd_send_grlc_data_ind ( UBYTE bsn_i ) +{ + T_NEXT_ARRAY *ptr_block; + UBYTE pdu_cnt; + UBYTE compl_pdu; + TRACE_FUNCTION( "rd_send_grlc_data_ind" ); + + + pdu_cnt = grlc_data->rd.data_array[bsn_i & WIN_MOD].pdu_cnt; + + if(grlc_data->rd.data_array[bsn_i & WIN_MOD].pdu_complete) + compl_pdu = grlc_data->rd.data_array[bsn_i & WIN_MOD].pdu_cnt; + else if (pdu_cnt) + compl_pdu = grlc_data->rd.data_array[bsn_i & WIN_MOD].pdu_cnt -1; + else + compl_pdu = 0; + + if ((ptr_block = grlc_data->rd.data_array[bsn_i & WIN_MOD].first) EQ NULL) + { + TRACE_EVENT_P4("NO DATA IND first empty bsn=%d bsn_mod=%d vr=%d vq=%d", bsn_i, bsn_i&WIN_MOD,grlc_data->rd.vr,grlc_data->rd.vq); + return; + } + + do + { + if(grlc_data->rd.pdu_complete) + { + grlc_data->rd.ptr_grlc = ptr_block; + grlc_data->rd.grlc_data_ind.desc_list.first = (ULONG) grlc_data->rd.ptr_grlc; + grlc_data->rd.pdu_len = ptr_block->len; + grlc_data->rd.bsn_pdu_start = bsn_i; + } + else + { + grlc_data->rd.pdu_len += ptr_block->len; + grlc_data->rd.ptr_grlc->next = (ULONG*) ptr_block; + grlc_data->rd.ptr_grlc = (T_NEXT_ARRAY*) grlc_data->rd.ptr_grlc->next; + } + grlc_data->rd.pdu_complete = FALSE; + + if(grlc_data->rd.pdu_len > MAX_LLC_PDU_SIZE) + { + TRACE_EVENT_P5("PDU SIZE TO BIG = %ld pdu_st=%d vr=%d compl_pdu=%d pdu_cnt=%d" + ,grlc_data->rd.pdu_len + ,grlc_data->rd.bsn_pdu_start + ,grlc_data->rd.vr + ,compl_pdu + ,pdu_cnt); + if(!compl_pdu) + { + /* no pdu in data block */ + grlc_data->rd.ignore_pdu = TRUE; + + /* free only linked partions */ + rd_free_desc_list_partions(); + + return; + } + else + { + /* pdu boundary in data block */ + ptr_block = (T_NEXT_ARRAY*) ptr_block->next; + grlc_data->rd.ptr_grlc->next = NULL; + + /* + * free only linked partions + */ + rd_free_desc_list_partions(); + + compl_pdu--; + } + + } + else if( compl_pdu ) + { + + TRACE_EVENT_P5("GRLC_DATA_IND len=%ld bsn_start=%d bsn_end=%d las_len=%d dl_fn=%ld" + + + + + + + + + + + + + + + + + + + + + + ,grlc_data->rd.pdu_len + ,grlc_data->rd.bsn_pdu_start + ,bsn_i + ,ptr_block->len + ,grlc_data->dl_fn); + ptr_block = (T_NEXT_ARRAY*) ptr_block->next; + grlc_data->rd.ptr_grlc->next = NULL; + grlc_data->rd.grlc_data_ind.desc_list.list_len = grlc_data->rd.pdu_len; + grlc_data->rd.grlc_data_ind.tlli = grlc_data->downlink_tbf.tlli; + + #ifdef _TARGET_ + { + rd_out_grlc_data_ind(); + } + # endif + +# ifdef _SIMULATION_ + { + rd_out_grlc_data_ind_test(); + } +# endif + grlc_data->rd.pdu_complete = TRUE; + compl_pdu--; + } + if(!pdu_cnt) + pdu_cnt = 0; + else + pdu_cnt--; + } + while(pdu_cnt); + + grlc_data->rd.pdu_complete = grlc_data->rd.data_array[bsn_i & WIN_MOD].pdu_complete; + + /* + * block combined, first element reseted + */ + grlc_data->rd.data_array[bsn_i & WIN_MOD].first = NULL; + +} /* rd_send_grlc_data_ind() */ + + + +/* ++------------------------------------------------------------------------------ +| Function : rd_check_window_size ++------------------------------------------------------------------------------ +| Description : The function rd_check_window_size() .... +| +| Parameters : dummy - description of parameter dummy +| ++------------------------------------------------------------------------------ +*/ +GLOBAL BOOL rd_check_window_size ( UBYTE bsn_i ) +{ + BOOL result; + + TRACE_FUNCTION( "rd_check_window_size" ); + + if(grlc_data->rd.rlc_mode EQ CGRLC_RLC_MODE_ACK) + { + if( bsn_i >= grlc_data->rd.ssn ) + { + if((bsn_i - grlc_data->rd.ssn) < WIN_SIZE) + { + result = TRUE; + } + else + { + result = FALSE; + } + } + else + { + if((bsn_i + 128 - grlc_data->rd.ssn) < WIN_SIZE) + { + result = TRUE; + } + else + { + result = FALSE; + } + } + } + else if(grlc_data->rd.rlc_mode EQ CGRLC_RLC_MODE_UACK) + { + if( bsn_i >= grlc_data->rd.vr ) + { + if((bsn_i - grlc_data->rd.vr) < WIN_SIZE) + { + result = TRUE; + } + else + { + result = FALSE; + } + } + else + { + if((bsn_i + 128 - grlc_data->rd.vr) < WIN_SIZE) + { + result = TRUE; + } + else + { + result = FALSE; + } + } + } + else + { + result =FALSE; + TRACE_EVENT_P4("unknown rlc mode in rd_check_window_size: rlc_mode=%d, bsn_i=%d,ssn=%d,vr=%d " + ,grlc_data->rd.rlc_mode + ,bsn_i + ,grlc_data->rd.ssn + ,grlc_data->rd.vr); + } + + + return result; +} /* rd_check_window_size() */ + + + +/* ++------------------------------------------------------------------------------ +| Function : rd_save_block ++------------------------------------------------------------------------------ +| Description : The function rd_save_block() .... +| +| Parameters : bsn_i - block sequence number of the saved block +| *ptr_data_block_i - pointer the data field of the rlc data +| block without header and li field +| fbi_i - final block indication bit of the received +| data block +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void rd_save_block ( UBYTE bsn_i, UBYTE * ptr_data_block_i, UBYTE fbi_i) +{ + T_NEXT_ARRAY *ptr_temp=NULL; + UBYTE block_nr; + UBYTE i; + UBYTE *ptr_data; + USHORT len; + TRACE_FUNCTION( "rd_save_block" ); + + if(!(grlc_data->rd.li_cnt)) + { + /* + * only a part of a pdu + */ + MALLOC(ptr_temp, sizeof(T_NEXT_ARRAY)); + ptr_temp->next = NULL; + ptr_temp->len = grlc_data->rd.rlc_data_len; + memcpy((ptr_temp->data),(ptr_data_block_i),(ptr_temp->len)); + grlc_data->rd.data_array[bsn_i & WIN_MOD].first = ptr_temp; + if(fbi_i) + { + grlc_data->rd.data_array[bsn_i & WIN_MOD].pdu_cnt = 1; + grlc_data->rd.data_array[bsn_i & WIN_MOD].pdu_complete =TRUE; + } + else + { + grlc_data->rd.data_array[bsn_i & WIN_MOD].pdu_cnt = 0; + grlc_data->rd.data_array[bsn_i & WIN_MOD].pdu_complete =FALSE; + } + + } + else + { + /* + * for the first part + */ + MALLOC(ptr_temp, sizeof(T_NEXT_ARRAY)); + if(grlc_data->rd.li[0] EQ 0 ) + ptr_temp->len = grlc_data->rd.rlc_data_len-1; + else + ptr_temp->len = grlc_data->rd.li[0]; + + ptr_data = ptr_data_block_i; + memcpy((ptr_temp->data), + (ptr_data), + (ptr_temp->len)); + grlc_data->rd.data_array[bsn_i & WIN_MOD].first = ptr_temp; + block_nr = 1; + while((block_nr <= grlc_data->rd.li_cnt) AND (grlc_data->rd.m[block_nr-1])) + { + ptr_data = &(ptr_data[ptr_temp->len]); + MALLOC(ptr_temp->next, sizeof(T_NEXT_ARRAY)); + ptr_temp = (T_NEXT_ARRAY *)ptr_temp->next; + /* + * check if it islast pdu in rlc data block + */ + if((block_nr EQ grlc_data->rd.li_cnt) + OR (grlc_data->rd.li[block_nr] EQ 0)) + { + /* + * last block, len is REST + */ + len = 0; + for(i=0; i < grlc_data->rd.li_cnt; i++) + len += grlc_data->rd.li[i]; + ptr_temp->len = grlc_data->rd.rlc_data_len - grlc_data->rd.li_cnt - len; + } + else + { + /* + * not last part + */ + ptr_temp->len = grlc_data->rd.li[block_nr]; + } + memcpy((ptr_temp->data), + (ptr_data), + (ptr_temp->len)); + block_nr++; + } + ptr_temp->next = NULL; + if(grlc_data->rd.m[grlc_data->rd.li_cnt-1] EQ 0) + grlc_data->rd.data_array[bsn_i & WIN_MOD].pdu_cnt = grlc_data->rd.li_cnt; + else + grlc_data->rd.data_array[bsn_i & WIN_MOD].pdu_cnt = grlc_data->rd.li_cnt + 1; + + if(fbi_i + OR + ((grlc_data->rd.li[grlc_data->rd.li_cnt-1]) + AND (grlc_data->rd.m[grlc_data->rd.li_cnt-1] EQ 0))) + grlc_data->rd.data_array[bsn_i & WIN_MOD].pdu_complete = TRUE; + else + grlc_data->rd.data_array[bsn_i & WIN_MOD].pdu_complete = FALSE; + + } + +} /* rd_save_block() */ + + + +/* ++------------------------------------------------------------------------------ +| Function : rd_comp_rec_par ++------------------------------------------------------------------------------ +| Description : The function rd_comp_rec_par() .... +| +| Parameters : dummy - description of parameter dummy +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void rd_comp_rec_par ( UBYTE bsn_i ) +{ + UBYTE vq_help; + TRACE_FUNCTION( "rd_comp_rec_par" ); + + if(grlc_data->rd.rlc_mode EQ CGRLC_RLC_MODE_ACK) + { + if( ( grlc_data->rd.vr >= grlc_data->rd.ssn) && + ( (bsn_i >= grlc_data->rd.vr ) || + (bsn_i < grlc_data->rd.ssn) ) ) + grlc_data->rd.vr = (bsn_i+1) & 0x7F; + else if( ( grlc_data->rd.vr < grlc_data->rd.ssn) && + ( (bsn_i >= grlc_data->rd.vr ) && + (bsn_i < grlc_data->rd.ssn) ) ) + grlc_data->rd.vr = (bsn_i+1) & 0x7F; + + grlc_data->rd.vn[bsn_i & WIN_MOD] = VN_RECEIVED; + vq_help = grlc_data->rd.vq; + while( (grlc_data->rd.vn[vq_help & WIN_MOD] EQ VN_RECEIVED) AND + vq_help NEQ grlc_data->rd.vr) + { + vq_help = (vq_help+1) & 0x7F; + } + grlc_data->rd.vq = vq_help; + } + else if(grlc_data->rd.rlc_mode EQ CGRLC_RLC_MODE_UACK) + { + if(grlc_data->rd.vr EQ bsn_i) + { + grlc_data->rd.vr = (1+grlc_data->rd.vr) % 128; + grlc_data->rd.vq = (1+grlc_data->rd.vq) % 128; + grlc_data->rd.inSequence = TRUE; + } + else + { + grlc_data->rd.vr = bsn_i; + grlc_data->rd.inSequence = FALSE; + } + } + else + TRACE_ERROR(" unknown RLC Mode during dl tbf in rd_comp_rec_par"); + + + +} /* rd_comp_rec_par() */ + + + + +/* ++------------------------------------------------------------------------------ +| Function : rd_check_fbi ++------------------------------------------------------------------------------ +| Description : The function rd_check_fbi() .... +| +| Parameters : dummy - description of parameter dummy +| ++------------------------------------------------------------------------------ +*/ +GLOBAL UBYTE rd_check_fbi ( UBYTE fbi_i, UBYTE sp , ULONG fn , UBYTE rrbp ) +{ + TRACE_FUNCTION( "rd_check_fbi" ); + + /* + * mark the bsn with fbi=1 + */ + if(fbi_i) + { + grlc_data->rd.last_bsn = grlc_data->rd.vr; + if(!sp) + { + TRACE_EVENT_P1("NO SP BUT FINAL DATA BLOCK t3192=%d",grlc_data->downlink_tbf.t3192_val); + } + } + + + /* + * if last bsn is left window element, than tbf is going to be released + */ + if(grlc_data->rd.last_bsn EQ grlc_data->rd.vq AND + !grlc_data->rd.f_ack_ind) /* to avoid retransmission */ + { + PALLOC(prim,CGRLC_T3192_STARTED_IND); + PSEND(hCommGRR,prim); + if(grlc_data->rd.rlc_mode EQ CGRLC_RLC_MODE_ACK ) + { + SET_STATE(RD,RD_REL_ACK); + } + else + { + SET_STATE(RD,RD_REL_UACK); + } + + grlc_data->tbf_ctrl[grlc_data->dl_index].fbi = 1; + + if(sp) + { + grlc_data->rd.fn_p_tbf_rel = grlc_decode_tbf_start_rel(fn,(USHORT)(rrbp+3)); + } + return 1; + } + else + { + return 0; + } +}/* rd_check_fbi() */ + + + + +/* ++------------------------------------------------------------------------------ +| Function : rd_set_acknack ++------------------------------------------------------------------------------ +| Description : The function rd_set_acknack() .... +| +| Parameters : dummy - description of parameter dummy +| ++------------------------------------------------------------------------------ +*/ +GLOBAL UBYTE* rd_set_acknack ( void ) +{ + MCAST (u_dl_ack,U_GRLC_DL_ACK); + UBYTE * ptr_block; + UBYTE i; + UBYTE index; + UBYTE help,neg_ack=0; + ULONG rbb1=0,rbb2=0,dummy1=0,dummy2=0; + + TRACE_FUNCTION( "rd_set_acknack" ); + + + if(grlc_data->rd.channel_req AND (grlc_data->tbf_type EQ TBF_TYPE_DL)) + { + u_dl_ack->v_chan_req_des = 1; + u_dl_ack->chan_req_des = grlc_data->chan_req_des; + grlc_data->rd.channel_req = 0; + grlc_data->rd.ch_req_in_ack_prog = TRUE; + /* TRACE_EVENT_P6("channel req des in dl ack nack:ptp=%d,rp=%d,rlc_mode=%d,llc_pt=%d,rlc_oc=%d, pst=%d", + grlc_data->chan_req_des.peak_thr_class, + grlc_data->chan_req_des.radio_prio, + grlc_data->chan_req_des.rlc_mode, + grlc_data->chan_req_des.llc_pdu_type, + grlc_data->chan_req_des.rlc_octet_cnt, + grlc_data->prim_start_tbf);*/ + if(grlc_data->prim_start_tbf >= PRIM_QUEUE_SIZE_TOTAL) + { + TRACE_EVENT_P3("PST=%d PSF=%d PDU=%d: rd_set_acknack" + ,grlc_data->prim_start_tbf + ,grlc_data->prim_start_free + ,grlc_data->grlc_data_req_cnt); + } + + } + else + { + u_dl_ack->v_chan_req_des = 0; + grlc_data->rd.channel_req = 0; + } + + u_dl_ack->msg_type = U_GRLC_DL_ACK_c; + u_dl_ack->dl_tfi = grlc_data->dl_tfi; + u_dl_ack->ack_nack_des.f_ack_ind = grlc_data->rd.f_ack_ind; + u_dl_ack->ack_nack_des.ssn = grlc_data->rd.vr; + memset(u_dl_ack->ack_nack_des.rbb, 1, WIN_SIZE ); + for(i=0; i< WIN_SIZE; i++) + { + if(grlc_data->rd.vr EQ grlc_data->rd.ssn OR grlc_data->rd.rlc_mode EQ CGRLC_RLC_MODE_UACK) + break; + index = (grlc_data->rd.vr-1-i) & 0x7F; + if(grlc_data->rd.vn[index & WIN_MOD] NEQ VN_RECEIVED) + { + u_dl_ack->ack_nack_des.rbb[WIN_SIZE-1-i] = 0; + neg_ack++; + } + if(grlc_data->rd.ssn EQ index ) + { + help = grlc_data->rd.ssn; + while(help NEQ grlc_data->rd.vq) + { + grlc_data->rd.vn[help & WIN_MOD] = VN_INVALID; + help = (help + 1) & 0x7F; + } + break; + } + } + + /* TRACE ONLY if there is channel desc or negative ack or the final ack*/ + if(u_dl_ack->v_chan_req_des OR + u_dl_ack->ack_nack_des.f_ack_ind OR + neg_ack) + { + if(neg_ack AND !u_dl_ack->ack_nack_des.f_ack_ind) + { + for(i=0; i<32;i++) + { + dummy1 = u_dl_ack->ack_nack_des.rbb[WIN_SIZE-1-i]; + dummy2 = u_dl_ack->ack_nack_des.rbb[WIN_SIZE-1-i-32]; + rbb1 += dummy1 <<i; + rbb2 += dummy2 <<i; + } + TRACE_EVENT_P7("dl_ack:p_fn=%ld,CD=%d ssn=%d nacks=%d vq=%d rbb2=%lx rbb1=%lx", + grlc_data->next_poll_array[grlc_data->poll_start_tbf].fn, + u_dl_ack->v_chan_req_des, + u_dl_ack->ack_nack_des.ssn, + neg_ack, + grlc_data->rd.vq, + rbb2, + rbb1); + } + else + { + rbb1 = 0xFFFFFFFF; + rbb2 = 0xFFFFFFFF; + TRACE_EVENT_P6("dl_ack:p_fn=%ld,CD=%d fbi=%d ssn=%d nacks=%d vq=%d", + grlc_data->next_poll_array[grlc_data->poll_start_tbf].fn, + u_dl_ack->v_chan_req_des, + u_dl_ack->ack_nack_des.f_ack_ind, + u_dl_ack->ack_nack_des.ssn, + neg_ack, + grlc_data->rd.vq); + } + } + else + { + rbb1 = 0xFFFFFFFF; + rbb2 = 0xFFFFFFFF; + } + + u_dl_ack->chan_qual_rep.c_value = 0; + u_dl_ack->chan_qual_rep.rxqual = 0; + u_dl_ack->chan_qual_rep.signvar = 0; + + { + /* processing channel quality report */ + + /* processing of C value */ + u_dl_ack->chan_qual_rep.c_value = meas_grlc_c_get_value( ); + + /* processing of RXQUAL value */ + u_dl_ack->chan_qual_rep.rxqual = meas_sq_get_rxqual_value( ); + + /* processing of signal variance */ + u_dl_ack->chan_qual_rep.signvar = meas_sv_get_value( ); + + /* processing of relative interference levels */ + meas_int_get_rel_i_level( &u_dl_ack->chan_qual_rep.ilev ); + } + +#if !defined (NTRACE) + + if( grlc_data->meas.v_im_trace NEQ 0 ) + { + TRACE_EVENT_P3( "rd_set_acknack: %d %d %d", + u_dl_ack->chan_qual_rep.c_value, + u_dl_ack->chan_qual_rep.rxqual, + u_dl_ack->chan_qual_rep.signvar ); + } + +#endif /* #if !defined (NTRACE) */ + +#ifdef REL99 + + u_dl_ack->v_release_99_str_u_grlc_dl_ack = 1; + + if (grlc_data->pfi_support AND u_dl_ack->v_chan_req_des ) + { + u_dl_ack->release_99_str_u_grlc_dl_ack.v_pfi = 1; + u_dl_ack->release_99_str_u_grlc_dl_ack.pfi = grlc_data->pfi_value; + } + else + { + u_dl_ack->release_99_str_u_grlc_dl_ack.v_pfi = 0; + } + +#endif + + + grlc_data->rd.ssn = grlc_data->rd.vq; + ptr_block = (_decodedMsg); + + + return ptr_block; +} /* rd_set_acknack() */ + + +/* ++------------------------------------------------------------------------------ +| Function : rd_calc_rlc_data_len ++------------------------------------------------------------------------------ +| Description : The function rd_calc_rlc_data_len() calculates the Data size of +| an RLC data block depending on coding scheme. +| The size is described in bytes. +| +| Parameters : block_status_i - includes the Coding scheme which +| determines the size of an RLC data block +| ++------------------------------------------------------------------------------ +*/ +GLOBAL UBYTE rd_calc_rlc_data_len ( USHORT block_status_i ) +{ + UBYTE result=0; + TRACE_FUNCTION( "rd_calc_rlc_data_len" ); + + /* + * the coding scheme is only in the first four bits + */ + block_status_i = block_status_i & 0x000F; + + switch( block_status_i) + { + case 2: + grlc_data->rd.cs_type = CS_1; + break; + case 4: + grlc_data->rd.cs_type = CS_2; + break; + case 5: + grlc_data->rd.cs_type = CS_3; + break; + case 6: + grlc_data->rd.cs_type = CS_4; + break; + default: + TRACE_EVENT("No Coding Scheme in RLC data block defined, old CS is used"); + break; + } + + + switch( grlc_data->rd.cs_type) + { + /* + * NO CS defined in all previously received RLC data blocks, + * therefore default CS_1 is used + */ + case CS_ZERO: + 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: + TRACE_ERROR("unknown Coding Scheme"); + break; + } + + return result; +} /* rd_calc_rlc_data_len() */ + + + +/* ++------------------------------------------------------------------------------ +| Function : rd_fill_blocks ++------------------------------------------------------------------------------ +| Description : The function rd_fill_blocks() fills not received but needed +| RLC data blocks with the value Zero. +| +| Parameters : bsn_i - bsn value of the recently received RLC data block, +| which is not inSequence(not equal VR at receiving the block) +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void rd_fill_blocks ( UBYTE bsn_i ) +{ + T_NEXT_ARRAY * ptr_temp=NULL; + TRACE_FUNCTION( "rd_fill_blocks" ); + + do + { + MALLOC(ptr_temp, sizeof(T_NEXT_ARRAY)); + ptr_temp->next = NULL; + ptr_temp->len = grlc_data->rd.rlc_data_len; + memset(ptr_temp->data,0,ptr_temp->len); + grlc_data->rd.data_array[grlc_data->rd.vq & WIN_MOD].first = ptr_temp; + grlc_data->rd.data_array[grlc_data->rd.vq & WIN_MOD].pdu_cnt = 0; + grlc_data->rd.data_array[grlc_data->rd.vq & WIN_MOD].pdu_complete =FALSE; + rd_send_grlc_data_ind(grlc_data->rd.vq); + grlc_data->rd.vq = (1+grlc_data->rd.vq) % 128; /*modulo 128*/ + } + while(grlc_data->rd.vq NEQ bsn_i); + + grlc_data->rd.vq = (1+grlc_data->rd.vq) % 128; /*modulo 128*/ + grlc_data->rd.vr = grlc_data->rd.vq; + grlc_data->rd.inSequence = TRUE; + + + +} /* rd_fill_blocks() */ + + + + +/* ++------------------------------------------------------------------------------ +| Function : rd_calc_delta_fn ++------------------------------------------------------------------------------ +| Description : The function rd_calc_delta_fn() calculates delta_fn. It is +| needed at receiving mac_ready_ind to send a poll block. +| In Target Enviroment, the poll block(Ack/nack or Control block) +| must be calculated one radio block earlier then the send time. +| This is needed due to the functional interface. +| Parameters : fn_i - framenumber for the uplink call +| +| ++------------------------------------------------------------------------------ +*/ +GLOBAL ULONG rd_calc_delta_fn ( ULONG fn_i ) +{ + ULONG result; + TRACE_FUNCTION( "rd_calc_delta_fn" ); + + #ifdef _TARGET_ + { + if(fn_i EQ FN_MAX-5) + result = grlc_data->next_poll_array[grlc_data->poll_start_tbf].fn + 5; + else + result = grlc_data->next_poll_array[grlc_data->poll_start_tbf].fn - fn_i; + } +#endif + +#ifdef _SIMULATION_ + { + if(fn_i EQ grlc_data->next_poll_array[grlc_data->poll_start_tbf].fn) + result = 4; /*valid: send block*/ + else + result = 0; /*no poll sending*/ + } +#endif + + return result; + + +} /* rd_calc_delta_fn() */ + +/* ++------------------------------------------------------------------------------ +| Function : rd_free_desc_list_partions ++------------------------------------------------------------------------------ +| Description : The function rd_free_desc_list_partions() frees the partions, +| which are linked for a candidate LLC pdu. PDU is stored as a +| description list, but not passed to LLC because of incomplete. +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void rd_free_desc_list_partions ( void ) +{ + UBYTE cnt = 0; + T_NEXT_ARRAY *help = NULL; + + TRACE_FUNCTION( "rd_free_desc_list_partions" ); + + help = (T_NEXT_ARRAY*)grlc_data->rd.grlc_data_ind.desc_list.first; + + grlc_data->rd.grlc_data_ind.desc_list.first = NULL; + + while(help != NULL) + { + T_NEXT_ARRAY *ptr = (T_NEXT_ARRAY*) help->next; + MFREE(help); + help = ptr; + cnt++; + } + + + #ifdef _SIMULATION_ + TRACE_EVENT_P1("freed partion (linked) : cnt=%d",cnt); +#endif /* _SIMULATION_*/ + + + grlc_data->rd.pdu_complete = TRUE; + grlc_data->rd.pdu_len = 0; + + +} /* rd_free_desc_list_partions() */ + +/* ++------------------------------------------------------------------------------ +| Function : rd_free_database_partions ++------------------------------------------------------------------------------ +| Description : The function rd_free_database_partions() frees the partions, +| which are stored in the RD database. They are not linked to a +| LLC pdu because data blocks are not received in sequence. +| Partions are removed from left window size (vq) up to the +| right window size (vr). +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void rd_free_database_partions ( void ) +{ + USHORT bsn; + + UBYTE cnt=0; + + T_NEXT_ARRAY *help = NULL; + + TRACE_FUNCTION( "rd_free_database_partions" ); + + bsn = grlc_data->rd.vq; + + while (bsn NEQ grlc_data->rd.vr) + { + help = grlc_data->rd.data_array[bsn & WIN_MOD].first; +#ifdef _SIMULATION_ + TRACE_EVENT_P2("candiate bsn=%d vn=%d",bsn,grlc_data->rd.vn[bsn & WIN_MOD]); +#endif /* _SIMULATION_*/ + + while (help != NULL) + { + grlc_data->rd.data_array[bsn & WIN_MOD].first = + (T_NEXT_ARRAY *)grlc_data->rd.data_array[bsn & WIN_MOD].first->next; + + MFREE(help); + + cnt++; +#ifdef _SIMULATION_ + TRACE_EVENT_P1("element free : bsn=%d",bsn); +#endif /* _SIMULATION_*/ + if(grlc_data->rd.data_array[bsn & WIN_MOD].pdu_cnt) + help = grlc_data->rd.data_array[bsn & WIN_MOD].first; + else + help = NULL; + } + grlc_data->rd.data_array[bsn & WIN_MOD].pdu_complete = FALSE; + grlc_data->rd.data_array[bsn & WIN_MOD].pdu_cnt = 0xFF; + grlc_data->rd.data_array[bsn & WIN_MOD].first = NULL; + + bsn = (bsn + 1) & 0x7F; + } + TRACE_EVENT_P2("rd_free_database_partions after: bsn=%d cnt=%d ", bsn, cnt); + + +} /* rd_free_database_partions() */ + + +/* ++------------------------------------------------------------------------------ +| Function : rd_cgrlc_st_time_ind ++------------------------------------------------------------------------------ +| Description : The function rd_cgrlc_st_time_ind () informs higher layers +| that the starting time is elapsed +| +| Parameters : - +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void rd_cgrlc_st_time_ind ( void ) +{ + PALLOC(cgrlc_starting_time_ind,CGRLC_STARTING_TIME_IND); /* T_CGRLC_STARTING_TIME_IND */ + + TRACE_FUNCTION( "rd_cgrlc_st_time_ind " ); + + cgrlc_starting_time_ind->tbf_mode = CGRLC_TBF_MODE_DL; + cgrlc_starting_time_ind->tfi = grlc_data->dl_tfi; + + PSEND(hCommGRR,cgrlc_starting_time_ind); + + grlc_data->dl_tn_mask = grlc_data->downlink_tbf.ts_mask; + + +} /* rd_cgrlc_st_time_ind () */