#include <stdio.h>
#include <string.h>

#include "bme.h"
#include "include/vdsl_ch.h"
#include "include/xdsl_rmc.h"
#include "include/drvUtils.h"
#include "include/bme_dma.h"
#include "include/sdram_map.h"
#include "bme_app.h"
#include "mem.h"
#include "hostType.h"

#define MAX_NUM_RX_PARAMS	16

 
#define writeControlPort(x,y,z)			wrBme(y,z);
#define readControlPort(x,y,z)			z = rdBme (y);
 
void rmc_start_line(u16 line_num, u16 fft_scale_shift, u16 num_tones, u8 win_enable, u16 beta_len, u16 loaded_tones)
{
	u16 param[MAX_NUM_RX_PARAMS];
	
	param[0] = ((fft_scale_shift&0xf)<<8)|num_tones;
	param[1] = (win_enable<<8)|0;
    param[2] = loaded_tones;
	RxCpuSendCommand(line_num, RCPU_LINE_UP, RCPU_FRAME_IMMEDIATE, param);
}

void rmc_stop_line(u16 line_num, u16 frame_num)
{
	RxCpuSendCommand(line_num, RCPU_LINE_DOWN,	RCPU_FRAME_RELATIVE|frame_num, NULL);
}

void rmc_config_tra(u16 line_num, u16 fft_scale_shift, u16 num_tones, u8 win_enable, u16 tx_beta_len, u8 teq_scale_shift, u8 num_teq_taps,
				u16 prefix_len, u16 suffix_len, u16 loaded_tones, int frame_no)
{
	u16 param[MAX_NUM_RX_PARAMS];
	
	/*
	*-----------------------------------------------------------------
	*	[MSB: FFT Scale shift  ; LSB: Num tone (11 means 2048 tones)]
	*	[MSB: Windowing enable ; LSB: Num Beta Sample]
	*	[MSB: TEQ scale shift  ; LSB: Num taps]
	*	[Num Prefix samples]
	*	[Num suffix samples]
	*---------------------------------------------------------------
	*/
	if(prefix_len+suffix_len-tx_beta_len>0) 	
		writePIO_short((u16 *)(ADDRESS_RXCPU_DCACHE_PIO+0x1f04), (1<<num_tones)*2+prefix_len+suffix_len-tx_beta_len); 							
	param[0] = ((fft_scale_shift&0xf)<<8)|num_tones;
	param[1] = (win_enable<<8)|0;
	param[2] = (teq_scale_shift<<8)|num_teq_taps;
	param[3] = prefix_len;
	param[4] = suffix_len-tx_beta_len;
    param[5] = loaded_tones;
	RxCpuSendCommand(line_num, RCPU_TR_CONFIG, frame_no /*RCPU_FRAME_IMMEDIATE*/, param);
	// RxCpuSendCommand(line_num, RCPU_TR_UPBO, RCPU_FRAME_IMMEDIATE, NULL);
}

void rmc_capture_fft_out(u16 line_num, int frame_offset, int duration)
{
	u16		frame_no;
	
	frame_no = RxCpuGetCurrentFrame(line_num);
	if(frame_no>65500)
		frame_no = 0;
	RxCpuSendCommand(line_num, RCPU_TR_FFT_OUT, frame_no+frame_offset, NULL);
	RxCpuSendCommand(line_num, RCPU_TR_NO_FEQ_NO_DATA, frame_no+frame_offset+duration, NULL);	
	// logMsg("\n*** curr frame No in the fft capture = %d, offset = %d, duration = %d ***\n", frame_no, frame_offset, duration);
}

void rmc_start_feq_train(u16 line_num)
{
  	RxCpuSendCommand(line_num, RCPU_TR_FEQ_TRAIN, RCPU_FRAME_IMMEDIATE, NULL);
}
	 
void rmc_no_feq_update(u16 line_num)
{
	RxCpuSendCommand(line_num, RCPU_TR_NO_FEQ_NO_DATA, RCPU_FRAME_IMMEDIATE, NULL);
}

void rmc_start_dfe_feq_training(u16 line_num)
{
	RxCpuSendCommand(line_num, RCPU_MED_SLICER_DATA, RCPU_FRAME_IMMEDIATE, NULL);
}

