#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "include/FIXtypedef.h"
#include "include/FIXbasic_op.h"
#include "include/fixed_bgtable.h"
#include "include/vdsl_framer.h"

#define logMsg      printf

// #define	TEST
#define NEG_INF_DB			-20000
#define POS_INF_DB			20000
#define MAX_GAIN_MARGIN			0
#define MAX_N_POW			33554432
#define MIN_BIT_BG			2
#define MAX_BIT_BG			11 

/********************************************************************************************
 *   FEQ_COARSE_GAIN_NEW * FEQ_FINE_GAIN_NEW = FEQ_ADJ * FEQ_COARSE_GAIN * FEQ_FINE_GAIN
 *   FEQ_ADJ = rx_fine_gain/g; FEQ_COARSE_GAIN = 2^k ( 0 <= k <= 11);
 *   rx_fine_gain -- q.15s; g -- q3.9us; FEQ_FINE_GAIN -- q.15s
 *******************************************************************************************/
#define  MAX_24					(long)(0x007fffff)
#define  MIN_24					(long)(~MAX_24)
#define	 MAX(x,y)				((x) > (y) ? (x) :  (y))
#define  ABS(x)					((x) > 0   ? (x) : -(x))
#define  FINE_GAIN_TABLE_SIZE   (10)
#define  TWO_POW_24             (1L << 24)
#define  MAX_COARSE_GAIN        (11)
#define  MIN_COARSE_GAIN        (0)
#define  HALF_16S_BITS          (1  << 14)    /* 0.5 * 2^15 */
#define  HALF_24S_BITS          (1L << 22)    /* 0.5 * 2^23 */


/**************************************************************************************
 *  if(status_flag == UPSTREAM_TRAINING)
 *     G_train_up[k] = G_precomp_up[k] * G_qam[2] * G_upbo[k];
 *  else // SHOWTIME
 *     G_train_up[k] = G_precomp_up[k] * G_qam[bit_size[k]] * G_upbo[k] * G[k];
 *
 *     G_train_up, G_precomp_up, G_qam and G_upbo are q.15us
 *     G is q3.9us
 **************************************************************************************/
void train_up_gain_correction(unsigned short *train_up, unsigned short *precomp_up, unsigned char *bit_size, 
							  unsigned short *g, unsigned short *g_upbo, unsigned short length, 
							  int status_flag, int pilot_tone)
{
  	short 			k;
  	unsigned short 	gqq,temp_16, shl_g;
  	unsigned int 	temp_32;
	unsigned short 	GNSrmsFineGain[16] = {
						47424>>1, 47424>>1, 47424>>1, 54761>>1,
						42417>>1, 59987>>1, 41395>>1, 59251>>1,
						41151>>1, 59071>>1, 41091>>1, 59027>>1,
						41075>>1, 59016>>1, 41072>>1, 41072>>1
					};

	if(status_flag == 0) { /* training */
    	for( k = 0; k < length; k++) {
			if(bit_size[k] == 0) {
				train_up[k] = 0;
				if(k == pilot_tone)
					gqq = GNSrmsFineGain[2];
				else 
					continue;
			} else
				gqq    		= GNSrmsFineGain[bit_size[k]];
      		temp_32     = precomp_up[k] * gqq + (1<<14);		//	q.30
      		temp_16     = (unsigned short)(temp_32 >> 15);      //	q.15
	  		temp_32     = temp_16 * g_upbo[k] + (1<<14);
			temp_16		= temp_32>>15;
			shl_g		= g[k];
	  		temp_32		= temp_16 * shl_g + (1<<8);				// q.31
      		temp_32	>>= 9;
	  		if(temp_32 > MAX_16) {
	    		train_up[k] = MAX_16;
				logMsg("TRAIN_UP_ERROR in training stage\n");
	  		} else
        		train_up[k] = (unsigned short)temp_32;
		}
  	} else{  		 
    	for( k = 0; k < length; k++) {
			if(bit_size[k] == 0) {
				train_up[k]=0;
				if(k == pilot_tone) {
					gqq = GNSrmsFineGain[2];
					g[k]  = 1<<9;
				} else 
					continue;
			} else
	   			gqq     = GNSrmsFineGain[bit_size[k]];
	  		temp_32 =  precomp_up[k] * gqq;
      		temp_16 = (unsigned short)(temp_32 >> 15);           //q.15
      		temp_32 =  temp_16 * g_upbo[k];
      		temp_16 = (unsigned short)(temp_32 >> 15);           //q.15 
			/************************* log2(x) ************************************/	   
	  		shl_g     = g[k];
			/**************************************************************************
		 	* q3.9 = q.15 * 2^6
 			* G_train_up[k] = G_precomp_up[k] * G_qam[bit_size[k]] * G_upbo[k] * G[k]
 			* temp_32       = G_precomp_up[k] * G_qam[bit_size[k]];
 			* temp_16       = temp_32 >> 15;
 			* temp_32       = temp_16 * G_upbo[k];
 			* temp_16       = temp_32 >> 15;
 			* temp_32       = (temp_16 * G[k])
 			* G_train_up[k] = temp_32 * 2^9)
 			**************************************************************************/
      		temp_32  = temp_16 * shl_g;                   // q.31
      		temp_32 >>= 9;
	  		if(temp_32 > MAX_16) {
	    		train_up[k] = MAX_16;
				logMsg("TRAIN_UP_ERROR\n");
	  		} else
        		train_up[k] = (unsigned short)temp_32;
		}
  	}

  	return;
}


