#include "gpib.h"
#include "globals.h"
#include "flash.h"
#include "error_utils.h"
#include "bus.h"


/* TNT Configuration --------------------------------------------------------*/

/* I/O */

#define max_gpib_input_length 512

#define READ_EOS_BYTE  0x00				/* EOS byte for reads/inputs/receives*/
#define WRITE_EOS_BYTE 0x00				/* EOS byte for writes/outputs/sends */
#define USE_EIGHT_BIT_EOS_COMPARE	NO	/* Compare EOS byte 7 or 8 bits */
#define USE_TRANSMIT_EOI_WITH_EOS	NO	/* Send EOI with EOS byte (writes) */
#define USE_HIGH_SPEED_T1	NO			/* Short T1 delay while doing three wire handshaking */


/* Miscellaneous Handlers */
#define USE_SPOLL_BIT	NO				/* STBO (SPOLL) - Serial Poll */

/* TNT Hardware Parameters */
#define TNT_BASE_ADDRESS	0x4100		/* Board Base I/O address */


/* TNT Constants ------------------------------------------------------------*/

#define	YES		1
#define	ENABLE	1
#define	SET		1
#define	NO		0
#define	NONE	0
#define	DISABLE	0
#define	CLEAR	0
#define	INPUT	4
#define	INPUT_BYTE	16
#define	OUTPUT	2
#define	INTERFACE	1

/* Interface Status Constants */
#define ERR		(1<<15)
#define TIMO	(1<<14)
#define END		(1<<13)
#define EOS		(1<<12)
#define RQS		(1<<11)
#define IFC		(1<<10)
#define SPOLL	(1<<9)
#define UCMPL	(1<<8)
#define LOK		(1<<7)
#define REM		(1<<6)
#define ASYNC	(1<<5)
#define DTAS	(1<<4)
#define DCAS	(1<<3)
#define LACS	(1<<2)
#define TACS	(1<<1)
#define NACS	(1<<0)
#define SYNC	0
#define NONE	0
#define EOI		END


/* Error Codes */
#define ENOL 1
#define EARG 2
#define EABO 3


/* 488.2 Status Registers */
#define STB 0
#define SRE 1
#define ESE 2
#define ESR 3
#define IST 4


/****************************************************************************
 *
 * Define TNT register map and TL related bits and functions
 *
 * FORMAT:
 *		register		 address
 *				B_bits			value
 *				F_function	  value	  (F_field)
 *
 ****************************************************************************/

/* Interrupt Mask and Status Registers */

#define	R_imr0	0x1d
#define	B_glint	(1<<7)

#define	R_isr0	0x1d
#define	B_stbo	(1<<6)
#define	B_eos	(1<<4)
#define	B_ifc	(1<<3)
#define	B_to	(1<<1)

#define	R_imr1	0x02
#define	R_isr1	0x02
#define	B_det	(1<<5)
#define	B_end	(1<<4)
#define	B_dec	(1<<3)
#define	B_err	(1<<2)
#define	B_do	(1<<1)

#define	R_isr2	0x04
#define	B_int	(1<<7)
#define	B_lok	(1<<5)
#define	B_rem	(1<<4)

#define	R_isr3		0x1a
#define	B_x			(1<<7)
#define	B_intsrc2	(1<<6)
#define	B_nff		(1<<3)
#define	B_nef		(1<<2)
#define	B_done		(1<<0)

/* Serial Poll Status and Mode Registers */

#define	R_spsr	0x06
#define	B_pend	(1<<6)
#define	R_spmr	0x06

/* Address Mode, Status and Control Registers */

#define	R_adsr	0x08
#define	B_natn	(1<<6)
#define	B_spms	(1<<5)
#define	B_la	(1<<2)
#define	B_ta	(1<<1)

#define	R_admr	0x08

#define	F_noaddress		0x30
#define	F_normalprimary	0x31

#define	R_adr	0x0c
#define	B_ars	(1<<7)
#define	B_dt	(1<<6)
#define	B_dl	(1<<5)

/* Data Count Registers */

#define	R_cnt0	0x14
#define	R_cnt1	0x16
#define	R_cnt2	0x09
#define	R_cnt3	0x0b

/* Auxillary and Hidden Registers */
#define	R_auxmr	0x0a
#define	F_pon	0x00
#define	F_chrst	0x02
#define	F_rhdf	0x03
#define	F_ist0	0x01
#define	F_ist1	0x09
#define	F_lut	0x0b
#define	F_lul	0x0c
#define	F_reqt	0x18
#define	F_reqf	0x19
#define	F_hldi	0x51