void rmc_showtime(u16 line_num, u16 kf)
{
	u16 param[MAX_NUM_RX_PARAMS];

	param[0] = kf;
	RxCpuSendCommand(line_num, RCPU_SHOW_START,RCPU_FRAME_IMMEDIATE, param);
}

void rmc_showtime_once(u16 line_num, u16 kf, int duration)
{
	u16		frame_no;
	u16 param[MAX_NUM_RX_PARAMS];

	frame_no = RxCpuGetCurrentFrame(line_num);
	if(frame_no>65500)
		frame_no = 0;
	
	param[0]=kf;
	RxCpuSendCommand(line_num, RCPU_SHOW_START, frame_no+200, param);
	RxCpuSendCommand(line_num, RCPU_LINE_DOWN,	frame_no+200+duration, NULL);
}

void rmc_skip_samples(u16 line_num, u16 num_samples, u16 tag)
{
    u16 samples_2_skip;
	u16	param[MAX_NUM_RX_PARAMS];
		
    while(num_samples>0) {
        samples_2_skip = num_samples>=512? 512:num_samples;
        param[0] = samples_2_skip;
		param[1] = 1;  // # of times to skip
		param[2] = tag;  // seq #
	    RxCpuSendCommand(line_num, RCPU_TR_SKIP_SAMPLE, RCPU_FRAME_IMMEDIATE, param);
        num_samples-=samples_2_skip;
    }
}

void rmc_capture_snr(u16 line_num)
{
    RxCpuSendCommand(line_num, RCPU_TR_TST_SNR, RCPU_FRAME_IMMEDIATE, NULL);
}

void rmc_capture_showtime_snr(u16 line_num)
{
	RxCpuSendCommand(line_num, RCPU_SHOW_SNR, RCPU_FRAME_IMMEDIATE, NULL);
}

void rmc_capture_slicer_snr(u16 line_num)
{
	RxCpuSendCommand(line_num, 	RCPU_MED_SLICER_SNR, RCPU_FRAME_IMMEDIATE, NULL);
}

void write_bit_table(XDSL_LINE *curr_line)
{
	int	num_tones = curr_line->fft_size>>1;
	
	num_tones-=0;
	
	if(host_mode_flag) {
		hostWriteBMEMemories((u8 *)(ADDRESS_DEMAPPERTONEORDER + curr_line->ch_num*num_tones*sizeof(u16)), (u8 *)curr_line->rx_tone_bit_table, 
			(num_tones)*sizeof(s16), 1, 0, curr_line->ch_num);
	} else
	{
		writeBMEMemories_diag ((char *)(curr_line->rx_tone_bit_table), (char *)ADDRESS_DEMAPPERTONEORDER, 0, (num_tones)*sizeof(u16), curr_line->ch_num, DMA_BUSY_POLLING, 
						DMA_FOR_INIT_RX, DMA_ECR_SW_INIT_DMA);
	}		
}

void write_feq_gains(XDSL_LINE *curr_line)
{
  	int num_tones = curr_line->fft_size>>1;

	if(host_mode_flag) {
		hostWriteBMEMemories((u8 *)(ADDRESS_FEQ_TABLE_COARSE + curr_line->ch_num*(num_tones/2)*sizeof(u8)), (u8 *)curr_line->feq_cg, 
			(num_tones>>1)*sizeof(u8), 1, 0, curr_line->ch_num);
		hostWriteBMEMemories((char *)(ADDRESS_FEQ_TABLE_FINE_S16 + curr_line->ch_num*num_tones*sizeof(tComplex_s16)),
				(char *)curr_line->feq_coef_msb16, num_tones*sizeof(tComplex_s16), 1, 0, curr_line->ch_num); 
	} else
	{
		writeBMEMemories_diag ((char *)curr_line->feq_cg, (char *)ADDRESS_FEQ_TABLE_COARSE, 0, num_tones>>1, curr_line->ch_num, DMA_BUSY_POLLING, 
						DMA_FOR_INIT_RX, DMA_ECR_SW_INIT_DMA);
					
		writeBMEMemories_diag ((char *)curr_line->feq_coef_msb16, (char *)ADDRESS_FEQ_TABLE_FINE_S16, 0, num_tones*sizeof(tComplex_s16), curr_line->ch_num, 
						DMA_BUSY_POLLING, DMA_FOR_INIT_RX, DMA_ECR_SW_INIT_DMA);		
							
	}		
}

			
int is_right_dma_data(XDSL_LINE *curr_line)
{
    BUF_ID 	*header;

    header = (BUF_ID *)curr_line->b_buf_start;

    if(header->frame_num>=curr_line->next_sym_2_cap) 
        return 1;
    writePIO_SingleRegChannel((int *)CBIT_B, curr_line->ch_num, 0x0);  
    return 0;
}

