/******************************************************************************
 *
 *	UART 16550/ 16552 / Z8530 DIAGNOSTIC
 *
 * This module contains  UART 16550/ 16552 / Z8530 diagnostic tests
 *
 * History:
 *   +----------+------------+------------------------------------------------+
 *   |   Date   |     by     |     Description                                |
 *   +----------+------------+------------------------------------------------+
 *   |          | Amir       | Written                                        |
 *   +----------+------------+------------------------------------------------+
 * 
 *****************************************************************************/

#include "cc_def.h"
#include SERIAL_FILE

#include "diag.h"


UART_INIT_TABLE;

#pragma interrupt (receive0_handler__);
#pragma interrupt (receive1_handler__);

private volatile unsigned char r_ch0, r_ch1;

/* forward private functions */
/*****************************/

private char * run_test_16550 ();
private char * run_test_z8530 ();
private char * run_test_fx200uart ();


/****************************************************************************
 *
 *	test_16550__()
 *
 ****************************************************************************/

#if (UART_TYPE == NS16550)
public char * test_16550__ ()
{
    char    *chp;

    chp = run_test_16550 ();
    init_uart(0, DIAG_BAUD, 0);
#ifdef UART_1_ADDR
    init_uart(1, DIAG_BAUD, 0);
#endif
    return chp;
}
#endif

/****************************************************************************
 *
 *	test_z8530__ ()
 *
 ****************************************************************************/

#if (UART_TYPE == Z8530)
public char * test_z8530__ ()
{
    char    *chp;

    chp = run_test_z8530 ();
    init_uart(1, DIAG_BAUD, 0);
    init_uart(0, DIAG_BAUD, 0);
    return chp;
}
#endif

/****************************************************************************
 *
 *	test_fx200uart()
 *
 ****************************************************************************/

#if (UART_TYPE == FX200UART)
public char * test_fx200uart__ ()
{
    char    *chp;

    chp = run_test_fx200uart ();
    init_uart(0, DIAG_BAUD, 0);
    return chp;
}
#endif

/****************************************************************************
 *
 *	loop_back_test()
 *
 ****************************************************************************/

private boolean loop_back_test(port, divisor_idx)
int port;
int divisor_idx;
{
    int divisor;
    int i;
    byte c;

    divisor = uart_table[divisor_idx].divisor;

    init_uart(port, divisor, 1);
    if (READ_CHAR_IS_READY(port)) {
	strcpy (error, "FAILURE: DATA READY BIT STUCK AT 1, BAUD ");
	bin_to_dec(uart_table[divisor_idx].baud, &error[strlen(error)]);
	return FALSE;
    }
    while (NOT READY_TO_WRITE_CHAR(port));
    PUT_CHAR(port,0xa5); /* a5 */
    for (i = 0; i < 0x100000; i ++) {
	if (READ_CHAR_IS_READY(port))
	    break;
    }
    c = GET_CHAR(port);
    if (i== 0x100000 OR  c != 0xa5) { /* a5 */
	strcpy (error, "FAILURE: LOOP-BACK MODE ERROR AT BAUD ");
	bin_to_dec(uart_table[divisor_idx].baud, &error[strlen(error)]);
	return FALSE;
    }

    /* Try to workaround the Z8530 problem Which write to the terminal     **
    ** in loopback mode. To workaround it we print back space to this port */
    init_uart(port, DIAG_BAUD, 0);
    while (NOT READY_TO_WRITE_CHAR(port));
    PUT_CHAR(port,0x0d); /* Back Space */


    if (debug_flag) {
	init_uart(DIAG_PORT, DIAG_BAUD, 0);
	strcpy (msg__, "UART LOOP BACK test PASS BAUD = ");
	bin_to_dec(uart_table[divisor_idx].baud, &msg__[strlen(msg__)]);
	print_str(msg__);
    }
    return TRUE;
}



#if (UART_TYPE == NS16550)

/****************************************************************************
 *
 *	receive0_handler__()
 *
 ****************************************************************************/

void receive0_handler__()
{
    r_ch0 = GET_CHAR(0);
}

/****************************************************************************
 *
 *	receive1_handler__()
 *
 ****************************************************************************/

void receive1_handler__()
{
    r_ch1 = GET_CHAR(1);
}

/****************************************************************************
 *
 *	run_test_16550 ()
 *
 ****************************************************************************/

