RLC UeCb Changes
[o-du/l2.git] / src / du_app / du_ue_mgr.c
1 /*******************************************************************************
2 ################################################################################
3 #   Copyright (c) [2017-2019] [Radisys]                                        #
4 #                                                                              #
5 #   Licensed under the Apache License, Version 2.0 (the "License");            #
6 #   you may not use this file except in compliance with the License.           #
7 #   You may obtain a copy of the License at                                    #
8 #                                                                              #
9 #       http://www.apache.org/licenses/LICENSE-2.0                             #
10 #                                                                              #
11 #   Unless required by applicable law or agreed to in writing, software        #
12 #   distributed under the License is distributed on an "AS IS" BASIS,          #
13 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
14 #   See the License for the specific language governing permissions and        #
15 #   limitations under the License.                                             #
16 ################################################################################
17  *******************************************************************************/
18 /* This file contains UE management handling functionality for DU APP */
19 #include "common_def.h"
20 #include "lrg.h"
21 #include "lrg.x"
22 #include "ckw.h"
23 #include "ckw.x"
24 #include "kwu.h"
25 #include "kwu.x"
26 #include "lkw.h"
27 #include "lkw.x"
28 #include "legtp.h"
29 #include "du_app_mac_inf.h"
30 #include "du_app_rlc_inf.h"
31 #include "du_cfg.h"
32 #include "du_utils.h"
33 #include<ProtocolIE-Field.h>
34 #include "F1AP-PDU.h"
35 #include "du_f1ap_msg_hdl.h"
36 #include "du_mgr.h"
37 #include "du_ue_mgr.h"
38
39 #ifdef EGTP_TEST
40 U32 sduId = 0;
41 #endif
42
43 DuMacDlCcchInd packMacDlCcchIndOpts[] =
44 {
45    packMacDlCcchInd,   /* Loose coupling */
46    MacProcDlCcchInd,    /* TIght coupling */
47    packMacDlCcchInd    /* Light weight-loose coupling */
48 };
49
50 DuMacUeCreateReq packMacUeCreateReqOpts[] =
51 {
52    packDuMacUeCreateReq,       /* Loose coupling */
53    MacProcUeCreateReq,          /* TIght coupling */
54    packDuMacUeCreateReq,       /* Light weight-loose coupling */
55 };
56
57 DuRlcUlUeCreateReq packRlcUlUeCreateReqOpts[] =
58 {
59    packDuRlcUlUeCreateReq,       /* Loose coupling */
60    RlcUlProcUeCreateReq,          /* TIght coupling */
61    packDuRlcUlUeCreateReq,       /* Light weight-loose coupling */
62 };
63
64 /*******************************************************************
65  *
66  * @brief Handles EGTP data from CU 
67  *
68  * @details
69  *
70  *    Function : duHdlEgtpData
71  *
72  *    Functionality: 
73  *      Processes EGTP header and sends data to RLC
74  *
75  * @params[in]  Pointer to EGTP Message 
76  * @return ROK     - success
77  *         RFAILED - failure
78  *
79  * ****************************************************************/
80 uint8_t duHdlEgtpDlData(EgtpMsg  *egtpMsg)
81 {
82    /* TODO : Extract RbId/UeID/CellID/SduId from database
83       using tunnel id in egtp header */
84
85    DU_LOG("\nDU_APP : Processing DL data");
86
87    Pst pst;
88    KwuDatReqInfo datReqInfo;
89
90 #ifdef EGTP_TEST
91    datReqInfo.rlcId.rbId = RB_ID;
92    datReqInfo.rlcId.rbType = CM_LTE_DRB;
93    datReqInfo.rlcId.ueId = UE_ID;
94    datReqInfo.rlcId.cellId = NR_CELL_ID;
95
96    datReqInfo.sduId = ++sduId;
97    datReqInfo.lcType = CM_LTE_LCH_DTCH;
98 #endif
99    /* Filling pst and Sending to RLC DL */
100    pst.selector  = ODU_SELECTOR_LWLC;
101    pst.srcEnt    = ENTDUAPP;
102    pst.dstEnt    = ENTKW;
103    pst.dstInst   = RLC_DL_INST;
104    pst.dstProcId = DU_PROC;
105    pst.srcProcId = DU_PROC;
106    pst.region    = duCb.init.region;
107
108    cmPkKwuDatReq(&pst, &datReqInfo, egtpMsg->msg);
109    return ROK;
110 }
111
112 /*******************************************************************
113  *
114  * @brief Handles UL data and send to CU
115  *
116  * @details
117  *
118  *    Function : duHdlRlcUlData
119  *
120  *    Functionality: 
121  *     Processes UL Data from RLC and sends to CU
122  * 
123  *  @params[in]  Pointer to EGTP Message 
124  *  @return ROK     - success
125  *          RFAILED - failure
126  * 
127  *****************************************************************/
128
129 uint8_t duHdlRlcUlData(Pst *pst, KwuDatIndInfo* datInd, Buffer *mBuf)
130 {
131    DU_LOG("\nDU_APP : Received UL Data at DU_APP");
132
133    /* Send UL data to CU via EGTP */
134    duSendEgtpDatInd(mBuf);
135    SPutMsg(mBuf);
136
137    return ROK;
138 }
139
140 /******************************************************************
141  *
142  * @brief Builds and Sends DL CCCH Ind to MAC
143  *
144  * @details
145  *
146  *    Function : duBuildAndSendDlCcchInd 
147  *
148  *    Functionality: Builds and sends DL CCCH Ind Msg to MAC
149  *
150  * @params[in] dlCcchMsg - uint8_t*
151  * @return ROK     - success
152  *         RFAILED - failure
153  *
154  * ****************************************************************/
155 uint8_t duBuildAndSendDlCcchInd(uint16_t cellId, uint16_t crnti, \
156       DlCcchMsgType msgType, uint8_t *dlCcchMsg, uint16_t dlCcchMsgSize)
157 {
158    uint8_t ret                  = ROK;
159    uint16_t idx2;
160    DlCcchIndInfo *dlCcchIndInfo = NULLP;
161    Pst pst;
162    memset(&pst, 0, sizeof(Pst));
163
164    DU_LOG("\nDU APP : Building and Sending DL CCCH Ind to MAC");
165
166    DU_ALLOC_SHRABL_BUF(dlCcchIndInfo, sizeof(DlCcchIndInfo));
167
168    if(!dlCcchIndInfo)
169    {
170       DU_LOG("\nDU APP : Memory alloc failed while building DL CCCH Ind");
171       return RFAILED;
172    }
173
174    dlCcchIndInfo->cellId = cellId;
175    dlCcchIndInfo->crnti = crnti;
176    dlCcchIndInfo->msgType = msgType;
177    dlCcchIndInfo->dlCcchMsgLen = dlCcchMsgSize;
178
179    DU_ALLOC_SHRABL_BUF(dlCcchIndInfo->dlCcchMsg, dlCcchIndInfo->dlCcchMsgLen);
180    if(!dlCcchIndInfo->dlCcchMsg)
181    {
182       DU_LOG("\nDU APP : Memory alloc failed while building DL CCCH Ind");
183       DU_FREE_SHRABL_BUF(DU_APP_MEM_REGION, DU_POOL, dlCcchIndInfo, sizeof(DlCcchIndInfo));
184       return RFAILED;
185    }
186    for(idx2 = 0; idx2 < dlCcchIndInfo->dlCcchMsgLen; idx2++)
187    {
188       dlCcchIndInfo->dlCcchMsg[idx2] = dlCcchMsg[idx2];
189    }
190    DU_FREE(dlCcchMsg, dlCcchMsgSize);
191
192    /* Fill Pst */
193    FILL_PST_DUAPP_TO_MAC(pst, EVENT_MAC_DL_CCCH_IND);
194    ret = (*packMacDlCcchIndOpts[pst.selector])(&pst, dlCcchIndInfo);
195    if(ret != ROK)
196    {
197       DU_LOG("\nDU_APP : Failure in sending DL CCCH to MAC");
198       DU_FREE_SHRABL_BUF(DU_APP_MEM_REGION, DU_POOL, dlCcchIndInfo->dlCcchMsg,\
199             dlCcchIndInfo->dlCcchMsgLen);
200       DU_FREE_SHRABL_BUF(DU_APP_MEM_REGION, DU_POOL, dlCcchIndInfo, \
201             sizeof(DlCcchIndInfo));
202       ret = RFAILED; 
203    }
204
205    return ret;
206
207 }
208
209 /******************************************************************
210  *
211  * @brief Processes DL RRC Message Transfer  sent by CU
212  *
213  * @details
214  *
215  *    Function : procDlRrcMsgTrans 
216  *
217  *    Functionality: Processes DL RRC Message Transfer sent by CU
218  *
219  * @params[in] F1AP_PDU_t ASN decoded F1AP message
220  * @return ROK     - success
221  *         RFAILED - failure
222  *
223  * ****************************************************************/
224 uint8_t procDlRrcMsgTrans(F1AP_PDU_t *f1apMsg)
225 {
226    DLRRCMessageTransfer_t *dlRrcMsg = NULLP;
227    uint8_t                *dlCcchMsg = NULLP;
228    uint8_t                idx, ret, srbId;
229    uint16_t               idx2, crnti, cellId, dlCcchMsgSize;
230    uint32_t               gnbCuUeF1apId, gnbDuUeF1apId;
231
232
233    DU_LOG("\nDU_APP : DL RRC message transfer Recevied");
234    dlRrcMsg = &f1apMsg->choice.initiatingMessage->value.choice.DLRRCMessageTransfer;
235
236    ret = ROK;
237
238    for(idx=0; idx<dlRrcMsg->protocolIEs.list.count; idx++)
239    {
240       switch(dlRrcMsg->protocolIEs.list.array[idx]->id)
241       {
242          case ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID:
243             {
244                gnbCuUeF1apId = dlRrcMsg->protocolIEs.list.array[idx]->value.choice.GNB_CU_UE_F1AP_ID;
245                break;
246             }
247          case ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID:
248             {
249                gnbDuUeF1apId = dlRrcMsg->protocolIEs.list.array[idx]->value.choice.GNB_DU_UE_F1AP_ID;
250                break;
251             }
252          case ProtocolIE_ID_id_SRBID:
253             {
254                srbId = dlRrcMsg->protocolIEs.list.array[idx]->value.choice.SRBID;
255                break;
256             }
257          case ProtocolIE_ID_id_ExecuteDuplication:
258             break;
259
260          case ProtocolIE_ID_id_RRCContainer:
261             {
262                if(dlRrcMsg->protocolIEs.list.array[idx]->value.choice.RRCContainer.size > 0)
263                {
264                   dlCcchMsgSize = dlRrcMsg->protocolIEs.list.array[idx]->value.choice.RRCContainer.size;
265                   DU_ALLOC(dlCcchMsg, dlCcchMsgSize);
266                   for(idx2 = 0; idx2 < dlCcchMsgSize; idx2++)
267                   {
268                      dlCcchMsg[idx2] = \
269                         dlRrcMsg->protocolIEs.list.array[idx]->value.choice.RRCContainer.buf[idx2];
270                   }
271                }
272                else
273                {
274                   DU_LOG("\nDU_APP : RRC Container Size is invalid:%ld",\
275                         dlRrcMsg->protocolIEs.list.array[idx]->value.choice.RRCContainer.size);
276                }
277                break;
278             }
279
280          default:
281             DU_LOG("\nDU_APP : Invalid IE received in DL RRC Msg Transfer:%ld",
282                   dlRrcMsg->protocolIEs.list.array[idx]->id);
283       }
284    }
285
286    for(idx=0; idx<duCb.numUe; idx++)
287    {
288       if(gnbDuUeF1apId == duCb.ueCcchCtxt[idx].gnbDuUeF1apId)
289       {
290          crnti  = duCb.ueCcchCtxt[idx].crnti;
291          cellId = duCb.ueCcchCtxt[idx].cellId;
292          break;
293       }
294    }
295    if(srbId == SRB_ID_1) //RRC connection setup
296    {
297       ret = duBuildAndSendDlCcchInd(cellId, crnti, RRC_SETUP, dlCcchMsg, dlCcchMsgSize);
298       if(ret)
299       {
300          DU_LOG("\nDU_APP: Falied at duBuildAndSendDlCcchInd()");
301       }
302       else
303       {
304          if(duCb.actvCellLst[cellId-1]->numActvUes < MAX_NUM_UE)
305          {
306             ret = duCreateUeCb(&duCb.ueCcchCtxt[idx], gnbCuUeF1apId);
307             if(ret)
308             {
309                DU_LOG("\nDU_APP: Failed at duCreateUeCb for cellId [%d]", duCb.ueCcchCtxt[idx].cellId);
310                ret = RFAILED;
311             }
312          }
313          else
314          {
315             DU_LOG("\nDU_APP: Max Active UEs has reached");
316             ret = RFAILED;
317          }
318       }
319    }            
320    return ret;
321 }
322
323 /******************************************************************
324  *
325  * @brief Generates GNB DU Ue F1AP ID
326  *
327  * @details
328  *
329  *    Function : genGnbDuUeF1apId
330  *
331  *    Functionality: Generates GNB DU Ue F1AP ID
332  *
333  * @params[in] void
334  * @return gnbDuF1apId
335  *
336  * ****************************************************************/
337 uint32_t genGnbDuUeF1apId()
338 {
339    static uint32_t gnbDuUeF1apId = 0;
340
341    return ++gnbDuUeF1apId;
342 }
343
344 /******************************************************************
345  *
346  * @brief Processes UL CCCH Ind recvd from MAC
347  *
348  * @details
349  *
350  *    Function : duProcUlCcchInd
351  *
352  *    Functionality: Processes UL CCCH Ind recvd from MAC
353  *
354  * @params[in] UlCcchIndInfo *ulCcchIndInfo
355  * @return ROK     - success
356  *         RFAILED - failure
357  *
358  * ****************************************************************/
359 uint8_t duProcUlCcchInd(UlCcchIndInfo *ulCcchIndInfo)
360 {
361
362    uint8_t ret = ROK;
363    uint32_t gnbDuUeF1apId = 0;
364
365    gnbDuUeF1apId = genGnbDuUeF1apId();
366
367    /* Store Ue mapping */
368    duCb.ueCcchCtxt[duCb.numUe].gnbDuUeF1apId = gnbDuUeF1apId;
369    duCb.ueCcchCtxt[duCb.numUe].crnti         = ulCcchIndInfo->crnti;
370    duCb.ueCcchCtxt[duCb.numUe].cellId        = ulCcchIndInfo->cellId;
371
372    duCb.numUe++;
373
374    ret = (BuildAndSendInitialRrcMsgTransfer(gnbDuUeF1apId, ulCcchIndInfo->crnti,
375             ulCcchIndInfo->ulCcchMsg));
376    if(ret != ROK)
377    {
378       DU_LOG("\nDU_APP : BuildAndSendInitialRrcMsgTransfer failed");
379    }
380
381    DU_FREE_SHRABL_BUF(MAC_MEM_REGION, MAC_POOL, ulCcchIndInfo->ulCcchMsg, strlen((const char*)ulCcchIndInfo->ulCcchMsg));
382    DU_FREE_SHRABL_BUF(MAC_MEM_REGION, MAC_POOL, ulCcchIndInfo, sizeof(UlCcchIndInfo));
383
384    return ret;
385
386 }
387
388 /******************************************************************
389  *
390  * @brief Fills Initial DL Bandwidth Part
391  *
392  * @details
393  *
394  *    Function : fillInitDlBwp
395  *
396  *    Functionality: Fills Initial DL Bandwidth Part
397  *
398  *
399  *****************************************************************/
400 void fillInitDlBwp(InitialDlBwp *initDlBwp)
401 {
402    uint8_t idx = 0;
403
404    if(initDlBwp)
405    {
406       /* Filling PDCCH Config */
407       initDlBwp->pdcchPresent = TRUE;
408       if(initDlBwp->pdcchPresent)
409       {
410          initDlBwp->pdcchCfg.numCRsetToAddMod = PDCCH_CTRL_RSRC_SET_ONE_ID;
411          memset(initDlBwp->pdcchCfg.cRSetToAddModList, 0, MAX_NUM_CRSET);
412          if(initDlBwp->pdcchCfg.numCRsetToAddMod <= MAX_NUM_CRSET)
413          {
414             initDlBwp->pdcchCfg.cRSetToAddModList[idx].cRSetId = \
415                PDCCH_CTRL_RSRC_SET_ONE_ID;
416             memset(initDlBwp->pdcchCfg.cRSetToAddModList[idx].freqDomainRsrc, 0,\
417                FREQ_DOM_RSRC_SIZE); 
418             initDlBwp->pdcchCfg.cRSetToAddModList[idx].freqDomainRsrc[idx] =\
419                PDCCH_FREQ_DOM_RSRC;
420             initDlBwp->pdcchCfg.cRSetToAddModList[idx].duration = \
421                PDCCH_CTRL_RSRC_SET_ONE_DURATION;
422             initDlBwp->pdcchCfg.cRSetToAddModList[idx].cceRegMappingType = \
423                CCE_REG_MAPPINGTYPE_PR_NONINTERLEAVED;
424             initDlBwp->pdcchCfg.cRSetToAddModList[idx].precoderGranularity = \
425                ALL_CONTIGUOUS_RBS;
426             initDlBwp->pdcchCfg.cRSetToAddModList[idx].dmrsScramblingId = \
427                SCRAMBLING_ID;
428          }
429          initDlBwp->pdcchCfg.numCRsetToRel = 0;
430          /* Filling Serach Space */
431          initDlBwp->pdcchCfg.numSearchSpcToAddMod = PDCCH_CTRL_RSRC_SET_ONE_ID;
432          memset(initDlBwp->pdcchCfg.searchSpcToAddModList, 0, MAX_NUM_CRSET);
433          if(initDlBwp->pdcchCfg.numSearchSpcToAddMod <= MAX_NUM_CRSET)
434          {
435             initDlBwp->pdcchCfg.searchSpcToAddModList[idx].searchSpaceId =\
436                PDCCH_SRCH_SPC_TWO_ID;
437             initDlBwp->pdcchCfg.searchSpcToAddModList[idx].cRSetId = \
438                PDCCH_CTRL_RSRC_SET_ONE_ID;
439             initDlBwp->pdcchCfg.searchSpcToAddModList[idx].\
440                mSlotPeriodicityAndOffset = SLOTPERIODICITYANDOFFSET_PR_SL1;
441             memset(initDlBwp->pdcchCfg.searchSpcToAddModList[idx].mSymbolsWithinSlot, 0,\
442                MONITORING_SYMB_WITHIN_SLOT_SIZE);
443             initDlBwp->pdcchCfg.searchSpcToAddModList[idx].mSymbolsWithinSlot[idx] =\
444                PDCCH_SYMBOL_WITHIN_SLOT;
445             initDlBwp->pdcchCfg.searchSpcToAddModList[idx].numCandidatesAggLevel1 =\
446                AGGREGATIONLEVEL_N8; 
447             initDlBwp->pdcchCfg.searchSpcToAddModList[idx].numCandidatesAggLevel2 =\
448                AGGREGATIONLEVEL_N8; 
449             initDlBwp->pdcchCfg.searchSpcToAddModList[idx].numCandidatesAggLevel4 =\
450                AGGREGATIONLEVEL_N4; 
451             initDlBwp->pdcchCfg.searchSpcToAddModList[idx].numCandidatesAggLevel8 =\
452                AGGREGATIONLEVEL_N2; 
453             initDlBwp->pdcchCfg.searchSpcToAddModList[idx].numCandidatesAggLevel16 =\
454                AGGREGATIONLEVEL_N1;
455             initDlBwp->pdcchCfg.searchSpcToAddModList[idx].searchSpaceType = \
456                SEARCHSPACETYPE_PR_UE_SPECIFIC;
457             initDlBwp->pdcchCfg.searchSpcToAddModList[idx].ueSpecificDciFormat =\
458                PDCCH_SRCH_SPC_TWO_UE_SPEC_DCI_FORMAT;
459
460             initDlBwp->pdcchCfg.numSearchSpcToRel = 0;
461
462          }
463       }
464       /* Filling PDSCH Config */
465       initDlBwp->pdschPresent = TRUE;
466       if(initDlBwp->pdschPresent)
467       {
468          initDlBwp->pdschCfg.dmrsDlCfgForPdschMapTypeA.addPos = ADDITIONALPOSITION_POS0;
469          initDlBwp->pdschCfg.resourceAllocType = RESOURCEALLOCATION_TYPE1;
470          initDlBwp->pdschCfg.numTimeDomRsrcAlloc = 1;
471          initDlBwp->pdschCfg.timeDomRsrcAllociList[idx].mappingType = \
472             MAPPING_TYPEA;
473          initDlBwp->pdschCfg.timeDomRsrcAllociList[idx].startSymbol = PDSCH_START_SYMBOL; 
474          initDlBwp->pdschCfg.timeDomRsrcAllociList[idx].symbolLength = PDSCH_LENGTH_SYMBOL;
475          initDlBwp->pdschCfg.timeDomRsrcAllociList[idx].startSymbolAndLength = \
476             calcSliv(PDSCH_START_SYMBOL, PDSCH_LENGTH_SYMBOL);
477          initDlBwp->pdschCfg.rbgSize = RBG_SIZE_CONFIG1;
478          initDlBwp->pdschCfg.numCodeWordsSchByDci = CODEWORDS_SCHED_BY_DCI_N1;
479          initDlBwp->pdschCfg.bundlingType = TYPE_STATIC_BUNDLING;
480       }
481    }
482
483 }
484
485 /******************************************************************
486  *
487  * @brief Fills Initial UL Bandwidth Part
488  *
489  * @details
490  *
491  *    Function : fillInitUlBwp
492  *
493  *    Functionality: Fills Initial UL Bandwidth Part
494  *
495  *
496  *****************************************************************/
497 void fillInitUlBwp(InitialUlBwp *initUlBwp)
498 {
499    uint8_t idx;
500    if(initUlBwp)
501    {
502       initUlBwp->pucchPresent = FALSE;
503
504       /*Filling PUSCH Config */
505       initUlBwp->puschPresent = TRUE;
506       if(initUlBwp->puschPresent)
507       {
508          initUlBwp->puschCfg.dmrsUlCfgForPuschMapTypeA.addPos = ADDITIONALPOSITION_POS0; 
509          initUlBwp->puschCfg.dmrsUlCfgForPuschMapTypeA.transPrecodDisabled. \
510             scramblingId0 = SCRAMBLING_ID; 
511          initUlBwp->puschCfg.resourceAllocType = RESOURCEALLOCATION_TYPE1;
512          initUlBwp->puschCfg.numTimeDomRsrcAlloc = 1;
513          idx = 0;
514          if(initUlBwp->puschCfg.numTimeDomRsrcAlloc <= MAX_NUM_UL_ALLOC)
515          {
516             initUlBwp->puschCfg.timeDomRsrcAllocList[idx].k2 = PUSCH_K2;
517             initUlBwp->puschCfg.timeDomRsrcAllocList[idx].mappingType =\
518                MAPPING_TYPEA;
519             initUlBwp->puschCfg.timeDomRsrcAllocList[idx].startSymbol = PUSCH_START_SYMBOL;
520             initUlBwp->puschCfg.timeDomRsrcAllocList[idx].symbolLength = PUSCH_LENGTH_SYMBOL;
521             initUlBwp->puschCfg.timeDomRsrcAllocList[idx].startSymbolAndLength =\
522                calcSliv(PUSCH_START_SYMBOL, PUSCH_LENGTH_SYMBOL);
523          }
524          initUlBwp->puschCfg.transformPrecoder = TRANSFORM_PRECODER_DISABLED;
525       }
526    }
527    else
528    {
529       DU_LOG("\n DUAPP: Memory is NULL of InitalUlBwp");
530    }
531
532 }
533 /******************************************************************
534  *
535  * @brief Fills SpCell Group Info
536  *
537  * @details
538  *
539  *    Function : fillSpCellGrpInfo
540  *
541  *    Functionality: Fills Sp Cell Group Info
542  *
543  *
544  *****************************************************************/
545 void fillSpCellGrpInfo(SpCellCfg *spCell)
546 {
547    if(spCell)
548    {
549       spCell->servCellIdx = SERV_CELL_IDX;
550       /* Filling Initial Dl Bwp */
551       fillInitDlBwp(&spCell->servCellCfg.initDlBwp);
552
553       spCell->servCellCfg.numDlBwpToAdd    = 0; 
554       spCell->servCellCfg.firstActvDlBwpId = ACTIVE_DL_BWP_ID;
555       spCell->servCellCfg.defaultDlBwpId   = ACTIVE_DL_BWP_ID;
556       spCell->servCellCfg.bwpInactivityTmr = NULLP;
557       spCell->servCellCfg.pdschServCellCfg.maxMimoLayers = NULLP;
558       spCell->servCellCfg.pdschServCellCfg.maxCodeBlkGrpPerTb = NULLP;
559       spCell->servCellCfg.pdschServCellCfg.codeBlkGrpFlushInd = NULLP;
560       spCell->servCellCfg.pdschServCellCfg.xOverhead = NULLP;
561       spCell->servCellCfg.pdschServCellCfg.numHarqProcForPdsch =\
562          NUM_HARQ_PROC_FOR_PDSCH_N_16;
563       /* Filling Initial UL Bwp*/
564       fillInitUlBwp(&spCell->servCellCfg.initUlBwp);
565       spCell->servCellCfg.numUlBwpToAdd     = 0; 
566       spCell->servCellCfg.firstActvUlBwpId  = ACTIVE_DL_BWP_ID; 
567    }
568    else
569    {
570       DU_LOG("\n DU_APP: Memory is NULL for SpCellGrp");
571    }
572 }
573
574 /******************************************************************
575  *
576  * @brief Fills Physical Cell Group Info
577  *
578  * @details
579  *
580  *    Function : fillPhyCellGrpInfo
581  *
582  *    Functionality: Fills Physical Cell Group Info
583  *
584  *
585  *****************************************************************/
586 void fillPhyCellGrpInfo(PhyCellGrpCfg *cellGrp)
587 {
588    if(cellGrp)
589    {
590       cellGrp->pdschHarqAckCodebook = PDSCH_HARQ_ACK_CODEBOOK_DYNAMIC;
591       cellGrp->pNrFr1 = P_NR_FR1;
592    }
593    else
594    {
595       DU_LOG("\nDUAPP: Memory is NULL for Physical Cell Group");
596    }
597 }
598
599 /******************************************************************
600  *
601  * @brief Fills Mac Cell Group Info
602  *
603  * @details
604  *
605  *    Function : fillMacCellGrpInfo
606  *
607  *    Functionality: Fills Mac Cell Group Info
608  *
609  *
610  *****************************************************************/
611 void fillMacCellGrpInfo(MacCellGrpCfg *cellGrp)
612 {
613    uint8_t idx;
614
615    if(cellGrp)
616    {
617       /* Filling Scheduling Request Config */
618       cellGrp->schReqCfg.addModListCount = 1;
619       if(cellGrp->schReqCfg.addModListCount <= MAX_NUM_SR_CFG_PER_CELL_GRP)
620       {
621          for(idx = 0; idx < cellGrp->schReqCfg.addModListCount; idx++)
622          {
623             cellGrp->schReqCfg.addModList[idx].schedReqId    = SCH_REQ_ID;
624             cellGrp->schReqCfg.addModList[idx].srProhibitTmr = SR_PROHIBIT_MS_32;
625             cellGrp->schReqCfg.addModList[idx].srTransMax    = SR_TRANS_MAX_N_16;
626          }
627       }
628       cellGrp->schReqCfg.relListCount = 0;
629
630       /* Filling Tag config */
631       cellGrp->tagCfg.addModListCount = 1;
632       if(cellGrp->tagCfg.addModListCount <= MAC_NUM_TAGS)
633       {
634          for(idx = 0; idx < cellGrp->tagCfg.addModListCount; idx++)
635          {
636             cellGrp->tagCfg.addModList[idx].tagId = TAG_ID;
637             cellGrp->tagCfg.addModList[idx].timeAlignTimer = TIME_ALIGNMENT_TIMER_INFINITY;
638          }
639       }
640       cellGrp->tagCfg.relListCount = 0;
641
642       /* Filling BSR config */
643       cellGrp->bsrTmrCfg.periodicTimer = PERIODIC_BSR_TMR;
644       cellGrp->bsrTmrCfg.retxTimer = RETX_BSR_TMR;
645       cellGrp->bsrTmrCfg.srDelayTimer = SR_DELAY_TMR;
646
647       /* Filling PHR config */
648       cellGrp->phrCfgSetupPres = true;
649       cellGrp->phrCfg.periodicTimer = PHR_PERIODIC_TIMER_INFINITY;
650       cellGrp->phrCfg.prohibitTimer = PHR_PROHIBIT_TIMER_SF_0;
651       cellGrp->phrCfg.txPowerFactor = PHR_TX_PWR_FACTOR_CHANGE_INFINITY;
652       cellGrp->phrCfg.multiplePHR   = false;
653       cellGrp->phrCfg.dummy         = false;
654       cellGrp->phrCfg.phrType2OtherCell = false;
655       cellGrp->phrCfg.phrOtherCG = PHR_MODE_OTHER_CG_REAL;  
656
657    }
658    else
659    {
660       DU_LOG("\nDUAPP: Memory is NULL for Master Cell Group");
661    }
662 }
663
664 /******************************************************************
665  *
666  * @brief Fills Logical Channel Config List
667  *
668  * @details
669  *
670  *    Function : fillLcCfgList
671  *
672  *    Functionality: Fills Logical channel Config List
673  *
674  *
675  *****************************************************************/
676 void fillLcCfgList(LcCfg *lcCfgInfo)
677 {
678    if(lcCfgInfo)
679    {
680       lcCfgInfo->lcId = SRB_ID_1;
681       lcCfgInfo->drbQos = NULLP;
682       lcCfgInfo->snssai = NULLP;
683       lcCfgInfo->ulLcCfg = NULLP;
684       lcCfgInfo->dlLcCfg.lcp = LC_PRIORITY_1;
685
686 #if 0
687       /* TODO: To be filled on receving UE CONTEXT SETUP from CU */
688       /* Filling Qos characteristics */
689       lcCfgInfo->drbQos.fiveQiType = QoS_Characteristics_PR_non_Dynamic_5QI;
690       lcCfgInfo->drbQos.u.nonDyn5Qi.fiveQi = 0;
691       lcCfgInfo->drbQos.u.nonDyn5Qi.priorLevel = 0;
692       lcCfgInfo->drbQos.u.nonDyn5Qi.avgWindow = 0;
693       lcCfgInfo->drbQos.u.nonDyn5Qi.maxDataBurstVol = 0;
694
695       /* Filling NgRAN */
696       lcCfgInfo->drbQos.ngRanRetPri.priorityLevel = PriorityLevel_highest;
697       lcCfgInfo->drbQos.ngRanRetPri.preEmptionCap = \
698                                                     Pre_emptionCapability_may_trigger_pre_emption;
699       lcCfgInfo->drbQos.ngRanRetPri.preEmptionVul = \
700                                                     Pre_emptionVulnerability_not_pre_emptable;
701
702       /* Filling Grb Qos */
703       lcCfgInfo->drbQos.grbQosInfo.maxFlowBitRateDl  = 0;
704       lcCfgInfo->drbQos.grbQosInfo.maxFlowBitRateUl  = 0;
705       lcCfgInfo->drbQos.grbQosInfo.guarFlowBitRateDl = 0;
706       lcCfgInfo->drbQos.grbQosInfo.guarFlowBitRateUl = 0;
707
708       /* Filling S-NSSAI */
709       /* TODO :To be filled when UE Context Setup Request is sent from CU */
710       /* Filling UL Logical Channel Config */
711       lcCfgInfo->ulLcCfg.priority = 0;
712       lcCfgInfo->ulLcCfg.lcGroup  = 0;
713       lcCfgInfo->ulLcCfg.schReqId = 0;
714       lcCfgInfo->ulLcCfg.pbr = 0;
715       lcCfgInfo->ulLcCfg.bsd = 0;
716
717       /* Filling DL Logical Channel Config */
718       lcCfgInfo->dlLcCfg.lcp = 0;
719 #endif
720    }
721    else
722    {
723       DU_LOG("\n Memory is null for LcCfgList");
724    }
725 }
726
727 /******************************************************************
728  *
729  * @brief Fills MacUeCfg structure
730  *
731  * @details
732  *
733  *    Function : fillMacUeCfg
734  *
735  *    Functionality: Fills MacUeCfg
736  *
737  *
738  *****************************************************************/
739 void fillMacUeCfg(uint16_t cellId, uint8_t ueIdx,\
740   uint16_t crnti, MacUeCfg *ueCfg)
741 {
742    uint8_t idx;
743    ueCfg->cellId       = cellId;
744    ueCfg->ueIdx        = ueIdx;
745    ueCfg->crnti        = crnti;
746    /* Filling MacCellGroup Config */ 
747    fillMacCellGrpInfo(&ueCfg->macCellGrpCfg);
748    /* Filling PhyCellGroup Config */ 
749    fillPhyCellGrpInfo(&ueCfg->phyCellGrpCfg);
750    /* Filling SpCellGroup Config */ 
751    fillSpCellGrpInfo(&ueCfg->spCellCfg);
752    /* Filling AMBR for UL and DL */ 
753    ueCfg->maxAggrBitRate = NULLP;
754    /* Filling LC Context */
755    ueCfg->numLcs = SRB_ID_1;
756    if(ueCfg->numLcs < MAX_NUM_LOGICAL_CHANNELS)
757    {
758       for(idx = 0; idx < ueCfg->numLcs; idx++)
759       {   
760          fillLcCfgList(&ueCfg->lcCfgList[idx]);
761       }
762    }
763
764 }
765
766 /******************************************************************
767  *
768  * @brief Fills Rlc AM Information
769  *
770  * @details
771  *
772  *    Function : fillAmInfo
773  *
774  *    Functionality: Fills Rlc AM Information
775  *
776  *
777  *****************************************************************/
778 void fillAmInfo(AmBearerCfg *amCfg)
779 {
780    /* DL AM */
781    amCfg->dlAmCfg.snLenDl     = AM_SIZE_12;
782    amCfg->dlAmCfg.pollRetxTmr = POLL_RETX_TMR_45MS;
783    amCfg->dlAmCfg.pollPdu     = POLL_PDU_TMR_INFINITY;
784    amCfg->dlAmCfg.pollByte    = POLL_BYTES_INFINITY;
785    amCfg->dlAmCfg.maxRetxTh   = RETX_TH_8;   
786  
787    /* UL AM */
788    amCfg->ulAmCfg.snLenUl     = AM_SIZE_12;
789    amCfg->ulAmCfg.reAssemTmr  = RE_ASM_40MS; 
790    amCfg->ulAmCfg.statProhTmr = PROH_35MS;
791
792 }
793
794 /******************************************************************
795  *
796  * @brief Fills RLC UM Bi Directional Information
797  *
798  * @details
799  *
800  *    Function : fillUmBiDirInfo
801  *
802  *    Functionality: Fills RLC UM Bi Directional Information
803  *
804  *
805  *****************************************************************/
806 void fillUmBiDirInfo(UmBiDirBearerCfg *umBiDirCfg)
807 {
808    /* UL UM BI DIR INFO */
809    umBiDirCfg->ulUmCfg.snLenUlUm = UM_SIZE_12;
810    umBiDirCfg->ulUmCfg.reAssemTmr = RE_ASM_40MS;
811
812    /* DL UM BI DIR INFO */
813    umBiDirCfg->dlUmCfg.snLenDlUm  = UM_SIZE_12;
814
815 }
816
817 /******************************************************************
818  *
819  * @brief Fills RLC UM Uni Directional UL Information
820  *
821  * @details
822  *
823  *    Function : fillUmUniDirUlInfo
824  *
825  *    Functionality: Fills RLC UM Uni Directional Info
826  *
827  *
828  *****************************************************************/
829 void fillUmUniDirUlInfo(UmUniDirUlBearerCfg *umUniDirUlCfg)
830 {
831    umUniDirUlCfg->ulUmCfg.snLenUlUm = UM_SIZE_12;
832    umUniDirUlCfg->ulUmCfg.reAssemTmr = RE_ASM_40MS;
833 }
834
835 /******************************************************************
836  *
837  * @brief Fills RLC UM Uni Directional DL Information
838  *
839  * @details
840  *
841  *    Function : fillUmUniDirDlInfo
842  *
843  *    Functionality: Fills RLC UM Uni Directional DL Info
844  *
845  *
846  *****************************************************************/
847 void fillUmUniDirDlInfo(UmUniDirDlBearerCfg *umUniDirDlCfg)
848 {
849    umUniDirDlCfg->dlUmCfg.snLenDlUm  = UM_SIZE_12;
850 }
851
852 /******************************************************************
853  *
854  * @brief Fills RlcBearerCfg structure
855  *
856  * @details
857  *
858  *    Function : fillRlcBearerCfg
859  *
860  *    Functionality: Fills Rlc Bearer Cfg
861  *
862  *
863  *****************************************************************/
864 void fillRlcBearerCfg(uint16_t cellId, uint8_t ueIdx, RlcUeCfg *ueCfg)
865 {
866    uint8_t idx;
867    ueCfg->cellId       = cellId;
868    ueCfg->ueIdx        = ueIdx;
869    ueCfg->numLcs       = SRB_ID_1; 
870
871    for(idx = 0; idx < ueCfg->numLcs; idx++)
872    {
873       ueCfg->rlcBearerCfg[idx].rbId         = RB_ID_SRB;
874       ueCfg->rlcBearerCfg[idx].rbType       = RB_TYPE_SRB;
875       ueCfg->rlcBearerCfg[idx].lcId         = SRB_ID_1;
876       ueCfg->rlcBearerCfg[idx].lcType       = LCH_DCCH;
877       ueCfg->rlcBearerCfg[idx].rlcMode      = RLC_AM;
878       switch(ueCfg->rlcBearerCfg[idx].rlcMode)
879       {
880          case RLC_AM:
881             memset(&ueCfg->rlcBearerCfg[idx].u.amCfg, 0, sizeof(AmBearerCfg));
882             fillAmInfo(&ueCfg->rlcBearerCfg[idx].u.amCfg);
883             break;
884          case RLC_UM_BI_DIRECTIONAL:
885             memset(&ueCfg->rlcBearerCfg[idx].u.umBiDirCfg, 0, sizeof(UmBiDirBearerCfg));
886             fillUmBiDirInfo(&ueCfg->rlcBearerCfg[idx].u.umBiDirCfg);
887             break;
888          case RLC_UM_UNI_DIRECTIONAL_UL:
889             memset(&ueCfg->rlcBearerCfg[idx].u.umUniDirUlCfg, 0, sizeof(UmUniDirUlBearerCfg));
890             fillUmUniDirUlInfo(&ueCfg->rlcBearerCfg[idx].u.umUniDirUlCfg);
891             break;
892          case RLC_UM_UNI_DIRECTIONAL_DL:
893             memset(&ueCfg->rlcBearerCfg[idx].u.umUniDirDlCfg, 0, sizeof(UmUniDirDlBearerCfg));
894             fillUmUniDirDlInfo(&ueCfg->rlcBearerCfg[idx].u.umUniDirDlCfg);
895             break;
896          default :
897             DU_LOG("\nDU_APP: Rlc Mode invalid %d", ueCfg->rlcBearerCfg[idx].rlcMode);
898             break;
899       }
900    }
901 }
902
903 /******************************************************************
904  *
905  * @brief creates UE context
906  *
907  * @details
908  *
909  *    Function : duCreateUeCb
910  *
911  *    Functionality: Creates UE Conetxt
912  *
913  * @params[in] UeCcchCtxt Pointer
914  *             UeIdx Pointer
915  *
916  * @return ROK     - success
917  *         RFAILED - failure
918  * ****************************************************************/
919 uint8_t duCreateUeCb(UeCcchCtxt *ueCcchCtxt, uint32_t gnbCuUeF1apId)
920 {
921    uint8_t cellIdx = 0;
922    uint8_t ret     = ROK;
923    uint8_t ueIdx;
924
925    for(cellIdx = 0; cellIdx < MAX_NUM_CELL; cellIdx++)
926    {
927       if(ueCcchCtxt->cellId == duCb.actvCellLst[cellIdx]->cellId)
928       {
929          GET_UE_IDX(ueCcchCtxt->crnti, ueIdx);
930          DU_LOG("\nDU_APP: Filling UeCb for ueIdx [%d]", ueIdx);
931
932          duCb.actvCellLst[cellIdx]->ueCb[ueIdx].gnbDuUeF1apId = ueCcchCtxt->gnbDuUeF1apId;
933          duCb.actvCellLst[cellIdx]->ueCb[ueIdx].gnbCuUeF1apId = gnbCuUeF1apId;
934          duCb.actvCellLst[cellIdx]->ueCb[ueIdx].ueState       = UE_ACTIVE;
935
936          /* Filling Mac Ue Config */ 
937          memset(&duCb.actvCellLst[cellIdx]->ueCb[ueIdx].macUeCfg, 0, sizeof(MacUeCfg));
938          ret = duBuildAndSendUeCreateReqToMac(ueCcchCtxt->cellId, ueIdx, ueCcchCtxt->crnti,\
939                 &duCb.actvCellLst[cellIdx]->ueCb[ueIdx].macUeCfg);
940          if(ret)
941             DU_LOG("\nDU_APP: Failed to send UE create request to MAC");
942          
943          /* Filling Rlc Ue Config */
944          memset(&duCb.actvCellLst[cellIdx]->ueCb[ueIdx].rlcUeCfg, 0, sizeof(RlcUeCfg));
945          ret = duBuildAndSendUeCreateReqToRlc(ueCcchCtxt->cellId, ueIdx, \
946                 &duCb.actvCellLst[cellIdx]->ueCb[ueIdx].rlcUeCfg);
947          if(ret)
948             DU_LOG("\nDU_APP: Failed to send UE create request to RLC");
949
950          duCb.actvCellLst[cellIdx]->numActvUes++;
951          memset(ueCcchCtxt, 0, sizeof(UeCcchCtxt));
952       }
953    }
954    return ret;
955 }
956
957 /******************************************************************
958  *
959  * @brief Builds and Send UE Create Request to MAC
960  *
961  * @details
962  *
963  *    Function : duBuildAndSendUeCreateReqToMac
964  *
965  *    Functionality: Builds and Send UE Create Request to MAC
966  *
967  * @Params[in]  cellId,
968  *              ueIdx
969  * @return ROK     - success
970  *         RFAILED - failure
971  *
972  * ****************************************************************/
973
974 uint8_t duBuildAndSendUeCreateReqToMac(uint16_t cellId, uint8_t ueIdx,\
975    uint16_t crnti, MacUeCfg *duMacUeCfg)
976 {
977    uint8_t ret = ROK;
978    MacUeCfg *macUeCfg = NULLP;
979    Pst pst;
980    memset(&pst, 0, sizeof(Pst));
981
982    fillMacUeCfg(cellId, ueIdx, crnti, duMacUeCfg);
983
984    /* Fill Pst */
985    FILL_PST_DUAPP_TO_MAC(pst, EVENT_MAC_UE_CREATE_REQ);
986
987    /* Copying ueCb to a sharable buffer */
988    DU_ALLOC_SHRABL_BUF(macUeCfg, sizeof(MacUeCfg));
989    if(macUeCfg)
990    {
991       memset(macUeCfg, 0, sizeof(MacUeCfg));
992       memcpy(macUeCfg, &duCb.actvCellLst[cellId - 1]->ueCb[ueIdx].macUeCfg, sizeof(MacUeCfg));
993       DU_LOG("\nDU_APP: Sending UE create request to MAC");
994       /* Processing one Ue at a time to MAC */
995       ret = (*packMacUeCreateReqOpts[pst.selector])(&pst, macUeCfg);
996       if(ret)
997       {
998          DU_LOG("\nDU_APP : Failure in sending Ue Create Req to MAC");
999          DU_FREE_SHRABL_BUF(DU_APP_MEM_REGION, DU_POOL, macUeCfg, sizeof(MacUeCfg));
1000          ret = RFAILED;
1001       }
1002    }
1003    else
1004    {
1005       DU_LOG("\n DU_APP: Memory alloc failed at duBuildAndSendUeCreateReqToMac()");
1006       ret = RFAILED;
1007    }
1008    return ret;
1009 }
1010
1011 /*******************************************************************
1012  *
1013  * @brief Handle UE create response from MAC
1014  *
1015  * @details
1016  *
1017  *    Function : DuHandleMacUeCreateRsp
1018  *
1019  *    Functionality: Handle UE create response from MAC
1020  *
1021  * @params[in] Pointer to MacUeCfgRsp and Pst 
1022  * @return ROK     - success
1023  *         RFAILED - failure
1024  *
1025  * ****************************************************************/
1026 uint8_t DuHandleMacUeCreateRsp(Pst *pst, MacUeCfgRsp *cfgRsp)
1027 {
1028    if(cfgRsp->result == MAC_DU_APP_RSP_OK)
1029    {
1030       DU_LOG("\nDU APP : MAC UE Create Response : SUCCESS [UE IDX : %d]", cfgRsp->ueIdx);
1031    }
1032    else
1033    {
1034       DU_LOG("\nDU APP : MAC UE Create Response : FAILURE [UE IDX : %d]", cfgRsp->ueIdx);
1035    }
1036    return ROK;
1037 }
1038
1039 /*******************************************************************
1040  *
1041  * @brief Processes UE create Req to RLC UL
1042  *
1043  * @details
1044  *
1045  *    Function : duBuildAndSendUeCreateReqToRlc
1046  *
1047  *    Functionality: 
1048  *     Processes UE create Req to RLC UL
1049  * 
1050  *  @params[in]  cellId,
1051  *               ueIdx,
1052  *               Pointer to RlcUeCfg
1053  *  @return ROK     - success
1054  *          RFAILED - failure
1055  * 
1056  *****************************************************************/
1057
1058 uint8_t duBuildAndSendUeCreateReqToRlc(uint16_t cellId, uint8_t ueIdx, RlcUeCfg *duRlcUeCfg)
1059 {
1060    uint8_t ret = ROK;
1061    RlcUeCfg *rlcUeCfg = NULLP;
1062    Pst pst;
1063    memset(&pst, 0, sizeof(Pst));
1064   
1065    fillRlcBearerCfg(cellId, ueIdx, duRlcUeCfg);
1066    FILL_PST_DUAPP_TO_RLC(pst, RLC_UL_INST, EVENT_RLC_UL_UE_CREATE_REQ);
1067
1068    /* Copying ueCfg to a sharable buffer */
1069    DU_ALLOC_SHRABL_BUF(rlcUeCfg, sizeof(RlcUeCfg));
1070    if(rlcUeCfg)
1071    {
1072       memset(rlcUeCfg, 0, sizeof(RlcUeCfg));
1073       memcpy(rlcUeCfg, duRlcUeCfg, sizeof(RlcUeCfg));
1074       /* Processing one Ue at a time to RLC */
1075       DU_LOG("\nDU_APP: Sending UE create request to RLC UL");
1076       ret = (*packRlcUlUeCreateReqOpts[pst.selector])(&pst, rlcUeCfg);
1077       if(ret)
1078       {
1079          DU_LOG("\nDU_APP : Failure in sending Ue Create Req to RLC");
1080          DU_FREE_SHRABL_BUF(DU_APP_MEM_REGION, DU_POOL, rlcUeCfg, sizeof(RlcUeCfg));
1081          ret = RFAILED;
1082       }
1083    }
1084    else
1085    {
1086       DU_LOG("\n DU_APP: Memory alloc failed at duBuildAndSendUeCreateReqToRlc()");
1087       ret = RFAILED;
1088    }
1089    return ret;
1090 }
1091
1092
1093
1094 /*******************************************************************
1095  *
1096  * @brief Processes UE create Rsp received from RLC UL
1097  *
1098  * @details
1099  *
1100  *    Function : DuProcRlcUlUeCfgRsp
1101  *
1102  *    Functionality: 
1103  *     Processes UE create Rsp received from RLC UL
1104  * 
1105  *  @params[in]  Post structure
1106  *               Pointer to RlcCfgCfm
1107  *  @return ROK     - success
1108  *          RFAILED - failure
1109  * 
1110  *****************************************************************/
1111
1112 uint8_t DuProcRlcUlUeCreateRsp(Pst *pst, RlcUeCfgRsp *cfgRsp)
1113 {
1114    uint8_t ret = ROK;
1115
1116    if(cfgRsp)
1117    {
1118       if(cfgRsp->result == RLC_DU_APP_RSP_OK)
1119       {
1120          DU_LOG("\nDU_APP: RLC UE Create Response : SUCCESS [UE IDX:%d]", cfgRsp->ueIdx);
1121       }
1122       else
1123       {
1124          DU_LOG("\nDU_APP: RLC UE Create Response : FAILED [UE IDX:%d, REASON :%d]",\
1125             cfgRsp->ueIdx, cfgRsp->reason);
1126          ret = RFAILED;
1127       }
1128       DU_FREE_SHRABL_BUF(DU_APP_MEM_REGION, DU_POOL, cfgRsp, sizeof(RlcUeCfgRsp));
1129    }
1130    else
1131    {
1132       DU_LOG("\nDU_APP: Received RLC Ue Create Response is NULL");
1133       ret = RFAILED;
1134    }
1135    return ret;
1136 }
1137 /**********************************************************************
1138   End of file
1139  ***********************************************************************/