#include <stdio.h>
#include "bme.h"
#include "include/vdsl_ch.h"
#include "include/xdsl_rmc.h"
#include "include/bme_dma.h"
#include "include/dfrmhal.h" 
#include "bme_app.h"
#include "mem.h"
#include "framercpu.h" 
#include "hostType.h" 

extern int  tot_dma_out_standing;
extern int host_mode_flag;
extern char capTest; 
 
int xfer_bbuf_data_out(XDSL_LINE *line, u16 expected_frame_num, u8 expected_tag, int duration, int loaded_tones, int tag_len)
{
	u8		*dst;
	int		b_fifo_start_addr, fifo_size, data_avail;
	int		xfer_size;
	int		i;
		
		
	iposDelay();
	read_ibfifo_status(line->ch_num, &b_fifo_start_addr, &fifo_size);
	i = 0;

	// fifo_size = 0x8000;
	while((data_avail =ibfifo_data_avail(line->ch_num, fifo_size))!=duration*((loaded_tones*4)+tag_len)){
		// logMsg("\n data_avail = %d", data_avail);
    	iposDelay();
		if(i>0x2000) {
			logMsg(" waiting for correct amount of data in ibfifo timed out");
			break;
		}
		i++;
		// ibfifo_data_avail(2, fifo_size);
	}
	
	if(data_avail == duration*((loaded_tones*4)+tag_len)) { 
		// logMsg("\n** Capturing %d bytes from bfifo to sdram buffer **\n", data_avail);
		if(host_mode_flag)
			hostReadBMEMemories(line->b_buf_start, (u8 *)ADDRESS_BFIFOINTERLEAVE, data_avail, 1, 1, line->ch_num);								
		else
		{
			dst =  line->b_buf_start;
			while(1) {
				xfer_size = data_avail>8192? 8192 : data_avail;
				readBMEMemories_diag ((u8 *)ADDRESS_BFIFOINTERLEAVE, dst, 0x0, xfer_size, line->ch_num, DMA_BUSY_POLLING, 
						DMA_FOR_INIT_RX, DMA_ECR_SW_INIT_DMA);
				data_avail-=xfer_size;
				if(data_avail<=0)
					break;
				dst +=xfer_size;
			} 		
		}	
		line->b_buf_data_avail =  data_avail;
		clear_bfifo(line->ch_num);
		return 1;
	} else {
		printf("\n-- Wrong number of bytes in b fifo - %d\n", data_avail);
        iposDelay();
		clear_bfifo(line->ch_num);
		iposDelay();
		return 0;
	}
}

int capture_Bbuf(XDSL_LINE *line, u16 expected_frame_num, u8 expected_tag, int duration, int loaded_tones, int tag_len)
{	
	rmc_capture_fft_out(line->ch_num, line->frame_offset, duration);
	
	xfer_bbuf_data_out(line, expected_frame_num, expected_tag, duration, loaded_tones, tag_len);	
	return 0;
}

void capture_feq_fg(XDSL_LINE *line)
{
	int		num_tones = line->fft_size>>1;

	if(host_mode_flag) {
		hostReadBMEMemories((u8 *)line->feq_coef_msb16, (u8 *)(ADDRESS_FEQ_TABLE_FINE_S16+line->ch_num*num_tones*sizeof(tComplex_s16)), 
				num_tones*sizeof(tComplex_s16), 1, 0, 0);	
	} else
	{
		readBMEMemories_diag ((void *)ADDRESS_FEQ_TABLE_FINE_S16, (void *)line->feq_coef_msb16, 0, num_tones*sizeof(tComplex_s16), line->ch_num, 
				DMA_BUSY_POLLING, DMA_FOR_INIT_RX, DMA_ECR_SW_INIT_DMA);				
	}		
}

