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

#include "bme.h"
#include "include/fixed_bgtable.h"
#include "include/vdsl_framer.h"
#include "include/vdsl_ch.h"
#include "include/sdram_map.h"
#include "include/xdsl_rmc.h"
#include "bme_app.h"
#include "mem.h"
#include "hostType.h"

#define  TX_ZFIFO_STARTING_OFST   0 //512 

static int	send_periodic_data = 0;
static int	is_zero_ce = 0;

void send_periodicData()
{ 
	send_periodic_data = 1;
}

void send_random_data()
{
	send_periodic_data = 0;
}

void set_zero_ce()
{
	is_zero_ce = 1;
}

void set_non_zero_ce()
{
	is_zero_ce = 0;
}


void init_ch_tx(XDSL_LINE *line, int ch_num, LOCATION location, VDSL_CFG *vdsl_cfg)
{
	int			i;
	u8 	  		*xdata;
	XDSL_LINE	*curr_line = line + ch_num;
	
	// tx initialization
	// writePIO_SingleRegChannel((int *) (ZFIFO_CZFT_A),  ch_num, ((0/128)<<7) + (9<<3) + 1);
	strcpy(curr_line->tx_showtime_init_infile, vdsl_cfg->tx_showtime_param_file);
	strcpy(curr_line->tx_showtime_file_sem, vdsl_cfg->tx_showtime_sem_file);
	strcpy(curr_line->tx_showtime_param_sem_file, vdsl_cfg->tx_showtime_param_sem_file);
	if(location == UP_STREAM) {
		strcpy(curr_line->tx_medley_start_file_sem, vdsl_cfg->cpe_tx_medley_start_file_sem);
		strcpy(curr_line->tx_medley_start_done_file_sem, vdsl_cfg->cpe_tx_medley_start_done_file_sem);
		strcpy(curr_line->cpe_tx_start_file_sem, vdsl_cfg->cpe_tx_start_file_sem);
	} else
	{
	   	strcpy(curr_line->tx_medley_start_file_sem, vdsl_cfg->co_tx_medley_start_file_sem);
		strcpy(curr_line->tx_medley_start_done_file_sem, vdsl_cfg->co_tx_medley_start_done_file_sem);	
	}
	curr_line->is_tx_ptone_scr_on = vdsl_cfg->tx_ptone_scr_on;
	curr_line->bandplan = vdsl_cfg->bandplan;
	curr_line->location = location;
	curr_line->ch_num = ch_num;
	curr_line->ch_state = ACTIVE;
	curr_line->is_op_training_started = 0;
	curr_line->is_medley_training_started = 0;
	curr_line->curr_tx_symbol_num = 0;
	curr_line->curr_tx_state = OP_TRAINING;
	curr_line->tx_showtime_start = 10000;
	curr_line->tx_tone_bit_table = sdram_map->tx_bit_tone_table[ch_num];
	curr_line->tx_gain_table = sdram_map->tx_gain_table[ch_num];
	curr_line->tx_gi = sdram_map->tx_gi;
	curr_line->tx_bit_table = sdram_map->tx_showtime_bit_table;
	curr_line->tx_upb = sdram_map->tx_upb;
	curr_line->tx_precmp = sdram_map->tx_precmp;
	curr_line->num_tx_bands = vdsl_cfg->num_tx_bands;
	for(i=0;i<curr_line->num_tx_bands;i++) {
		curr_line->tx_band_start[i] = vdsl_cfg->tx_band_start[i];
		curr_line->tx_band_stop[i] = vdsl_cfg->tx_band_stop[i];
	}
	curr_line->tx_pilot_tone = vdsl_cfg->tx_pilot_tone;
	curr_line->zbuf_offset = vdsl_cfg->zbuf_offset;
	curr_line->tx_fft_size = 4096;
    curr_line->tx_prefix_len = 192; 				//excluding beta
	curr_line->tx_suffix_len = 128;
	curr_line->tx_beta_len = 0;

	if(is_zero_ce) {
		curr_line->tx_beta_len = 0;
		curr_line->tx_prefix_len = 0; 				//excluding beta
		curr_line->tx_suffix_len = 0;
	}
		
	tx_chg_pilot_tone(curr_line->tx_pilot_tone);
	tx_set_lcs_lcp((u8)curr_line->ch_num, 2*curr_line->tx_prefix_len,  2*curr_line->tx_suffix_len, 2*curr_line->tx_beta_len);
	tx_set_upb(curr_line->tx_upb, curr_line->tx_fft_size>>1);
	tx_set_precmp(curr_line->tx_precmp, curr_line->tx_fft_size>>1, curr_line->location, curr_line->bandplan);
	tx_set_gi(curr_line->tx_gi, curr_line->tx_fft_size>>1);
	tx_init_table(curr_line);
	if(curr_line->is_tx_ptone_scr_on == 0)
		turn_off_ptone_scr();
	
	if ((xdata = (u8 *) malloc(4096)) == NULL) { 
	    logMsg("** ERROR xfifo data malloc failed **\n"); 
	} else { 
		if(send_periodic_data)
		    memset(xdata, 0x00, 4096);
		else {
	    	for (i=0; i<4096; i++) { 
				xdata[i] = i;
	    	}
		}
		
	    write_XF_Fifo(ch_num, xdata, 4096); 
	    free(xdata);
	} 	
}

