/******************************************************************************
 *
 *	CENTRONICS DIAGNOSTIC
 *
 * This module contains centronics diagnostic tests
 *
 * History:
 *   +----------+------------+------------------------------------------------+
 *   |   Date   |     by     |     Description                                |
 *   +----------+------------+------------------------------------------------+
 *   |          | 	     | Written                                        |
 *   +----------+------------+------------------------------------------------+
 * 
 *  cent_init()		cent_disable()		int_dma()
 *  check_buffer()	test_centronics__()
 *
 *  The centronics diagnostic works as follows:
 *  @ The DMA is initialized to work with the Centronics in an 
 *    apropriate mode.
 *  @ The centronics is initialized.
 *  @ The oparator is asked to type the string "0@ABDH" on the PC.
 *  @ The test enters a wait state in which, if a charecter arrives 
 *    it creates an interrupt. The interrupt is handeld and the test 
 *    waits for the next charecter. Then the arrived string is 
 *    compared against a reference.
 *    If no charecters arrive, a TIME OUT is created after a few seconds.    
 *
 *****************************************************************************/


#include "cc_def.h"
#include "diag.h"

#pragma interrupt(int_dma) 

/*  Forward private functions. */
/*******************************/

private void cent_init();
private void cent_read();
private void cent_disable();
private char *check_buffer();


/* DMA definitions */
/*******************/

#define DMA0_ADD                0xfffff020
#define DMA1_ADD                0xfffff040

#define ADCA_CH0                *((unsigned long *) DMA0_ADD)
#define ADRA_CH0                *((unsigned long *) (DMA0_ADD + 0x04))
#define ADCB_CH0                *((unsigned long *) (DMA0_ADD + 0x08))
#define ADRB_CH0                *((unsigned long *) (DMA0_ADD + 0x0c))
#define BLTC_CH0                *((unsigned long *) (DMA0_ADD + 0x10))
#define BLTR_CH0                *((unsigned long *) (DMA0_ADD + 0x14))
#define MODE_CH0                *((unsigned long *) (DMA0_ADD + 0x18))
#define CTL_CH0                 *((unsigned long *) (DMA0_ADD + 0x1c))

#define ADCA_CH1                *((unsigned long *) DMA1_ADD)
#define ADRA_CH1                *((unsigned long *) (DMA1_ADD + 0x04))
#define ADCB_CH1                *((unsigned long *) (DMA1_ADD + 0x08))
#define ADRB_CH1                *((unsigned long *) (DMA1_ADD + 0x0c))
#define BLTC_CH1                *((unsigned long *) (DMA1_ADD + 0x10))
#define BLTR_CH1                *((unsigned long *) (DMA1_ADD + 0x14))
#define MODE_CH1                *((unsigned long *) (DMA1_ADD + 0x18))
#define CTL_CH1                 *((unsigned long *) (DMA1_ADD + 0x1c))

/* register and masks  */
/***********************/

#define DMA_STAT                *((unsigned long *) 0xfffff010 )
#define DMA_IMASK               *((unsigned long *) 0xfffff014 )
#define DMA_DSTAT               *((unsigned long *) 0xfffff018 )

#define DMA0_TC                 0x01
#define DMA0_EOT                0x02
#define DMA0_OVR                0x04
#define DMA0_CHAC               0x08

#define DMA1_TC                 0x10
#define DMA1_EOT                0x20
#define DMA1_OVR                0x40
#define DMA1_CHAC               0x80

#define DMA_DIP                 0x80

#define DMA_CHEN                0x01
#define DMA_VLD                 0x02

#define MAX_CENT_BUF		1
#define BUFSIZE			20

#if (BOARD == VECTOR)
    byte recieved_data[BUFSIZE];
#else         /* SWIFT */
    unsigned short recieved_data[BUFSIZE];
#endif

volatile int data_arrived;
byte dummy;

/******************************************************************
 *
 *  cent_init()
 *
 *   The centronics operating mode is totaly dependent on the DMA operating
 *   mode, and the DMA is therefor initialized accordingly.
 *   The SWIFT can only work in DMA FLY-BY mode (non block mode).
 *   The VECTOR only works in DMA memory to memory mode.
 *   
 *****************************************************************/