/* Clear Interrupt Flags */
#define	F_clrEND	0x55
#define	F_clrDEC	0x56
#define	F_clrERR	0x57

/* Hidden Auxillary Registers */
#define	B_u	(1<<4)
#define	B_s	(1<<3)

#define	HR_auxra	0x80
#define	F_normal	0x00
#define	F_hlda		0x01
#define	F_hlde		0x02
#define	B_endoneos	(1<<2)|((USE_EIGHT_BIT_EOS_COMPARE)? (1<<4):0)

#if(!(USE_TRANSMIT_EOI_WITH_EOS))
#define	B_xeoiweos	(1<<3)|((USE_EIGHT_BIT_EOS_COMPARE)? (1<<4):0)
#else
#define	B_xeoiweos	0x00
#endif

#define	HR_auxrb	0xa0
#define	B_hst1		(1<<2)

#define	HR_auxre	0xc0
#define	B_dhdc		(1<<0)

#define	HR_auxri	0xe0
#define	B_ustd		(1<<3)

#define	HR_auxrj	0xf0

#define	R_hier		0x13
#define	B_dga		(1<<7)
#define	B_dgb		(1<<6)

#define	R_eosr		0x0e

#define	R_misc		0x15

#define	R_sts1		0x10
#define	B_halt		(1<<1)

#define	R_cfg		0x10
#define	B_in		(1<<5)
#define	B_ccen		(1<<3)
#define	B_tmoe		(1<<2)
#define	B_timbytn	(1<<1)
#define	B_16bit		(1<<0)
#define	B_8bit		(0)
#define	F_input_config	(B_in|B_tmoe|B_timbytn|B_ccen|B_8bit)
#define	F_output_config	(B_tmoe|B_timbytn|B_8bit)

#define	R_dsr		0x11

#define	R_hssel		0x0d
#define	B_go2sids	(1<<5)
#define	F_onechip	0x01

#define	R_keyrg		0x17

/* TNTs FIFOs */
#define	R_fifob		0x18

#define	R_sasr		0x1b

#define	R_cmdr		0x1c
#define	F_softreset	0x22
#define	F_resetfifo	0x10
#define	F_stop		0x08
#define	F_go		0x04

#define	R_bsr		0x1f

/* --------------------------------------------------------------------------*/


/* TNT4882 GLOBAL VARIABLES -------------------------------------------------*/

int INTERFACE_ERROR;				/* Error Code */
int INTERFACE_STATUS;				/* Interface Status */
unsigned int MR_4882_status[5];		/* 4882 status memory registers */

unsigned long int DATA_COUNT;		/* Transfer count */
unsigned long int Requested_Count;	/* Requested transfer count */
unsigned long int cnt;
int prev_brq;
int spoll_count;


static int TNT_INT_STATUS(void);
static void TNT_Adr_Mode();
static void TNT_Gen_Error(int code);
static void TNT_Setup_IO(int IO_type, unsigned long int cnt, int term);
static void TNT_DONE_Handler(int IO_type,unsigned long int *count_sent);
static unsigned long int TNT_DATA_COUNT();
static void TNT_Out(int reg, unsigned int byte);
static unsigned char TNT_In(int reg);
static int TNT_input_bav(void);
static int TNT_update_brq(void);
static void TNT_RFD_Holdoff();
static void TNT_Holdoff_off();


void TNT_4882_Status(int status_register,unsigned int byte,int operation)
{
	int set_srq;

	MR_4882_status[STB] = TNT_In(R_spsr);	/* Get STB */

	switch (operation) {
	case SET:
		/* Cannot set SRQ directly */
		if((status_register==STB)||(status_register==SRE)) {
			byte&=~0x40;
		}

		MR_4882_status[status_register]|= byte;/* OR in new register value */

		if(status_register==IST) {
			TNT_Out(R_auxmr,F_ist1);    /* if IST set IST bit */
		}

		break;

	case CLEAR:
		MR_4882_status[status_register]&=~byte;	/* ~AND requested bits */
		if(status_register==IST) {
			TNT_Out(R_auxmr,F_ist0);    /* if IST clear IST bit */
		}
		break;

	default:
		TNT_Gen_Error(EARG);					/* Neither SET/CLEAR then EARG */
		break;
	}
	/* If ESE&ESR set ESB bit */
	MR_4882_status[STB]|=(MR_4882_status[ESE]&MR_4882_status[ESR])? 0x20 : 0;

	/* If STB&SRE set RQS bit */
	set_srq = (MR_4882_status[STB]&MR_4882_status[SRE])? TRUE : FALSE;

	if(set_srq) {									/* If SRQ desired */
		TNT_Out(R_auxmr,F_reqt);    /* Set request true */
	} else {										/* Else */
		TNT_Out(R_auxmr,F_reqf);    /* Set request false */
	}

	TNT_Out(R_spmr,MR_4882_status[STB]);			/* Set new serial poll byte */
}


