/* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The OpenAirInterface Software Alliance licenses this file to You under
 * the OAI Public License, Version 1.0  (the "License"); you may not use this file
 * except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.openairinterface.org/?page_id=698
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *-------------------------------------------------------------------------------
 * For more information about the OpenAirInterface (OAI) Software Alliance:
 *      contact@openairinterface.org
 */

/*! \file PHY/LTE_TRANSPORT/SIB_NB_IoT.c
* \Fucntions for the generation of SIB information for NB_IoT,	 TS 36-212, V13.4.0 2017-02
* \author M. KANJ
* \date 2018
* \version 0.0
* \company bcom
* \email: matthieu.kanj@b-com.com
* \note
* \warning
*/


#include "PHY/NBIoT_TRANSPORT/defs_NB_IoT.h"
#include "PHY/NBIoT_TRANSPORT/proto_NB_IoT.h"
//#include "PHY/CODING/defs_NB_IoT.h"
//#include "PHY/LTE_REFSIG/defs_NB_IoT.h"
//#include "PHY/impl_defs_lte_NB_IoT.h"
//#include "PHY/impl_defs_top_NB_IoT.h"
#include "PHY/impl_defs_lte.h"

/////////////////////////////////////////////////////////////////////////////////////////

int generate_SIB1(NB_IoT_eNB_NDLSCH_t 		*sib1_struct,
                   int32_t 					**txdataF,
                   int16_t                  amp,
                   LTE_DL_FRAME_PARMS 	    *frame_parms,
                   uint32_t 				frame,
                   uint32_t 				subframe,
                   int                      RB_IoT_ID,
                   uint8_t                  operation_mode,
                   uint8_t                release_v13_5_0)
{
 	int done=0;
 	uint8_t *sib1_pdu  = sib1_struct->harq_process->pdu;
 	uint8_t opr_mode = 3;
 	if(operation_mode>=2)
 	{
 		opr_mode =0;
 	}
	uint8_t tmp =0;
    uint8_t rep_val = 0;
    uint8_t start_frame = get_start_frame_SIB1_NB_IoT(frame_parms, get_rep_num_SIB1_NB_IoT(sib1_struct->repetition_number_SIB1));

    switch( get_rep_num_SIB1_NB_IoT(sib1_struct->repetition_number_SIB1) )
    {
      case 4:
              rep_val = 64;
      break;

      case 8:
              rep_val = 32;
      break;
              
      case 16:
              rep_val = 16;
      break;

      default:
            printf("Error in SIB1");

    }

    uint8_t var = 0;

    if(start_frame == 1)
    {
      var =1;
    }

    if(start_frame>=16)
    {
        tmp = 1;
    }

    uint8_t born_inf = 0 + start_frame*tmp;
    uint8_t born_sup = 16 + start_frame*tmp;

    if((subframe == 4)  && (frame%2 == var) && (born_inf<= frame % rep_val) && (frame % rep_val < born_sup ))
    {
        LOG_D(PHY,"[%3d][%2d] Generating SIB1\n",frame,subframe);
    	  int G = get_G_SIB1_NB_IoT(frame_parms,operation_mode);

        if( frame % rep_val == var )
        {
            dlsch_encoding_NB_IoT(sib1_pdu,
                                  sib1_struct,
                                  8,             ///// number_of_subframes_required
                                  G);         //// this vallue is fixed, should take into account in future the case of stand-alone & guard-band 
        
             dlsch_scrambling_Gen_NB_IoT(frame_parms,
                                         sib1_struct,
                                         8*G,
                                         frame, 
                                         subframe*2,
                                         sib1_struct->rnti,
                                         release_v13_5_0,
                                         1);
        }

        dlsch_modulation_NB_IoT(txdataF,
                                amp,
                                frame_parms,
                                opr_mode,       // control region size for LTE , values between 0..3, (0 for stand-alone / 1, 2 or 3 for in-band)
                                sib1_struct,
                                G,              // number of bits per subframe
                                ((frame%16)/2),
                                4,       
                                RB_IoT_ID);
        done =1;
        frame_parms->flag_free_sf =1;
        
    }

 return(done);
}


//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

