#include "gpib.h" #include "globals.h" #include "flash.h" #include "error_utils.h" #include "bus.h" #include /* 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; 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 globals.Remote.vxi_service_request = 1; TNT_Out(R_auxmr,F_reqt); // Set request true } 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 if ((TNT_In(R_sts2) & 0xB0) == 0x90) { globals.HWDetect.gpib = 1; } else { globals.HWDetect.gpib = 0; printf ("Error: TNT4882 chip not found\n"); return; } 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.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) { 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=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 (!globals.HWDetect.gpib) { return FALSE; } if (TNT_INT_STATUS() & DCAS) { TNT_Out(R_auxmr,F_clrDEC); TNT_4882_Status(STB,0x10,CLEAR); // Clear MAV bit g_free (globals.Registers.pending_output_message); globals.Registers.pending_output_message = NULL; TNT_Holdoff_off(); TNT_INT_STATUS(); return TRUE; } else { return FALSE; } } int GPIB_check_for_messages(char *gpib_buf) { #define ib_empty (!(strlen(gpib_buf))) if (!globals.HWDetect.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.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, char *in_string) { g_assert (ignore_this == NULL); g_assert (in_string != NULL); if (!globals.HWDetect.gpib) { return; } 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); TNT_4882_Status(STB,0x10,SET); // Set MAV bit } void GPIB_finish_query_response() { if (!globals.HWDetect.gpib) { return; } 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); 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 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); 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; } 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 } } } void GPIB_check_remote_status (int *is_remote, int *is_lockout) { *is_remote = *is_lockout = 0; if (!globals.HWDetect.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 () { if (!globals.HWDetect.gpib) { return; } TNT_Out(R_auxmr,0x05); // issue TNT rtl command return; } void GPIB_clear_events () { if (!globals.HWDetect.gpib) { return; } 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 () { if (!globals.HWDetect.gpib) { return 0; } 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) { if (!globals.HWDetect.gpib) { return; } TNT_4882_Status(ESR,byte,operation); } void GPIB_set_SRE (unsigned int byte,int operation) { if (!globals.HWDetect.gpib) { return; } TNT_4882_Status(SRE,byte,operation); } void GPIB_set_ESE (unsigned int byte,int operation) { if (!globals.HWDetect.gpib) { return; } TNT_4882_Status(ESE,byte,operation); } void GPIB_Set_Execution_Error () { if (!globals.HWDetect.gpib) { return; } TNT_4882_Status(ESR,0x10,1); } void GPIB_Set_Command_Error () { if (!globals.HWDetect.gpib) { return; } TNT_4882_Status(ESR,0x20,1); } void GPIB_Set_Query_Error () { if (!globals.HWDetect.gpib) { return; } TNT_4882_Status(ESR,0x04,1); } void GPIB_Set_Device_Dependent_Error () { if (!globals.HWDetect.gpib) { return; } TNT_4882_Status(ESR,0x08,1); }