FreeCalypso > hg > fc-selenite
view src/g23m-gprs/grlc/grlc_rdf.c @ 192:4f40ae165be4
abb.c & init.c: sync with Magnetite for Luna additions
These Luna target-specific additions are conditionalized on CONFIG_TARGET_LUNA,
a C preprocessor symbol that will never be defined in Selenite, hence this
change has exactly zero impact on FC Selenite. However, they are being pulled
in as a sync in order to keep the diff between Magnetite and Selenite to a
minimum; keeping this diff to a minimum increases our opportunities for
possible evolution of future FC firmwares.
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 23 May 2020 07:03:46 +0000 |
parents | d393cd9bb723 |
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 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 () */