int generate_SIB23(NB_IoT_eNB_NDLSCH_t 	  *SIB23,
	                 int32_t 				        **txdataF,
	                 int16_t                amp,
	                 LTE_DL_FRAME_PARMS 	  *frame_parms,
	                 uint32_t 			        frame,
	                 uint32_t 			        subframe,
	                 int                    RB_IoT_ID,
                   uint8_t                release_v13_5_0)
{
    int done=0;

    if( SIB23->active == 1 )
    {
        //LOG_I(PHY,"[Frame: %d][Subframe: %d]sent SIB23\n",frame,subframe);

    	uint8_t *SIB23_pdu  = SIB23->harq_process->pdu;
	 	  uint32_t rep =  SIB23->resource_assignment;
	 	  uint8_t eutra_control_region = 3;

	    uint32_t counter_rep    =  SIB23->counter_repetition_number;
	    uint32_t pointer_to_sf  =  SIB23->pointer_to_subframe;             /// to identify wich encoded subframe to transmit 

    	int G = get_G_NB_IoT(frame_parms);
    	uint8_t Nsf = SIB23->resource_assignment;   //value 2 or 8

        if(counter_rep == rep)
        {
            dlsch_encoding_NB_IoT(SIB23_pdu,
                                  SIB23,
                                  Nsf,             ///// number_of_subframes_required
                                  G);              //// this vallue is fixed, should take into account in future the case of stand-alone & guard-band 
        
             dlsch_scrambling_Gen_NB_IoT(frame_parms,
                                         SIB23,
                                         Nsf*G,
                                         frame, 
                                         subframe*2,
                                         SIB23->rnti,
                                         release_v13_5_0,
                                         1);
        }

        dlsch_modulation_NB_IoT(txdataF,
                                amp,
                                frame_parms,
                                eutra_control_region,     //should be replace by start_symbole   // control region size for LTE , values between 0..3, (0 for stand-alone / 1, 2 or 3 for in-band)
                                SIB23,
                                G,                  // number of bits per subframe
                                pointer_to_sf,
                                subframe,       
                                RB_IoT_ID);

        SIB23->counter_repetition_number--;
        SIB23->pointer_to_subframe++;
        
        frame_parms->flag_free_sf =1;

        if(SIB23->counter_repetition_number == 0)
        {
        	SIB23->active = 0;
        	
        }
        done =1;
    }

 return(done);

}

////////////////////////////////////////////////////////////////////////


