#include "gpib.h"
#include "globals.h"
#include "flash.h"
#include "error_utils.h"
#include "bus.h"
#include "vxi11_server.h"
#include <glib.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 */


/* 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	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_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 R_sts2          0x1c

#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_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


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


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

int INTERFACE_ERROR;			/* Error Code */
int INTERFACE_STATUS;			/* Interface Status */
unsigned char 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;

	if (globals.HWDetect.has_gpib) {
		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
		if (globals.Remote.vxi_service_request == 0) {
			// don't fire interrupt every time status is checked
			vxi11_fireinterrupt();
			globals.Remote.vxi_service_request = 1;
		}
	} else {
		globals.Remote.vxi_service_request = 0;
		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;
}


/****************************************************************************
 *
 *  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)
{
	INTERFACE_STATUS=0;		/* Initialize Globals to zero */
	INTERFACE_ERROR=0;
	DATA_COUNT=0;
	Requested_Count=0;

	// test to detect TNT chip
	globals.HWDetect.has_gpib = 1;
	if ((TNT_In(R_sts2) & 0xB0) != 0x90) {
		globals.HWDetect.has_gpib = 0;
		printf ("Error: TNT4882 chip not found\n");
		return;
	} else {
		printf ("OK: TNT4882 chip found\n");
	}

	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)
{
	if (!globals.HWDetect.has_gpib) {
		return;
	}

	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)
{
	if (!globals.HWDetect.has_gpib) {
		return;
	}

	bus_writebyte ((uint8_t) (TNT_Port + reg), (uint8_t) byte);
}


static unsigned char TNT_In(int reg)
{
	if (!globals.HWDetect.has_gpib) {
		return (unsigned char) 0;
	}

	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=state_SGNS;
		return state_SGNS;
	} else {
		prev_brq=state_SGNS;
		return 0;
	}
}


int GPIB_check_for_device_clear_signal(void)
{
	/* reset interface if a device clear is received */

	if (!globals.HWDetect.has_gpib) {
		return FALSE;
	}

	if (TNT_INT_STATUS() & DCAS) {
		GPIB_and_VXI_device_clear();
		return TRUE;
	} else {
		return FALSE;
	}
}


void GPIB_and_VXI_device_clear(void)
{
	TNT_Out(R_auxmr,F_clrDEC);
	GPIB_and_VXI_clear_MAV();

	g_free (globals.Registers.pending_output_message);
	globals.Registers.pending_output_message = NULL;

	TNT_Holdoff_off();
	TNT_INT_STATUS();
}


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

	if (!globals.HWDetect.has_gpib) {
		return FALSE;
	}

	// 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)) {
		// exit if not listen addressed
		return OK;
	}

	// 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)
{
	if (!globals.HWDetect.has_gpib) {
		return FALSE;
	}

	// 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
}


void GPIB_and_VXI_start_query_response(gpointer ignore_this, gchar *in_string)
{
	g_assert (ignore_this == NULL);
	g_assert (in_string != NULL);

	if (globals.Registers.pending_output_message != NULL) {
		queue_error_for_gpib_only(query_error_interrupted);
		g_free (globals.Registers.pending_output_message);
		globals.Registers.pending_output_message = NULL;
	}

	globals.Registers.pending_output_message = g_strdup_printf ("%s\n", in_string);
	GPIB_and_VXI_set_MAV();
}


void GPIB_finish_query_response()
{
	if (globals.Registers.pending_output_message == NULL) {
		return;
	}

	// just a pointer
	char *out_buffer = globals.Registers.pending_output_message;
	int i;
	unsigned long int out_cnt = strlen (out_buffer);
	unsigned long int count_sent;		// Local count variable

	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.

	if (!(INTERFACE_STATUS&TACS)) {
		TNT_RFD_Holdoff();
		if (GPIB_check_for_device_clear_signal()) {
			return;

		} 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();
			return;

		} else {
			// abandon if input bytes available, and generate query error
			TNT_Holdoff_off();
			queue_error_for_gpib_only(query_error_interrupted);
			GPIB_and_VXI_clear_MAV();
			prev_brq=1;				// reset brq
			TNT_update_brq();			// update it so that it doesn't get
			return;					// confused in idle state
		}
	} else {
		// We are talk-addressed. Send some data.

		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;
		}

		// 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

		g_free (globals.Registers.pending_output_message);
		globals.Registers.pending_output_message = NULL;

		if (GPIB_check_for_device_clear_signal()) {
			return;
		}

		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);
			GPIB_and_VXI_clear_MAV();
			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;
		}

		if(DATA_COUNT>0) {
			GPIB_and_VXI_clear_MAV();
			prev_brq=1;				// brq was active during send */
			TNT_update_brq();			// update it so that it doesn't get
			// confused in idle state
		}
	}
}


void GPIB_check_remote_status (int *is_remote, int *is_lockout)
{
	*is_remote = *is_lockout = 0;
	if (!globals.HWDetect.has_gpib) {
		return;
	}

	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;
}


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_and_VXI_get_STB ()
{
//	return (TNT_In(R_spsr)&0xbf) | (((TNT_In(R_spsr)&0xbf) & MR_4882_status[SRE])?0x40:0);
	return (MR_4882_status[STB]&0xbf) | (((MR_4882_status[STB]&0xbf) & MR_4882_status[SRE])?0x40:0);
}


void GPIB_and_VXI_set_MAV()
{
	TNT_4882_Status(STB,0x10,SET);
}


void GPIB_and_VXI_clear_MAV()
{
	TNT_4882_Status(STB,0x10,CLEAR);
}


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


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


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


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


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


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


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