/****************************************************************************
 *
 *  TNT_INT_STATUS(): Used to update INTERFACE_STATUS word by reading
 *									  R_isr0,R_isr1,R_isr2,R_isr3,R_adsr,R_spmr and
 *									  updating the appropriate INTERFACE_STATUS bits.
 *
 *  INTERFACE_STATUS bits:
 *
 *	 ERR  (1<<15)	Error				- Check INTERFACE_ERROR for error
 *	 TIMO (1<<14)	Timeout				- If timeouts are used
 *	 END  (1<<13)	End/EOI/EOS			- End of transmition received
 *	 EOS  (1<<12)	End of String		- End of string received
 *	 RQS  (1<<11)	Requesting Service	- TNT asserting SRQ line
 *	 IFC  (1<<10)	Interface Clear		- Interface Clear Asserted
 *	 SPOLL (1<<9)	Serial Poll Active	- Serial Poll Byte STB is requested
 *	 UCMPL (1<<8)	User Complete		- User I/O function terminated
 *
 *	 LOK	(1<<7)	Local Lockout		- Lockout front panel controls
 *	 REM	(1<<6)	Remote Programming	- TNT in remote programming state
 *	 ASYNC (1<<5)	Asyncronous I/O		- NOT USED IN NON-INT ESP
 *	 DTAS  (1<<4)	Trigger Active State - Requested Device Trigger
 *	 DCAS  (1<<3)	Clear Active State	- Requested Device Clear
 *	 LACS  (1<<2)	Listener Active		- TNT listen addressed
 *	 TACS  (1<<1)	Talker Active		- TNT talk addressed
 *	 NACS  (1<<0)	Not Active State	- TNT not addressed
 *
 *
 ****************************************************************************/

/*----------------------------------------------------------------------------------------------------------*/
static int TNT_INT_STATUS(void)
{
	int mr_isr0,mr_isr1,mr_isr2,mr_spsr,mr_adsr;

	mr_isr1=TNT_In(R_isr1);		/* Read status register isr1 */
	mr_isr2=TNT_In(R_isr2);		/* Read status register isr2 */
	mr_isr0=TNT_In(R_isr0);		/* Read status register isr0 */
	mr_spsr=TNT_In(R_spsr);		/* Read status register spsr */
	mr_adsr=TNT_In(R_adsr);		/* Read status register adsr */

	INTERFACE_STATUS&=(UCMPL|END|EOS|TIMO|ERR);	/* Maintain I/O bits */
	/* These are cleared at the */
	/*	beginning of a new I/O call */

	/* Get new status */
	INTERFACE_STATUS|=((mr_isr0&B_to)  ?TIMO :0)|((mr_isr2&B_rem) ?REM :0)
	                  |((mr_isr1&B_end) ?END  :0)|((mr_isr0&B_eos) ?EOS :0)
	                  |((mr_spsr&B_pend)?RQS  :0)|((mr_isr0&B_ifc) ?IFC :0)
	                  |((mr_isr0&B_stbo)?SPOLL:0)|((mr_isr2&B_lok) ?LOK :0)
	                  |((mr_isr1&B_det) ?DTAS :0)|((mr_isr1&B_dec) ?DCAS:0)
	                  |((mr_adsr&B_ta)  ?TACS :0)|((mr_adsr&B_la)  ?LACS:0);

	INTERFACE_STATUS|=((INTERFACE_STATUS&(LACS|TACS)) ? 0:NACS);

	return INTERFACE_STATUS;					/* Return status */
}