int generate_NDLSCH_NB_IoT(PHY_VARS_eNB           *eNB,
                           NB_IoT_eNB_NDLSCH_t 	  *RAR,
		                       int32_t 				        **txdataF,
		                       int16_t                amp,
		                       LTE_DL_FRAME_PARMS 	  *frame_parms,
		                       uint32_t 			        frame,
		                       uint32_t 			        subframe,
		                       int                    RB_IoT_ID,
                           uint8_t                release_v13_5_0)
{
    int done = 0;

    if( RAR->active == 1 )
    {
    	uint8_t *RAR_pdu  = RAR->harq_process->pdu;
      
      if(RAR->active_msg2 == 1 && RAR_pdu!=NULL)
      {
          uint8_t one_byte = RAR_pdu[2]>>3;
          uint8_t subcarrier_spacing = one_byte & 0x01;
          eNB->ulsch_NB_IoT[0]->harq_process->subcarrier_spacing = subcarrier_spacing;
      }
      // make different between RAR data and NPDSCH data   // add a flag in NPDSCH to switch between RA and normal data transmission
	 	  uint32_t rep =  RAR->repetition_number;
	 	  uint8_t  eutra_control_region = 3;

	    uint32_t counter_rep    =  RAR->counter_repetition_number;
	    uint32_t counter_sf_rep =  RAR->counter_current_sf_repetition;   /// for identifiying when to trigger new scrambling
	    uint32_t pointer_to_sf  =  RAR->pointer_to_subframe;             /// to identify wich encoded subframe to transmit 

    	int     G   = get_G_NB_IoT(frame_parms);
    	uint8_t Nsf = RAR->number_of_subframes_for_resource_assignment;

        //LOG_I(PHY,"[Frame: %d][Subframe: %d]sent RAR, rep : %d, counter_rep:%d, Num_res:%d\n",frame,subframe,rep,counter_rep,Nsf);

      if( (counter_rep == rep) && (counter_sf_rep == 0) && (pointer_to_sf == 0) )
      {
        	
            dlsch_encoding_NB_IoT(RAR_pdu,
                                  RAR,
                                  Nsf,             ///// number_of_subframes_required
                                  G);              //// this vallue is fixed, should take into account in future the case of stand-alone & guard-band 
        
             dlsch_scrambling_Gen_NB_IoT(frame_parms,
                                         RAR,
                                         Nsf*G,
                                         frame, 
                                         subframe*2,
                                         RAR->rnti,
                                         release_v13_5_0,
                                         0);
      }

		  if( (counter_rep != rep) && (counter_sf_rep == 0) && (pointer_to_sf == 0) )
		  {
			       dlsch_scrambling_Gen_NB_IoT(frame_parms,
                                         RAR,
                                         Nsf*G,
                                         frame, 
                                         subframe*2,
                                         RAR->rnti,
                                         release_v13_5_0,
                                         0);
		  }

        if( rep > 4)
        {

		        RAR->counter_current_sf_repetition++;

		        dlsch_modulation_NB_IoT(txdataF,
		                                amp,
		                                frame_parms,
		                                eutra_control_region,     //should be replace by start_symbole   // control region size for LTE , values between 0..3, (0 for stand-alone / 1, 2 or 3 for in-band)
		                                RAR,
		                                G,                  // number of bits per subframe
		                                pointer_to_sf,
		                                subframe,       
		                                RB_IoT_ID);

		        if(RAR->counter_current_sf_repetition == 4)
		        {
		        	RAR->pointer_to_subframe++;
		        	RAR->counter_current_sf_repetition =0;

		        	if (Nsf == RAR->pointer_to_subframe && (RAR->counter_repetition_number > 4))
		        	{
		        		RAR->counter_repetition_number = RAR->counter_repetition_number-4;
		        		RAR->pointer_to_subframe =0;
		        		RAR->counter_current_sf_repetition =0;

		        	} else {
                        
		        		RAR->active      = 0;
                RAR->active_msg2 = 0;
		        		done =1;
		        	}

		        }

        } else {

        		RAR->counter_current_sf_repetition++;

		        dlsch_modulation_NB_IoT(txdataF,
		                                amp,
		                                frame_parms,
		                                eutra_control_region,     //should be replace by start_symbole   // control region size for LTE , values between 0..3, (0 for stand-alone / 1, 2 or 3 for in-band)
		                                RAR,
		                                G,                  // number of bits per subframe
		                                pointer_to_sf,
		                                subframe,       
		                                RB_IoT_ID);

		        if(RAR->counter_current_sf_repetition == rep)
		        {
		        	RAR->pointer_to_subframe++;
              RAR->counter_current_sf_repetition =0;

		        	if (Nsf == RAR->pointer_to_subframe)
		        	{
                       
		        		RAR->active      = 0;
                RAR->active_msg2 = 0;
		        		done =1;
		        	}

		        }
        }   
    }

	return(done);
}