private char * run_test_16550 ()
{
    volatile int v = 0;
    int	    i;
    char    ch;

    UART0[SCR] = 0x5a;				/* Check data path to uart0 */
    v++;
    if (UART0[SCR] != 0x5a ){
	strcpy (error, "FAILURE: DATA PATH WRITE/READ ERROR AT PORT 0");
	return error;
    }
    UART0[SCR] = 0xa5;
    v++;
    if (UART0[SCR] != 0xa5 ){
	strcpy (error, "FAILURE: DATA PATH WRITE/READ ERROR AT PORT 0");
	return error;
    }
    if (debug_flag) {
	strcpy (msg__, "UART 16550 PORT 0,  DATA PATH test PASS \n");
	print_str(msg__);
    }

   for (i=0; uart_table[i].baud > 0; i++) { 	/* Loop back test at uart 0 */
	if ( ! loop_back_test(0, i)) {
	    strcat(error, ", PORT = 0");
	    return error;
	}
   }


#ifndef NO_UART_INT     /* temp dragon and parrot icu test not implemented */
    _interrupt_disable();
    init_uart (0, DIAG_BAUD, 3);
    icu_init__ ();
    set_handler__ (UART0_INT, receive0_handler__);
    _interrupt_enable();
    r_ch0 = 0;

    while (NOT READY_TO_WRITE_CHAR(0));
    PUT_CHAR(0,0x5a);
    for (i = 0; i < 0x100000; i ++) {
	if (r_ch0 != 0)
	    break;
    }
    _interrupt_disable();
    if (i== 0x100000 OR (r_ch0 != 0x5a)) {
	strcpy (error, "FAILURE: NO INTERRUPT FROM PORT 0 AT BAUD 9600");
	return error;
    }
    if (debug_flag) {
	init_uart(DIAG_PORT, DIAG_BAUD, 0);
	strcpy (msg__, "UART 16550 PORT 0, INTERRUPT test PASS \n");
	print_str(msg__);
    }
#endif

#   ifndef	ONE_UART

    UART1[SCR] = 0x5a; 			/* Check data path to uart1 */
    v++;
    if (UART1[SCR] != 0x5a ){
        strcpy (error, "FAILURE: DATA PATH WRITE/READ ERROR AT PORT 1");
        return error;
    }
    UART1[SCR] = 0xa5;
    v++;
    if (UART1[SCR] != 0xa5 ){
        strcpy (error, "FAILURE: DATA PATH WRITE/READ ERROR AT PORT 1");
        return error;
    }
    if (debug_flag) {
	init_uart(DIAG_PORT, DIAG_BAUD, 0);
	strcpy (msg__, "UART 16550 PORT 1, DATA PATH test PASS \n");
	print_str(msg__);
    }

   for (i=0; uart_table[i].baud > 0; i++) {
	if ( ! loop_back_test(1, i)) {
	    strcat(error, ", PORT = 1");
	    return error;
	}
   }

#ifndef NO_UART_INT     /* temp dragon and parrot icu test not implemented */
    _interrupt_disable();
    init_uart (1, DIAG_BAUD, 3);
    icu_init__ ();
    set_handler__ (UART1_INT, receive1_handler__);
    _interrupt_enable();
    r_ch1 = 0;
    while (NOT READY_TO_WRITE_CHAR(1));
    PUT_CHAR(1,0x5a);
    for (i = 0; i < 0x100000; i ++) {
        if (r_ch1 != 0)
    	break;
    }
    _interrupt_disable();
    if (i== 0x100000 OR (r_ch0 != 0x5a)) {
        strcpy (error, "FAILURE: NO INTERRUPT FROM PORT 1 AT BAUD 9600");
        return error;
    }
    if (debug_flag) {
        init_uart(DIAG_PORT, DIAG_BAUD, 0);
        strcpy (msg__, "UART 16550 PORT 1, INTERRUPT test PASS \n");
        print_str(msg__);
    }
    
#endif

#   endif	/* NOT ONE_UART */
    return NULL;
}
#endif



#if (UART_TYPE == Z8530)

/****************************************************************************
 *
 *	receive0_handler__()
 *
 ****************************************************************************/

void receive0_handler__()
{
    r_ch0 = READ_CHAR_IS_READY(0) ? GET_CHAR(0): '\0';
}

/****************************************************************************
 *
 *	receive1_handler__()
 *
 ****************************************************************************/