/****************************************************************************
 *
 *  TNT_Gen_Error():  Used to Update INTERFACE_ERROR. INTERFACE_ERROR is
 *							only valid when ERR is set in INTERFACE_STATUS.
 *
 *  INTERFACE_ERROR values:
 *
 *	 xxxx  0  - No Error
 *	 ENOL  1  - No Listeners I/O aborted because no listeners on bus.
 *	 EARG  2  - Bad Argument in parameter list.
 *	 EABO  3  - I/O Aborted due to timeout.
 *
 *  Related Functions: None
 *
 *  Valid Parameters:  code = 1,2..7
 *
 *  Note:				  This is a system function.
 *
 ****************************************************************************/

/*----------------------------------------------------------------------------------------------------------*/
static void TNT_Gen_Error(int code)
{
	INTERFACE_STATUS|=ERR;	/* Set error bit & enter code */
	INTERFACE_ERROR=code;	/* Set error code */
}


/**************************** INITIALIZATION ********************************
 *
 *  GPIB_initialize(): Sets the TNT into a known initialized state,
 *						clears global values (mask registers,status words),
 *						and loads current addressing setup.
 *
 *						Normally, this function is executed once at power
 *						up, however it may be used to reinitialize the
 *						interface during operation.
 *
 ****************************************************************************/

/*----------------------------------------------------------------------------------------------------------*/
void GPIB_initialize(void)
{
	int i;

	for(i=0; i<5; ++i) {
		MR_4882_status[i]=0;    /* do this because these variable are 2-byte integers */
	}
	/* but Nat Inst code assumes they are one-byte */

	INTERFACE_STATUS=0;						/* Initialize Globals to zero */
	INTERFACE_ERROR=0;
	DATA_COUNT=0;
	Requested_Count=0;

	TNT_Out(R_cmdr,F_softreset);			/* Reset FIFOS */

	TNT_Out(R_spmr ,0x80);					/* This sequence of commands */
	TNT_Out(R_auxmr,0x80);					/*	insures that the TNT */
	TNT_Out(R_auxmr,0x99);					/*	will be in the normal 7210 */
	TNT_Out(R_keyrg,0);						/*	mode and not 9914 */

	TNT_Out(R_hssel,F_onechip);				/* Set TNT to one chip WINK mode */
	TNT_Out(R_misc,0);						/* Disable HS mode */
	TNT_Out(R_hier,B_dga|B_dgb);			/* Set deglitching circuits to */

	TNT_Out(R_auxmr,F_chrst);				/* Reset TNT */

	TNT_4882_Status(STB,0xff,CLEAR);		/* Initialize Serial Poll Byte */
	TNT_4882_Status(SRE,0xff,CLEAR);		/* Initialize SRE memory register */
	TNT_4882_Status(ESR,0xff,CLEAR);		/* Initialize ESR memory register */
	TNT_4882_Status(ESR,0x80,SET);			/* Indicate power on */
	TNT_4882_Status(ESE,0xff,CLEAR);		/* Initialize ESE memory register */

	TNT_Adr_Mode();
	GPIB_change_address(globals.Flash.gpib_address);
	/* Set auxri for non-static bits and */
	/*	possibly ultra short t1 delay*/
	TNT_Out(R_auxmr,HR_auxri|((USE_HIGH_SPEED_T1)? B_ustd : 0));

	/* If not using HS488 set only hst1*/
	TNT_Out(R_auxmr,HR_auxrb|((USE_HIGH_SPEED_T1)? B_hst1 : 0));

	TNT_Out(R_auxmr,F_hldi);				/* Issue hold off immediately */
	TNT_Out(R_auxmr,F_pon);					/* Clear Power On */

	TNT_Out(R_imr0,B_glint);				/* Enable setting of tlcint */
}


static void TNT_Adr_Mode()
{
	TNT_Out(R_admr,F_noaddress);		/* Clear address mode */
	TNT_Out(R_adr,B_dt|B_dl);			/* Disable talk & listener */
	TNT_Out(R_adr,B_ars|B_dt|B_dl);		/* capabilities */
	TNT_Out(R_auxmr,F_lut);				/* Untalk TNT4882 */
	TNT_Out(R_auxmr,F_lul);				/* Unlisten TNT4882 */
	TNT_Out(R_admr,F_normalprimary);	/* Set single primary address mode*/
}


void GPIB_change_address(int new_address)
{
	int eprom_loc;

	TNT_Out(R_adr,new_address);		/* Load new address setting */

	globals.Flash.gpib_address=new_address;
	eprom_loc = (char *) &(globals.Flash.gpib_address) - (char *) &(globals.Flash.flash_start);
	writeUserBlock(&globals.Flash, eprom_loc, sizeof(globals.Flash.gpib_address));
}