/////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
int generate_NPDCCH_NB_IoT(NB_IoT_eNB_NPDCCH_t 	  *DCI_pdu,
		                   int32_t 				  **txdataF,
		                   int16_t                amp,
		                   LTE_DL_FRAME_PARMS 	  *frame_parms,
		                   uint32_t 			  frame,
		                   uint32_t 			  subframe,
		                   int                    RB_IoT_ID)
{
    int done=0;
    

 	for(int i=0; i<2; i++) 
    {		
    	uint8_t ncce_index = 0;   /// = DCI->ncce_index[i];
 	    uint8_t agr_level = 2;	  /// = DCI->aggregation_level[i];

		    if( DCI->active[i] == 1)
		    {
                //LOG_I(PHY,"[Frame: %d][Subframe: %d]sent DCI\n",frame,subframe);
		    	uint8_t  *DCI_pdu  = DCI->pdu[i];
			 	uint32_t rep =  DCI->dci_repetitions[i];         /// repetition number
			 	uint8_t  eutra_control_region = 3;
			 	uint8_t num_bits_of_DCI =DCI->A[i];  //DCI->dci_bits_length;    /// value to be passed through nfapi when filling the PHY structures
			    uint32_t counter_rep    =  DCI->counter_repetition_number[i];          ////// Buffer for repetitions 

		    	int G = get_G_NB_IoT(frame_parms);
		    	////////////  uint8_t Nsf = DCI->number_of_subframes_for_resource_assignment;

		        if( counter_rep == rep)
		        {

		            dci_encoding_NB_IoT(DCI_pdu,		     // Array of two DCI pdus, even if one DCI is to transmit , the number of DCI is indicated in dci_number
										DCI,                  ////uint8_t    *e[2],				// *e should be e[2][G]
										num_bits_of_DCI,       //////A = number of bits of the DCI
										G,
										ncce_index,
										agr_level);

		             npdcch_scrambling_NB_IoT(frame_parms,
											  DCI,			// Input data
											  G,        	// Total number of bits to transmit in one subframe(case of DCI = G)
											  subframe*2,	//XXX we pass the subframe	// Slot number (0..19)
											  ncce_index,
											  agr_level);
		        }

				if( ((counter_rep %4)== 0) && (counter_rep != rep) )
				{
					npdcch_scrambling_NB_IoT(frame_parms,
											  DCI,			// Input data
											  G,        	// Total number of bits to transmit in one subframe(case of DCI = G)
											  subframe*2,				//XXX we pass the subframe	// Slot number (0..19)
											  ncce_index,
											  agr_level);
				}

		        dci_modulation_NB_IoT(txdataF,
									  amp,
									  frame_parms,
									  eutra_control_region,      // control region size for LTE , values between 0..3, (0 for stand-alone / 1, 2 or 3 for in-band)
									  DCI,
									  0,		     // npdsch_data_subframe, // subframe index of the data table of npdsch channel (G*Nsf)  , values are between 0..Nsf  			
									  agr_level,
									  ncce_index,
									  subframe,
									  RB_IoT_ID);

				DCI->counter_repetition_number[i]--; 

		        if(DCI->counter_repetition_number[i] == 0)
		        { 	
                        //printf("DCI REP done\n");
		        		DCI->active[i] = 0;
		        		done =1;
		        }
		          
		    }
	}
	return(done);
}


////////////////////////////////////////////////// backup ///////////////////////////
//////////////////////////////////////////////////// SIB23 ////////////////////////////////////////////////////////////////////////
 /* if( (subframe >0) && (subframe !=5) && (With_NSSS == 0) && (frame%2==1) && (frame%64<16) )   ////if((subframe != 0)  && (subframe != 4) && (subframe != 9) ) 
  {
        

        if( subframe == 1 )
        {
            dlsch_encoding_NB_IoT(sib23_pdu,
                                  sib23,
                                  8,                      ///// number_of_subframes_required
                                  236);                   //////////// G*2
        
            dlsch_scrambling_Gen_NB_IoT(fp,                    // is called only in subframe 4
                                         sib23,
                                         1888,            //////   total_bits
                                         frame,
                                         subframe*2,
                                         eNB->ndlsch_SIB23->rnti);
        }

        if( subframe < 5 )
        {

        dlsch_modulation_NB_IoT(txdataF,
                                AMP,
                                fp,
                                3,                          // control region size for LTE , values between 0..3, (0 for stand-alone / 1, 2 or 3 for in-band)
                                sib23,
                                236,                       // number of bits per subframe
                                (subframe-1),   ///npdsch_data_subframe, data per subframe//subframe index of the data table of npdsch channel (G*Nsf) ((frame%32)/2),values are between 0..Nsf        
                                subframe,
                                RB_IoT_ID);
       } else {

         dlsch_modulation_NB_IoT(txdataF,
                                AMP,
                                fp,
                                3,                          // control region size for LTE , values between 0..3, (0 for stand-alone / 1, 2 or 3 for in-band)
                                sib23,
                                236,                       // number of bits per subframe
                                (subframe-2),///npdsch_data_subframe, data per subframe//subframe index of the data table of npdsch channel (G*Nsf) ((frame%32)/2),values are between 0..Nsf        
                                subframe,
                                RB_IoT_ID);

       }
        
  }
*/