int capture_Abuf(u8 *a_buf, u16 line_num, u16 num_tones, u16 beta_len, u16 duration, int is_to_capture)
{
	u8	status;
	short	*data_out;
	int	i;
	int	a_fifo_start_addr;
	int	fifo_size;
	int xfer_size; 
	int data_avail;
	int	data_len;

	data_len = 4096;

	writePIO_short((u16 *)(ADDRESS_RXCPU_DCACHE_PIO+0x0200), (0x8800 | line_num));
	writePIO_short((u16 *)(ADDRESS_RXCPU_DCACHE_PIO+0x0202), (0x8800 | line_num));
	writePIO_short((u16 *)(ADDRESS_RXCPU_DCACHE_PIO+0x0210), (0x8800 | line_num));
	writePIO_short((u16 *)(ADDRESS_RXCPU_DCACHE_PIO+0x0212), (0x8800 | line_num));
	writePIO_short((u16 *)(ADDRESS_RXCPU_DCACHE_PIO+0x0102), duration);
	writePIO_short((u16 *)(ADDRESS_RXCPU_DCACHE_PIO+0x0100), 0x1);
	read_afifo_status(line_num, &a_fifo_start_addr, &fifo_size);	
	
	while((data_avail = afifo_data_avail(line_num, fifo_size))<(duration-1)*data_len*2){
        if (!capTest) {
            logMsg("\n data_avail = %d", data_avail);
        }
		flush_xframer_cmd_q(line_num);
	}
    
	if(is_to_capture == 0)
		return(0);		
		
	if(host_mode_flag) 
	{
		status = hostReadBMEMemories(a_buf, (u8 *)ADDRESS_AFIFO, data_avail, 1, 1, line_num);
	} else
	{
	   	while(1) {
			xfer_size = MAX_DMA_SIZE<fifo_size?	data_avail : MAX_DMA_SIZE;
			status = readBMEMemories_diag ((void *)a_fifo_start_addr, (void *)a_buf, 0, xfer_size, line_num, DMA_BUSY_POLLING|FIFO_AS_MEM, DMA_FOR_INIT_RX, 
					DMA_ECR_SW_INIT_DMA);
			a_fifo_start_addr+=xfer_size;
			a_buf+=xfer_size;
			fifo_size-=xfer_size;
			if(fifo_size<=0)
				break;
	   	}  
	}

    if (capTest) {
		data_out = (short *)a_buf;
	
		for(i=0;i<data_avail/4;i++)
			printf("%d\n", data_out[i]);
        }
	return(status);	
}

int capture_tx_tone_bit_tab(XDSL_LINE *line)
{
	int	num_tones;
	int addr_offset;
	int mapper_reg;
	int	tmp;
		
	mapper_reg = readPIO_SingleRegChannel((int *)(MAP_MCT), line->ch_num);
	addr_offset = (mapper_reg&0xff)*128;
	
	mapper_reg>>=8;
	tmp = mapper_reg&0x7;
	if(tmp == 6)
		num_tones = 2048;
	else if(tmp == 5)
		num_tones = 1024;
	else {
		logMsg("\n unsupported tones");
		return(0);
	}
		
	if(host_mode_flag) {
		hostReadBMEMemories((u8 *)line->tx_tone_bit_table, (u8 *)(ADDRESS_MAPPERTONEORDER+addr_offset), 
			num_tones*sizeof(u16), 1, 0, 0);
	} else
	{
		readBMEMemories_diag ((void *)ADDRESS_MAPPERTONEORDER, (void *)line->tx_tone_bit_table, 0, num_tones*sizeof(u16), line->ch_num, 
						DMA_BUSY_POLLING, DMA_FOR_SNR, SNR_DMA_REQ);		
	}
	
	return(num_tones);
	
}

int capture_rx_tone_bit_tab(XDSL_LINE *line)
{
	int	num_tones;
	int addr_offset;
	int demapper_reg;
	int	tmp;
	
	demapper_reg = readPIO_SingleRegChannel((int *)(DMPCTX), line->ch_num);
	addr_offset = (demapper_reg&0x7f)*128;
	
	demapper_reg>>=28;
	tmp = demapper_reg&0x7;
	if(tmp == 6)
		num_tones = 2048;
	else if(tmp == 5)
		num_tones = 1024;
	else {
		logMsg("\n unsupported tones");
		return(0);
	}
	
	if(host_mode_flag) {
		hostReadBMEMemories((u8 *)line->rx_tone_bit_table, (u8 *)(ADDRESS_DEMAPPERTONEORDER+addr_offset), 
			num_tones*sizeof(u16), 1, 0, 0);
	} else
	{
		readBMEMemories_diag ((void *)ADDRESS_DEMAPPERTONEORDER, (void *)line->rx_tone_bit_table, 0, num_tones*sizeof(u16), line->ch_num, 
						DMA_BUSY_POLLING, DMA_FOR_SNR, SNR_DMA_REQ);		
	}
	
	return(num_tones);	
}

