/* Application - HPDI32 - Any OS */
/* $Workfile: tx.c $ */
/* $Revision: 2 $ */
/* $Date: 10/27/07 4:20p $ */
/* $Log: /NEW SOURCESAFE DATABASE/SDK/PLX/gsc/hpdi32/xfer/tx.c $
 * 
 * 2     10/27/07 4:20p Dnewbold
 * Linux porting changes.
 * 
 * 1     8/22/05 4:17p Dnewbold
*/

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

#include "hpdi32_api.h"
#include "main.h"
#include "util_time.h"
#include "util_sleep.h"



/*****************************************************************************
*
*	Function:	_show_tx_clock
*
*	Purpose:
*
*		Show the Tx clock rate.
*
*	Arguments:
*
*		device		The handle used to access the device under test.
*
*		clk			The clock rate is recorded here.
*
*	Returned:
*
*		GSC_SUCCESS	All went well.
*		else		An appropriate error status.
*
*****************************************************************************/

static U32 _show_tx_clock(void* device, U32* clk)
{
	unsigned long	divide;
	U32				status;

	printf("Tx Clock:       ");
	status	= HPDI32_TX_CLOCK_DIVIDER__GET(device, &divide);
	test_status(status, "HPDI32_TX_CLOCK_DIVIDER__GET");

	if (status == GSC_SUCCESS)
	{
		divide	= (divide <= 1) ? 1 : divide * 2;
		clk[0]	= io_clock / divide;
		printf("%lu / %lu = ", (long) io_clock, (long) divide);
		format_value(clk[0], "Hz");

		if (clk[0] < 1)
		{
			printf("\nERROR: The clock rate is too low.\n");
			status	= GSC_FAILED;
		}

		printf("\n");
	}

	return(status);
}



/*****************************************************************************
*
*	Function:	_show_flow_control
*
*	Purpose:
*
*		Show the cable's Tx Flow Control confg\iguration.
*
*	Arguments:
*
*		device		The handle used to access the device under test.
*
*	Returned:
*
*		GSC_SUCCESS	All went well.
*		else		An appropriate error status.
*
*****************************************************************************/

static U32 _show_flow_control(void* device)
{
	unsigned long	fv;
	unsigned long	lv;
	unsigned long	lv_off;
	unsigned long	lv_on;
	U32				status;
	unsigned long	sv;
	unsigned long	sv_on;

	for (;;)	// A convenience loop.
	{
		printf("Flow Control:   Tx Clock");

		status	= HPDI32_CABLE_COMMAND_MODE__FV_GET(device, &fv);
		if (test_status(status, "HPDI32_CABLE_COMMAND_MODE__FV_GET"))	break;

		status	= HPDI32_CABLE_COMMAND_MODE__LV_GET(device, &lv);
		if (test_status(status, "HPDI32_CABLE_COMMAND_MODE__LV_GET"))	break;

		status	= HPDI32_CABLE_COMMAND_MODE__SV_GET(device, &sv);
		if (test_status(status, "HPDI32_CABLE_COMMAND_MODE__SV_GET"))	break;

		status	= HPDI32_TX_LINE_VALID_OFF_COUNT__GET(device, &lv_off);
		if (test_status(status, "HPDI32_TX_LINE_VALID_OFF_COUNT__GET"))	break;

		status	= HPDI32_TX_LINE_VALID_ON_COUNT__GET(device, &lv_on);
		if (test_status(status, "HPDI32_TX_LINE_VALID_ON_COUNT__GET"))	break;

		status	= HPDI32_TX_STATUS_VALID_COUNT__GET(device, &sv_on);
		if (test_status(status, "HPDI32_TX_STATUS_VALID_COUNT__GET"))	break;

		if (fv == HPDI32_CABLE_COMMAND_MODE_FLOW_CONTROL)
			printf(", Frame Valid");

		if (lv == HPDI32_CABLE_COMMAND_MODE_FLOW_CONTROL)
		{
			printf(", Line Valid");

			if ((lv_on) && (lv_off))
				printf(" (%lu,%lu)", (long) lv_off, (long) lv_on);
			else
				printf(" (Hi)");

			if (sv == HPDI32_CABLE_COMMAND_MODE_FLOW_CONTROL)
				printf("(Status Valid: %lu)", (long) sv_on);
		}

		if (sv == HPDI32_CABLE_COMMAND_MODE_FLOW_CONTROL)
			printf(", Status Valid (%lu)", (long) sv_on);

		printf("\n");
		break;
	}

	return(status);
}



/*****************************************************************************
*
*	Function:	_wait_for_tx_empty
*
*	Purpose:
*
*		Wait for the transmitted data to exit the Tx FIFO.
*
*	Arguments:
*
*		device		The handle used to access the device under test.
*
*	Returned:
*
*		GSC_SUCCESS	All went well.
*		else		An appropriate error status.
*
*****************************************************************************/

static U32 _wait_for_tx_empty(void* device)
{
	unsigned long	fifo;
	U32				status;

	printf("Waiting for Tx: ");
	fflush(stdout);
	sleep_ms(5);

	for (;;)
	{
		status	= HPDI32_FIFO_STATUS__TX_GET(device, &fifo);
		if (test_status(status, "HPDI32_FIFO_STATUS__TX_GET"))	break;

		if (fifo == HPDI32_FIFO_STATUS_EMPTY)
		{
			// Allow time for the last few items.
			sleep_ms(5);
			break;
		}
	}

	if (status == GSC_SUCCESS)
		printf("Done  (Data sent out cable interface.)\n");

	return(status);
}