static void TNT_Setup_IO(int IO_type, unsigned long int cnt, int term)
{
	unsigned long int twos_cnt;				/* Obtain the twos compliment cnt */

	twos_cnt=-cnt;

	Requested_Count=cnt;					/* Save requested transfer cnt */

	TNT_Out(R_cmdr,F_resetfifo);			/* Reset TNT fifos */

	TNT_Out(R_cnt0, (char)(twos_cnt));		/* Load twos compliment count */
	TNT_Out(R_cnt1, (char)(twos_cnt>>8));	/*  into TNT count registers */
	TNT_Out(R_cnt2, (char)(twos_cnt>>16));
	TNT_Out(R_cnt3, (char)(twos_cnt>>24));

	TNT_Out(R_imr0,B_glint);				/* Set write to imr0 to be sure */
	TNT_Out(R_auxmr,HR_auxrj|0);			/* B_to is cleared */

	switch(IO_type) {

	case INPUT_BYTE:
		TNT_Out(R_imr1, B_end);	  		/* End transfer on eoi or eos */

		TNT_Out(R_eosr, READ_EOS_BYTE);	/* Set eos byte */
		TNT_Out(R_auxmr,HR_auxra|F_hlde|((term&EOS)?B_endoneos:0));
		/* Configure for byte input */
		TNT_Out(R_cfg , F_input_config&~B_16bit);
		/* Holdoff on end & enable eos */
		TNT_Out(R_auxmr,F_rhdf);		/* Release holdoff */
		TNT_Out(R_cmdr, F_go);			/* Start transfer state machine */
		break;

	case INPUT:
		TNT_Out(R_imr1, B_end);	  		/* End transfer on eoi or eos */
		TNT_Out(R_eosr, READ_EOS_BYTE);	/* Set eos byte */
		TNT_Out(R_auxmr,HR_auxra|F_hlde|((term&EOS)?B_endoneos:0));
		TNT_Out(R_cfg , F_input_config);	/* Configure for *byte* input */
		/* Holdoff on end & enable eos */
		TNT_Out(R_auxmr,F_rhdf);			/* Release holdoff */
		TNT_Out(R_cmdr, F_go);				/* Start transfer state machine */
		break;

	case OUTPUT:
		TNT_Out(R_imr1, B_err);	  			/* End transfer on err */
		TNT_Out(R_eosr, WRITE_EOS_BYTE);	/* Set EOS byte */
		/* Holdoff on all & enable EOS */
		TNT_Out(R_auxmr,HR_auxra|F_hlda|((term&EOS)?B_xeoiweos:0));
		/* Configure for *byte* output */
		TNT_Out(R_cfg , F_output_config|((term)?B_ccen:0));
		TNT_Out(R_auxmr,F_hldi);			/* Hold off immediately */
		TNT_Out(R_cmdr, F_go);				/* Start transfer state machine */
		break;

	default:
		TNT_Gen_Error(EARG);				/* If IO_type incorrect issue EARG*/
		break;
	}
}


static void TNT_DONE_Handler(int IO_type,unsigned long int *count_sent)
{
	TNT_Out(R_cmdr,F_stop);							/* Stop fifos */
	TNT_Out(R_cmdr,F_resetfifo);					/* Reset the fifos */

	if(TNT_In(R_isr1)&B_end) {					/* If we received an END */
		TNT_Out(R_auxmr,F_clrEND);    /*	Clear status bit */
	}

	if(TNT_In(R_isr1)&B_err) {
		TNT_Gen_Error(ENOL);						/* No listeners */
		TNT_Out(R_auxmr,F_clrERR);					/* Clear error bit */

		if(IO_type==OUTPUT) {
			TNT_Out(R_hssel,F_onechip|B_go2sids);	/* if error set to idle state. */
			TNT_Out(R_hssel,F_onechip);
		}
	}

	*count_sent = TNT_DATA_COUNT();					/* Obtain transfer count */
}


static unsigned long int TNT_DATA_COUNT()
{
	unsigned long int return_value;

	return_value=(unsigned long int) TNT_In(R_cnt0);
	return_value|=((unsigned long int) TNT_In(R_cnt1)) << 8;
	return_value|=((unsigned long int) TNT_In(R_cnt2)) << 16;
	return_value|=((unsigned long int) TNT_In(R_cnt3)) << 24;
	return_value+=(unsigned long int) Requested_Count;

	return( (unsigned long int) return_value );
}


