b5afd680a1d27f4bb798c711b93b2d122eb0ca3d
[o-du/l2.git] / src / 5gnrsch / rg_sch_lmm.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
19 /************************************************************************
20  
21      Name:     LTE-MAC layer
22   
23      Type:     C source file
24   
25      Desc:     C source code for Layer Manager Interface Module 
26   
27      File:     rg_sch_lmm.c 
28   
29 **********************************************************************/
30
31 /** @file rg_sch_lmm.c
32 @brief This file contains the Layer Management interface module implementation for scheduler.
33        The functions for the configuration, control, status and statistics 
34        request primitives are defined here.
35 */
36
37
38 /* header include files (.h) */
39 #include "common_def.h"
40 #include "rg_env.h"        /* MAC Environment Defines */
41 #include "rgr.h"           /* RGR Interface defines */
42 #include "tfu.h"           /* RGU Interface defines */
43 #include "lrg.h"           /* LRG Interface defines */
44 #include "rgm.h"           /* RGM Interface defines */
45 #include "rg_sch.h"        /* Scheduler defines */
46 #include "rg_sch_inf.h"        /* Scheduler defines */
47 #include "rg_sch_err.h"        /* MAC error defines */
48 #ifdef LTE_L2_MEAS
49 #include "rg_sch_cmn.h"    /* typedefs for Scheduler */
50 #endif
51 #include "rl_interface.h"
52 #include "rl_common.h"
53
54 /* header/extern include files (.x) */
55 #include "rgr.x"           /* RGR Interface includes */
56 #include "rgm.x"           /* RGM Interface includes */
57 #include "tfu.x"           /* RGU Interface includes */
58 #include "lrg.x"           /* LRG Interface includes */
59 #include "rg_sch_inf.x"    /* Scheduler defines */
60 #include "rg_sch.x"        /* Scheduler includes */
61 #ifdef LTE_L2_MEAS
62 #include "rg_sch_cmn.x"    /* typedefs for Scheduler */
63 #endif 
64 #ifndef LTE_L2_MEAS
65 Void rgSCHCmnInit ARGS((Void));
66 #endif 
67 /* forward references */
68 extern int schActvInit(Ent entity, Inst instId, Region region, Reason reason);
69 #ifdef UNUSE_FUN
70 static uint16_t rgSCHLmmSapCfg ARGS((
71    Inst           inst,
72    RgCfg          *cfg,
73    uint8_t             sapIdx,
74    Elmnt          sapType
75 ));
76 #endif
77 static Void rgSCHLmmShutdown ARGS((
78    Inst inst
79 ));
80
81
82 void printSchCellInfo(void)
83 {
84    uint8_t idx=0;
85    uint8_t inst=0;
86    for (idx = 0; idx < rgSchCb[inst].numSaps; idx++)
87    {
88       /* Unbind all the TFU SAP */
89       /* Free the memory held by the cell associated
90        * with this SAP */
91       if (rgSchCb[inst].tfuSap[idx].cell != NULLP)
92       {
93          DU_LOG("\nINFO  -->  SCH : CELL %d\n", idx);
94          DU_LOG("\nINFO  -->  SCH : NUM UEs :%d\n",rgSchCb[inst].tfuSap[idx].cell->ueLst.nmbEnt);
95       }
96    }
97 }
98
99 /**
100  * @brief SAP Configuration Handler. 
101  *
102  * @details
103  *
104  *     Function : rgSCHLmmSapCfg
105  *     
106  *     This function in called by SchProcGenCfgReq(). It handles the
107  *     interface SAP configuration of the scheduler instance. It 
108  *     initializes the sapState to LRG_UNBND. Returns
109  *     reason for success/failure of this function.
110  *     
111  *  @param[in]  RgCfg *cfg, the Configuaration information 
112  *  @return  uint16_t
113  *      -# LCM_REASON_GENCFG_NOT_DONE
114  *      -# LCM_REASON_INVALID_SAP
115  *      -# LCM_REASON_NOT_APPL
116  **/
117 #ifdef UNUSE_FUN
118 static uint16_t rgSCHLmmSapCfg
119 (
120 Inst  dInst,
121 RgCfg *cfg,            /* Configuaration information */
122 uint8_t sapIdx,          /* SAP index */
123 Elmnt sapType             /* SAP Type */
124 )
125 {
126    uint16_t                  ret = LCM_REASON_NOT_APPL;
127    RgSchLowSapCfgInfo   *lowSapCfg = NULLP;
128    RgSchUpSapCfgInfo    *upSapCfg = NULLP;
129    Inst  inst = (dInst - SCH_INST_START);
130
131    /* Check if Gen Config has been done */
132
133    switch(sapType)
134    {   
135       case STRGRSAP:
136 #ifndef CL_MAC_LWLC
137          if ((cfg->s.schInstCfg.rgrSap[sapIdx].selector != ODU_SELECTOR_TC) &&
138              (cfg->s.schInstCfg.rgrSap[sapIdx].selector != ODU_SELECTOR_LC))
139          {
140             ret = LCM_REASON_INVALID_PAR_VAL;
141             DU_LOG("\nERROR  -->  SCH : rgSCHLmmSapCfg(): unsupported"
142                " Selector value for RGR.");
143             break;
144          }
145 #endif
146          if(rgSchCb[inst].rgrSap[sapIdx].sapSta.sapState == LRG_NOT_CFG)
147          { 
148             rgSchCb[inst].rgrSap[sapIdx].sapSta.sapState = LRG_UNBND;
149          }
150          upSapCfg = &rgSchCb[inst].rgrSap[sapIdx].sapCfg;
151
152          upSapCfg->sapPst.dstEnt = cfg->s.schInstCfg.rgrSap[sapIdx].ent;
153          upSapCfg->sapPst.dstInst = cfg->s.schInstCfg.rgrSap[sapIdx].inst;
154          upSapCfg->sapPst.dstProcId = cfg->s.schInstCfg.rgrSap[sapIdx].procId;
155          upSapCfg->sapPst.srcEnt = rgSchCb[inst].rgSchInit.ent;
156          upSapCfg->sapPst.srcInst = rgSchCb[inst].rgSchInit.inst +
157          SCH_INST_START;
158          upSapCfg->sapPst.srcProcId = rgSchCb[inst].rgSchInit.procId;
159          upSapCfg->sapPst.region = cfg->s.schInstCfg.rgrSap[sapIdx].mem.region;
160          upSapCfg->sapPst.pool = cfg->s.schInstCfg.rgrSap[sapIdx].mem.pool;
161          upSapCfg->sapPst.selector = cfg->s.schInstCfg.rgrSap[sapIdx].selector;
162          upSapCfg->sapPst.route = cfg->s.schInstCfg.rgrSap[sapIdx].route;
163          upSapCfg->sapPst.intfVer = 0; 
164          upSapCfg->sapPst.event = 0; 
165          upSapCfg->sapPst.prior = cfg->s.schInstCfg.rgrSap[sapIdx].prior;
166          upSapCfg->suId = cfg->s.schInstCfg.rgrSap[sapIdx].suId;
167          upSapCfg->spId = cfg->s.schInstCfg.rgrSap[sapIdx].spId;
168          break;
169       case STTFUSAP:
170 #ifndef CL_MAC_LWLC
171          if ((cfg->s.schInstCfg.tfuSap[sapIdx].selector != ODU_SELECTOR_TC) &&
172              (cfg->s.schInstCfg.tfuSap[sapIdx].selector != ODU_SELECTOR_LC))
173          {
174             ret = LCM_REASON_INVALID_PAR_VAL;
175             DU_LOG("\nERROR  -->  SCH : rgSCHLmmSapCfg(): unsupported"
176                      " Selector value for TFU.");
177             break;
178          }
179 #endif
180          if (rgSchCb[inst].tfuSap[sapIdx].sapSta.sapState == LRG_NOT_CFG) 
181          { 
182             rgSchCb[inst].tfuSap[sapIdx].sapSta.sapState = LRG_UNBND;
183          }
184          /* Initialize the  sap timer */
185          cmInitTimers(&(rgSchCb[inst].tfuSap[sapIdx].tmrBlk), 1);
186          lowSapCfg = &rgSchCb[inst].tfuSap[sapIdx].sapCfg;
187
188          lowSapCfg->sapPst.dstEnt = cfg->s.schInstCfg.tfuSap[sapIdx].ent;
189          lowSapCfg->sapPst.dstInst = cfg->s.schInstCfg.tfuSap[sapIdx].inst;
190          lowSapCfg->sapPst.dstProcId = cfg->s.schInstCfg.tfuSap[sapIdx].procId;
191          lowSapCfg->sapPst.srcEnt = rgSchCb[inst].rgSchInit.ent;
192          lowSapCfg->sapPst.srcInst = rgSchCb[inst].rgSchInit.inst +
193          SCH_INST_START;
194          lowSapCfg->sapPst.srcProcId = rgSchCb[inst].rgSchInit.procId;
195          lowSapCfg->sapPst.region = cfg->s.schInstCfg.tfuSap[sapIdx].mem.region;
196          lowSapCfg->sapPst.pool = cfg->s.schInstCfg.tfuSap[sapIdx].mem.pool;
197          lowSapCfg->sapPst.selector = cfg->s.schInstCfg.tfuSap[sapIdx].selector;
198          lowSapCfg->sapPst.route = cfg->s.schInstCfg.tfuSap[sapIdx].route;
199          lowSapCfg->sapPst.intfVer = 0; 
200           lowSapCfg->sapPst.event = 0; 
201          lowSapCfg->sapPst.prior = cfg->s.schInstCfg.tfuSap[sapIdx].prior;
202          lowSapCfg->suId = cfg->s.schInstCfg.tfuSap[sapIdx].suId;
203          lowSapCfg->spId = cfg->s.schInstCfg.tfuSap[sapIdx].spId;
204          memcpy(&lowSapCfg->bndTmr, 
205                   &cfg->s.schInstCfg.tfuSap[sapIdx].bndTmr,
206                   sizeof(TmrCfg));
207          break;
208       case STRGMSAP:
209 #ifndef RGM_LWLC
210          if ((cfg->s.schInstCfg.rgmSap[sapIdx].selector != RGM_SEL_LWLC) &&
211              (cfg->s.schInstCfg.rgmSap[sapIdx].selector != RGM_SEL_LC) &&
212              (cfg->s.schInstCfg.rgmSap[sapIdx].selector != RGM_SEL_TC))
213          {
214             ret = LCM_REASON_INVALID_PAR_VAL;
215             DU_LOG("\nERROR  -->  SCH : rgSCHLmmSapCfg(): unsupported"
216                      " Selector value for RGM.");
217             break;
218          }
219 #endif
220          if (rgSchCb[inst].rgmSap[sapIdx].sapSta.sapState == LRG_NOT_CFG) 
221          { 
222             rgSchCb[inst].rgmSap[sapIdx].sapSta.sapState = LRG_UNBND;
223          }
224          upSapCfg = &rgSchCb[inst].rgmSap[sapIdx].sapCfg;
225          upSapCfg->sapPst.dstEnt = cfg->s.schInstCfg.rgmSap[sapIdx].ent;
226          upSapCfg->sapPst.dstInst = cfg->s.schInstCfg.rgmSap[sapIdx].inst;
227          upSapCfg->sapPst.dstProcId = cfg->s.schInstCfg.rgmSap[sapIdx].procId;
228          upSapCfg->sapPst.srcEnt = rgSchCb[inst].rgSchInit.ent;
229          upSapCfg->sapPst.srcInst = rgSchCb[inst].rgSchInit.inst +
230          SCH_INST_START;
231          upSapCfg->sapPst.srcProcId = rgSchCb[inst].rgSchInit.procId;
232          upSapCfg->sapPst.region = cfg->s.schInstCfg.rgmSap[sapIdx].mem.region;
233          upSapCfg->sapPst.pool = cfg->s.schInstCfg.rgmSap[sapIdx].mem.pool;
234          upSapCfg->sapPst.selector = cfg->s.schInstCfg.rgmSap[sapIdx].selector;
235          upSapCfg->sapPst.route = cfg->s.schInstCfg.rgmSap[sapIdx].route;
236          upSapCfg->sapPst.intfVer = 0; 
237          upSapCfg->sapPst.event = 0; 
238          upSapCfg->sapPst.prior = cfg->s.schInstCfg.rgmSap[sapIdx].prior;
239          upSapCfg->suId = cfg->s.schInstCfg.rgmSap[sapIdx].suId;
240          upSapCfg->spId = cfg->s.schInstCfg.rgmSap[sapIdx].spId;
241
242          break;
243       default:
244          /* would never reach here */
245          break;
246    }
247    return (ret);
248 }
249 #endif
250 \f
251 /***********************************************************
252  *
253  *     Func : rgSCHLmmShutdown
254  *        
255  *
256  *     Desc : Handles the scheduler instance shutdown request. Calls 
257  *     rgSCHCfgFreeCellCb(RgSchCellCb*) to handle each cellCb deallocation.
258  *            
259  *
260  *     Ret  : Void
261  *
262  *     Notes: 
263  *
264  *     File : rg_sch_lmm.c 
265  *
266  **********************************************************/
267 static Void rgSCHLmmShutdown(Inst inst)
268 {
269    Inst          dInst = inst + SCH_INST_START;
270    uint8_t       idx;
271 #ifdef LTE_L2_MEAS
272    CmLList       *lnk = NULLP;
273    RgSchCb       *instCb =  &rgSchCb[inst];
274    RgSchCellCb   *cell = NULLP;
275    RgSchL2MeasCb *measCb;
276    uint8_t       ulAllocIdx;
277    RgSchCmnUlCell *cellUl;
278    RgSchClcBoRpt  *bo = NULL;
279 #endif
280
281 #ifdef LTE_L2_MEAS
282    for (idx = 0; idx < instCb->numSaps; idx++)
283    {
284      /* got the cell break the loop */
285      cell = instCb->rgrSap[idx].cell;
286      if(cell != NULLP)
287      {
288         /* Free the memory held up by  ulAllocInfo */
289         cellUl = RG_SCH_CMN_GET_UL_CELL(cell);
290 #ifdef LTE_TDD
291         for(ulAllocIdx = 0; ulAllocIdx < RGSCH_SF_ALLOC_SIZE; ulAllocIdx++)
292 #else
293         for(ulAllocIdx = 0; ulAllocIdx < RGSCH_NUM_SUB_FRAMES; ulAllocIdx++)
294 #endif
295         {
296            if(cell->sfAllocArr[ulAllocIdx].ulUeInfo.ulAllocInfo != NULLP)
297            {
298              /* ccpu00117052 - MOD - Passing double pointer
299              for proper NULLP assignment*/
300              rgSCHUtlFreeSBuf(cell->instIdx, 
301                     (Data **)(&(cell->sfAllocArr[ulAllocIdx].ulUeInfo.\
302                                 ulAllocInfo)),
303                     cellUl->maxAllocPerUlSf * sizeof(RgInfUeUlAlloc));
304            }
305         }
306         /* Free the memory allocated to measCb */
307         lnk = cell->l2mList.first;
308         while(lnk != NULLP)
309         {
310            measCb = (RgSchL2MeasCb *)lnk->node;
311            cmLListDelFrm(&cell->l2mList, lnk);
312            lnk = lnk->next;
313              /* ccpu00117052 - MOD - Passing double pointer
314              for proper NULLP assignment*/
315            rgSCHUtlFreeSBuf(cell->instIdx, (Data **)&measCb,\
316                           sizeof(RgSchL2MeasCb));
317         }
318
319         /* Free mem if any present for boLst for common channels */
320         for(idx = 0; idx < RGSCH_MAX_CMN_LC_CB; idx++)
321         {
322            lnk = (CmLList *)cell->cmnLcCb[idx].boLst.first;
323            while (lnk)
324            {
325               bo = (RgSchClcBoRpt *)(lnk->node);
326               lnk = lnk->next;
327               cmLListDelFrm(&cell->cmnLcCb[idx].boLst, &bo->boLstEnt);
328               rgSCHUtlFreeSBuf(cell->instIdx, (Data **)&bo, sizeof(RgSchClcBoRpt));
329            }
330         }
331      }
332    }
333 #endif
334
335 #ifdef LTE_ADV
336    rgSCHLaaDeInitEnbCb(&rgSchCb[inst]);
337 #endif
338    for (idx = 0; idx < rgSchCb[inst].numSaps; idx++)
339    {
340       /* Unbind all the TFU SAP */
341       if(rgSchCb[inst].tfuSap[idx].sapSta.sapState == LRG_WAIT_BNDCFM)
342       {
343          //rgSCHUtlTfuUBndReq(inst, rgSchCb[inst].tfuSap[idx].sapCfg, LRG_UNBND);
344          if (rgSchCb[inst].tfuSap[idx].sapCfg.bndTmr.enb == TRUE)
345          {
346             rgSCHLmmStopTmr(inst, RGSCH_BNDREQ_TMR, (PTR)&rgSchCb[inst].tfuSap[idx]); 
347          }
348          rgSchCb[inst].tfuSap[idx].sapSta.sapState = LRG_UNBND;
349       }
350       if(rgSchCb[inst].tfuSap[idx].sapSta.sapState == LRG_BND)
351       {
352          //rgSCHUtlTfuUBndReq(inst, rgSchCb[inst].tfuSap[idx].sapCfg, LRG_UNBND);
353          rgSchCb[inst].tfuSap[idx].sapSta.sapState = LRG_UNBND;
354       }
355       /* Free the memory held by the cell associated with this SAP */
356       if (rgSchCb[inst].tfuSap[idx].cell != NULLP)
357          rgSCHCfgFreeCellCb(rgSchCb[inst].tfuSap[idx].cell);
358       rgSchCb[inst].tfuSap[idx].cell = NULLP;
359    }
360    /* Free the memory held by the scheduler instance */
361    /* Deallocate RGR saps */
362    SPutSBuf(rgSchCb[inst].rgSchInit.region,
363                 rgSchCb[inst].rgSchInit.pool,
364                 (Data *)rgSchCb[inst].rgrSap,
365                 (sizeof(RgSchUpSapCb) * rgSchCb[inst].numSaps));
366    rgSchCb[inst].rgrSap = NULLP;
367    /* Deallocate RGM saps */
368    SPutSBuf(rgSchCb[inst].rgSchInit.region,
369                 rgSchCb[inst].rgSchInit.pool,
370                 (Data *)rgSchCb[inst].rgmSap,
371                 (sizeof(RgSchUpSapCb) * rgSchCb[inst].numSaps));
372    rgSchCb[inst].rgmSap = NULLP;
373
374    /* Deallocate TFU saps */
375    SPutSBuf(rgSchCb[inst].rgSchInit.region,
376                 rgSchCb[inst].rgSchInit.pool,
377                 (Data *)rgSchCb[inst].tfuSap,
378                 (sizeof(RgSchLowSapCb) * rgSchCb[inst].numSaps));
379    rgSchCb[inst].tfuSap = NULLP;
380
381    /* Deallocate bndCfmResponses */
382    SPutSBuf(rgSchCb[inst].rgSchInit.region,
383                 rgSchCb[inst].rgSchInit.pool,
384                 (Data *)rgSchCb[inst].genCfg.bndCfmResp,
385                 (sizeof(RgSchLmResponse) * rgSchCb[inst].numSaps));
386    rgSchCb[inst].genCfg.bndCfmResp = NULLP;
387    /* De-register the Timer Service */
388    (Void) SDeregTmrMt(rgSchCb[inst].rgSchInit.ent, dInst,
389                      (S16)rgSchCb[inst].genCfg.tmrRes, schActvTmr); 
390
391    /* call back the task initialization function to intialize
392     * the global rgSchCb[inst] Struct */
393    schActvInit(rgSchCb[inst].rgSchInit.ent, dInst, rgSchCb[inst].rgSchInit.region, 
394               rgSchCb[inst].rgSchInit.reason);
395    
396    /* Set Config done in TskInit */
397    rgSchCb[inst].rgSchInit.cfgDone = FALSE;
398
399    return;
400 }
401
402 \f
403 /***********************************************************
404  *
405  *     Func : rgSCHLmmGenCntrl 
406  *        
407  *
408  *     Desc : Processes the LM control request for STGEN elmnt.
409  *            
410  *
411  *     Ret  : Void
412  *
413  *     Notes: 
414  *
415  *     File : rg_sch_lmm.c 
416  *
417  **********************************************************/
418 Void rgSCHLmmGenCntrl(RgMngmt *cntrl,RgMngmt *cfm,Pst  *cfmPst)
419 {
420    Inst      inst = (cfmPst->srcInst - SCH_INST_START); /* Scheduler instance ID */
421
422    cfm->cfm.status = LCM_PRIM_OK;
423    cfm->cfm.reason = LCM_REASON_NOT_APPL;
424    
425
426    switch(cntrl->t.cntrl.action)
427    {
428       case AENA:
429          /* Action is Enable */
430          switch(cntrl->t.cntrl.subAction)
431          {
432             case SAUSTA:   
433             /* Enable Unsolicited Status (alarms) */
434                rgSchCb[inst].rgSchInit.usta = TRUE;
435                /*Store the response and TransId for sending the Alarms */
436                memcpy(&rgSchCb[inst].genCfg.ustaResp.response, 
437                &cntrl->hdr.response, sizeof(Resp));
438                rgSchCb[inst].genCfg.ustaResp.transId = cntrl->hdr.transId;
439                break;
440             case SADBG:
441             /* Enable Debug Printing */
442 #ifdef DEBUGP
443                rgSchCb[inst].rgSchInit.dbgMask |= cntrl->t.cntrl.s.rgDbgCntrl.dbgMask;
444 #endif
445                break;
446 #ifdef PHY_ERROR_LOGING
447             case SAELMNT:
448                {
449                   rgSchUlAllocCntr.mcs = cntrl->t.cntrl.s.rgSchUlAllocCntrl.mcs;
450                   rgSchUlAllocCntr.numOfRb = cntrl->t.cntrl.s.rgSchUlAllocCntrl.numOfRb;
451                   rgSchUlAllocCntr.rbStart = cntrl->t.cntrl.s.rgSchUlAllocCntrl.rbStart;
452                   rgSchUlAllocCntr.testStart = cntrl->t.cntrl.s.rgSchUlAllocCntrl.testStart;
453                   rgSchUlAllocCntr.enaLog = cntrl->t.cntrl.s.rgSchUlAllocCntrl.enaLog;
454                   rgSchUlAllocCntr.logTime = cntrl->t.cntrl.s.rgSchUlAllocCntrl.logTime;
455                   rgSchUlAllocCntr.crcOk = 0;
456                   rgSchUlAllocCntr.crcErr = 0;
457                   rgSchUlAllocCntr.numUlPackets = 0;
458                   rgSchUlAllocCntr.numPrach = 0;
459                   rgSchUlAllocCntr.taZero = 0;
460 #ifdef MAC_SCH_STATS
461                   /* Reset
462                    * L2
463                    * statistics
464                    * */
465                   memset(&hqRetxStats, 0, sizeof(RgSchHqRetxStats));
466                   memset(&hqFailStats, 0, sizeof(RgSchNackAckStats));
467 #endif
468                   break;
469                }
470 #endif
471             default:
472                cfm->cfm.status = LCM_PRIM_NOK;
473                cfm->cfm.reason = LCM_REASON_INVALID_PAR_VAL;
474                DU_LOG("\nERROR  -->  SCH : rgSCHLmmGenCntrl(): "
475                   "invalid subaction=%d", cntrl->t.cntrl.subAction);
476                break;
477          }
478          break;
479       case ADISIMM:
480          /* Action is Diable immidiately */
481          switch(cntrl->t.cntrl.subAction)
482          {
483             case SAUSTA:
484             /* Disable Unsolicited Status (alarms) */
485                rgSchCb[inst].rgSchInit.usta = FALSE;
486                break;
487             case SADBG:
488             /* Disable Debug Printing */
489 #ifdef DEBUGP
490                rgSchCb[inst].rgSchInit.dbgMask &=\
491                           ~cntrl->t.cntrl.s.rgDbgCntrl.dbgMask;
492 #endif
493                break;
494
495             default:
496                cfm->cfm.status = LCM_PRIM_NOK;
497                cfm->cfm.reason = LCM_REASON_INVALID_PAR_VAL;
498                DU_LOG("\nERROR  -->  SCH : rgSCHLmmGenCntrl():"
499                  " invalid subaction=%d", cntrl->t.cntrl.subAction);
500                break;
501          }
502          break;
503       case ASHUTDOWN:
504          /* Free all the memory dynamically allocated by MAC */
505          rgSCHLmmShutdown(inst);
506          break;
507       default:
508          cfm->cfm.status = LCM_PRIM_NOK;
509          cfm->cfm.reason = LCM_REASON_INVALID_PAR_VAL;
510          DU_LOG("\nERROR  -->  SCH : rgSCHLmmGenCntrl(): invalid"
511           " action=%d", cntrl->t.cntrl.action);
512          break;
513    }
514    RgMiLrgSchCntrlCfm(cfmPst, cfm);
515    return;
516 }
517
518 \f
519 /***********************************************************
520  *
521  *     Func : rgSCHLmmSapCntrl 
522  *        
523  *
524  *     Desc : Processes the LM control request for STxxxSAP elmnt.
525  *            
526  *
527  *     Ret  : Void
528  *
529  *     Notes: 
530  *
531  *     File : rg_sch_lmm.c 
532  *
533  **********************************************************/
534 Void rgSCHLmmSapCntrl 
535 (
536 RgMngmt       *cntrl,
537 RgMngmt       *cfm,
538 Pst           *cfmPst
539 )
540 {
541    uint8_t       idx;
542
543    /* TODO Pass InstId instead of using InstId from cfmPst */
544    Inst      inst = (cfmPst->srcInst - SCH_INST_START); /* Scheduler instance Id */
545
546    /* Only TFU SAP can be controlled by LM */
547    switch(cntrl->hdr.elmId.elmnt)
548    {
549       case STTFUSAP:
550          idx = (uint8_t)cntrl->t.cntrl.s.rgSapCntrl.suId;
551          if (idx > LRG_MAX_SAPS_PER_INST)
552          {
553             cfm->cfm.status = LCM_PRIM_NOK;
554             cfm->cfm.reason = LCM_REASON_INVALID_SAP;
555          }
556          switch(cntrl->t.cntrl.action)
557          {
558             case ABND:
559                /* Bind Enable Request */
560                if ((rgSchCb[inst].tfuSap[idx].sapSta.sapState == LRG_NOT_CFG) ||
561                    (rgSchCb[inst].tfuSap[idx].sapSta.sapState == LRG_BND))
562                {
563                   cfm->cfm.status = LCM_PRIM_NOK;
564                   cfm->cfm.reason = LCM_REASON_INVALID_SAP;
565                }
566                else
567                {
568                   if (rgSchCb[inst].tfuSap[idx].sapCfg.bndTmr.enb == TRUE)
569                   {
570                      rgSCHLmmStartTmr(inst, RGSCH_BNDREQ_TMR,
571                                   rgSchCb[inst].tfuSap[idx].sapCfg.bndTmr.val, 
572                                   (PTR)&rgSchCb[inst].tfuSap[idx]);
573                   }
574                   /* Change SAP state */
575                   rgSchCb[inst].tfuSap[idx].sapSta.sapState = LRG_WAIT_BNDCFM;
576                   rgSchCb[inst].tfuSap[idx].numBndRetries++;
577                   /* Store the response and TransId for sending 
578                    * the Control confirm */
579                   memcpy(&rgSchCb[inst].genCfg.bndCfmResp[idx].response,
580                            &cntrl->hdr.response, sizeof(Resp));
581                   rgSchCb[inst].genCfg.bndCfmResp[idx].transId = 
582                                                 cntrl->hdr.transId;
583                   
584                   cfm->cfm.status = LCM_PRIM_OK_NDONE;
585                   cfm->cfm.reason = LCM_REASON_NOT_APPL;
586
587                   /* Sending Control Confirm before sending Bind
588                    * Request to TFU  */
589                   RgMiLrgSchCntrlCfm(cfmPst, cfm);
590                   
591                   //rgSCHUtlTfuBndReq(inst, rgSchCb[inst].tfuSap[idx].sapCfg.suId, 
592                     //             rgSchCb[inst].tfuSap[idx].sapCfg.spId);
593                  return; 
594                }
595                break;
596             case AUBND:
597             /* Unbind request */
598
599                /* Check if the SAP is configured */
600                if( (rgSchCb[inst].tfuSap[idx].sapSta.sapState == LRG_NOT_CFG) ||
601                      (rgSchCb[inst].tfuSap[idx].sapSta.sapState == LRG_UNBND))
602                {
603                   cfm->cfm.status = LCM_PRIM_NOK;
604                   cfm->cfm.reason = LCM_REASON_INVALID_MSGTYPE;
605                }
606                else
607                {
608                   //rgSCHUtlTfuUBndReq(inst, rgSchCb[inst].tfuSap[idx].sapCfg,
609                     //              TFU_UBNDREQ_MNGMT);
610                   if (rgSchCb[inst].tfuSap[idx].sapCfg.bndTmr.enb == TRUE)
611                   {
612                      rgSCHLmmStopTmr(inst, RGSCH_BNDREQ_TMR, 
613                                        (PTR)&rgSchCb[inst].tfuSap[idx]);
614                   }
615                   /* Change SAP state */
616                   rgSchCb[inst].tfuSap[idx].sapSta.sapState = LRG_UNBND;
617                   cfm->cfm.status = LCM_PRIM_OK;
618                   cfm->cfm.reason = LCM_REASON_NOT_APPL;
619                }
620                break;
621             case ADEL:
622                /* Delete SAP, does initialization of SAP */
623                if ((rgSchCb[inst].tfuSap[idx].sapSta.sapState == LRG_WAIT_BNDCFM) ||
624                    (rgSchCb[inst].tfuSap[idx].sapSta.sapState == LRG_BND))
625                {
626                   //rgSCHUtlTfuUBndReq(inst, rgSchCb[inst].tfuSap[idx].sapCfg,
627                     //              TFU_UBNDREQ_MNGMT);
628                   if (rgSchCb[inst].tfuSap[idx].sapCfg.bndTmr.enb == TRUE)
629                   {
630                      rgSCHLmmStopTmr(inst, RGSCH_BNDREQ_TMR,
631                                      (PTR)&rgSchCb[inst].tfuSap[idx]);
632                   }
633                }
634                memset(&rgSchCb[inst].tfuSap[idx], 0, sizeof(RgSchLowSapCb));
635                rgSchCb[inst].tfuSap[idx].sapSta.sapState = LRG_NOT_CFG;
636                cfm->cfm.status = LCM_PRIM_OK;
637                cfm->cfm.reason = LCM_REASON_NOT_APPL;
638                break;
639             default:
640                cfm->cfm.status = LCM_PRIM_NOK;
641                cfm->cfm.reason = LCM_REASON_INVALID_PAR_VAL;
642                DU_LOG("\nERROR  -->  SCH : rgSCHLmmSapCntrl(): "
643                   "invalid action=%d", cntrl->t.cntrl.action);
644                break;
645          }
646          break;
647       case STRGRSAP:
648          idx = (uint8_t)cntrl->t.cntrl.s.rgSapCntrl.spId;
649          if (idx > LRG_MAX_SAPS_PER_INST)
650          {
651             cfm->cfm.status = LCM_PRIM_NOK;
652             cfm->cfm.reason = LCM_REASON_INVALID_SAP;
653          }
654          switch(cntrl->t.cntrl.action)
655          {
656             case ADEL:
657                memset(&rgSchCb[inst].rgrSap[idx], 0, sizeof(RgSchUpSapCb));
658                rgSchCb[inst].rgrSap[idx].sapSta.sapState = LRG_NOT_CFG;
659                cfm->cfm.status = LCM_PRIM_OK;
660                cfm->cfm.reason = LCM_REASON_NOT_APPL;
661                break;
662             default:
663                cfm->cfm.status = LCM_PRIM_NOK;
664                cfm->cfm.reason = LCM_REASON_INVALID_PAR_VAL;
665                DU_LOG("\nERROR  -->  SCH : rgSCHLmmSapCntrl(): "
666                      "invalid action=%d", cntrl->t.cntrl.action);
667                break;
668          }
669          break;
670       case STRGMSAP:
671          idx = (uint8_t)cntrl->t.cntrl.s.rgSapCntrl.spId;
672          if (idx > LRG_MAX_SAPS_PER_INST)
673          {
674             cfm->cfm.status = LCM_PRIM_NOK;
675             cfm->cfm.reason = LCM_REASON_INVALID_SAP;
676          }
677          switch(cntrl->t.cntrl.action)
678          {
679             case ADEL:
680                memset(&rgSchCb[inst].rgmSap[idx], 0, sizeof(RgSchUpSapCb));
681                rgSchCb[inst].rgmSap[idx].sapSta.sapState = LRG_NOT_CFG;
682                cfm->cfm.status = LCM_PRIM_OK;
683                cfm->cfm.reason = LCM_REASON_NOT_APPL;
684                break;
685             default:
686                cfm->cfm.status = LCM_PRIM_NOK;
687                cfm->cfm.reason = LCM_REASON_INVALID_PAR_VAL;
688                DU_LOG("\nERROR  -->  SCH : rgSCHLmmSapCntrl(): "
689                      "invalid action=%d", cntrl->t.cntrl.action);
690                break;
691          }
692          break;
693
694        default:
695          /* Would never come here. */
696          return;
697    }
698    RgMiLrgSchCntrlCfm(cfmPst, cfm);
699    return;
700 }
701
702 \f
703 /***********************************************************
704  *
705  *     Func : SchFillCfmPst 
706  *        
707  *
708  *     Desc : Fills the Confirmation Post Structure cfmPst using the reqPst 
709  *            and the cfm->hdr.response.
710  *            
711  *
712  *     Ret  : Void
713  *
714  *     Notes: 
715  *
716  *     File : rg_sch_lmm.c 
717  *
718  **********************************************************/
719 Void SchFillCfmPst
720 (
721 Pst           *reqPst,
722 Pst           *cfmPst,
723 RgMngmt       *cfm
724 )
725 {
726    Inst inst;
727
728    inst = (reqPst->dstInst - SCH_INST_START);
729
730    cfmPst->srcEnt    = ENTMAC;
731    cfmPst->srcInst   = (Inst) 1;
732    cfmPst->srcProcId = rgSchCb[inst].rgSchInit.procId;
733    cfmPst->dstEnt    = ENTMAC;
734    cfmPst->dstInst   = (Inst) 0;
735    cfmPst->dstProcId = reqPst->srcProcId;
736
737    cfmPst->selector  = cfm->hdr.response.selector;
738    cfmPst->region    = cfm->hdr.response.mem.region;
739    cfmPst->pool      = cfm->hdr.response.mem.pool;
740
741    return;
742 }
743
744 \f
745 /**
746  * @brief Timer start handler. 
747  *
748  * @details
749  *
750  *     Function : rgSCHLmmStartTmr
751  *     
752  *     This function based on the input parameters starts the timer for 
753  *     "tmrVal" duration. As of now scheduler instance uses the timer 
754  *     functionality for BndReq only. Hence there is no conditional
755  *     code based on "tmrEvnt".
756  *     
757  *  @param[in]  S16   tmrEvnt, the Timer Event    
758  *  @param[in]  uint32_t   tmrVal,  the Wait Time
759  *  @param[in]  PTR   cb,  Entry for which Timer expired
760  *  @return  S16
761  *      -# ROK
762  **/
763 S16 rgSCHLmmStartTmr
764 (
765 Inst       inst,
766 S16        tmrEvnt,            /* Timer Event */
767 uint32_t   tmrVal,             /* Wait Time */
768 PTR        cb                  /* Entry for which Timer Expired */
769 )
770 {
771    CmTmrArg    arg;
772 /*   Inst        dInst = inst + SCH_INST_START; */
773
774    UNUSED(tmrEvnt);
775
776    /* Initialize the arg structure */
777    memset(&arg, 0, sizeof(CmTmrArg));
778
779    arg.tqCp = &rgSchCb[inst].tmrTqCp;
780    arg.tq = rgSchCb[inst].tmrTq;
781    arg.timers = &((RgSchLowSapCb *)cb)->tmrBlk;
782    arg.cb = cb;
783    arg.tNum = 0;
784    arg.max = RGSCH_MAX_TIMER;
785    arg.evnt = RGSCH_BNDREQ_TMR;
786    arg.wait = tmrVal;      
787    cmPlcCbTq(&arg);
788
789    return ROK;
790 }
791
792 \f
793 /**
794  * @brief Timer stop handler. 
795  *
796  * @details
797  *
798  *     Function : rgSCHLmmStopTmr
799  *     
800  *     This function based on the input parameters stops the timer for 
801  *     "tmrEvnt". As of now Scheduler instance uses the timer functionality for
802  *     BndReq only. Hence there is no conditional code based on "tmrEvnt".
803  *     Once the bind happens and this timer is stopped, the timer functionality
804  *     is deregistered with SSI. As there is no further use of timer processing.
805  *     
806  *  @param[in]  S16   tmrEvnt, the Timer Event    
807  *  @param[in]  PTR   cb,  Entry for which Timer expired
808  *  @return  S16
809  *      -# ROK
810  *      -# RFAILED
811  **/
812 S16 rgSCHLmmStopTmr
813 (
814 Inst inst,             /* Scheduler instance */
815 S16  tmrEvnt,            /* Timer Event */
816 PTR  cb                  /* Entry for which Timer Expired */
817 )
818 {
819    CmTmrArg   arg;
820    uint8_t    i;
821    S16        ret; 
822
823    ret = RFAILED;
824
825    for(i=0;i<RGSCH_MAX_TIMER;i++)
826    {
827       /* Search for the Timer Blocks */
828       if(((RgSchLowSapCb *)cb)->tmrBlk.tmrEvnt == tmrEvnt)
829       {
830          /* Initialize the arg structure */
831          memset(&arg, 0, sizeof(CmTmrArg));
832
833          arg.tqCp = &rgSchCb[inst].tmrTqCp;
834          arg.tq = rgSchCb[inst].tmrTq;
835          arg.timers = &(((RgSchLowSapCb *)cb)->tmrBlk);
836          arg.cb = cb;
837          arg.max = RGSCH_MAX_TIMER;
838          arg.evnt = tmrEvnt;
839
840          arg.tNum = i;   
841          cmRmvCbTq(&arg);
842          ret = ROK;
843          break;
844       }
845
846    }
847
848
849    return (ret);
850 }
851
852 \f
853 /**
854  * @brief Timer Expiry handler. 
855  *
856  * @details
857  *
858  *     Function : rgSCHLmmTmrExpiry
859  *     
860  *     This is a callback function used as an input parameter to cmPrcTmr()
861  *     to check expiry of any timer. In this function, we are only concerned
862  *     about tmrEvnt=Bind timer.
863  *     
864  *  @param[in]  PTR   cb,  Entry for which Timer expired
865  *  @param[in]  S16   tmrEvnt, the Timer Event    
866  *  @return  S16
867  *      -# ROK
868  **/
869 S16 rgSCHLmmTmrExpiry
870 (
871 PTR cb,               /* Pointer to timer control block */
872 S16 tmrEvnt           /* Timer Event */
873 )
874 {
875    S16           ret = ROK;
876    RgSchLowSapCb *tfuSap = (RgSchLowSapCb *)cb;
877
878    
879    switch(tmrEvnt)
880    {
881       case RGSCH_BNDREQ_TMR:
882          tfuSap->numBndRetries++;
883          if(tfuSap->numBndRetries > RGSCH_MAX_BNDRETRY)
884          {
885             rgSCHLmmStaInd((uint8_t)(tfuSap->sapCfg.sapPst.srcInst - SCH_INST_START),
886                            (uint16_t)LCM_CATEGORY_INTERFACE, (uint16_t)LCM_EVENT_BND_FAIL,
887                            (uint16_t)LCM_CAUSE_TMR_EXPIRED, (RgUstaDgn *)NULLP);
888          }
889          else
890          {
891             /* Restart the bind timer */
892             if (tfuSap->sapCfg.bndTmr.enb == TRUE)
893             {
894                ret = rgSCHLmmStartTmr((uint8_t)(tfuSap->sapCfg.sapPst.srcInst - SCH_INST_START),
895                                   RGSCH_BNDREQ_TMR, 
896                                  (uint32_t)tfuSap->sapCfg.bndTmr.val, cb);
897             }
898
899             /* Send bind request */
900             //rgSCHUtlTfuBndReq((uint8_t)(tfuSap->sapCfg.sapPst.srcInst - SCH_INST_START), 
901             //tfuSap->sapCfg.suId, tfuSap->sapCfg.spId);
902          }
903          break;
904       default:
905          DU_LOG("\nERROR  -->  SCH : rgSCHLmmTmrExpiry(): Invalid"
906                  " tmrEvnt=%d", tmrEvnt);
907          ret = RFAILED;
908          break;
909    }
910    return (ret);
911 }
912
913 \f
914 /**
915  * @brief Layer Manager Control Confirm generation handler
916  *        for Bind Confirm reception at TFU interface.
917  *        RgLiTfuBndCfm() forwards the confirmation to this 
918  *        function. All SAP state related handling is restricted
919  *        to LMM modules, hence the cfm forwarding.
920  *
921  * @details
922  *
923  *     Function : rgSCHLmmBndCfm 
924  *     
925  *     This API is used by the LIM module of MAC to forward
926  *     the Bind Confirm it receives over the TFU interface.
927  *     
928  *  @param[in]   Pst *pst, Post Structure
929  *  @param[in]   SuId suId, Service user ID
930  *  @param[in]   uint8_t status, Status
931  *  @return  S16
932  *      -# ROK
933  **/
934 S16 rgSCHLmmBndCfm
935 (
936 Pst *pst,               /* Post Structure */
937 SuId suId,              /* Service user ID */
938 uint8_t status               /* Status */
939 )
940 {
941    S16       ret = ROK;
942    RgMngmt   cntrlCfm;
943    Pst       cfmPst;
944    Inst      inst = (pst->dstInst - SCH_INST_START); /* scheduler instance */
945
946
947    /* check the SAP State */
948    switch(rgSchCb[inst].tfuSap[suId].sapSta.sapState)
949    {
950       case LRG_WAIT_BNDCFM:
951          break;
952       case LRG_BND:
953          /* SAP is already bound */
954          return ROK;
955       default:
956          return RFAILED;
957    }
958
959    cfmPst = rgSchCb[inst].rgSchInit.lmPst;
960    cfmPst.selector = rgSchCb[inst].genCfg.bndCfmResp[suId].response.selector;
961    cfmPst.prior = rgSchCb[inst].genCfg.bndCfmResp[suId].response.prior;
962    cfmPst.route = rgSchCb[inst].genCfg.bndCfmResp[suId].response.route;
963    cfmPst.region = rgSchCb[inst].genCfg.bndCfmResp[suId].response.mem.region;
964    cfmPst.pool = rgSchCb[inst].genCfg.bndCfmResp[suId].response.mem.pool;
965    
966    memset(&cntrlCfm, 0, sizeof(RgMngmt));
967
968    switch(status)
969    {
970       case CM_BND_OK: /* status is OK */
971          /* Change SAP state to Bound */
972          rgSchCb[inst].tfuSap[suId].sapSta.sapState = LRG_BND;
973          if (rgSchCb[inst].tfuSap[suId].sapCfg.bndTmr.enb == TRUE)
974          {
975             ret = rgSCHLmmStopTmr(inst, RGSCH_BNDREQ_TMR, (PTR)&rgSchCb[inst].tfuSap[suId]);
976          }
977          /* Send Control Confirm with status as OK to Layer Manager */
978          cntrlCfm.cfm.status = LCM_PRIM_OK;
979          cntrlCfm.cfm.reason = LCM_REASON_NOT_APPL;
980         /* Sending Status Indication to Layer Manager */
981          rgSCHLmmStaInd((uint8_t)(rgSchCb[inst].tfuSap->sapCfg.sapPst.srcInst - SCH_INST_START),
982                LCM_CATEGORY_INTERFACE, LCM_EVENT_BND_OK,
983                LCM_CAUSE_LYR_SPECIFIC, (RgUstaDgn *)NULLP);
984          break;
985
986       default:
987          /* Change SAP state to UnBound */
988          rgSchCb[inst].tfuSap[suId].sapSta.sapState = LRG_UNBND;
989          if (rgSchCb[inst].tfuSap[suId].sapCfg.bndTmr.enb == TRUE)
990          {
991             ret = rgSCHLmmStopTmr(inst, RGSCH_BNDREQ_TMR, (PTR)&rgSchCb[inst].tfuSap[suId]);
992          }
993          /* Send Control Confirm with status as NOK to Layer Manager */
994          cntrlCfm.cfm.status = LCM_PRIM_NOK;
995          cntrlCfm.cfm.reason = LCM_REASON_NEG_CFM;
996          break;
997    }
998    rgSchCb[inst].tfuSap[suId].numBndRetries = 0;
999    cntrlCfm.hdr.elmId.elmnt = STTFUSAP;
1000    cntrlCfm.hdr.transId = rgSchCb[inst].genCfg.bndCfmResp[suId].transId;
1001
1002    ret = RgMiLrgSchCntrlCfm(&cfmPst, &cntrlCfm);
1003
1004    return (ret);
1005 }
1006
1007 /**
1008  * @brief Layer Manager Unsolicited Status Indication generation. 
1009  *
1010  * @details
1011  *
1012  *     Function : rgSCHLmmStaInd 
1013  *     
1014  *     This API is used by the other modules of MAC to send a unsolicited
1015  *     status indication to the Layer Manager.
1016  *     
1017  *  @param[in]  uint16_t category, the Alarm category
1018  *  @param[in]  uint16_t event, the Alarm event
1019  *  @param[in]  uint16_t cause, the cause of the Alarm
1020  *  @param[in]  RgUstaDgn *dgn, Alarm Diagonostics
1021  *  @return  S16
1022  *      -# ROK
1023  **/
1024 S16 rgSCHLmmStaInd
1025 (
1026 Inst inst,
1027 uint16_t  category,
1028 uint16_t  event,
1029 uint16_t  cause,
1030 RgUstaDgn *dgn
1031 )
1032 {
1033    RgMngmt    usta;
1034
1035    if(rgSchCb[inst].rgSchInit.usta == FALSE)
1036    {
1037       return ROK;
1038    }
1039    memset(&usta, 0, sizeof(RgMngmt));
1040
1041    SGetDateTime(&usta.t.usta.cmAlarm.dt);
1042    usta.t.usta.cmAlarm.category = category;
1043    usta.t.usta.cmAlarm.event = event;
1044    usta.t.usta.cmAlarm.cause = cause;
1045    if (dgn != NULLP)
1046    {
1047       memcpy(&usta.t.usta.dgn, dgn, sizeof(RgUstaDgn));
1048    }
1049
1050    rgSchCb[inst].rgSchInit.lmPst.selector = 
1051                        rgSchCb[inst].genCfg.ustaResp.response.selector;
1052    rgSchCb[inst].rgSchInit.lmPst.prior = 
1053                        rgSchCb[inst].genCfg.ustaResp.response.prior;
1054    rgSchCb[inst].rgSchInit.lmPst.route = 
1055                        rgSchCb[inst].genCfg.ustaResp.response.route;
1056    rgSchCb[inst].rgSchInit.lmPst.region = 
1057                        rgSchCb[inst].genCfg.ustaResp.response.mem.region;
1058    rgSchCb[inst].rgSchInit.lmPst.pool = 
1059                        rgSchCb[inst].genCfg.ustaResp.response.mem.pool;
1060    usta.hdr.transId = rgSchCb[inst].genCfg.ustaResp.transId;
1061
1062    return (RgMiLrgSchStaInd(&rgSchCb[inst].rgSchInit.lmPst, &usta));
1063 }
1064
1065 \f
1066 /**
1067  * @brief Scheduler instance timer call back function registered with SSI. 
1068  *
1069  * @details
1070  *
1071  *     Function :  schActvTmr
1072  *     
1073  *     This function is invoked by SSI for every timer activation
1074  *     period expiry. Note that SS_MT_TMR flag needs to be enabled for this
1075  *     as isntId is needed.As part of SRegTmr call for scheduler instance 
1076  *     SS_MT_TMR flag needs to be enabled and schActvTmr needs to be given as 
1077  *     callback function
1078  *     
1079  *  @return  S16
1080  *      -# ROK
1081  **/
1082 S16 schActvTmr(Ent ent,Inst inst)
1083 {
1084    Inst schInst = (inst  - SCH_INST_START);
1085
1086    /* Check if any timer in the scheduler instance has expired */ 
1087    cmPrcTmr(&rgSchCb[schInst].tmrTqCp,
1088             rgSchCb[schInst].tmrTq, (PFV) rgSCHLmmTmrExpiry);
1089  
1090    return ROK;
1091  
1092 } /* end of schActvTmr */
1093
1094 \f
1095 /**********************************************************************
1096  
1097          End of file
1098 **********************************************************************/