/*****************************************************************************
*
*	Function:	_tx_data
*
*	Purpose:
*
*		Transmit data per the existing parameters.
*
*	Arguments:
*
*		device		The handle used to access the device under test.
*
*		src			The source buffer to transmit.
*
*		bytes		The size of the buffer in bytes.
*
*	Returned:
*
*		GSC_SUCCESS	All went well.
*		else		An appropriate error status.
*
*****************************************************************************/

static U32 _tx_data(void* device, const void* src, U32 bytes)
{
	U32	block;
	U32	status;
	U32	xfer;

	for (;;)	// A convenience loop.
	{
		printf("Transmitting:   ");
		status	= HPDI32_TX_ENABLE__YES(device);
		if (test_status(status, "HPDI32_TX_ENABLE__YES"))	break;

		for (block = 0; block < block_count; block++)
		{
			printf(".");
			status	= hpdi32_write(device, src, bytes, &xfer);
			if (test_status(status, "hpdi32_write"))	break;

			if (((block % 50) == 49) || ((block + 1) == block_count))
				printf(" %ld", (long) block + 1);

			if ((block % 50) == 49)
				printf("\n                ");
		}

		if (status == GSC_SUCCESS)
			printf(" Done\n");

		break;
	}

	return(status);
}



/*****************************************************************************
*
*	Function:	tx_process
*
*	Purpose:
*
*		Implement the data transmission process.
*
*	Arguments:
*
*		device		The handle used to access the device under test.
*
*	Returned:
*
*		GSC_SUCCESS	All went well.
*		else		An appropriate error status.
*
*****************************************************************************/

U32 tx_process(void* device)
{
	unsigned long	begin;
	double			bytes;
	U32				clk;
	long			l;
	void*			ptr;
	const char*		psz;
	unsigned long	size;
	struct tm*		stm;
	U32				status;
	time_t			tt;
	U8*				u8p;
	U16*			u16p;
	U32				u32;
	U32*			u32p;

	for (;;)	// A convenience loop.
	{
		printf("DATA TRANSMISSION:\n");

		status	= tx_rx_tristate(device);
		if (status != GSC_SUCCESS)	break;

		status	= _show_tx_clock(device, &clk);
		if (status != GSC_SUCCESS)	break;

		status	= show_data_set(device, HPDI32_WHICH_TX, &size, &bytes);
		if (status != GSC_SUCCESS)	break;

		status	= show_data_rate(HPDI32_WHICH_TX, clk, size);
		if (status != GSC_SUCCESS)	break;

		status	= estimate_duration(clk, size, bytes);
		if (status != GSC_SUCCESS)	break;

		status	= _show_flow_control(device);
		if (status != GSC_SUCCESS)	break;

		printf("Begin Time:     ");
		time(&tt);
		stm	= localtime(&tt);
		psz	= asctime(stm);
		printf("%s", psz);
		begin	= time_ms_get_run();

		u32		= size * block_samples;
		ptr		= malloc(u32);

		if (ptr)
		{
			if (size == 1)
			{
				u8p	= (U8*) ptr;

				for (l = 0; l < (long) block_samples; l++)
					u8p[l]	= (U8) (l & 0xFF);

				for (l = 0; l < (long) block_samples; l++)
				{
					u8p[l]	= (U8) ((((U32) l /  1) % 10) <<  0)
							| (U8) ((((U32) l / 10) % 10) <<  4);
				}

				for (l = 0; (l < 8) && (l < (long) block_samples); l++)
					u8p[l]	= (U8) (0x1L << l);

				for (l = 8; (l < 16) && (l < (long) block_samples); l++)
					u8p[l]	= (U8) (~(0x1UL << ((U8) l - 8)));
			}
			else if (size == 2)
			{
				u16p	= (U16*) ptr;

				for (l = 0; l < (long) block_samples; l++)
				{
					u16p[l]	= (U16) ((((U32) l /    1) % 10) <<  0)
							| (U16) ((((U32) l /   10) % 10) <<  4)
							| (U16) ((((U32) l /  100) % 10) <<  8)
							| (U16) ((((U32) l / 1000) % 10) << 12);
				}

				for (l = 0; (l < 16) && (l < (long) block_samples); l++)
					u16p[l]	= (U16) (0x1L << l);

				for (l = 16; (l < 32) && (l < (long) block_samples); l++)
					u16p[l]	= (U16) (~(0x1UL << ((U32) l - 16)));
			}
			else
			{
				u32p	= (U32*) ptr;

//				for (l = 0; l < (long) block_samples; l++)
//				{
//					u32p[l]	= ((((U32) l /      1) % 10) <<  0)
//							| ((((U32) l /     10) % 10) <<  4)
//							| ((((U32) l /    100) % 10) <<  8)
//							| ((((U32) l /   1000) % 10) << 12)
//							| ((((U32) l /  10000) % 10) << 16)
//							| ((((U32) l / 100000) % 10) << 20);
//				}

//				for (l = 0; (l < 32) && (l < (long) block_samples); l++)
//					u32p[l]	= 0x1L << l;

//				for (l = 32; (l < 64) && (l < (long) block_samples); l++)
//					u32p[l]	= (U32) ~(0x1UL << ((U32) l - 32));

				for (l = 0; l < (long) block_samples; l++)
					u32p[l]	= l;
			}

			status	= _tx_data(device, ptr, u32);
			free(ptr);

			status	= _wait_for_tx_empty(device);
			if (status != GSC_SUCCESS)	break;
		}
		else
		{
			printf("ERROR: malloc(%ld) failure.\n", (long) u32);
			status	= GSC_FAILED;
		}

		actual_duration((long) begin);
		break;
	}

	return(status);
}