static void TNT_Out(int reg, unsigned int byte)
{
	bus_writebyte ((uint8_t) (TNT_Port + reg), (uint8_t) byte);
}


static unsigned char TNT_In(int reg)
{
	return (unsigned char) bus_readbyte ((uint8_t) (TNT_Port + reg));
}


static int TNT_input_bav(void)
{
	/* is a byte available (bav) in the TNT4882 FIFOs? Used mostly for GPIB reads */
	return (int) TNT_In(R_isr3)&B_nef;
}


static int TNT_update_brq(void)
{
	/* is the GPIB requesting data from the TNT4882? */
	int state_SGNS;
	int state_TACS;

	state_TACS = (TNT_In(R_adsr)&B_ta) && (TNT_In(R_adsr)&B_natn) && !(TNT_In(R_adsr)&B_spms);
	state_SGNS = state_TACS && !(TNT_In(R_sasr)&0x02) && !(TNT_In(R_sasr)&0x01);

	/* the IEEE488.2 standard says that this signal should be set only for for
		each data request, so some memory is required to avoid generating multiple,
	    stateless brq messages. */

	if (!prev_brq) {	/* prev_brq=0 */
		prev_brq=state_SGNS;
		return state_SGNS;
	} else {
		prev_brq=state_SGNS;
		return 0;
	}
}


int GPIB_check_for_device_clear_signal(void)
{
	/* added by MJC - June 20/06 */
	/* reset interface if a device clear is received */

	if (TNT_INT_STATUS() & DCAS) {
		TNT_Out(R_auxmr,F_clrDEC);
		TNT_INT_STATUS();
		return TRUE;
	} else {
		return FALSE;
	}
}


int GPIB_check_for_messages(char *gpib_buf)
{
#define ib_empty  (!(strlen(gpib_buf)))

	/* If the GPIB has requested data, and no output messages are in the TNT4882 FIFOs, generate a query error */
	if (TNT_update_brq() && !TNT_input_bav() && ib_empty) {
		queue_error_for_gpib_only(query_error_unterminated);
	}

	/* If the TNT4882 is talk addressed, the controller must be still reading output data in the TNT4882
		FIFOs. Wait until this process has completed and the TNT4882 is listen addressed. */
	if ( (TNT_In(R_adsr)&B_ta) && (TNT_In(R_isr3)&B_nef) && !(TNT_In(R_cfg)&B_in)) {
		return OK;						/* exit if not listen addressed */
	}


	/* if no I/O is begin done, set up for input. Note that TLCHLTE must be set to zero, so that the */
	/* HALT signal is set only by the STOP and GO commands. */
	if (TNT_In(R_sts1)&B_halt) {
		cnt=max_gpib_input_length-8;
		gpib_buf[0]=0;
		INTERFACE_STATUS=0;
		TNT_Setup_IO(INPUT,cnt,EOI|EOS);
	}

	/* is data available to read? */
	return (TNT_In(R_isr3)&B_nef) && (TNT_In(R_cfg)&B_in);
}