// 	code to capture pilot tone from host 
// RMC must be setup to send pilot tone (for all ch) 
// then use foll code in the rx fn to capture pilot tone for specified # of 
// symbols. out_buf should be big enough to hold reqd # of ptone values
//
void capture_ptone( int *out_buf, int nSymbols) 
{ 
    unsigned int  	p_wr; // prev wrt pos 
    unsigned int  	n_wr; // new wrt pos 
    int    		nInts, index;
    int				i;

    //  DMC's data memory location to be initialized as below: 
    //	0x3c20: DMC_ADR_PTONE_CHNUM    =  ch # 
    //	0x3c22: DMC_ADR_PTONE_RD_PTR   =  DMC_ADR_PTONE_BUF_BEGIN
    //	0x3c24: DMC_ADR_PTONE_WRT_PTR: changed by DMC 

    p_wr = readPIO_SingleRegChannel( (int *)(ADDRESS_DEMAPPERCPU_DCACHE_PIO+DMC_ADR_PTONE_WRT_PTR), 0);
    p_wr = ((p_wr >> 16) & 0xffff); 
    index = 0; 

    while (nSymbols > 0) {
        n_wr = readPIO_SingleRegChannel( (int *)(ADDRESS_DEMAPPERCPU_DCACHE_PIO+DMC_ADR_PTONE_WRT_PTR), 0);
        n_wr = ((n_wr >> 16) & 0xffff); 

		if (n_wr >= p_wr) {
	    	nInts = (n_wr - p_wr) >> 2; 
	    	if (nInts > nSymbols) 
	        	nInts = nSymbols; 
	    	if (nInts > 32) 
	        	nInts = 32; 
	    	if (nInts > 0) {
				for(i = 0; i<nInts;i++)
            		*out_buf++ = readPIO_SingleRegChannel( (int *)(ADDRESS_DEMAPPERCPU_DCACHE_PIO+i*4+p_wr), 0);
				nSymbols -= nInts;
				p_wr += (nInts<<2); 
	    	} 
		} else {  // wrapped case 
	    	nInts = (DMC_ADR_PTONE_BUF_END - p_wr) >> 2; 
	    	if(nInts > nSymbols) 
	        	nInts = nSymbols; 
	    	if(nInts > 0) { 
        		for(i = 0; i<nInts;i++)
            		*out_buf++ = readPIO_SingleRegChannel( (int *)(ADDRESS_DEMAPPERCPU_DCACHE_PIO+i*4+p_wr), 0);
				nSymbols -= nInts;
	        	p_wr = DMC_ADR_PTONE_BUF_BEGIN; 
	    	} 
		} 
		iposDelay();
    }
}

void skip_ptone_capture(int *buf, int nsymbols, int skip_shift)
{
	
	int	i, rd_ptr, wr_ptr, num_captures;
	int	ptone_avail;
	int	skips;
	int	cnt;
	
	skips=1<<skip_shift;
	rd_ptr = readPIO_SingleRegChannel((int *)(ADDRESS_DEMAPPERCPU_DCACHE_PIO+DMC_ADR_PTONE_WRT_PTR), 0);
    rd_ptr = ((rd_ptr >> 16) & 0xffff); 
	ptone_avail = 0;
	cnt = 0;

	while(nsymbols>0) {
		num_captures = 0;
		while(num_captures == 0) {
			// logMsg("\nrd_ptr=%x wr_ptr = %x ptone_avail=%d", rd_ptr, wr_ptr, ptone_avail);
			wr_ptr = readPIO_SingleRegChannel((int *)(ADDRESS_DEMAPPERCPU_DCACHE_PIO+DMC_ADR_PTONE_WRT_PTR), 0);
	    	wr_ptr = ((wr_ptr >> 16) & 0xffff); 
		
			if(wr_ptr>=rd_ptr)
				ptone_avail = (wr_ptr-rd_ptr)>>2;
			else
				ptone_avail = ((DMC_ADR_PTONE_BUF_END - DMC_ADR_PTONE_BUF_BEGIN) - (rd_ptr-wr_ptr))>>2;
		
			num_captures = ptone_avail>>skip_shift;	
			if(num_captures>=nsymbols)
				break;
			else if(ptone_avail<128)
				iposDelay();
		}
		
		for(i=0;i<num_captures;i++) {
			*buf++=readPIO_SingleRegChannel((int *)(ADDRESS_DEMAPPERCPU_DCACHE_PIO+rd_ptr), 0);	
			rd_ptr+=(skips*4);
			if(rd_ptr>=DMC_ADR_PTONE_BUF_END)
				rd_ptr = DMC_ADR_PTONE_BUF_BEGIN+(rd_ptr- DMC_ADR_PTONE_BUF_END);
			// logMsg("\n num_cap = %d, i= %d, num_sym_left = %d", num_captures, i, nsymbols);
			nsymbols--;
			if(nsymbols<=0) {
				logMsg("\n got all the ptones");
				return;	
			}

			if(cnt == 80) {
				iposDelay();
				cnt=0;
			}
			cnt++;			
		}	

	}
}