void receive1_handler__()
{
    r_ch1 = READ_CHAR_IS_READY(1) ? GET_CHAR(1): '\0';
}

/****************************************************************************
 *
 *	run_test_z8530 ()
 *
 ****************************************************************************/

private char * run_test_z8530 ()
{
    volatile int v = 0;
    int	    i;
    char    ch;

   for (i=0; uart_table[i].baud > 0; i++) {
	DELAY(0x10000);
	if ( ! loop_back_test(0, i)) {
	    strcat(error, ", PORT = 0");
	    return error;
	}
   }

   DELAY(0x10000);
   init_uart(0,DIAG_BAUD, 3);
   icu_init__ ();
   set_handler__ (SCC_INT, receive0_handler__);
   _interrupt_enable();
   r_ch0 = 0;
   while (NOT READY_TO_WRITE_CHAR(0));
   DELAY(0x10000);
   PUT_CHAR(0,0x5a);
   for (i = 0; i < 0x100000; i ++) {
	if (r_ch0 != 0)
	     break;
   }
   _interrupt_disable();
   if (i== 0x100000 OR (r_ch0 != 0x5a)) {
	 strcpy (error, "FAILURE: NO INTERRUPT FROM PORT 0 AT BAUD 9600");
	 return error;
   }

   /* Try to workaround the Z8530 problem Which write to the terminal     **
   ** in loopback mode. To workaround it we print back space to this port */
   init_uart(0, DIAG_BAUD, 0);
   while (NOT READY_TO_WRITE_CHAR(0));
   PUT_CHAR(0,0x0d); /* Back Space */

   if (debug_flag) {
	 init_uart(DIAG_PORT, DIAG_BAUD, 0);
	 strcpy (msg__, "UART Z8530 PORT 0, INTERRUPT test PASS \n");
	 print_str(msg__);
   }

#   ifndef	ONE_UART

   for (i=0; uart_table[i].baud > 0; i++) {
	DELAY(0x10000);
	if ( ! loop_back_test(1, i)) {
	    strcat(error, ", PORT = 1");
	    return error;
	}
   }

   DELAY(0x10000);
   init_uart(1, DIAG_BAUD, 3);
   icu_init__ ();
   set_handler__ (SCC_INT, receive1_handler__);
   _interrupt_enable();
   r_ch1 = 0;
   while (NOT READY_TO_WRITE_CHAR(1));
   DELAY(0x10000);
   PUT_CHAR(1,0x5a);
   for (i = 0; i < 0x100000; i ++) {
	if (r_ch1 != 0)
	    break;
   }
   _interrupt_disable();
   if (i== 0x100000 OR (r_ch1 != 0x5a)) {
	strcpy (error, "FAILURE: NO INTERRUPT FROM PORT 1 AT BAUD 9600");
	return error;
   }
   if (debug_flag) {
	init_uart(DIAG_PORT, DIAG_BAUD, 0);
	strcpy (msg__, "UART Z8530 PORT 1, INTERRUPT test PASS \n");
	print_str(msg__);
   }
#endif /* ONE_UART */
    return NULL;
}
#endif

#if (UART_TYPE == FX200UART)

/****************************************************************************
 *
 *	receive0_handler__()
 *
 ****************************************************************************/

void receive0_handler__()
{
    r_ch0 = READ_CHAR_IS_READY(0) ? GET_CHAR(0): '\0';
}
void receive1_handler__() {}

/****************************************************************************
 *
 *	run_test_fx200uart ()
 *
 ****************************************************************************/

private char * run_test_fx200uart ()
{
    volatile int v = 0;

    UART[UTXB] = 0x5a;			/* Check data path to uart */
    v++;
    if (UART[UTXB] != 0x5a ){
	strcpy (error, "FAILURE: DATA PATH WRITE/READ ERROR AT UART PORT");
	return error;
    }
    UART[UTXB] = 0xa5;
    v++;
    if (UART[UTXB] != 0xa5 ){
	strcpy (error, "FAILURE: DATA PATH WRITE/READ ERROR AT UART PORT");
	return error;
    }
    if (debug_flag) {
	strcpy (msg__, "UART FX200 ,DATA PATH test PASS \n");
	print_str(msg__);
    }
    return NULL;
}

#endif
#if (UART_TYPE ==  PC_EMUL)
void receive0_handler__(){}
void receive1_handler__(){}
#endif