int GPIB_handle_new_input(char *gpib_buf)
{
	/* read until done or buffers empty. Then reset DAC holdoff */

	unsigned long int count_sent;		/* Local count variable */
	int i;
	char *buffer_pos;

	buffer_pos = gpib_buf;

	count_sent=0;						/* Clear I/O status bits */
	DATA_COUNT=0;						/* Clear count global */

	/* read FIFOs until transaction completed or interrupted */
	while( 		!( INTERFACE_STATUS & DCAS)								/* device clear */
	                && !( !TNT_input_bav() && (INTERFACE_STATUS & END))		/* proper transaction end */
	                && !( !TNT_input_bav() && TNT_In(R_isr3)&B_done)		/* proper transaction end */
	                && !( !TNT_input_bav() && (INTERFACE_STATUS & TIMO))	/* improper timeout */
	                && !( !TNT_input_bav() && TNT_update_brq() && ib_empty)	/* brq message true, GPIB requesting data */
	     ) {

		/* choose the most efficient fifo-emptying method based on FIFO flags */
		switch(TNT_In(R_isr3)&(B_nff|B_intsrc2|B_nef)) {
		case (B_nef):
		case (B_nef|B_intsrc2):
			for(i=0; i<15; i++) {
				*(buffer_pos++)=TNT_In(R_fifob);
			}
			break;

		case (B_nff|B_intsrc2|B_nef):
			for(i=0; i<8; i++) {
				*(buffer_pos++)=TNT_In(R_fifob);
			}
			break;

		case (B_nff|B_nef):
			*(buffer_pos++)=TNT_In(R_fifob);
			break;
		}

		TNT_INT_STATUS();						/* Update to get current status */

	}

	TNT_DONE_Handler(INPUT,&count_sent);		/* Finish up and get count */
	DATA_COUNT+=count_sent;						/* Update total transfer count */
	cnt-=count_sent;							/* Update total requested count */
	buffer_pos=buffer_pos+((int) count_sent);		/* Update buffer pointer */


	INTERFACE_STATUS|=UCMPL;					/* Set the user complete bit */

	if (GPIB_check_for_device_clear_signal()) {
		return FALSE;			/* abandon if SDC, DCL */
	}

	if (TNT_update_brq() && !TNT_input_bav() && ib_empty)
		/* abandon if brq with no commands to process */
	{
		queue_error_for_gpib_only(query_error_unterminated);
		prev_brq=1;			/* reset brq */
		TNT_update_brq();	/* update it so that it doesn't get confused in idle state */
		return FALSE;
	}

	gpib_buf[(int) DATA_COUNT]=0;
	return TRUE;
}


static void TNT_RFD_Holdoff()
{
	/* holdoff accepting data until software has checked the state of the TNT4882 */
	TNT_Out(R_auxmr,F_hldi);	/* set immediate RFD holdoff */
}


static void TNT_Holdoff_off()
{
	TNT_Out(R_auxmr,F_rhdf);	/* cancel immediate RFD holdoff */
}


int GPIB_send_query_response(char *out_buffer)
{
	/* message must be available if this function has been called */

	unsigned long int out_cnt;
	unsigned long int count_sent;				/* Local count variable */
	int i;

	out_cnt = strlen (out_buffer);

	TNT_4882_Status(STB,0x10,SET);		 		/*  Set MAV bit */

	TNT_INT_STATUS();

	/* if the TNT4882 isn't talk addressed, wait until it is, or until the GPIB sends a clear signal,
		or until the GPIB writes more data to the TNT4882, generating a query error. */
	while (!(INTERFACE_STATUS&TACS)) {
		TNT_RFD_Holdoff();
		if (INTERFACE_STATUS&DCAS) {
			/* device has been cleared. return to idle state */
			TNT_4882_Status(STB,0x10,CLEAR);	/* Clear MAV bit */
			TNT_Holdoff_off();

			/* added by MJC - June 20/06 */
			/* reset interface if a device clear is received */
			TNT_Out(R_auxmr,F_clrDEC);
			TNT_INT_STATUS();

			return OK;
		} else if (!TNT_input_bav()) {
			/* if no bytes are available, we're still waiting for the GPIB to request data. Repeat loop. */
			TNT_Setup_IO(INPUT,out_cnt,EOI|EOS);
			TNT_INT_STATUS();
			TNT_Holdoff_off();
		} else {
			/* abandon if input bytes available, and generate query error */
			TNT_Holdoff_off();
			queue_error_for_gpib_only(query_error_interrupted);
			TNT_4882_Status(STB,0x10,CLEAR);	/* Clear MAV bit */
			prev_brq=1;							/* reset brq */
			TNT_update_brq();					/* update it so that it doesn't get confused in idle state */
			return OK;
		}
	}

	TNT_Setup_IO(OUTPUT,out_cnt,EOI|EOS);

	count_sent=0;
	INTERFACE_STATUS=0;		/* Clear I/O status bits */
	DATA_COUNT=0;			/* Clear count global */

	if(out_cnt==0) {
		INTERFACE_STATUS|=UCMPL;
		return OK;
	}

	/* send data until completed or interrupted */
	while( 		!(INTERFACE_STATUS&(DCAS|TIMO|END|ERR|LACS))
	                && !(TNT_In(R_isr3)&B_done)
	     ) {

		/* choose the most efficient fifo-filling method based on flags */
		switch(TNT_In(R_isr3)&(B_nff|B_intsrc2|B_nef)) {
		case (B_nff):
		case (B_nff|B_intsrc2):			/* 16 words in fifo are empty */
			for(i=0; i<16; i++) {
				TNT_Out(R_fifob,*((char  *)(out_buffer++)));
			}
			break;

		case (B_nff|B_intsrc2|B_nef):	/* 8 words in fifo are empty */
			for(i=0; i<8; i++) {
				TNT_Out(R_fifob,*((char  *)(out_buffer++)));
			}
			break;

		case (B_nff|B_nef):				/* 1 word in fifo is empty */
			TNT_Out(R_fifob,*((char  *)(out_buffer++)));
			break;
		}

		TNT_INT_STATUS();					/* Get current status */
	}

	TNT_DONE_Handler(OUTPUT,&count_sent);		/* Finish up and get count */
	DATA_COUNT+=count_sent;						/* Update total transfer count */
	out_cnt-=count_sent;						/* Update total requested count */
	out_buffer=out_buffer+((int) count_sent);	/* Update buffer pointer */

	INTERFACE_STATUS|=UCMPL;					/* Set the user complete bit */

	if (INTERFACE_STATUS&DCAS) {
		TNT_4882_Status(STB,0x10,CLEAR);		/* Clear MAV bit */

		/* added by MJC - June 20/06 */
		/* reset interface if a device clear is received */
		TNT_Out(R_auxmr,F_clrDEC);
		TNT_INT_STATUS();

		return OK;								/* abandon if SDC or DCL */
	}

	if ((INTERFACE_STATUS&LACS) && (TNT_In(R_isr3)&B_nef)) {
		/* abandon gracefully if listen-addressed with data in buffer */
		queue_error_for_gpib_only(query_error_interrupted);
		TNT_4882_Status(STB,0x10,CLEAR);		/* Clear MAV bit */
		prev_brq=1;								/* reset brq */
		TNT_update_brq();						/* update it so that it doesn't get confused in idle state */
		TNT_Setup_IO(INPUT,cnt,EOI|EOS);
		return OK;
	}

	if(DATA_COUNT>0) {
		TNT_4882_Status(STB,0x10,CLEAR);		/* Clear MAV bit */
		prev_brq=1;								/* brq was active during send */
		TNT_update_brq();						/* update it so that it doesn't get confused in idle state */
	}

	return OK;
}


