home *** CD-ROM | disk | FTP | other *** search
- page ,132
- title GPIB - GPIB Service Routines
-
- ;* General Purpose Interface Bus Service Routines.
- ;
- ; Copyright 1990, Sydex. All rights reserved.
- ;
- ; These are simple 'C'-callable routines which, with the proper
- ; cable, can drive most GPIB/HPIB/IEEE-488 devices. Consult the
- ; accompanying documentation for specific licensing rights and
- ; descriptive information.
- ;
-
- .model small,c
-
- .data
-
- BasePort dw 0 ; base port of parallel adapter
- Talker db 0 ; talker address to use
- Start_Time dw 0 ; time we started
- Tick_Time dw 0 ; ticks to wait
-
- .code
-
- ; I/O port offsets from base for parallel printer adapter.
-
- po_data equ 0 ; data
- po_ctl equ 2 ; control
- po_sts equ 1 ; status
-
- ; Control bits (output to pctl)
-
- O_Input equ 020h ; Input bit
- O_DAV equ 001h ; Data Available
- O_ATN equ 002h ; Attention
- O_RFD equ 004h ; Ready for Data (note inversion)
- O_NDAC equ 008h ; Not data accepted
-
- ; Input status bits (input from psts)
-
- I_NIFC equ 040h ; not interface clear
- I_NREN equ 020h ; not remote enable
- I_NEOI equ 010h ; not EOI
- I_NSRQ equ 008h ; not Service request
-
- ; Specialized commands (pdata)
-
- M_LIS equ 020h ; Listen
- M_UNL equ 03fh ; Unlisten
- M_TAL equ 040h ; Talk
- M_UNT equ 05fh ; Untalk
- M_SPE equ 018h ; Serial Poll Enable
- M_SPD equ 019h ; Serial Poll Disable
- M_DCL equ 014h ; Universal clear
-
- subttl GPIB Service Routines
- page
-
- ;* GPIB_Init - Initialize GPIB
- ;
- ; int GPIB_Init( int io_port, int our_address)
- ;
- ; Initialize GPIB interface. "io_port" is the base port of the
- ; printer adapter used. "our_address" is the address that we
- ; use as the controller/talker.
- ;
- ; On exit, returns 0 if okay, -1 if error.
- ;
-
- GPIB_Init proc ioport:word, us:word
- mov al,byte ptr (us)
- mov Talker,al ; save the talker address
- mov dx,ioport ; get the port
- mov BasePort,dx ; save it
- mov al,not 0 ; set data to null
- out dx,al
-
- add dx,po_ctl ; to control port
- mov al,O_NDAC+O_Input ; known state
- out dx,al ; set it up
-
- mov ah,M_DCL
- call SendAddr ; send DCL out--use whatever status
- call ReduceStatus
- ret ; exit...
- GPIB_Init endp
-
- ;* GPIB_Send - Send a character.
- ;
- ; int GPIB_Send( int listen, char what)
- ;
- ; The target device has address "listen"; "what" is sent.
- ;
- ; On exit, returns 0 if okay, -1 if error.
- ;
-
- GPIB_Send proc listen:word, what:byte
- mov ah,M_UNL
- call SendAddr ; send an unlisten
- jc GPSend2 ; if error
- mov ah,Talker
- or ah,M_TAL
- call SendAddr ; send ours as talker
- jc GPSend2 ; if error
- mov ah,byte ptr (listen)
- or ah,M_LIS ; make it a listen
- call SendAddr ; send address
- jc GPSend2 ; if error
- mov al,what
- call SendData ; send data
- jc GPSend2 ; if timeout
- mov ah,M_UNL
- call SendAddr ; send Unlisten
- GPSend2:
- call ReduceStatus
- ret
- GPIB_Send endp
-
-
- ;* GPPutStr - Send a string to a device.
- ;
- ; int GPIB_PutStr( int listen, char *string, int count)
- ;
- ; "count" bytes of "string" are output to the listener address
- ; "listen".
- ;
- ; On exit, returns 0 if okay, -1 if error.
- ;
-
- GPIB_PutStr proc uses si, listen:word, str:word, count:word
- mov ah,M_UNL
- call SendAddr ; send an unlisten
- jc GPPutStr4 ; if error
- mov ah,Talker
- or ah,M_TAL
- call SendAddr ; send ours as talker
- jc GPPutStr4 ; if error
- mov ah,byte ptr (listen) ; save address
- or ah,M_LIS ; make it a listen
- call SendAddr ; send address
- jc GPPutStr4 ; if error
- cld
- mov si,str
- mov cx,count
- jcxz GPPutStr3 ; if zero bytes
- GPPutStr2:
- lodsb ; get a byte
- mov ah,al
- call SendData ; send it
- jc GPPutStr4 ; if error
- loop GPPutStr2 ; keep going
- GPPutStr3:
- mov ah,M_UNL ; unlisten
- call SendAddr ; end the transmission
- GPPutStr4:
- call ReduceStatus
- ret ; exit...
- GPIB_PutStr endp
-
- ;* GPIB_Stat - Status - Return line status.
- ;
- ; Returns: IFC REN EOI SRQ NDAC NRFD ATN DAV
- ;
- ; int GPIB_Stat(void);
- ;
-
- GPIB_Stat proc
- mov dx,BasePort
- add dx,po_sts
- in al,dx ; get upper
- shl al,1
- and al,0f0h
- mov ah,al
- add dx,po_ctl-po_sts
- in al,dx ; get lower
- and al,0fh
- or al,ah
- xor al,11110100b ; invert the proper bits
- xor ah,ah
- ret
- GPIB_Stat endp
-
-
- ;* GPIB_Get - Get a character.
- ;
- ; int GPIB_Get( int listen)
- ;
- ; "listen" is target address.
- ;
- ; Returns character or -1 if timeout.
- ;
-
- GPIB_Get proc listen:word
- mov ah,M_UNL
- call SendAddr ; send unlisten
- jc GPGet2 ; if error
- mov ah,byte ptr (listen)
- or ah,M_TAL ; make it a talker
- call SendAddr ; send address
- jc GPGet2 ; if error
- mov ah,Talker
- or ah,M_LIS ; make us a listener
- call SendAddr
- jc GPGet2 ; if error
- call GetData ; send data
- jc GPGet2 ; if timeout
- push ax
- mov ah,M_UNT
- call SendAddr ; send Untalk
- pop ax
- xor ah,ah ; clear out upper bits
- ret
-
- GPGet2:
- mov ax,-1 ; say error
- ret
- GPIB_Get endp
-
-
- ;* GPIB_GetStr - Get a String.
- ;
- ; int GPIB_GetStr( int listen, char *buf)
- ;
- ; Returns count of bytes read or -1 if error.
- ;
-
- GPIB_GetStr proc uses di,listen:word, buf:word
- mov ah,M_UNL
- call SendAddr ; send unlisten
- jc GPGetStr4 ; if error
- mov ah,byte ptr (listen)
- or ah,M_TAL ; make it a talker
- call SendAddr ; send address
- jc GPGetStr4 ; if error
- mov ah,Talker
- or ah,M_LIS ; make us a listener
- call SendAddr
- jc GPGetStr4 ; if error
- mov di,buf
- cld
- GPGetStr2:
- call GetData ; send data
- jc GPGetStr4 ; if timeout
- jz GPGetStr3 ; if end of data
- stosb
- loop GPGetStr2 ; more data
- GPGetStr3:
- mov ah,M_UNT
- call SendAddr ; send Untalk
- mov ax,di
- sub ax,buf
- jmp short GPGetStr6 ; just exit with count
-
- GPGetStr4:
- mov ax,-1
- GPGetStr6:
- ret
- GPIB_GetStr endp
-
- ;* GPIB_SerPoll - Execute a serial poll.
- ;
- ; int GPIB_SerPoll( int listen)
- ;
- ; Returns serial poll status or -1 if error.
- ;
-
- GPIB_SerPoll proc listen:word
-
- mov ah,M_UNL
- call SendAddr ; send unlisten
- jc GPSerPoll2
- mov ah,byte ptr (listen)
- or ah,M_TAL
- call SendAddr ; send talk address
- jc GPSerPoll2
-
- mov ah,Talker
- or ah,M_LIS
- call SendAddr ; give us as listener
- jc GPSerPoll2
-
- mov ah,M_SPE
- call SendAddr
- jc GPSerPoll2 ; if error
- call GetData ; get data
- jc GPSerPoll2 ; if error
- push ax
- mov ah,M_UNT
- call SendAddr ; say untalk
- mov ah,M_SPD
- call SendAddr ; say serial poll disable
- pop ax
- xor ah,ah
- jmp GPSerPoll4
-
- GPSerPoll2:
- mov ax,-1
- GPSerPoll4:
- ret ; exit...
- GPIB_SerPoll endp
-
- ;* GPIB_PutAdd - Primitive - Put a byte in address mode.
- ;
- ; int GPIB_PutAdd( char what)
- ;
- ; returns 0 if success, -1 if error.
- ;
-
- GPIB_PutAdd proc what:word
- mov ah,byte ptr (what)
- call SendAddr
- call ReduceStatus
- ret ; exit...
- GPIB_PutAdd endp
-
-
- ;* GPIB_PutData - Primitive - Put a byte in data mode.
- ;
- ; int GPIB_PutData( char what)
- ;
- ; returns 0 if success, -1 if error.
- ;
-
- GPIB_PutData proc what:word
- mov ah,byte ptr (what)
- call SendData
- call ReduceStatus
- ret ; exit...
- GPIB_PutData endp
-
- ;* GPIB_GetData - Primitive - Get a byte of data.
- ;
- ; int GPIB_GetData();
- ;
- ; Returns data or -1 if error.
- ;
-
- GPIB_GetData proc near
- call GetData
- mov ah,0
- jnc GPGetData2
- mov ax,-1
- GPGetData2:
- ret
- GPIB_GetData endp
-
- subttl Utility Subroutines
- page
-
- ;* ReduceStatus - Reduce carry status to 0 or -1.
- ;
- ; Used by most of the routines.
- ;
-
- ReduceStatus proc near
- mov ax,0
- jnc ReduceStatus2
- mov ax,-1
- ReduceStatus2:
- ret
- ReduceStatus endp
-
- ;* StartTimer - Start a Countdown timer.
- ;
- ; On entry, (ax) = number of 55 msec ticks to wait on.
- ;
-
- StartTimer proc near
- mov Tick_Time,ax
- push dx
- push cx
- mov ah,0
- int 1ah ; get time of day
- mov Start_Time,dx
- pop cx
- pop dx
- ret
- StartTimer endp
-
- ;* TestTimer - Test the timer for expiration.
- ;
- ; carry is set upon expired time limit.
- ;
-
- TestTimer proc near
- push ax
- push dx
- push cx
- mov ah,0
- int 1ah ; time of day
- sub dx,Start_Time
- cmp dx,Tick_Time
- cmc
- pop cx
- pop dx
- pop ax
- ret
- TestTimer endp
-
- ;* SendAddr - Send Device address.
- ;
- ; On entry -
- ; (ah) = address
- ; On return -
- ; (carry) - timeout
- ;
-
- SendAddr proc near
- push bx
- push cx
- push dx
- push ax ; save registers
-
- ; Wait for device ready - a long wait.
-
- mov dx,BasePort
- add dx,po_ctl
- mov al,O_RFD
- out dx,al ; set attention+ready for data
- mov ax,20*18
- call StartTimer
- mov dx,BasePort
- add dx,po_ctl
- SendAddr2:
- in al,dx ; get status
- test al,O_RFD
- jnz SendAddr6 ; if RFD high
- call TestTimer
- jnb SendAddr2 ; keep trying...
-
- ; Timeout, set carry after going back to idle
-
- SendAddr4:
- mov dx,BasePort
- add dx,po_ctl
- mov al,O_Input+O_RFD
- out dx,al ; set not data accepted
- stc
- pop ax
- pop dx
- pop cx
- pop bx
- ret ; back to main routine
-
- ; Send the talk address.
-
- SendAddr6:
- mov al,O_RFD+O_ATN
- out dx,al ; assert ATN
- mov al,ah
- not al
- mov dx,BasePort ; for data
- out dx,al ; set the inverse of the data
- add dx,po_ctl
- mov al,O_DAV+O_RFD+O_ATN
- out dx,al ; say DAV
-
- ; Now, with DAV asserted, RFD should go low. If not, we have
- ; no devices connected.
-
- xor cx,cx
- SendAddr8:
- in al,dx ; wait for RFD low
- test al,O_RFD
- jz SendAddr9 ; if it did
- loop SendAddr8 ; keep trying
- jmp SendAddr4
-
- ; Wait for listener to release NDAC.
-
- SendAddr9:
- xor cx,cx
- SendAddr10:
- in al,dx ; get status
- test al,O_NDAC
- jz SendAddr12 ; if released
- loop SendAddr10 ; keep trying
- jmp SendAddr4 ; timeout
-
- ; Release DAV wait for RFD - may take a while.
-
- SendAddr12:
- mov al,O_RFD+O_Input
- out dx,al ; Return to input state
- mov ax,20*18
- call StartTimer
- mov dx,BasePort
- add dx,po_ctl
- SendAddr14:
- in al,dx
- test al,O_RFD
- jnz SendAddr16 ; if released
- call TestTimer
- jnb SendAddr14 ; loop for more
- jmp SendAddr4 ; timeout error
-
- SendAddr16:
- clc
- pop ax
- pop dx
- pop cx
- pop bx
- ret ; exit...
- SendAddr endp
-
-
- ;* SendData - Send Data.
- ;
- ; On entry (ah) = data byte
- ;
- ; On exit (carry) - timeout
- ;
-
- SendData proc near
- push bx
- push cx
- push dx
- push ax
-
- ; Wait for quiet and ready.
-
- mov dx,BasePort
- add dx,po_ctl
- mov al,O_RFD
- out dx,al ; set ready for data
- mov ax,18*20
- call StartTimer
- mov dx,BasePort
- add dx,po_ctl
- SendData2:
- in al,dx ; get status
- test al,O_RFD
- jnz SendData6 ; if RFD high
- call TestTimer
- jnb SendData2 ; loop if not timeout yet
-
- ; Timeout, set carry after going back to idle
-
- SendData4:
- mov dx,BasePort
- add dx,po_ctl
- mov al,O_Input+O_RFD
- out dx,al ; set ready for data
- stc
- pop ax
- pop dx
- pop cx
- pop bx
- ret ; back to main routine
-
- ; Okay, Ready for Data..
-
- SendData6:
- mov al,O_RFD
- out dx,al ; keep RFD
- pop ax
- push ax
- mov al,ah
- not al
- mov dx,BasePort
- out dx,al ; set the inverse of the data
- add dx,po_ctl
- mov al,O_DAV+O_RFD
- out dx,al ; say DAV
-
- ; Now, with DAV asserted, RFD should go low. If not, we have
- ; no devices connected.
-
- xor cx,cx
- SendData8:
- in al,dx ; wait for RFD low
- test al,O_RFD
- jz SendData9 ; if it did
- loop SendData8 ; keep trying
- jmp SendData4
-
- ; Wait for listener to release NDAC.
-
- SendData9:
- xor cx,cx
- SendData10:
- in al,dx ; get status
- test al,O_NDAC
- jz SendData12 ; if released
- loop SendData10 ; keep trying
- jmp SendData4 ; timeout
-
- ; Release DAV and wait for RFD.
-
- SendData12:
- mov al,O_RFD+O_Input
- out dx,al ; Return to input state
- mov ax,18*20
- call StartTimer
- mov dx,BasePort
- add dx,po_ctl
- SendData14:
- in al,dx
- test al,O_RFD
- jnz SendData16 ; if released
- call TestTimer
- jnb SendData14
- jmp SendData4 ; timeout
-
- SendData16:
- clc
- pop ax
- pop dx
- pop cx
- pop bx
- ret ; exit...
- SendData endp
-
- ;* GetData - Get a byte of data.
- ;
- ; On return (carry) if timeout,
- ; (al) = data read, (zero) if EOI encountered
- ;
-
- GetData proc near
- push dx
- push cx
- mov al,O_Input+O_RFD+O_NDAC ; say not data accepted
- mov dx,BasePort
- mov dx,po_ctl
- out dx,al ; set up as ready for data
- xor cx,cx
- GetData2:
- in al,dx ; wait for DAV
- test al,O_DAV
- jnz GetData6 ; if got DAV
- loop GetData2 ; if error
- GetData4:
- mov al,O_Input+O_RFD
- out dx,al
- stc
- pop cx
- pop dx
- ret ; timeout exit
-
- GetData6:
- mov dx,BasePort
- in al,dx ; get the data
- not al
- mov ah,al
- add dx,po_sts
- in al,dx ; see about eoi
- push ax
- add dx,po_ctl-po_sts ; back to control
- mov al,O_Input
- out dx,al ; assert data accepted
- xor cx,cx
- GetData8:
- in al,dx
- test al,O_DAV
- jz GetData10 ; if DAV released
- loop GetData8 ; continue...
- pop ax
- jmp GetData4 ; error...
-
- GetData10:
- mov al,O_Input+O_NDAC
- out dx,al ; assert NDAC
- jmp GetData12
- GetData12:
- mov al,O_Input
- out dx,al ; assert RFD, release NDAC
- pop ax
- test al,I_NEOI ; if not EOI
- mov al,ah
- pop cx
- pop dx
- ret ; exit, zero flag indicates status
- GetData endp
-
- end