1 /*******************************************************************************
2 ################################################################################
3 # Copyright (c) [2017-2019] [Radisys] #
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 #
9 # http://www.apache.org/licenses/LICENSE-2.0 #
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 *******************************************************************************/
19 /************************************************************************
25 Desc: C source code for Scheduler common functions
29 **********************************************************************/
31 /** @file rg_sch_mga.c
32 @brief This module handles schedulers' measurement gap and ack-nack repetiton functionality */
34 static const char* RLOG_MODULE_NAME="MAC";
35 static int RLOG_MODULE_ID=4096;
36 static int RLOG_FILE_ID=169;
38 /* header include files -- defines (.h) */
39 #include "common_def.h"
44 #include "rg_sch_inf.h"
45 #include "rg_sch_err.h"
47 #include "rg_sch_cmn.h"
48 #include "rl_interface.h"
49 #include "rl_common.h"
51 /* header/extern include files (.x) */
52 #include "tfu.x" /* RGU types */
53 #include "lrg.x" /* layer management typedefs for MAC */
54 #include "rgr.x" /* layer management typedefs for MAC */
55 #include "rg_sch_inf.x" /* typedefs for Scheduler */
56 #include "rg_sch.x" /* typedefs for Scheduler */
59 static S16 rgSCHMeasGapANRepUtlAddUe ARGS((
62 RgrUeMeasGapCfg *cfg));
64 static S16 rgSCHMeasGapANRepUtlRmvUe ARGS((
68 static S16 rgSchAckNackRepUtlRmvUe ARGS((
72 static Void rgSchAckNackRepUtlHdlTti ARGS((
74 CmLListCp *ackNackRepQ));
76 static Void rgSCHMeasGapANRepUtlHdlTti ARGS((
78 CmLListCp *measGapQ));
80 static uint8_t rgSCHAckNakRepFindUlDuration ARGS((
83 CmLteTimingInfo repTime,
85 static Void rgSCHAckNakRepGetUlOffsetFrmDl ARGS((
87 CmLteTimingInfo crntDlTime,
92 * @brief Handles Measurement gap and ack-nack repetition related
93 * configuration for a UE.
97 * Function : rgSCHMeasGapANRepUeCfg
99 * Invoking Module Processing:
100 * - This shall be invoked by SCH_GOM at UE configuration. It shall do the
101 * validations for the spec-defined values.
104 * - For UE-specific measurement gap related configuration,
105 * - If measurementGap is configured,
106 * - Update UE with the configured values.
107 * - Add Ue to cell->measGapCb->gapPrdQ depending on the gap period
108 * configuration at index = the configured gap offset.
109 * - measGapOffst = the configured gap offset
110 * - Initialize timers.
112 * - measGapOffst = RG_INVALID_MEASGAPQ_ID
113 * - For UE-specific ACK-NACK repetition related configuration,
114 * - Update the configured value. Set 'cfgRepCnt' variable value.
115 * - repCntr = cfgRepCnt.
116 * - qOffst = RG_INVALID_ACKNACKREPQ_ID
119 * @param[in] RgSchCellCb *cell
120 * @param[in] RgSchUeCb *ue
121 * @param[in] RgrUeCfg *ueCfg
127 S16 rgSCHMeasGapANRepUeCfg(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeCfg *ueCfg)
130 ue->measGapCb.isMesGapEnabled = ueCfg->ueMesGapCfg.isMesGapEnabled;
132 if (ueCfg->ueMesGapCfg.isMesGapEnabled)
134 ue->measGapCb.gapPrd = ueCfg->ueMesGapCfg.gapPrd;
135 ue->measGapCb.gapOffst = ueCfg->ueMesGapCfg.gapOffst;
136 rgSCHMeasGapANRepUtlAddUe (cell, ue, &(ueCfg->ueMesGapCfg));
137 cmInitTimers (&ue->measGapCb.measGapTmr, 1);
138 cmInitTimers (&ue->measGapCb.measGapUlInactvTmr, 1);
139 cmInitTimers (&ue->measGapCb.measGapDlInactvTmr, 1);
142 /* ACK NACK repetition part */
143 if (ueCfg->ueAckNackCfg.isAckNackEnabled)
145 ue->ackNakRepCb.cfgRepCnt = ueCfg->ueAckNackCfg.ackNackRepFactor;
146 ue->ackNakRepCb.repCntr = ue->ackNakRepCb.cfgRepCnt;
147 ue->ackNakRepCb.isAckNackEnabled = TRUE;
148 ue->ackNakRepCb.pucchRes = ueCfg->ueAckNackCfg.pucchAckNackRep;
149 cmInitTimers (&ue->ackNakRepCb.ackNakRepUlInactvTmr, 1);
150 cmInitTimers (&ue->ackNakRepCb.ackNakRepDlInactvTmr, 1);
151 cmInitTimers (&ue->ackNakRepCb.ackNakRepTmr, 1);
157 * @brief Handles Measurement gap and ack-nack repetition related
158 * re-configuration for a UE.
162 * Function : rgSCHMeasGapANRepUeRecfg
164 * Invoking Module Processing:
165 * - This shall be invoked by SCH_GOM at UE re-configuration. It shall do the
166 * validations for the spec-defined values.
169 * - For measurement gap,
170 * - If measurement gap period or offset is re-configured, remove UE from
171 * the previous list, if any and add it to the new list.
172 * - Update configured values appropriately.
173 * - For ACK-NACK repetition,
174 * - Update the configured value. Set 'cfgRepCnt' variable value.
175 * - If (repCntr == 0)
176 * - repCntr = cfgRepCnt.
177 * - qOffst = RG_INVALID_ACKNACKREPQ_ID
179 * @param[in] RgSchCellCb *cell
180 * @param[in] RgSchUeCb *ue
181 * @param[in] RgrUeRecfg *ueRecfg
188 S16 rgSCHMeasGapANRepUeRecfg(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeRecfg *ueRecfg)
190 RgrUeMeasGapCfg *reCfg;
191 RgSchUeMeasGapCb *ueMeasCb;
192 RgrUeAckNackRepCfg *ackNackReCfg = &(ueRecfg->ueAckNackRecfg);
193 RgSchUeAckNakRepCb *ackNakRepCb = &(ue->ackNakRepCb);
195 reCfg = &(ueRecfg->ueMeasGapRecfg);
196 ueMeasCb = &(ue->measGapCb);
198 /* Removed extra comments
199 * Check this once again Check to see if anything changed or not */
200 if ((reCfg->isMesGapEnabled == TRUE) &&
201 (ueMeasCb->isMesGapEnabled == TRUE) &&
202 (reCfg->gapPrd == ueMeasCb->gapPrd) &&
203 (reCfg->gapOffst == ueMeasCb->gapOffst))
205 /* Nothing changed hence nothing to do */
209 if (reCfg->isMesGapEnabled)
211 if (ueMeasCb->isMesGapEnabled)
213 rgSCHMeasGapANRepUtlRmvUe (cell, ue);
217 cmInitTimers (&ueMeasCb->measGapTmr, 1);
218 cmInitTimers (&ueMeasCb->measGapUlInactvTmr, 1);
219 cmInitTimers (&ueMeasCb->measGapDlInactvTmr, 1);
222 /* Add to the correct Measurement gap queue */
223 rgSCHMeasGapANRepUtlAddUe (cell, ue, reCfg);
225 ueMeasCb->gapPrd = reCfg->gapPrd;
226 ueMeasCb->gapOffst = reCfg->gapOffst;
227 ueMeasCb->isMesGapEnabled = TRUE;
228 } /* if new config has Measurement gap enabled */
231 if (ueMeasCb->isMesGapEnabled)
233 /* check if return value needed or not */
234 rgSCHMeasGapANRepUtlRmvUe (cell, ue);
235 ueMeasCb->isMesGapEnabled = FALSE;
237 } /* if new config has Measurement gap disabled */
238 } /* For MeasGap configuration */
240 if (ackNackReCfg->isAckNackEnabled)
242 if (!ackNakRepCb->isAckNackEnabled)
244 ackNakRepCb->isAckNackEnabled = TRUE;
245 /* Timers need to be init immediately after config*/
246 cmInitTimers (&ue->ackNakRepCb.ackNakRepUlInactvTmr, 1);
247 cmInitTimers (&ue->ackNakRepCb.ackNakRepDlInactvTmr, 1);
248 cmInitTimers (&ue->ackNakRepCb.ackNakRepTmr, 1);
249 } /* repetition was disabled */
250 ackNakRepCb->pucchRes = ackNackReCfg->pucchAckNackRep;
251 ackNakRepCb->cfgRepCnt = ackNackReCfg->ackNackRepFactor;
252 if (ackNakRepCb->repCntr == 0)
254 ackNakRepCb->repCntr = ackNackReCfg->ackNackRepFactor;
256 } /* repetition enabled in re configuration */
259 ackNakRepCb->isAckNackEnabled = FALSE;
260 } /* repetition disabled in re configuration */
265 /** @brief This function is a utility to add the UE to the correct Measurement
266 * queue present in the cellCb.
280 static S16 rgSCHMeasGapANRepUtlAddUe(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeMeasGapCfg *cfg)
285 case RG_MEAS_GAPPRD_40:
286 /* Insert the UE into the linked list based on the gap Offset */
287 ue->measGapCb.measQLnk.node = (PTR)ue;
288 cmLListAdd2Tail (&(cell->measGapCb.gapPrd40Q[cfg->gapOffst]),
289 &(ue->measGapCb.measQLnk));
291 case RG_MEAS_GAPPRD_80:
292 ue->measGapCb.measQLnk.node = (PTR)ue;
293 cmLListAdd2Tail (&(cell->measGapCb.gapPrd80Q[cfg->gapOffst]),
294 &(ue->measGapCb.measQLnk));
297 RLOG_ARG1(L_ERROR,DBG_CELLID,cell->cellId,
298 "rgSCHMeasGapANRepUeRecfg() Incorrect GAP Period"
299 "CRNTI:%d",ue->ueId);
303 } /* end of rgSCHMeasGapANRepUtlAddUe */
306 /** @brief This function is a utility function to remove the ue from the measQ
307 * preset in tthe cell Cb.
320 static S16 rgSCHMeasGapANRepUtlRmvUe(RgSchCellCb *cell,RgSchUeCb *ue)
323 switch (ue->measGapCb.gapPrd)
325 case RG_MEAS_GAPPRD_40:
326 /* Remove from the existing list */
327 cmLListDelFrm (&(cell->measGapCb.gapPrd40Q[ue->measGapCb.gapOffst]),
328 &(ue->measGapCb.measQLnk));
329 ue->measGapCb.measQLnk.node = NULLP;
331 case RG_MEAS_GAPPRD_80:
332 /* Remove from the existing list */
333 cmLListDelFrm (&(cell->measGapCb.gapPrd80Q[ue->measGapCb.gapOffst]),
334 &(ue->measGapCb.measQLnk));
335 ue->measGapCb.measQLnk.node = NULLP;
339 } /* end of rgSCHMeasGapANRepUtlRmvUe */
342 * @brief Frees Measurement gap and ack-nack repetition related data structures in UE
346 * Function : rgSCHMeasGapANRepUeDel
348 * Invoking Module Processing:
349 * - This shall be invoked by SCH_GOM at Ue deletion.
352 * - For measurement gap,
353 * - if (measGapOffst != RG_INVALID_MEASGAPQ_ID)
354 * - Remove from the measurement queue depending on the measGapPrd
356 * - Delete all timers
357 * - For ACK-NACK repetition,
358 * - if (qOffst != RG_INVALID_ACKNACKREPQ_ID)
359 * - Remove from the ackNakRepQ queue
360 * - Delete all timers
363 * @param[in] RgSchCellCb *cell
364 * @param[in] RgSchUeCb *ue
370 Void rgSCHMeasGapANRepUeDel(RgSchCellCb *cell,RgSchUeCb *ue,Bool isUeDel)
373 if (ue->measGapCb.isMesGapEnabled)
375 rgSCHMeasGapANRepUtlRmvUe (cell, ue);
376 /* Must stop the timer if its running */
377 if (ue->measGapCb.isMeasuring)
379 rgSCHTmrStopTmr (cell, RG_SCH_TMR_MEASGAP, ue);
382 ue->measGapCb.isMesGapEnabled = FALSE;
385 /* Stop timers if running */
386 if (ue->dl.dlInactvMask)
388 if (ue->dl.dlInactvMask & RG_MEASGAP_INACTIVE)
390 rgSCHTmrStopTmr (cell, RG_SCH_TMR_DL_MEASGAP, ue);
392 if (ue->dl.dlInactvMask & RG_ACKNAKREP_INACTIVE)
394 rgSCHTmrStopTmr (cell, RG_SCH_TMR_DL_ACKNACK, ue);
396 ue->dl.dlInactvLnk.node = NULLP;
398 if (ue->ul.ulInactvMask)
400 if (ue->ul.ulInactvMask & RG_MEASGAP_INACTIVE)
402 rgSCHTmrStopTmr (cell, RG_SCH_TMR_UL_MEASGAP, ue);
404 if (ue->ul.ulInactvMask & RG_ACKNAKREP_INACTIVE)
406 rgSCHTmrStopTmr (cell, RG_SCH_TMR_UL_ACKNACK, ue);
408 ue->ul.ulInactvLnk.node = NULLP;
411 /* ccpu00133470- Releasing ACKNACK Rep UE Deleted */
412 if (isUeDel & ue->ackNakRepCb.isAckNakRep)
414 rgSCHTmrStopTmr (cell, RG_SCH_TMR_ACKNACK_REP, ue);
415 rgSchAckNackRepUtlRmvUe (cell, ue);
420 /** @brief This function deletes the UEs information related to ACK NACK
428 * - Mainly we need to remove the UEs hqProcs from the ackNackQ(s)
429 * present in the subframes.
436 static S16 rgSchAckNackRepUtlRmvUe(RgSchCellCb *cell,RgSchUeCb *ue)
442 RgSchDlHqProcCb *hqP;
445 RgSchDlHqEnt *hqEnt = RG_SCH_CMN_GET_UE_HQE(ue, cell);
447 for (hqIdx = 0; hqIdx < hqEnt->numHqPrcs; hqIdx++)
449 hqP = &hqEnt->procs[hqIdx];
450 /* Starting from index 1 as index 0 isn't used */
451 for (repIdx = 1; repIdx < ue->ackNakRepCb.cfgRepCnt; repIdx++)
453 for (tbCnt = 0; tbCnt < 2; tbCnt++)
455 if ((hqP->tbInfo[tbCnt].crntSubfrm[repIdx] != NULLP) &&
456 (hqP->tbInfo[tbCnt].anRepLnk[repIdx].node != NULLP))
458 cmLListDelFrm(&((hqP->tbInfo[tbCnt].crntSubfrm[repIdx])->\
459 ackNakRepQ), &hqP->tbInfo[tbCnt].anRepLnk[repIdx]);
460 hqP->tbInfo[tbCnt].anRepLnk[repIdx].node = NULLP;
461 hqP->tbInfo[tbCnt].crntSubfrm[repIdx] = NULLP;
472 * @brief Per TTI processing for measurement gap and ack nack repetition
477 * Function : rgSCHMeasGapANRepTtiHndl
479 * Invoking Module Processing:
480 * - This shall be invoked by SCH_TOM on recieving TTI indication from PHY
481 * . SCH_TOM shall update the cell->crntTime before invoking this API.
484 * - Compute qOffset for 40ms queue as =
485 * ((cell->crntTime->sfn * 10)+cell->crntTime->subframe)%RG_MEAS_GAPPRD_40.
486 * - Mark all the UEs at computed offset for performing measurement. Set
487 * isMeasuring = TRUE.
488 * - Start measGapTmr for each UE:
489 * - length = RG_MEAS_GAP_LEN.
490 * - event = RG_MEASGAP_ON
491 * - handler = rgSCHMeasGapANRepTmrExpry
492 * - Reinitalize the list at the offset.
493 * - Compute qOffset for 80ms queue as =
494 * ((cell->crntTime->sfn * 10)+cell->crntTime->subframe)%RG_MEAS_GAPPRD_80.
495 * - Mark all the UEs at computed offset for performing measurement. Set
496 * isMeasuring = TRUE.
497 * - Start measGapTmr for each UE:
498 * - length = RG_MEAS_GAP_LEN.
499 * - event = RG_MEASGAP_ON
500 * - handler = rgSCHMeasGapANRepTmrExpry
501 * - Reinitalize the list at the offset.
502 * - Compute qOffset for ACK NACK repetition queue as =
503 * ((cell->crntTime->sfn * 10)+cell->crntTime->subframe)%RG_MAX_NUM_DLSF.
504 * - Mark all the UEs at computed offset for performing ack-nack repetition. Set
505 * isAckNakRep = TRUE.
506 * - Start ackNakRepTmr for each UE:
507 * - length = repCntr.
508 * - event = RG_ACKNAKREP_ON
509 * - handler = rgSchAckNakRepTmrExpry
510 * - Reinitalize the list at the offset.
511 * - 'isMeasuring' bool value shall be cheked
512 * - While sending dataRecpReq to PHY for non-adaptive uplink re-tx
513 * and if 'TRUE', no dataRecpReq shall be sent.
514 * - While sending NACK as feedback to UE and if 'TRUE' no PHICH shall
515 * be sent and shall mark the UE for adaptive re-tx.
516 * - While sending HqFbkRecpReq for a UE (applicable only if ACK NACK
517 * repetition coincides) and if 'TRUE',
518 * - The request shall not be sent.
519 * - Decrement repCntr
520 * - if (repCntr == 0)
521 * - Delete UE from the list.
522 * - Move the Ue to next subframe's list of ACK-NACK repeating UEs.
523 * - 'isAckNakRep' bool value shall be cheked
524 * - While sending dataRecpReq to PHY for non-adaptive uplink re-tx
525 * and if 'TRUE', no dataRecpReq shall be sent.
526 * - Check if any refresh for these cell-specific queues is needed
527 * anywhere else as well.
528 * - Check if TTI miss needs some trigger to the module.
531 * @param[in] RgSchCellCb *cell
537 S16 rgSCHMeasGapANRepTtiHndl(RgSchCellCb *cell)
542 CmLteTimingInfo repTime;
544 /* Measurement GAP Starts at offSet - however at MAC we are concerned at
545 * subframe + TFU_DELTA.
548 /* Introduced timing delta for DL control in FDD */
550 offset = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot + TFU_DELTA) %
553 offset = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot + TFU_DLCNTRL_DLDELTA) %
556 queue = &(cell->measGapCb.gapPrd40Q[offset]);
557 rgSCHMeasGapANRepUtlHdlTti (cell, queue);
559 /* Introduced timing delta for DL control in FDD */
561 offset = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot + TFU_DELTA) %
564 offset = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot + TFU_DLCNTRL_DLDELTA) %
567 queue = &(cell->measGapCb.gapPrd80Q[offset]);
568 rgSCHMeasGapANRepUtlHdlTti (cell, queue);
570 /* for ACK NACK repetition starts at offset - however at MAC we are
571 * concerned with subframe - TFU_DELTA */
572 /* offset = ((cell->crntTime.sfn * 10) + cell->crntTime.slot) %
573 * RG_MAX_NUM_DLSF; */
574 /* We wish to get the subframe whose HARQ Reception request would go out in
575 * this subframe. HARQ_RTT - TFU_DELTA
577 /* Introduced timing delta for reception req */
580 //RGSCHSUBFRMCRNTTIME(cell->crntTime, repTime, (4 - TFU_DELTA));
581 RGSCHDECRFRMCRNTTIME(cell->crntTime, repTime, (RG_SCH_CMN_HARQ_INTERVAL - TFU_RECPREQ_DLDELTA));
583 RGSCHDECRFRMCRNTTIME(cell->crntTime, repTime, (RG_SCH_CMN_HARQ_INTERVAL - TFU_RECPREQ_DLDELTA));
585 dlSf = rgSCHUtlSubFrmGet (cell, repTime);
586 queue = &(dlSf->ueLst);
587 rgSchAckNackRepUtlHdlTti (cell, queue);
592 /** @brief This function Marks the UE as ackNakRep so that Reception request
593 * isnt sent for any other thing than HARQ.
600 * - Loop through HARQ procs of the DlSf.
601 * - If the UE is a repeating one
602 * - Mark as ackNakRep = TRUE
605 * @param RgSchCellCb *cell
606 * @param CmLListCp *ackNakRepQ
609 static Void rgSchAckNackRepUtlHdlTti(RgSchCellCb *cell,CmLListCp *ackNackRepQ)
614 node = ackNackRepQ->first;
617 ue = (RgSchUeCb *)(node->node);
618 if ((NULLP != ue) && (ue->ackNakRepCb.isAckNackEnabled))
620 ue->ackNakRepCb.isAckNakRep = TRUE;
621 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_ACKNACK_REP,
622 ue->ackNakRepCb.repCntr);
630 /** @brief This function
644 static Void rgSCHMeasGapANRepUtlHdlTti(RgSchCellCb *cell,CmLListCp *measGapQ)
649 node = measGapQ->first;
652 ue = (RgSchUeCb*)node->node;
653 ue->measGapCb.isMeasuring = TRUE;
654 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_MEASGAP, RG_SCH_MEAS_GAP_LEN);
662 * @brief Determines the list of UEs inactive for DL scheduling due to
663 * measurement gap and ack nack repetitions
667 * Function : rgSCHMeasGapANRepGetDlInactvUe
669 * Invoking Module Processing:
670 * - This API shall be invoked to get list of inactive UEs for downlink
671 * scheduling due to measurement gaps and ACK NACK repetitions.
674 * - Compute qOffset for 40ms or 80ms queue as =
675 * ((cell->crntTime->sfn * 10)+cell->crntTime->subframe + DL_DELTA +
676 * RG_SCH_CMN_HARQ_INTERVAL)
677 * % RG_MEAS_GAPPRD_40 or RG_MEAS_GAPPRD_80.
678 * - Add all the UEs at computed offset to dlInactvUeLst since the
679 * DL transmission or feedback transmission from UE for DL
680 * transmissions shall collide with measurement gap.
681 * - Mark each UE. Set dlInactvMask |= RG_MEASGAP_INACTIVE
682 * - Start measGapDlInactvTmr timer for each UE,
683 * - length = RG_MEAS_GAP_LEN + RG_SCH_CMN_HARQ_INTERVAL
684 * - event = RG_MEASGAP_DLINACTV
685 * - handler = rgSCHMeasGapANRepDlInactvTmrExpry
686 * - Compute qOffset for ACK NACK repetition queue as =
687 * ((cell->crntTime->sfn * 10)+cell->crntTime->subframe + DL_DELTA +
688 * RG_SCH_CMN_HARQ_INTERVAL -1)
690 * - Add all the UEs at computed offset to dlInactvUeLst since the
691 * feedback transmission from UE for DL transmissions shall
692 * collide with ACK NACK repetition of the UE.
693 * - Mark each UE. Set dlInactvMask |= RG_ACKNAKREP_INACTIVE
694 * - Start ackNakRepDlInactvTmr timer for each UE,
695 * - length = repCntr - 1
696 * - event = RG_ACKNAKREP_DLINACTV
697 * - handler = rgSCHMeasGapANRepDlInactvTmrExpry
698 * - Verify the above computations before coding
702 * @param[in] RgSchCellCb *cell
703 * @param[out] CmLListCp *dlInactvUeLst
707 S16 rgSCHMeasGapANRepGetDlInactvUe(RgSchCellCb *cell,CmLListCp *dlInactvUeLst)
715 CmLteTimingInfo ackNakTime;
717 uint8_t harqFdbkOffset;
721 RgSchDlHqProcCb *hqP;
725 schedTime = cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot + RG_DL_DELTA;
728 RG_SCH_ADD_TO_CRNT_TIME(cell->crntTime, ackNakTime, RG_DL_DELTA);
729 if(rgSchTddUlDlSubfrmTbl[cell->ulDlCfgIdx][ackNakTime.subframe] !=
730 RG_SCH_TDD_DL_SUBFRAME)
735 dlSf = rgSCHUtlSubFrmGet (cell, ackNakTime);
736 if(dlSf->dlFdbkInfo.sfnOffset > 0)
739 (dlSf->dlFdbkInfo.sfnOffset - 1) * RGSCH_NUM_SUB_FRAMES+ \
740 RGSCH_NUM_SUB_FRAMES - ackNakTime.subframe + \
741 dlSf->dlFdbkInfo.subframe;
745 harqFdbkOffset = dlSf->dlFdbkInfo.subframe - ackNakTime.subframe;
748 harqFdbkOffset = RG_SCH_CMN_HARQ_INTERVAL;
750 /* Calc offset for Measurement gap 40 */
751 offset = (schedTime + harqFdbkOffset) % RG_MEAS_GAPPRD_40;
752 queue = &(cell->measGapCb.gapPrd40Q[offset]);
757 ue = (RgSchUeCb*)node->node;
758 ue->dl.dlInactvMask |= RG_MEASGAP_INACTIVE;
759 /* Add to the inactv list */
760 ue->dl.dlInactvLnk.node = (PTR)ue;
761 cmLListAdd2Tail (dlInactvUeLst, &(ue->dl.dlInactvLnk));
763 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_DL_MEASGAP,
764 (RG_SCH_MEAS_GAP_LEN + harqFdbkOffset));
768 /* Calc offset for Measurement gap 80 */
769 offset = (schedTime + harqFdbkOffset) % RG_MEAS_GAPPRD_80;
770 queue = &(cell->measGapCb.gapPrd80Q[offset]);
775 ue = (RgSchUeCb*)node->node;
776 ue->dl.dlInactvMask |= RG_MEASGAP_INACTIVE;
777 /* Add to the inactv list */
778 ue->dl.dlInactvLnk.node = (PTR)ue;
779 cmLListAdd2Tail (dlInactvUeLst, &(ue->dl.dlInactvLnk));
781 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_DL_MEASGAP,
782 (RG_SCH_MEAS_GAP_LEN + harqFdbkOffset));
786 /* Calc offset for ACK NACK repetition */
787 /*offset = (cell->crntTime.sfn * 10 +
788 cell->crntTime.slot + RG_DL_DELTA + RG_SCH_CMN_HARQ_INTERVAL - 1)
790 /* The ackNakRepQ resides in each dlSf corresponding to the repStart */
791 /* Must pick up the subframe that was scheduled in the last TTI */
793 if(cell->ulDlCfgIdx == 5)
797 rgSCHUtlGetPrevDlSfInfo(cell, ackNakTime, &ackNakTime, &repCntr);
798 dlSf = rgSCHUtlSubFrmGet (cell, ackNakTime);
799 /* crnt DL subframe */
800 RG_SCH_ADD_TO_CRNT_TIME(cell->crntTime, ackNakTime, RG_DL_DELTA);
804 /* Go to the subframe being scheduled */
805 RG_SCH_ADD_TO_CRNT_TIME(cell->crntTime, ackNakTime, RG_DL_DELTA);
806 /* Go to the previous subframe */
807 RGSCHDECRFRMCRNTTIME(ackNakTime, ackNakTime, 1);
811 RG_SCH_ADD_TO_CRNT_TIME(cell->crntTime, ackNakTime,
814 dlSf = rgSCHUtlSubFrmGet (cell, ackNakTime);
816 queue = &(dlSf->ueLst);
821 ue = (RgSchUeCb *)(node->node);
823 hqNode = ue->dl.dlSfHqInfo[cell->cellId][dlSf->dlIdx].hqPLst.first;
826 hqP = (RgSchDlHqProcCb *)hqNode->node;
827 hqNode = hqNode->next;
828 for (i = 0;(i<2) && (hqP->tbInfo[i].state == HQ_TB_WAITING);i++)
830 tbCb = &hqP->tbInfo[i];
831 if (tbCb->fbkRepCntr > 0)
833 ue->dl.dlInactvMask |= RG_ACKNAKREP_INACTIVE;
834 /* Check if already added to the list */
835 if (!(ue->dl.dlInactvMask & RG_MEASGAP_INACTIVE))
837 /* Add to the inactv list */
838 ue->dl.dlInactvLnk.node = (PTR)ue;
839 cmLListAdd2Tail (dlInactvUeLst, &(ue->dl.dlInactvLnk));
843 repCntr = rgSCHAckNakRepFindUlDuration(cell, dlSf, ackNakTime,
844 (uint8_t)(ue->ackNakRepCb.repCntr - 1));
845 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_DL_ACKNACK, repCntr);
847 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_DL_ACKNACK,
848 (ue->ackNakRepCb.repCntr - 1));
858 * @brief Determines the list of UEs inactive for UL scheduling due to
859 * measurement gap and ack nack repetitions
863 * Function : rgSCHMeasGapANRepGetUlInactvUe
865 * Invoking Module Processing:
866 * - This API shall be invoked to get list of inactive UEs for uplink
867 * scheduling due to measurement gaps and ACK NACK repetitions.
870 * - Compute qOffset for 40ms or 80ms queue as =
871 * ((cell->crntTime->sfn * 10)+cell->crntTime->subframe + TFU_DELTA +
872 * RG_SCH_CMN_HARQ_INTERVAL)
873 * % RG_MEAS_GAPPRD_40 or RG_MEAS_GAPPRD_80.
874 * - Add all the UEs at computed offset to ulInactvUeLst since the UL
875 * transmissions shall collide with measurement gap.
876 * - Mark each UE. Set ulInactvMask |= RG_MEASGAP_INACTIVE
877 * - Start measGapUlInactvTmr timer for each UE
878 * - length = RG_MEAS_GAP_LEN
879 * - event = RG_MEASGAP_ULINACTV
880 * - handler = rgSCHMeasGapANRepUlInactvTmrExpry
881 * - Compute qOffset for ACK NACK repetition queue as =
882 * ((cell->crntTime->sfn * 10)+cell->crntTime->subframe + TFU_DELTA +
883 * RG_SCH_CMN_HARQ_INTERVAL)
885 * - Add all the UEs at computed offset to ulInactvUeLst since the
886 * feedback transmission from UE for DL transmissions shall
887 * collide with repeating ACK ACK-NACKs.
888 * - Mark each UE. Set ulInactvMask |= RG_ACKNAKREP_INACTIVE
889 * - Start ackNakRepUlInactv timer for each UE
891 * - event = RG_ACKNAKREP_ULINACTV
892 * - handler = rgSCHMeasGapANRepUlInactvTmrExpry
893 * - Verify the above computations before coding
896 * @param[in] RgSchCellCb *cell
897 * @param[out] CmLListCp *ulInactvUeLst
902 S16 rgSCHMeasGapANRepGetUlInactvUe(RgSchCellCb *cell,CmLListCp *ulInactvUeLst)
910 CmLteTimingInfo ackNakTime;
913 uint8_t pdcchToPuschGap;
918 RgSchDlHqProcCb *hqP;
922 /*ccpu00139481- Meas Gap should be monitored in UL with TFU_ULCNTRL_DLDELTA*/
923 schedTime = cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot + \
926 pdcchToPuschGap = RGSCH_PDCCH_PUSCH_DELTA;
928 RG_SCH_ADD_TO_CRNT_TIME(cell->crntTime, ackNakTime, TFU_ULCNTRL_DLDELTA);
929 pdcchToPuschGap = rgSchTddPuschTxKTbl[cell->ulDlCfgIdx][ackNakTime.subframe];
930 for(idx=0; pdcchToPuschGap && (idx< (pdcchToPuschGap+RG_SCH_MEAS_GAP_LEN)) ; idx++)
933 /* Calc offset for Measurement gap 40 */
934 offset = (schedTime + pdcchToPuschGap -idx + RG_MEAS_GAPPRD_40) % RG_MEAS_GAPPRD_40;
935 queue = &(cell->measGapCb.gapPrd40Q[offset]);
939 ue = (RgSchUeCb*)node->node;
940 if(!(ue->ul.ulInactvMask & RG_MEASGAP_INACTIVE))
942 ue->ul.ulInactvMask |= RG_MEASGAP_INACTIVE;
943 /* Add to the inactv list */
944 ue->ul.ulInactvLnk.node = (PTR)ue;
945 cmLListAdd2Tail (ulInactvUeLst, &(ue->ul.ulInactvLnk));
946 /* Start timer Note the timer is started for a value GAP_LEN +
947 * RG_SCH_CMN_HARQ_INTERVAL. The "4"
948 * is added because for UE to transmit, the PDCCH must be sent 4 subframes
949 * ahead - UE cant read PDCCH format0 if it is in measurement gap. */
950 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_UL_MEASGAP,
951 (RG_SCH_MEAS_GAP_LEN + pdcchToPuschGap - idx));
952 //printf("Starting Meas Gap 40 @ DL TTI- (%d:%d) K-%d offset-%d Len %d \n", ackNakTime.sfn, ackNakTime.subframe, harqFdbkOffset, offset, RG_SCH_MEAS_GAP_LEN + harqFdbkOffset-idx);
957 /* Calc offset for Measurement gap 80 */
958 offset = (schedTime + pdcchToPuschGap - idx + RG_MEAS_GAPPRD_80) % RG_MEAS_GAPPRD_80;
959 queue = &(cell->measGapCb.gapPrd80Q[offset]);
964 ue = (RgSchUeCb*)node->node;
965 if(!(ue->ul.ulInactvMask & RG_MEASGAP_INACTIVE))
967 ue->ul.ulInactvMask |= RG_MEASGAP_INACTIVE;
968 /* Add to the inactv list */
969 ue->ul.ulInactvLnk.node = (PTR)ue;
970 cmLListAdd2Tail (ulInactvUeLst, &(ue->ul.ulInactvLnk));
972 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_UL_MEASGAP,
973 (RG_SCH_MEAS_GAP_LEN + pdcchToPuschGap - idx));
974 //printf("Starting Meas Gap 80 @ DL TTI- (%d:%d) K-%d offset-%d Len %d \n", ackNakTime.sfn, ackNakTime.subframe, harqFdbkOffset, offset, RG_SCH_MEAS_GAP_LEN + harqFdbkOffset-idx);
979 /* Calc offset for ACK NACK repetition */
980 /*offset = (cell->crntTime.sfn * 10 +
981 cell->crntTime.slot + RG_UL_SCHED_DELTA +
982 RG_SCH_CMN_HARQ_INTERVAL ) % RG_MAX_NUM_DLSF;*/
984 /* Must get the DLSF that is scheduled at TFU_DELTA Away */
986 if(cell->ulDlCfgIdx == 5)
990 RG_SCH_ADD_TO_CRNT_TIME(cell->crntTime, ackNakTime, TFU_DELTA);
991 if(rgSchTddUlDlSubfrmTbl[cell->ulDlCfgIdx][ackNakTime.subframe] !=
992 RG_SCH_TDD_DL_SUBFRAME)
997 /* Introduced timing delta for DL control in FDD */
998 RG_SCH_ADD_TO_CRNT_TIME(cell->crntTime, ackNakTime, TFU_DLCNTRL_DLDELTA);
1000 dlSf = rgSCHUtlSubFrmGet (cell, ackNakTime);
1001 queue = &(dlSf->ueLst);
1003 node = queue->first;
1006 ue = (RgSchUeCb *)(node->node);
1008 hqNode = ue->dl.dlSfHqInfo[cell->cellId][dlSf->dlIdx].hqPLst.first;
1011 hqP = (RgSchDlHqProcCb *)hqNode->node;
1012 hqNode = hqNode->next;
1013 for (i = 0;(i<2) && (hqP->tbInfo[i].state == HQ_TB_WAITING);i++)
1015 tbCb = &hqP->tbInfo[i];
1016 if (tbCb->fbkRepCntr > 0)
1018 ue->ul.ulInactvMask |= RG_ACKNAKREP_INACTIVE;
1019 /* Check if already added to the list */
1020 if (!(ue->ul.ulInactvMask & RG_MEASGAP_INACTIVE))
1022 /* Add to the inactv list */
1023 ue->ul.ulInactvLnk.node = (PTR)ue;
1024 cmLListAdd2Tail (ulInactvUeLst, &(ue->ul.ulInactvLnk));
1028 repCntr = rgSCHAckNakRepFindUlDuration(cell, dlSf, ackNakTime,
1029 ue->ackNakRepCb.repCntr);
1030 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_UL_ACKNACK, repCntr);
1032 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_UL_ACKNACK,
1033 (ue->ackNakRepCb.repCntr));
1043 * @brief Handles processing of DL Inactive timer expiry at the end of
1044 * measurement gap or ack nack repetition for a UE
1048 * Function : rgSCHMeasGapANRepDlInactvTmrExpry
1050 * Invoking Module Processing:
1051 * - This API shall be invoked to process DL inactive timer expiry
1054 * - If timer event is RG_MEASGAP_DLINACTV,
1055 * - dlInactvMask &= ~RG_MEASGAP_INACTIVE
1056 * - If timer event is RG_ACKNAKREP_DLINACTV,
1057 * - dlInactvMask &= ~RG_ACKNAKREP_INACTIVE
1058 * - if (!dlInactvMask)
1059 * - Invoke DL scheduler to put the UE back into the scheduling queues.
1060 * - Re-initialize timer.
1063 * @param[in] RgSchUeCb *ue
1064 * @param[in] Check if some timer related parameter needs to be passed
1069 Void rgSCHMeasGapANRepDlInactvTmrExpry(RgSchUeCb *ue,uint8_t tmrEvnt)
1072 RgSchCellCb *cell = ue->cell;
1076 case RG_SCH_TMR_DL_MEASGAP:
1077 RG_SCH_CMN_DL_UPDT_INACTV_MASK ( cell, ue, RG_MEASGAP_INACTIVE);
1079 case RG_SCH_TMR_DL_ACKNACK:
1080 RG_SCH_CMN_DL_UPDT_INACTV_MASK ( cell, ue, RG_ACKNAKREP_INACTIVE);
1083 if (!ue->dl.dlInactvMask)
1085 cmInitTimers (&ue->measGapCb.measGapDlInactvTmr, 1);
1086 cmInitTimers (&ue->ackNakRepCb.ackNakRepDlInactvTmr, 1);
1092 * @brief Handles processing of UL Inactive timer expiry at the end of
1093 * measurement gap or ack nack repetition for a UE
1097 * Function : rgSCHMeasGapANRepUlInactvTmrExpry
1099 * Invoking Module Processing:
1100 * - This API shall be invoked to process UL inactive timer expiry
1103 * - If timer event is RG_MEASGAP_ULINACTV,
1104 * - ulInactvMask &= ~RG_MEASGAP_INACTIVE
1105 * - If timer event is RG_ACKNAKREP_ULINACTV,
1106 * - ulInactvMask &= ~RG_ACKNAKREP_INACTIVE
1107 * - if (!ulInactvMask)
1108 * - Invoke UL scheduler to put the UE back into the scheduling queues.
1109 * - Re-initialize timer.
1112 * @param[in] RgSchUeCb *ue
1113 * @param[in] Check if some timer related parameter needs to be passed
1118 Void rgSCHMeasGapANRepUlInactvTmrExpry(RgSchUeCb *ue,uint8_t tmrEvnt)
1120 RgSchCellCb *cell = ue->cell;
1124 case RG_SCH_TMR_UL_MEASGAP:
1125 RG_SCH_CMN_UL_UPDT_INACTV_MASK ( cell, ue, RG_MEASGAP_INACTIVE);
1127 case RG_SCH_TMR_UL_ACKNACK:
1128 RG_SCH_CMN_UL_UPDT_INACTV_MASK ( cell, ue, RG_ACKNAKREP_INACTIVE);
1131 if (!ue->ul.ulInactvMask)
1133 cmInitTimers (&ue->measGapCb.measGapUlInactvTmr, 1);
1134 cmInitTimers (&ue->ackNakRepCb.ackNakRepUlInactvTmr, 1);
1140 * @brief Handles processing of measurement gap timer expiry at the end of
1145 * Function : rgSCHMeasGapANRepTmrExpry
1147 * Invoking Module Processing:
1148 * - This API shall be invoked to process measurement gap timer expiry
1151 * - Set ue->isMeasuring = FALSE
1152 * - Re-initialize timer.
1155 * @param[in] RgSchUeCb *ue
1156 * @param[in] Check if some timer related parameter needs to be passed
1161 Void rgSCHMeasGapANRepTmrExpry(RgSchUeCb *ue)
1164 ue->measGapCb.isMeasuring = FALSE;
1165 cmInitTimers (&ue->measGapCb.measGapTmr, 1);
1171 * @brief Handles processing of ACK-NACK repetition timer expiry at the end of
1172 * ACK-NACK repetition.
1176 * Function : rgSchAckNakRepTmrExpry
1178 * Invoking Module Processing:
1179 * - This API shall be invoked to process ACK-NACK repetition timer expiry
1182 * - Set ue->isAckNakRep = FALSE
1183 * - Re-initialize timer.
1186 * @param[in] RgSchUeCb *ue
1187 * @param[in] Check if some timer related parameter needs to be passed
1192 Void rgSCHAckNakRepTmrExpry(RgSchUeCb *ue)
1195 ue->ackNakRepCb.isAckNakRep = FALSE;
1196 cmInitTimers (&ue->ackNakRepCb.ackNakRepTmr, 1);
1203 * @brief Adds ACK-NACK repeating UEs to the ackNakRepQ
1207 * Function : rgSchAckNakRepAddToQ
1209 * Invoking Module Processing:
1210 * - This API shall be invoked for adding list of UEs to the ACK-NACK
1211 * repeating queue at appropriate poistion. Invoking module shall invoke
1212 * with the list of ACK-NACK repeating UEs for a sub-frame and timing info
1213 * at which ACK NACK repetition shall start for the UEs.
1216 * - Determine the qOffset depending on the timing info as
1217 * - qOffset = (repStartTime->sfn *10 + repStartTime->subframe) % RG_MAX_NUM_DLSF
1218 * - Initialize the list at the qOffset.
1219 * - For each UE in the list,
1220 * - Add the UE to ackNakRepQ to the list at the determined qOffset.
1221 * - Set ue->qOffset = qOffset
1222 * - Initialize timers.
1225 * @param[in] RgSchCellCb *cell
1226 * @param[in] RgSchDlSf *crntDlSf
1227 * @param[in] CmLteTimingInfo repStartTime
1233 Void rgSCHAckNakRepAddToQ(RgSchCellCb *cell,RgSchDlSf *crntDlSf)
1238 RgSchDlHqProcCb *hqP;
1239 RgSchDlHqTbCb *tbCb;
1242 node = crntDlSf->ueLst.first;
1245 ue = (RgSchUeCb *)(node->node);
1247 hqNode = ue->dl.dlSfHqInfo[cell->cellId][crntDlSf->dlIdx].hqPLst.first;
1250 hqP = (RgSchDlHqProcCb *)hqNode->node;
1251 hqNode = hqNode->next;
1252 for (i = 0;(i<2) && (hqP->tbInfo[i].state == HQ_TB_WAITING);i++)
1254 tbCb = &hqP->tbInfo[i];
1255 /* Add UEs that have enabled ACK NACK repetition */
1256 if (ue->ackNakRepCb.isAckNackEnabled)
1258 tbCb->fbkRepCntr = ue->ackNakRepCb.cfgRepCnt;
1259 tbCb->fbkRecpRepCntr = ue->ackNakRepCb.cfgRepCnt;
1260 /* Removed init of timers as the init will be happening during
1261 * config or timer expiry*/
1272 * @brief Finds the number of subframes used for ACK-NACK cycle
1276 * Function : rgSCHAckNakRepFindUlDuration
1278 * This function finds the number of subframes required
1279 * for ACK-NACK repetition cycle based on UL subframes.
1281 * @param[in] RgSchCellCb *cell
1282 * @param[in] RgSchDlSf *dlSf
1283 * @param[in] CmLteTimingInfo repTime
1284 * @param[in] uint8_t repCnt
1290 static uint8_t rgSCHAckNakRepFindUlDuration(RgSchCellCb *cell,RgSchDlSf *dlSf,CmLteTimingInfo repTime,uint8_t repCnt)
1292 CmLteTimingInfo ulfrm;
1293 uint8_t noSubfrms = 0;
1294 uint16_t ulDlCfgIdx = cell->ulDlCfgIdx;
1299 rgSCHAckNakRepGetUlOffsetFrmDl(dlSf, repTime, &noSubfrms);
1300 RG_SCH_ADD_TO_CRNT_TIME(repTime, ulfrm, noSubfrms);
1302 idx = ulfrm.subframe;
1305 idx = (idx + 1) % RGSCH_NUM_SUB_FRAMES;
1306 if(rgSchTddUlDlSubfrmTbl[ulDlCfgIdx][idx] ==
1307 RG_SCH_TDD_UL_SUBFRAME)
1319 * @brief Finds the number of subframes used for ACK-NACK cycle
1323 * Function : rgSCHAckNakRepGetUlOffsetFrmDl
1325 * This function finds the number of subframes after
1326 * which UL subframes are present for the gicen DL
1329 * @param[in] RgSchDlSf *dlSf
1330 * @param[in] CmLteTimingInfo crntDlTime
1331 * @param[in] uint8_t *noSubfrms
1337 static Void rgSCHAckNakRepGetUlOffsetFrmDl(RgSchDlSf *dlSf,CmLteTimingInfo crntDlTime,uint8_t *noSubfrms )
1340 if(dlSf->dlFdbkInfo.sfnOffset != 0)
1342 *noSubfrms = (dlSf->dlFdbkInfo.sfnOffset - 1) * RGSCH_NUM_SUB_FRAMES;
1343 *noSubfrms = *noSubfrms + RGSCH_NUM_SUB_FRAMES - crntDlTime.subframe;
1344 *noSubfrms = *noSubfrms + dlSf->dlFdbkInfo.subframe;
1348 *noSubfrms = dlSf->dlFdbkInfo.subframe - crntDlTime.subframe;
1354 /**********************************************************************
1357 **********************************************************************/