void init_rx_teq_coef(XDSL_LINE *curr_line)						
{
    memset((u8 *)curr_line->teq_coefs, 0x0, 64*sizeof(s16));
	curr_line->teq_coefs[curr_line->num_teq_taps-1] = 0x7fff;

	if(host_mode_flag) {
		hostWriteBMEMemories((u8 *)(ADDRESS_TEQ_TABLE + curr_line->ch_num*64*sizeof(s16)), (u8 *)curr_line->teq_coefs, 64*sizeof(s16), 1, 0, curr_line->ch_num);
	} else
	{
		
		writeBMEMemories_diag ((u8 *)curr_line->teq_coefs, (u8 *)ADDRESS_TEQ_TABLE, 0, 64*sizeof(s16), 
			curr_line->ch_num, DMA_BUSY_POLLING, DMA_FOR_INIT_RX, DMA_ECR_SW_INIT_DMA);
	}		
}

void init_rx_bit_table(XDSL_LINE *curr_line)
{
	int	i, j;
	int	num_tones = curr_line->fft_size>>1;
	
	j = 0;

    for(i=0;i<num_tones;i++)
        if(is_not_in_band(i, curr_line->num_rx_bands, curr_line->rx_band_start, curr_line->rx_band_stop))
            curr_line->rx_tone_bit_table[i] = (i<<4)|0x0;
        else
            curr_line->rx_tone_bit_table[i] = (i<<4)|2;
		
	write_bit_table(curr_line);	
}


void init_rx_feq_gains(XDSL_LINE *curr_line, int feq_cg_val)
{
	u8	cg;
    int i;
	int num_tones = curr_line->fft_size>>1;
	
	if(feq_cg_val<0 || feq_cg_val>11) {
		logMsg("\n feq coarse gain outside the limit in init_rx_feq_gains()");
		feq_cg_val = 0;
	}
	
	cg = (feq_cg_val<<4)|feq_cg_val;
	memset((u8 *)curr_line->feq_cg, cg, num_tones>>1);
	for(i=0;i<num_tones;i++) {
        curr_line->feq_coef_msb16[i].sReal = 0x0;
        curr_line->feq_coef_msb16[i].sImag = 0x0;
        curr_line->feq_coef_msb8[i].sReal = 0x0;
        curr_line->feq_coef_msb8[i].sImag = 0x0;
    }

	write_feq_gains(curr_line);
}

void rx_chg_pilot_tone(int ptone_index)
{
	int val; 

	val = readPIO_SingleRegChannel((int *)(DMPPLT+0x18), 0);
	val = (val & 0xffff0000) | (ptone_index & 0x0ffff);
	writePIO_SingleRegChannel((int *)(DMPPLT+0x18), 0, val);
}


extern void	reset_snr_acc(XDSL_LINE *curr_line)
{
	memset(sdram_map->snr_table, 0x0, 10*1024);
	if(host_mode_flag) {
		hostWriteBMEMemories((u8 *)(ADDRESS_SMCONTROLSNRMEMORY), (u8 *)sdram_map->snr_table, 8*1024, 1, 0, curr_line->ch_num);
	}else {
		writeBMEMemories_diag ((char *)sdram_map->snr_table, (char *)ADDRESS_SMCONTROLSNRMEMORY, 0, 8*1024, curr_line->ch_num, DMA_BUSY_POLLING, 
						DMA_FOR_INIT_RX, DMA_ECR_SW_INIT_DMA);
	}		
}

void enable_clk_recv(XDSL_LINE *curr_line)
{
	curr_line->is_enable_clk_recv = 1;
}

void disable_clk_recv(XDSL_LINE *curr_line)
{
	curr_line->is_enable_clk_recv = 0;
}