private void cent_init()
{
    dummy = CND; 	/* clear the centronics buffer by a dummy read */
    set_handler__(DMA_INT, int_dma);		/* set interupt handler    */

#if (BOARD == VECTOR)

    PATERN_SET(DMA1_TC | DMA_DIP, DMA_IMASK);	/* enable TC int` level 14 */
    ADCA_CH1 = (unsigned long) CND_ADDR;	/* source addr` counter    */
    ADCB_CH1 = (unsigned long) recieved_data;   /* dest` addr` counter     */
    BLTC_CH1 = 8;				/* block size = 6 bytes    */
    MODE_CH1 = 0x006c;				/* mode:
						 * non auto initialize
						 * FBY = mem` to mem`
						 * DIR = peripherial is source
						 * source bus width = 8 bits
						 * non increment
						 * dest` bus width  = 32 bits
						 * increment		   */	

    CENT_BITCLEAR(CEN + PE);	/* Cent` enabled, PE ok, on line, ERR ok   */
    CENT_BITSET(OL + ERR);

#else		/* SWIFT */

    CFR_SET_ROM_WAIT(2);
    PATERN_SET(DMA1_TC | DMA_DIP, DMA_IMASK);	/* enable TC int` level 14 */
    ADCA_CH1 = (unsigned long) recieved_data;   /* cent & dest` addr counter */
    BLTC_CH1 = (MAX_CENT_BUF << 1);		/* block size = 1 byte     */
    MODE_CH1 = 0x0280;				/* mode:
						 * non auto initialize
						 * FBY = fby
						 * DIR = peripherial is source
						 * (but due to reverse logic
						 * DIR bit must be 0 and not 1)
						 * source bus width = 8 bits.
						 * dest` bus width is forced
						 * to look like 16 bits.
						 * addr` non incremented.  */

     CENT_BITSET(DMSRC + OL + ERR); /* DMA serves CENT`, on line, ERR ok   */

#endif		/* SWIFT */

    _interrupt_enable();			/* enable interupt	   */
    PATERN_SET(DMA_CHEN, CTL_CH1);		/* enable DMA		   */
    DELAY(5700);
}

/*****************************************************************
 *
 *  cent_disable()
 *
 ****************************************************************/

private void cent_disable()
{
    CENT_BITCLEAR(OL);				/* off line         */
#if (BOARD == VECTOR)
    CENT_BITSET(CEN);				/* disable CENT`    */
#endif
    PATERN_CLEAR(DMA_CHEN, CTL_CH1);		/* disable DMA      */
}

/***************************************************************
 *
 *  int_dma()
 *
 *  For SWIFT a dummy read must be made every cycle because the 
 *  centronics is only one byte long and the DMA bus is two bytes 
 *  long. This way the odd byte has to be read to release
 *  the DMA for the next cycle.
 *
 *  In memory to memory mode (VECTOR),the transference of 6 charecters (a block
 *  of 6 bytes) causes an interrupt to the cpu.
 *  In FLY-BY mode (SWIFT) 6 transfers of one charecter accure each
 *  causing an interrupt to the cpu.
 *
 **************************************************************/

byte recieved_buffer[BUFSIZE];
int counter__;

void int_dma()
{
    PATERN_CLEAR(DMA_CHEN, CTL_CH1);		/* disable DMA		*/
    PATERN_SET(DMA1_TC, DMA_STAT);		/* clear TC		*/
    data_arrived = TRUE;
#if (BOARD == CG160LX)
    recieved_buffer[counter__++] = recieved_data[0];
    ADCA_CH1 = (unsigned long) recieved_data;
    BLTC_CH1 = (MAX_CENT_BUF << 1);		/* block size = 1 byte	*/
    PATERN_SET(DMA_CHEN, CTL_CH1);		/* enable DMA		*/
#endif
    DELAY(370);
}

    

/***************************************************************
 *
 *  check_buffer()
 *
 *  This function compares the string recieved from the PC to a reference.
 *
 **************************************************************/

#define REF_MSG "0@ABDH"
char ref_buffer[BUFSIZE];

private char *check_buffer()
{
     int i;

     strcpy(ref_buffer, REF_MSG);
     for(i = 0; ref_buffer[i] != '\0'; i++) {

#if (BOARD == VECTOR)
	if (ref_buffer[i] != recieved_data[i]) {
	    strcpy(error, "FAILURE: EXPECTED: 0@ABDH, RECEIVED: ");
	    recieved_data[BUFSIZE - 1] = '\0'; /* Ensure End of String */
	    strcat(error, &recieved_data[0]);
	    return error;
	}
#else		/* SWIFT */
	if (ref_buffer[i] != recieved_buffer[i]) {
	    strcpy(error, "FAILURE: EXPECTED: 0@ABDH, RECEIVED: ");
	    recieved_buffer[BUFSIZE - 1] = '\0';/* Ensure End of String */
	    strcat(error, &recieved_buffer[0]);
	    return error;
	}
#endif		/* SWIFT VECTOR */
    }
    return NULL;
}



/***************************************************************
 *
 *  test_centronics__()
 *
 *  This is the main test procedure. A time out accures if no carecters 
 *  arrive from the PC at given time.
 *
 **************************************************************/

public char *test_centronics__()
{
volatile int i = 0;
    cent_init();
    counter__ = 0;
    data_arrived = FALSE;
    print_str("Type on PC : 'echo 0@ABDH > prn:'");
    while (NOT data_arrived) {
        i++;
        if (i > 800) {
	    cent_disable();
	    strcpy(error, "FAILURE: TIMEOUT, NO DATA RECEIVED");
	    return error;
        }
	DELAY(28000);			/* give the user a chance to reply */
    }
    DELAY(10000);			/* let the string transfer finish  */
    cent_disable();
    return check_buffer();
}