#define MAX_SZ_PER_XFER	1024 

void coordinate_tx_rx(XDSL_LINE *tx_line, XDSL_LINE *rx_line, int mode)
{
	FILE	*fpin;
	int		wait_cnt;
	int 	num_items_read;
	int		xfer_cnt;
	int		data_len = tx_line->tx_fft_size>>1;
	
	if(mode == 0) {
		if(rx_line->isRxShowtime_inited) 
		{
			// get the bit table and gi from the rx
			memcpy(tx_line->tx_gi, rx_line->rx_gi, 2048*sizeof(u16));
			memcpy(tx_line->tx_bit_table, rx_line->rx_showtime_bit_table, 2048*sizeof(u8));
			//get the tc layer parameters from the rx
			memcpy((u8 *)(&tx_line->tx_framer_param), (u8 *)(&rx_line->fast_path_cfg), sizeof(VDSL_Framer_Param));
		
			tx_line->curr_tx_state = TX_SHOWTIME_INIT;
		}  else {
    	    printf("\n RX is not ready to go into showtime");
    	}
	} else
	{
		fpin = NULL;
		wait_cnt = 0;
		iposDelay();
		while(1) {
			fpin = fopen(tx_line->tx_showtime_init_infile, "rb");
			if(fpin!=NULL)
				break;
			wait_cnt++;
			iposDelay();
			if(wait_cnt>2000) {
				printf("\n timed out on waiting for RX showtime init parameter file - %s", tx_line->tx_showtime_init_infile);
				return;
			}
		}
		
		xfer_cnt = 0;
		while(xfer_cnt!=data_len) {
			num_items_read = fread(tx_line->tx_bit_table+xfer_cnt, sizeof(u8), MAX_SZ_PER_XFER, fpin);
			if(num_items_read!=MAX_SZ_PER_XFER) {
				logMsg("\n warning tx bit table reads wrong number of items");
			}
			xfer_cnt+=MAX_SZ_PER_XFER;
			iposDelay();	
		}

		xfer_cnt = 0;
		while(xfer_cnt!=data_len) {
			num_items_read = fread(tx_line->tx_gi+xfer_cnt, sizeof(u16), MAX_SZ_PER_XFER, fpin);
			if(num_items_read!=MAX_SZ_PER_XFER) {
				logMsg("\n  warning tx gi reads wrong number of items");
			}
			xfer_cnt+=MAX_SZ_PER_XFER;
			iposDelay();			
		}
		
		fread((char *)(&tx_line->tx_framer_param), sizeof(VDSL_Framer_Param), 1, fpin);
		fclose(fpin);
		tx_line->curr_tx_state = TX_SHOWTIME_INIT;
		//@SHRI logMsg("\n TX is ready to go into showtime");
	}
}