FreeCalypso > hg > fc-selenite
diff src/g23m-fad/l2r/l2r_upf.c @ 1:d393cd9bb723
src/g23m-*: initial import from Magnetite
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sun, 15 Jul 2018 04:40:46 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/g23m-fad/l2r/l2r_upf.c Sun Jul 15 04:40:46 2018 +0000 @@ -0,0 +1,1778 @@ +/* ++----------------------------------------------------------------------------- +| Project : CSD (8411) +| Modul : L2r_upf.c ++----------------------------------------------------------------------------- +| 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 Modul defines the procedures and functions for +| the component L2R of the base station ++----------------------------------------------------------------------------- +*/ + +#ifndef L2R_UPF_C +#define L2R_UPF_C +#endif + +#define ENTITY_L2R + +/*==== INCLUDES ===================================================*/ + +#include <string.h> +#include "typedefs.h" +#include "pconst.cdg" +#include "vsi.h" +#include "macdef.h" +#include "custom.h" +#include "gsm.h" +#include "cus_l2r.h" +#include "cnf_l2r.h" +#include "mon_l2r.h" +#include "prim.h" +#include "pei.h" +#include "tok.h" +#include "dti.h" /* functionality of the dti library */ + +#include "cl_ribu.h" +#include "l2r.h" + +/*==== CONST =======================================================*/ + +/*==== TYPES =======================================================*/ + +/*==== VAR EXPORT ==================================================*/ + +/*==== VAR LOCAL ===================================================*/ + +/*==== FUNCTIONS ===================================================*/ + +/* ++------------------------------------------------------------------------------ +| Function : up_init ++------------------------------------------------------------------------------ +| Description : initialise the l2r data for the uplink process +| +| Parameters : - +| +| +| Return : - ++------------------------------------------------------------------------------ +*/ + +GLOBAL void up_init(T_UP *dup) +{ + register ULONG i; + + TRACE_FUNCTION ("up_init()"); + + dup->FlowCtrlUsed = FALSE; + dup->DnFlow = FL_INACTIVE; + dup->UpFlow = FL_INACTIVE; + dup->ULFlow = FL_INACTIVE; + dup->LLFlow = FL_INACTIVE; + dup->MrgFlow = FL_INACTIVE; + dup->FlowThreshLo = MAX_UPRIM_RIBU_SIZE/2; + dup->FlowThreshHi = 3*MAX_UPRIM_RIBU_SIZE/4; + dup->DataSize = 0; + dup->FrameSize = 0; + dup->OldFrameSize = 0; + dup->FramesPerPrim = L2R_FRAMES_PER_PRIM_MAX; + dup->LastRcvdSa = 0; + dup->LastRcvdSb = 0; + dup->LastSentSa = 0; + dup->LastSentSb = 0; + dup->LastSentFlow = FL_INACTIVE; + dup->StoreDataActive = FALSE; + dup->UrgentMsg = FALSE; + dup->DiscardRemapData = FALSE; + dup->QRemapRead = 0; + dup->QRemapWrite = 0; + dup->BRemapAdr = NULL; + dup->BRemapLen = 0; + dup->BRemapSa = 0; + dup->BRemapSb = 0; + dup->BRemapLastState = 0; + dup->QRemapPrimDesc.prim = NULL; + + for (i = 0; i < MAX_UP_REMAP_QUEUE_SIZE; i++) + { + dup->QRemap[i] = NULL; + } + + for (i = 0; i < UP_REMAP_BUFFER_SIZE; i++) + { + dup->BRemap[i] = 0; + } + + dup->RiBu.idx.depth = MAX_UPRIM_RIBU_SIZE; + + INIT_STATE (UP_UL, IW_IDLE); + INIT_STATE (UP_LL, ISW_IDLE); + INIT_STATE (UP, UP_DISCONNECTED); +} + +/* ++------------------------------------------------------------------------------ +| Function : up_alloc_prim ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : - +| +| +| Return : - ++------------------------------------------------------------------------------ +*/ + + +LOCAL void up_alloc_prim(void) +{ + T_UP *dup = &l2r_data->up; + + T_PRIM_INDEX m; + T_P_UPRIM_DESCRIPTOR primDesc; + USHORT sduSize; + + TRACE_FUNCTION ("up_alloc_prim()"); + + sduSize = dup->FramesPerPrim * dup->FrameSize * 8; + primDesc = dup->RiBu.primDesc[dup->RiBu.alloc]; + { + PALLOC_SDU(data_req, RLP_DATA_REQ, sduSize); + primDesc->prim = data_req; + } + +#ifdef _SIMULATION_ + /* Clear SDU for test environment */ + { + UBYTE *p; + UBYTE *pend; + p = &primDesc->prim->sdu.buf[0]; + pend = p + (sduSize >> 3); + while (p < pend) + { + *p++ = 0; + } + } +#endif + + primDesc->prim->sdu.o_buf = 0; + primDesc->prim->sdu.l_buf = sduSize; + primDesc->nFr = dup->FramesPerPrim; + primDesc->index = 0; + primDesc->offset = 0; + primDesc->off_status = 0; + primDesc->full = FALSE; + primDesc->sa = FL_INACTIVE; + primDesc->sb = FL_INACTIVE; + /*lint -e416 (Warning -- Likely creation of out-of-bounds) */ + for (m = 0; m != dup->FramesPerPrim; m++) + { + (*primDesc->adr)[m] = (T_P_L2R_FRAME)(primDesc->prim->sdu.buf +L2R_ENCODING_OFFSET + m * dup->FrameSize); + } + /*lint +e416 (Warning -- Likely creation of out-of-bounds) */ + dup->RiBu.alloc++; + if (dup->RiBu.alloc EQ dup->RiBu.idx.depth) + { + dup->RiBu.alloc = 0; + } +} + +/* ++------------------------------------------------------------------------------ +| Function : up_send_prim_timeout ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : - +| +| +| Return : - ++------------------------------------------------------------------------------ +*/ + + +GLOBAL void up_send_prim_timeout(void) +{ + T_UP *dup = &l2r_data->up; + + TRACE_FUNCTION ("up_send_prim_timeout()"); + + if (!dup->RiBu.idx.filled) + { + if (dup->RiBu.alloc EQ dup->RiBu.idx.wi) + { + /* No primitive is there, so we allocate one */ + up_alloc_prim(); + } + + /* + No primitive is ready, so we take one away from the relay entity + */ + cl_ribu_write_index(&dup->RiBu.idx); /* point to next primitive */ + } + up_send_current_prim(); +} + +/* ++------------------------------------------------------------------------------ +| Function : up_next_remap_frame ++------------------------------------------------------------------------------ +| Description : Local function, which is used by up_copy_data_from_l2r +| to advance to the next frame in the primitive. +| The variable primDesc of the calling function is updated. +| +| Parameters : primDesc - +| +| Return : 1 - +| 0 - ++------------------------------------------------------------------------------ +*/ + +LOCAL UBYTE up_next_remap_frame(T_RPRIM_DESCRIPTOR *primDesc) +{ + T_UP *dup = &l2r_data->up; + + U8 i; + T_P_RLP_REMAP_DATA_IND prim; + + /* next frame */ + primDesc->index++; + + if (primDesc->index >= primDesc->nFr) + { + /* primitive is completely read out */ + PFREE(dup->QRemap [dup->QRemapRead]); + + /* next primitive */ + (dup->QRemapRead)++; + if (dup->QRemapRead >= MAX_UP_REMAP_QUEUE_SIZE) + { + dup->QRemapRead = 0; + } + if (dup->QRemapRead EQ dup->QRemapWrite) + { + /* no primitive is ready */ + primDesc->prim = NULL; + return (1); + } + + /* point to next primitive descriptor */ + + prim = dup->QRemap[dup->QRemapRead]; + primDesc->prim = prim; + primDesc->nFr = prim->sdu.l_buf / (8 * prim->data_size + HT_LEN); + primDesc->index = 0; + + for (i = 0; i < primDesc->nFr; i++) + { + primDesc->adr[i] = (T_P_L2R_FRAME)(prim->sdu.buf + (prim->sdu.o_buf>>3) + + HEADER_LEN + i * (prim->data_size + HT_LEN)); + } + } + primDesc->offset = 0; + primDesc->off_status = 0; + return (0); +} + +/* ++------------------------------------------------------------------------------ +| Function : up_copy_data_from_rq ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : buf - +| len - +| sa - +| sb - +| bytesCopied - +| +| Return : - ++------------------------------------------------------------------------------ +*/ + +LOCAL void up_copy_data_from_rq(U8 *buf, U16 len, U8 *sa, U8 *sb, U16 *bytesCopied) +{ + T_UP *dup = &l2r_data->up; + + register ULONG i; + register T_P_UBYTE pFrame; + register T_P_UBYTE pBuf; + register T_P_UBYTE pStat; + T_P_RLP_REMAP_DATA_IND prim; + T_P_L2R_FRAME frame; + T_P_UBYTE pEnd; + USHORT bytesToCopy; + USHORT blocklen; + UBYTE statOct; + UBYTE lastState; + + T_RPRIM_DESCRIPTOR *primDesc = &dup->QRemapPrimDesc; + +#ifdef _SIMULATION_ + TRACE_FUNCTION ("up_copy_data_from_rq()"); +#endif + + bytesToCopy = len; + + if (primDesc->prim EQ NULL) + { + prim = dup->QRemap[dup->QRemapRead]; + primDesc->prim = prim; + primDesc->nFr = prim->sdu.l_buf / ((prim->data_size<<3) + HT_LEN); + primDesc->index = 0; + primDesc->offset = 0; + primDesc->off_status = 0; + + for (i = 0; i < primDesc->nFr; i++) + { + primDesc->adr[i] = (T_P_L2R_FRAME)(prim->sdu.buf + (prim->sdu.o_buf>>3) + + HEADER_LEN + i * (prim->data_size + HT_LEN)); + } + } + + /* skip empty primitive */ + if (primDesc->nFr EQ 0) + { + *bytesCopied = 0; + return; + } + + frame = primDesc->adr[primDesc->index]; /* point to current l2r frame in primitive */ + pBuf = buf; /* point to destination buffer */ + pFrame = &((*frame)[primDesc->offset]); + pStat = &((*frame)[primDesc->off_status]); + + if (pFrame EQ pStat) + { + /* current byte is status octet */ + dup->BRemapLastState = *pFrame & SO_STATUS_BITS_MASK; + } + + lastState = dup->BRemapLastState; + *sa = GET_SO_SA_BIT(lastState); + *sb = GET_SO_SB_BIT(lastState); + + /************************************************************************************ + * loop until either + * - no more data are available or + * - status in L2R frame changes or + * - buffer for data is full + ************************************************************************************/ + + for (;;) + { +#ifdef _SIMULATION_ + TRACE_FUNCTION ("loop"); +#endif + + blocklen = pStat - pFrame; + if (blocklen EQ 0) + { + /* + * current byte is status octet + * (only in the first pass of the loop, there may be no status octet) + */ + + /***************************** + * evaluate status bits + *****************************/ + statOct = *pFrame; + if (lastState NEQ (statOct & SO_STATUS_BITS_MASK)) + { + /* + * status has changed. We have to stop, + * since only one state can be transmitted to the upper layer + */ + primDesc->offset = primDesc->off_status = pFrame - (T_P_UBYTE)frame; + + *bytesCopied = len - bytesToCopy; + return; + } + + pFrame++; + + /************************************ + * evaluate addrss bits + ************************************/ + statOct &= SO_ADR_MASK; + + switch (statOct) + { + case SO_BREAK_ACK: + case SO_BREAK_REQ: + case SO_END_EMPTY: + /* no more data in this frame */ + if (up_next_remap_frame(primDesc) EQ 1) + { + /* no more data available */ + *bytesCopied = len - bytesToCopy; /* this much data could be copied */ + return; + } + + frame = primDesc->adr[primDesc->index]; + pFrame = (T_P_UBYTE)frame; + pStat = (T_P_UBYTE)frame; + continue; /* continue with next frame */ + + case SO_END_FULL: + pStat = &((*frame)[primDesc->prim->data_size]); + blocklen = pStat - pFrame; + break; + + case SO_TWO_OCTET: + blocklen = *pFrame++ & SO_ADR_MASK_TWO_OCT; + pStat = pFrame + blocklen; + break; + + default: + blocklen = statOct; + pStat = pFrame + blocklen; + break; + } + } + + if (bytesToCopy < blocklen) + { + /*************************************** + * There is not enough space in the + * buffer to copy the complete block + ***************************************/ + + pEnd = pFrame + bytesToCopy; + + while (pFrame < pEnd) + { + *pBuf++ = *pFrame++; + } + + if (pFrame EQ &((*frame)[primDesc->prim->data_size])) + { + /* end of frame reached */ + up_next_remap_frame(primDesc); + } + else + { + primDesc->offset = pFrame - (T_P_UBYTE)frame; + primDesc->off_status = pStat - (T_P_UBYTE)frame; + } + *bytesCopied = len; /* this much data could be copied */ + return; + } + else + { + /*************************************** + * Copy the complete block + ***************************************/ + bytesToCopy -= blocklen; + + while (pFrame < pStat) + { + *pBuf++ = *pFrame++; + } + + if (pFrame EQ &((*frame)[primDesc->prim->data_size])) + { + /* end of frame reached */ + if (up_next_remap_frame(primDesc) EQ 1) + { + /* no more data available */ + *bytesCopied = len - bytesToCopy; /* this much data could be copied */ + return; + } + frame = primDesc->adr[primDesc->index]; + pFrame = (T_P_UBYTE)frame; + pStat = (T_P_UBYTE)frame; + } + if (bytesToCopy EQ 0) + { + primDesc->offset = pFrame - (T_P_UBYTE)frame; + primDesc->off_status = pStat - (T_P_UBYTE)frame; + *bytesCopied = len; /* this much data could be copied */ + return; + } + } + } +} + +/* ++------------------------------------------------------------------------------ +| Function : up_fill_in_status_octet ++------------------------------------------------------------------------------ +| Description : local function, which is used patch a status octet into a +| l2r frame. This function takes into acount the two octet +| format for 14400. +| +| Parameters : pFrame - points to begin of l2r frame +| offstat1 - offset of status octet to be patched +| offstat2 - offset of next status octet +| +| Return : ++------------------------------------------------------------------------------ +*/ + +LOCAL BOOL up_fill_in_status_octet(T_P_UBYTE pFrame, UBYTE offstat1, UBYTE offstat2) +{ + register T_P_UBYTE pStat, pSrc, pDes, pEnd; + register UBYTE dataLen; + + dataLen = offstat2 - offstat1 - 1; /* number of data bytes between status octets */ + pStat = pFrame + offstat1; + + if (dataLen <= DATA_SIZE_SHORT-2) + { + *pStat |= dataLen; + return (FALSE); + } + else + { + /* this is only possible with 14400 */ + if (offstat2 < DATA_SIZE_LONG - 1) + { + /* a two octet status must be inserted */ + pSrc = pFrame + offstat2; + pDes = pSrc + 1; + pEnd = pFrame + offstat1; + while (pSrc > pEnd) + { + *--pDes = *--pSrc; + } + *pStat |= SO_TWO_OCTET; + pStat++; + *pStat = dataLen; + } + else + { + /* a additional status octet (FULL) must be inserted somewhere in the frame */ + pSrc = pFrame + offstat2; + pDes = pSrc + 1; + pEnd = pFrame + offstat1 + DATA_SIZE_SHORT - 1; + while (pSrc > pEnd) + { + *--pDes = *--pSrc; + } + *pStat |= DATA_SIZE_SHORT - 2; + *pEnd = *pStat & SO_STATUS_BITS_MASK | SO_END_FULL; + } + return (TRUE); + } +} + +/* ++------------------------------------------------------------------------------ +| Function : up_next_frame ++------------------------------------------------------------------------------ +| Description : local function, which is used by up_copy_data_into_l2r to +| advance to the next frame in the primitive +| The variables primDesc, frame and pFrame of the calling function +| are updated. Moreover the return values of the calling function +| primToSend and bytesCopied are set. +| +| +| Parameters : primDesc - +| primToSend - +| +| Return : ++------------------------------------------------------------------------------ +*/ + +LOCAL UBYTE up_next_frame(T_P_UPRIM_DESCRIPTOR *primDesc, BOOL *primToSend) +{ + T_UP *dup = &l2r_data->up; + + TRACE_FUNCTION("up_next_frame()"); + + (*primDesc)->index++; + (*primDesc)->offset = 0; + + if ((*primDesc)->index >= dup->FramesPerPrim) /* primitive is filled */ + { + (*primDesc)->full = TRUE; + *primToSend = TRUE; + + cl_ribu_write_index(&dup->RiBu.idx); /* point to next primitive */ + + if (dup->RiBu.alloc EQ dup->RiBu.idx.wi) + { + /* no primitive is ready */ + return (1); + } + + /* point to next primitive descriptor */ + *primDesc = dup->RiBu.primDesc[dup->RiBu.idx.wi]; + (*primDesc)->index = 0; + } + return (0); +} + +LOCAL void up_copy_data_into_l2r(U8 *buf, U16 len, U8 sa, U8 sb, U8 x, BOOL *primToSend, U16 *bytesCopied) +{ + T_UP *dup = &l2r_data->up; + + T_P_UPRIM_DESCRIPTOR primDesc; + T_P_L2R_FRAME frame; + register T_P_UBYTE pFrame; + register T_P_UBYTE pEnd; + register T_P_UBYTE pBuf; + USHORT bytesToCopy; + UBYTE frameCount; + T_FLOW flow = FL_INVALID; + +#ifdef _SIMULATION_ + TRACE_FUNCTION ("up_copy_data_into_l2r()"); +#endif + + switch (x) + { + case DTI_FLOW_ON: + flow = FL_INACTIVE; + break; + case DTI_FLOW_OFF: + flow = FL_ACTIVE; + break; + } + +#ifdef _TARGET_ + if (dup->DataSize > DATA_SIZE_SHORT) + { + frameCount = 1; + } + else + { + frameCount = 2; + } +#else + { + frameCount = 100; + } +#endif + + up_store_status(sa, sb, flow); + + if (dup->LastSentFlow EQ dup->MrgFlow) + { + *primToSend = FALSE; + } + else + { + *primToSend = TRUE; + } + + /* don't copy into primitive if no primitive is ready */ + if (dup->RiBu.alloc EQ dup->RiBu.idx.wi) + { + *bytesCopied = 0; + return; + } + + bytesToCopy = len; + + primDesc = dup->RiBu.primDesc[dup->RiBu.idx.wi]; /* point to current primitive descriptor */ + frame = (*primDesc->adr)[primDesc->index]; /* point to current l2r frame in primitive */ + pFrame = &(*frame)[primDesc->offset]; /* point to current byte in frame */ + pBuf = buf; /* point to source buffer */ + + /************************************************************************************ + * + * Handle a partly filled frame, which has been written in the primitive previously + * + ************************************************************************************/ + + if (primDesc->offset NEQ 0) + { + /* partly filled frame is there */ + + if (bytesToCopy EQ 0) + /* no data to copy -> quit without writing status octet */ + { + *bytesCopied = len; + return; + } + + if (sa NEQ primDesc->sa OR sb NEQ primDesc->sb) + { + /* + * status has changed since last time + */ + + /* finish previous status octet */ + if ( + up_fill_in_status_octet( + (T_P_UBYTE)frame, + primDesc->off_status, + primDesc->offset + ) + ) + { + /* frame data has been moved to make space for two octet status */ + pFrame++; + (primDesc->offset)++; + + if (primDesc->offset >= (dup->DataSize)) + { + /* frame is just filled by patching the previous status frame */ + + if (up_next_frame(&primDesc, primToSend) EQ 1) + { + /* no more space for data */ + *bytesCopied = 0; /* no data could be copied */ + return; + } + frameCount--; +#ifdef _TARGET_ + if (frameCount EQ 0) + { + *bytesCopied = 0; /* no data could be copied */ + return; + } +#endif + frame = (*primDesc->adr)[primDesc->index]; /* point to current l2r frame in primitive */ + pFrame = &(*frame)[primDesc->offset]; /* point to current byte in frame */ + } + } + + if (primDesc->offset NEQ 0) + { + /* write status octet */ + *pFrame++ = (U8)(sa << SO_SA_BIT | sb << SO_SB_BIT | 0 << SO_X_BIT); /* x is set to 0 (inactive) by default */ + + /* store current status for next call */ + primDesc->sa = sa; + primDesc->sb = sb; + + primDesc->off_status = primDesc->offset; + (primDesc->offset)++; + if (primDesc->offset >= (dup->DataSize)) + { + /* frame is just filled by the status octet */ + + /* finish previous status octet */ + (*frame)[primDesc->off_status] |= SO_END_EMPTY; + + if (up_next_frame(&primDesc, primToSend) EQ 1) + { + /* no more space for data */ + *bytesCopied = 0; /* no data could be copied */ + return; + } + frameCount--; + if (frameCount EQ 0) + { + *bytesCopied = 0; /* no data could be copied */ + return; + } + frame = (*primDesc->adr)[primDesc->index]; /* point to current l2r frame in primitive */ + pFrame = &(*frame)[primDesc->offset]; /* point to current byte in frame */ + } + } + } + + /* + * write data into partly filled frame + */ + if (primDesc->offset NEQ 0) + { + if (bytesToCopy >= dup->DataSize - primDesc->offset) + { + /* enough data to fill frame completly */ + + for (pEnd = pFrame + dup->DataSize - primDesc->offset; pFrame < pEnd; ) + { + *pFrame++ = *pBuf++; + } + + /* finish previous status octet */ + (*frame)[primDesc->off_status] |= SO_END_FULL; + + bytesToCopy -= dup->DataSize - primDesc->offset; + + if (up_next_frame(&primDesc, primToSend) EQ 1) + { + /* no more space for data */ + *bytesCopied = len - bytesToCopy; /* this much data could be copied */ + return; + } + frameCount--; + if (frameCount EQ 0) + { + *bytesCopied = len - bytesToCopy; /* this much data could be copied */ + return; + } + frame = (*primDesc->adr)[primDesc->index]; /* point to current l2r frame in primitive */ + pFrame = &(*frame)[primDesc->offset]; /* point to current byte in frame */ + + } + else + { + /* not enough data to fill frame completly */ + + for (pEnd = pFrame + bytesToCopy; pFrame < pEnd; ) + { + *pFrame++ = *pBuf++; + } + primDesc->offset += bytesToCopy; + *bytesCopied = len; + return; /* Nothing else to do */ + } + } + } + + /************************************************************************************ + * + * Handle consecutive frames, which are filled starting with byte 0 + * + ************************************************************************************/ + + while (bytesToCopy > 0) + { + if (bytesToCopy >= dup->DataSize - 1) + { + /* + * There are enough data to fill a frame completely + */ + *pFrame++ = sa << SO_SA_BIT | sb << SO_SB_BIT | 0 << SO_X_BIT | SO_END_FULL; /* x is set to 0 (inactive) by default */ + + /* store current status for next call */ + primDesc->sa = sa; + primDesc->sb = sb; + + for (pEnd = pFrame + dup->DataSize - 1; pFrame < pEnd; ) + { + *pFrame++ = *pBuf++; + } + bytesToCopy -= dup->DataSize - 1; + + /* advance to next frame */ + if (up_next_frame(&primDesc, primToSend) EQ 1) + { + /* running out of primitives */ + *bytesCopied = len - bytesToCopy; /* this much data could be copied */ + return; + } + frameCount--; + if (frameCount EQ 0) + { + *bytesCopied = len - bytesToCopy; /* this much data could be copied */ + return; + } + frame = (*primDesc->adr)[primDesc->index]; /* point to current l2r frame in primitive */ + pFrame = &(*frame)[primDesc->offset]; /* point to current byte in frame */ + } + else + { + /* + * There are some data, but not enough to fill a frame completely + */ + *pFrame++ = (U8)(sa << SO_SA_BIT | sb << SO_SB_BIT | 0 << SO_X_BIT); /* x is set to 0 (inactive) by default */ + + /* store current status for next call */ + primDesc->sa = sa; + primDesc->sb = sb; + + for (pEnd = pFrame + bytesToCopy; pFrame < pEnd; ) + { + *pFrame++ = *pBuf++; + } + primDesc->off_status = 0; + primDesc->offset = bytesToCopy + 1; + bytesToCopy = 0; + } + } + *bytesCopied = len; +} + +/* ++------------------------------------------------------------------------------ +| Function : up_copy_remap_data ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : - +| +| +| Return : - ++------------------------------------------------------------------------------ +*/ + +LOCAL void up_copy_remap_data(void) +{ + T_UP *dup = &l2r_data->up; + + USHORT bytesCopied; + BOOL dummy; + +#ifdef _SIMULATION_ + TRACE_FUNCTION ("up_copy_remap_data()"); +#endif + + do + { + if (dup->BRemapLen EQ 0) + { + dup->BRemapAdr = dup->BRemap; + up_copy_data_from_rq + ( + dup->BRemapAdr, + UP_REMAP_BUFFER_SIZE, + &dup->BRemapSa, + &dup->BRemapSb, + &dup->BRemapLen + ); + if (dup->BRemapLen EQ 0) + { + up_check_flow(); + return; + } + } + up_copy_data_into_l2r + ( + dup->BRemapAdr, + dup->BRemapLen, + dup->BRemapSa, + dup->BRemapSb, + DTI_FLOW_OFF, + &dummy, + &bytesCopied + ); + dup->BRemapAdr += bytesCopied; + dup->BRemapLen -= bytesCopied; + + } while (bytesCopied NEQ 0); +} + +/* ++------------------------------------------------------------------------------ +| Function : up_check_alloc ++------------------------------------------------------------------------------ +| Description : This procedure allocates new primitives until there are +| UP_RIBU_PREALLOC primitives ready. +| +| I.e.: alloc = write + UP_RIBU_PREALLOC +| +| It may be less than this, if otherwise the alloc pointer +| would reach the read pointer. +| +| +| Parameters : - +| +| +| Return : - ++------------------------------------------------------------------------------ +*/ + +GLOBAL void up_check_alloc(void) +{ + T_UP *dup = &l2r_data->up; + + S8 i_from, i_to; + + TRACE_FUNCTION ("up_check_alloc()"); + + i_to = dup->RiBu.idx.ri - dup->RiBu.idx.wi - 1; + + if (i_to < 0) + { + i_to = i_to + dup->RiBu.idx.depth; + } + + if (i_to > UP_RIBU_PREALLOC) + { + i_to = UP_RIBU_PREALLOC; + } + + i_from = dup->RiBu.alloc - dup->RiBu.idx.wi; + + if (i_from < 0) + { + i_from = i_from + dup->RiBu.idx.depth; + } + + if (i_from >= i_to) + { + return; + } + + do + { + up_alloc_prim(); + i_from++; + } while (i_from < i_to); + + if (dup->QRemapRead NEQ dup->QRemapWrite) + { + up_copy_remap_data(); + return; + } + + switch (GET_STATE (UP_UL)) + { + case IW_WAIT: + break; + + case IW_IDLE: + if (dup->StoreDataActive EQ FALSE AND dup->Prim NEQ NULL) + { + up_store_data(); + } + break; + } +} + +/* ++------------------------------------------------------------------------------ +| Function : up_check_flow ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : - +| +| +| Return : - ++------------------------------------------------------------------------------ +*/ + +GLOBAL void up_check_flow(void) +{ + T_UP *dup = &l2r_data->up; + + U8 primCount; + + TRACE_FUNCTION ("up_check_flow()"); + + if (!dup->FlowCtrlUsed) + { + return; + } + + primCount = dup->RiBu.idx.filled; + + switch (dup->UpFlow) + { + case FL_ACTIVE: + if (primCount < dup->FlowThreshLo) + { + dup->UpFlow = FL_INACTIVE; + } + else + { + return; + } + break; + + case FL_INACTIVE: + if (primCount >= dup->FlowThreshHi) + { + dup->UpFlow = FL_ACTIVE; + } + else + { + return; + } + break; + } + sig_up_dn_flow(dup->UpFlow); +} + +/* ++------------------------------------------------------------------------------ +| Function : up_store_data ++------------------------------------------------------------------------------ +| Description : This procedure copies data from a dti_data_req primitive +| into the uplink ring buffer. +| +| +| Parameters : - +| +| +| Return : - ++------------------------------------------------------------------------------ +*/ + +GLOBAL void up_store_data(void) +{ + T_UP *dup = &l2r_data->up; + + T_P_UBYTE adr; + USHORT len; + BOOL primToSend; + USHORT bytesCopied; + USHORT i, j; + T_desc2 *desc; + + TRACE_FUNCTION ("up_store_data()"); + + dup->StoreDataActive = TRUE; + + do + { + desc = (T_desc2*)dup->Prim->desc_list2.first; + if (desc) + { + len = desc->len; + adr = desc->buffer; + } + else + { + len = 0; + adr = NULL; + } + + up_copy_data_into_l2r (adr, + len, + dup->Prim->parameters.st_lines.st_line_sa, + dup->Prim->parameters.st_lines.st_line_sb, + dup->Prim->parameters.st_lines.st_flow, + &primToSend, + &bytesCopied); + + dup->Prim->desc_list2.list_len -= bytesCopied; + + if (desc) + { + if ((bytesCopied EQ len)) + { + /* + * Block has been copied successfully + */ + dup->Prim->desc_list2.first = desc->next; + MFREE (desc); + } + else if (bytesCopied > 0) + { + /* + * remaining data must be copied to begin of block + */ + /*lint -e{661} (Warning -- Likely creation of out-of-bounds) */ + for (i=0, j = bytesCopied; j < len; i++, j++) + { + desc->buffer[i] = desc->buffer[j]; + } + desc->len -= bytesCopied; + } + } + up_check_alloc(); + + } while (dup->Prim->desc_list2.first NEQ 0 AND dup->RiBu.alloc NEQ dup->RiBu.idx.wi); + + if (dup->Prim->desc_list2.first EQ 0) + { + PFREE (dup->Prim); + dup->Prim = NULL; + up_send_ready(); + } + dup->StoreDataActive = FALSE; +} + +/* ++------------------------------------------------------------------------------ +| Function : up_send_ready ++------------------------------------------------------------------------------ +| Description : only used in test environment +| +| Parameters : - +| +| +| Return : - ++------------------------------------------------------------------------------ +*/ + +GLOBAL void up_send_ready(void) +{ + TRACE_FUNCTION ("up_send_ready()"); + + if (GET_STATE (UP_UL) EQ IW_IDLE) + { + if (l2r_data->up.DtiConnected EQ FALSE) + { + TRACE_EVENT("DTI not connected, but up_send_ready() called -> break"); + return; /* jk: DTI_READY_IND primitive cannot be sent when DTI disconnected (!) */ + } + + dti_start ( + l2r_hDTI, + L2R_DTI_UP_DEF_INSTANCE, + L2R_DTI_UP_INTERFACE, + L2R_DTI_UP_CHANNEL + ); + SET_STATE (UP_UL, IW_WAIT); + } +} + +LOCAL void clear_primDesc(T_P_UPRIM_DESCRIPTOR primDesc) +{ + primDesc->prim = NULL; + + primDesc->nFr = 0; + primDesc->index = 0; + primDesc->offset = 0; + primDesc->off_status = 0; + primDesc->full = FALSE; + primDesc->sa = FL_INACTIVE; + primDesc->sb = FL_INACTIVE; +} + +/* ++------------------------------------------------------------------------------ +| Function : up_free_prim ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : primDesc +| +| +| Return : - ++------------------------------------------------------------------------------ +*/ + +LOCAL void up_free_prim(T_P_UPRIM_DESCRIPTOR primDesc) +{ + TRACE_FUNCTION ("up_free_prim()"); + + if (primDesc->prim NEQ NULL) + { + PFREE (primDesc->prim); + clear_primDesc(primDesc); + } +} + +/* ++------------------------------------------------------------------------------ +| Function : up_deinit_ribu ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : - +| +| +| Return : - ++------------------------------------------------------------------------------ +*/ + +GLOBAL void up_deinit_ribu(void) +{ + T_UP *dup = &l2r_data->up; + + T_PRIM_DESC_RIBU_INDEX n; + + T_P_UPRIM_DESCRIPTOR primDesc; + + TRACE_FUNCTION ("up_deinit_ribu()"); + + for (n = 0; n < dup->RiBu.idx.depth; n++) + { + primDesc = dup->RiBu.primDesc[n]; + if (primDesc->prim NEQ NULL) + { + up_free_prim(primDesc); + } + } + if (GET_STATE (UP_LL) EQ ISW_SEND) + { + SET_STATE (UP_LL, ISW_IDLE); + } +} + +/* ++------------------------------------------------------------------------------ +| Function : up_send_status ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : sa - +| sb - +| flow - +| adr - +| +| Return : - ++------------------------------------------------------------------------------ +*/ + + + +GLOBAL void up_send_status + ( + T_BIT sa, + T_BIT sb, + T_FLOW flow, + UBYTE adr + ) +{ + T_UP *dup = &l2r_data->up; + + T_P_UPRIM_DESCRIPTOR primDesc; + T_P_L2R_FRAME frame; + T_BIT x = 0; + + TRACE_FUNCTION ("up_send_status()"); + + primDesc = dup->RiBu.primDesc[dup->RiBu.idx.wi]; + frame = (*primDesc->adr)[0]; + + switch (flow) + { + case FL_ACTIVE: + x = 1; + break; + case FL_INACTIVE: + x = 0; + break; + } + (*frame)[0] = sa << SO_SA_BIT | sb << SO_SB_BIT | x << SO_X_BIT | adr; + + /* jk:030501 - TEST CASE 251 - + new funktion parameter 'adr' was introduced + in order to cancel the older function 'up_send_break(...)' + */ + primDesc->sa = sa; /* the status has to be saved in order to be correctly stored later */ + primDesc->sb = sb; /* on into "dup->LastSentSa/Sb" [up_send current_prim()] */ + + primDesc->index = 1; + primDesc->offset = 0; + + cl_ribu_write_index(&dup->RiBu.idx); /* point to next primitive */ +} + +/* ++------------------------------------------------------------------------------ +| Function : up_set_flow_in_prim ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : prim - +| +| +| Return : - ++------------------------------------------------------------------------------ +*/ + +LOCAL void up_set_flow_in_prim(T_P_RLP_DATA_REQ prim) +{ + T_UP *dup = &l2r_data->up; + + if (dup->MrgFlow EQ FL_INACTIVE) + { + TRACE_FUNCTION ("up_set_flow_in_prim(INACTIVE)"); + } + else + { + T_PRIM_INDEX frames; + T_PRIM_INDEX ind; + UBYTE off; + register UBYTE statOct; + T_P_L2R_FRAME frame; + + TRACE_FUNCTION ("up_set_flow_in_prim(ACTIVE)"); + + frames = prim->sdu.l_buf / (8 * dup->FrameSize); + frame = (T_P_L2R_FRAME) (prim->sdu.buf + (prim->sdu.o_buf / 8) + HEADER_LEN); + off = 0; + ind = 0; + + while (ind < frames) + { + statOct = (*frame)[off]; + SET_BIT(statOct, SO_X_BIT); + (*frame)[off] = statOct; + + switch (statOct & SO_ADR_MASK) + { + case SO_BREAK_REQ: + case SO_BREAK_ACK: + case SO_END_EMPTY: + case SO_END_FULL: + ind++; + frame = (T_P_L2R_FRAME)((UBYTE*)frame + dup->FrameSize); + off = 0; + break; + + case SO_TWO_OCTET: + off++; + off += ((*frame)[off] & SO_ADR_MASK_TWO_OCT) + 1; + if (off >= dup->DataSize) + { + ind++; + frame = (T_P_L2R_FRAME)((UBYTE*)frame + dup->FrameSize); + off = 0; + } + break; + + default: + off += (statOct & SO_ADR_MASK) + 1; + if (off >= dup->DataSize) + { + ind++; + frame = (T_P_L2R_FRAME)((UBYTE*)frame + dup->FrameSize); + off = 0; + } + break; + } + } + } + dup->LastSentFlow = dup->MrgFlow; +} + +/* ++------------------------------------------------------------------------------ +| Function : up_send_current_prim ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : - +| +| +| Return : - ++------------------------------------------------------------------------------ +*/ + +GLOBAL void up_send_current_prim(void) +{ + T_UP *dup = &l2r_data->up; + T_P_UPRIM_DESCRIPTOR primDesc = dup->RiBu.primDesc[dup->RiBu.idx.ri]; + + TRACE_FUNCTION ("up_send_current_prim()"); + + if (!primDesc->full AND primDesc->index < primDesc->nFr) + { + TRACE_FUNCTION ("prim is not full"); + if (primDesc->offset > 0) + { + if (up_fill_in_status_octet((T_P_UBYTE)(*primDesc->adr)[primDesc->index], primDesc->off_status, primDesc->offset)) + { + primDesc->offset++; + if (primDesc->offset >= dup->DataSize) + { + primDesc->offset = 0; + primDesc->index++; + } + } + } + + if (primDesc->offset > 0 OR primDesc->index EQ 0) + { + /* + * Add status octet, if there is a partly filled frame + * or if status has changed since last write + */ + (*(*primDesc->adr)[primDesc->index])[primDesc->offset] = + dup->LastRcvdSa << SO_SA_BIT | + dup->LastRcvdSb << SO_SB_BIT | + 0 << SO_X_BIT | + SO_END_EMPTY; + primDesc->sa = dup->LastRcvdSa; + primDesc->sb = dup->LastRcvdSb; + primDesc->index++; + } + primDesc->prim->sdu.l_buf = primDesc->index * dup->FrameSize * 8; + } + + dup->LastSentSa = primDesc->sa; + dup->LastSentSb = primDesc->sb; + up_set_flow_in_prim(primDesc->prim); + + PSENDX (RLP, primDesc->prim); + + clear_primDesc(primDesc); /* this primitive doesn't belong to us any longer */ + + cl_ribu_read_index(&dup->RiBu.idx); /* point to next primitive */ + + dup->UrgentMsg = FALSE; + up_check_alloc(); + up_check_flow(); +} + + +/* ++------------------------------------------------------------------------------ +| Function : up_send_prim_cond ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : - +| +| +| Return : - ++------------------------------------------------------------------------------ +*/ + +GLOBAL void up_send_prim_cond(void) +{ + TRACE_FUNCTION ("up_send_prim_cond()"); + + switch (GET_STATE (UP_LL)) + { + case ISW_WAIT: + TIMERSTOP (TIMER_TUP_SND); + up_send_current_prim(); + SET_STATE (UP_LL, ISW_IDLE); + break; + + default: + l2r_data->up.UrgentMsg = TRUE; + up_check_flow(); + up_check_alloc(); + SET_STATE (UP_LL, ISW_SEND); + break; + } +} + +/* ++------------------------------------------------------------------------------ +| Function : up_init_ribu ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : - +| +| +| Return : - ++------------------------------------------------------------------------------ +*/ + + +GLOBAL void up_init_ribu(void) +{ + T_UP *dup = &l2r_data->up; + + T_PRIM_DESC_RIBU_INDEX n; + T_PRIM_INDEX m; + + TRACE_FUNCTION ("up_init_ribu()"); + + dup->RiBu.alloc = 0; + + cl_ribu_init(&dup->RiBu.idx, dup->RiBu.idx.depth); + + for (n = 0; n < dup->RiBu.idx.depth; n++) + { + dup->RiBu.primDesc[n] = &(dup->PrimDesc[n]); + + dup->PrimDesc[n].nFr = 0; + dup->PrimDesc[n].adr = (T_P_ADR_VECTOR)&(dup->AdrVec[n]); + dup->PrimDesc[n].index = 0; + dup->PrimDesc[n].offset = 0; + dup->PrimDesc[n].off_status = 0; + dup->PrimDesc[n].full = FALSE; + dup->PrimDesc[n].sa = FL_INACTIVE; + dup->PrimDesc[n].sb = FL_INACTIVE; + dup->PrimDesc[n].prim = NULL; + + for(m = 0;m < L2R_FRAMES_PER_PRIM_MAX; m++) + { + dup->AdrVec[n][m] = NULL; + } + + if (dup->RiBu.alloc < UP_RIBU_PREALLOC) + { + up_alloc_prim(); + } + } +} + +/* ++------------------------------------------------------------------------------ +| Function : up_store_status ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : sa +| sb +| flow +| +| Return : - ++------------------------------------------------------------------------------ +*/ + + +GLOBAL void up_store_status + ( + T_BIT sa, + T_BIT sb, + T_FLOW flow + ) +{ + T_UP *dup = &l2r_data->up; + +#ifdef _SIMULATION_ + TRACE_FUNCTION ("up_store_status()"); +#endif + + dup->LastRcvdSa = sa; + dup->LastRcvdSb = sb; + + if (dup->FlowCtrlUsed EQ FALSE OR flow EQ dup->ULFlow) + { + return; + } + + dup->ULFlow = flow; + + up_merge_flow(); + sig_up_dn_ul_flow(dup->ULFlow); +} + +/* ++------------------------------------------------------------------------------ +| Function : up_send_empty_frame ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : sa - +| sb - +| flow - +| +| Return : - ++------------------------------------------------------------------------------ +*/ + + +GLOBAL void up_send_empty_frame(T_BIT sa, T_BIT sb, T_FLOW flow) +{ + T_UP *dup = &l2r_data->up; + + T_BIT x = 0; + USHORT sduSize = dup->FrameSize << 3; + + PALLOC_SDU(data_req, RLP_DATA_REQ, sduSize); + + TRACE_FUNCTION ("up_send_empty_frame()"); + +#ifdef _SIMULATION_ + /* Clear SDU for test environment */ + { + UBYTE *p; + UBYTE *pend; + p = &data_req->sdu.buf[0]; + pend = p + dup->FrameSize; + while (p < pend) + { + *p++ = 0; + } + } +#endif + + data_req->sdu.o_buf = 0; + data_req->sdu.l_buf = sduSize; + + switch (flow) + { + case FL_ACTIVE: + x = 1; + break; + case FL_INACTIVE: + x = 0; + break; + } + /*lint -e416 (Warning -- Likely creation of out-of-bounds pointer) */ + /*lint -e415 (Warning -- Likely access of out-of-bounds pointer) */ + data_req->sdu.buf[L2R_ENCODING_OFFSET] = sa << SO_SA_BIT | sb << SO_SB_BIT | x << SO_X_BIT | SO_END_EMPTY; + /*lint +e416 (Warning -- Likely creation of out-of-bounds pointer) */ + /*lint +e415 (Warning -- Likely access of out-of-bounds pointer) */ + + dup->LastSentFlow = flow; + dup->LastSentSa = sa; + dup->LastSentSb = sb; + + PSENDX (RLP, data_req); +} + +/* ++------------------------------------------------------------------------------ +| Function : up_merge_flow ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : - +| +| +| Return : - ++------------------------------------------------------------------------------ +*/ + + +GLOBAL void up_merge_flow(void) +{ + T_UP *dup = &l2r_data->up; + +#ifdef _SIMULATION_ + TRACE_FUNCTION ("up_merge_flow()"); +#endif + + if (dup->FlowCtrlUsed AND (dup->DnFlow EQ FL_ACTIVE OR dup->ULFlow EQ FL_ACTIVE)) + { + /* flow control active */ + dup->MrgFlow = FL_ACTIVE; + } + else + { + /* flow control inactive */ + dup->MrgFlow = FL_INACTIVE; + } + +} + +/* ++------------------------------------------------------------------------------ +| Function : up_rq_init ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : - +| +| +| Return : - ++------------------------------------------------------------------------------ +*/ + +GLOBAL void up_rq_init(void) +{ +#ifdef _SIMULATION_ + TRACE_FUNCTION ("up_rq_init()"); +#endif + + l2r_data->up.QRemapWrite = 0; + l2r_data->up.QRemapRead = 0; +} + +/* ++------------------------------------------------------------------------------ +| Function : up_some_data_to_send ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : - +| +| +| Return : TRUE - +| FALSE - ++------------------------------------------------------------------------------ +*/ + +GLOBAL BOOL up_some_data_to_send(void) +{ + T_UP *dup = &l2r_data->up; + +#ifdef _SIMULATION_ + TRACE_EVENT ("check if any data to send"); +#endif + + if ( + dup->RiBu.idx.filled OR + (dup->RiBu.primDesc[dup->RiBu.idx.ri]->index > 0) OR + (dup->RiBu.primDesc[dup->RiBu.idx.ri]->offset > 0) OR + (dup->LastRcvdSa NEQ dup->LastSentSa) OR + (dup->LastRcvdSb NEQ dup->LastSentSb) + ) + { + return (TRUE); + } + return (FALSE); +}