void GPIB_check_remote_status (int *is_remote, int *is_lockout)
{
	*is_remote = *is_lockout = 0;

	TNT_INT_STATUS();					/* Update to get current status */
	if ((INTERFACE_STATUS&REM) == REM) {
		*is_remote = 1;
	}
	if ((INTERFACE_STATUS&LOK) == LOK) {
		*is_lockout = 1;
	}

	return;
}


unsigned char GPIB_response_already_pending ()
{
	return TNT_In(R_spsr) & 0x10;
}


void GPIB_go_to_local ()
{
	TNT_Out(R_auxmr,0x05);		/* issue TNT rtl command */
	return;
}


void GPIB_clear_events ()
{
	TNT_4882_Status(ESR,0xff,CLEAR);	/* Clear ESR register */
	TNT_4882_Status(STB,0x20,CLEAR);	/* Clear ESB bit in STB */
	return;
}


unsigned int GPIB_get_ESR ()
{
	return MR_4882_status[ESR];
}


unsigned int GPIB_get_SRE ()
{
	return MR_4882_status[SRE];
}


unsigned int GPIB_get_ESE ()
{
	return MR_4882_status[ESE];
}


unsigned int GPIB_get_STB ()
{
	return (TNT_In(R_spsr)&0xbf) | (((TNT_In(R_spsr)&0xbf) & MR_4882_status[SRE])?0x40:0);
}


void GPIB_set_ESR (unsigned int byte,int operation)
{
	TNT_4882_Status(ESR,byte,operation);
	return;
}


void GPIB_set_SRE (unsigned int byte,int operation)
{
	TNT_4882_Status(SRE,byte,operation);
	return;
}


void GPIB_set_ESE (unsigned int byte,int operation)
{
	TNT_4882_Status(ESE,byte,operation);
	return;
}


void GPIB_Set_Execution_Error ()
{
	TNT_4882_Status(3,0x10,1);
}


void GPIB_Set_Command_Error ()
{
	TNT_4882_Status(3,0x20,1);
}


void GPIB_Set_Query_Error ()
{
	TNT_4882_Status(3,0x04,1);
}


void GPIB_Set_Device_Dependent_Error ()
{
	TNT_4882_Status(3,0x08,1);
}