home *** CD-ROM | disk | FTP | other *** search
- title COM_PP.ASM
-
- ;**************************************************************************
- ;* COM_PP.ASM is a set of RS232 communications functions. These func-
- ;* provide basic, interrupt-driven serial communications through an 8052
- ;* UART. The com_open() and com_set_buffers() functions MUST be called
- ;* before the com_read() or com_write() functions.
- ;*
-
- .model small
-
- if @codesize ; large or compact model
- bp_ofs equ 6
- else ; small or medium model
- bp_ofs equ 4
- endif
-
-
- ;** Constant Definitions ***************
- ERROR equ -1
- OK equ 0
-
- ;* com port status report bits
- PORT_OPEN equ 0001h
- RECVD_CHAR equ 0002h
- SNDNG_PCKT equ 0004h
- HAND_SHAKING equ 0008h
- OVERRUN_ERR equ 0010h
- PARITY_ERR equ 0020h
- FRAMING_ERR equ 0040h
- BREAK_ERR equ 0080h
- OVERFLOW equ 0100h
- INVALID_PORT equ 0200h
- PORT_NOT_FND equ 0400h
-
- ;* hand-shaking function codes
- RECV_TEST equ 1
- SEND_TEST equ 2
- BUF_EMPTY equ 3
- ;* line status bits - used to test Line Status Register
- OVERRUN equ 02h
- PARITY equ 04h
- FRAMING equ 08h
- BREAK equ 10h
-
- ;* interrupt id register bits
- DATA_AVAILABLE equ 04h
- TRANS_EMPTY equ 02h
-
- ;* interrupt enable bits
- DATA_AVAIL_INT equ 01h ; Enable data available int
- TRANS_EMPTY_INT equ 02h ; Enable transmitter empty int
- LINE_STATUS_INT equ 04h ; Enable Line Status Reg int
- MODEM_STAT_INT equ 08h ; Enable Modem Status reg int
-
- ;* modem control bits
- DTR equ 01h
- RTS equ 02h
- OUT1 equ 04h
- OUT2 equ 08h
-
- ;* Programmable Interrupt Controller (PIC)
- PIC_MASK_REG equ 21h
- PIC_EOI equ 20h ; End Of Interrupt
-
- ;* com port addresses
- COM1 equ 3f8h
- COM2 equ 2f8h
-
- ;* these are offsets from the base com port address to its various control
- ;* and status registers
- INT_ENABLE equ 01h ; Interrupt Enable Register
- INT_ID equ 02h ; Interrupt Identification Reg.
- MODEM_CONTROL equ 04h ; Modem Control Register
- LINE_STATUS equ 05h ; Line Status Register
- MODEM_STATUS equ 06h ; Modem Status Register
-
- ;******************************************************************************
- .data
- public com_status, send_len, send_tail, send_buffer
- public recv_len, recv_tail, recv_buffer, old_stack, stack_top
- public int_enable_mask
-
- com_status dw 0 ; local status word
- com_port dw 0 ; base address of com port
- com_int db 0 ; com interrupt vector
- PIC_mask db 0 ; Programmable Interrupt
- ; Controller mask
- int_enable_mask db 0 ; this is the uart interrupt
- ; mask
- send_len dw 0 ; size of send buffer
- send_tail dw 0 ; send buffer tail
- send_buffer dd 0 ; pointer to private send buffer
- msg_len dw 0 ; length of send message
-
- recv_len dw 0 ; size of receive buffer
- recv_tail dw 0 ; receive buffer tail
- recv_buffer dd 0 ; pointer to private receive buffer
-
- old_vector dd 0 ; orginal com interrupt vector
- hand_shake dd 0 ; address of handshake function
- local_stack dw 100h dup(0)
- stack_top dw 0
-
- ;******************************************************************************
- .code
- public _com_open, _com_write, _com_read, _com_close, _com_start_sending
- public _com_stop_sending, _com_get_status, _com_clr_recv_buf
- public _com_clr_send_buf, _com_set_handshake, _com_set_buffers
- public _com_chars_recvd, _com_chars_sent, _com_read_char,
- public _com_write_char
-
- old_stack dd 0 ; stack of interrupted routine
- save_ax dw 0
- ;**************************************************************************
- ;* ASYNC_ISR is the interrupt service routine. It is invoked anytime
- ;* a byte is received by the UART (8250), or if the 8250 is ready to send
- ;* another character, or if a line error is detected. The Interrupt
- ;* Identification Register (INT_ID) is read to determine the interrupt type
- ;* - Receive, Transmit, or Error - and the appropriate sub-routine is
- ;* executed. Since the 8250 prioritizes simultaneous interrupts, the INT_ID
- ;* is checked again prior to exiting to be sure all pending interrupts have
- ;* been processed.
- ;*
- async_isr proc far
-
- ; first save the interrupted routine's stack and substitute our local stack
- ; old_stack is in the code segment because at this point that's all we can
- ; count on
- mov word ptr cs:old_stack,sp
- mov word ptr cs:old_stack + 2,ss
- mov save_ax,ax
- mov ax,seg com_status
- mov ss,ax
- mov sp,offset stack_top
- sti ; re-enable interrupts
-
- push bp
- push bx
- push cx
- push di
- push ds
- push dx
- push es
- push si
-
- mov ax,seg com_status
- mov ds,ax
- mov dx,com_port ; get base address of com port
- add dx,INT_ID ; point to Int. Id. Register
- in al,dx
-
- ai1:
- ; first check for a line status interrupt
- cmp al,6 ; check for error interrupt
- je ai3
- test al,DATA_AVAILABLE ; check for received character
- jz ai2 ; if not, make next test
- ; else
- call recv_char ; receive a character
- jmp ai_out
-
- ai2:
- ; check for a transmit hold register empty interrupt
- test al,TRANS_EMPTY ; check for transmitter empty
- jz ai_out ; if not, leave
- ; else
- call send_char ; send a character
- jmp ai_out
-
- ai3:
- ; it was an error interrupt so identify it
- mov dx,com_port ; get port base address
- add dx,LINE_STATUS ; point to Line Status Register
- in al,dx ; read the register
-
- test al,OVERRUN
- jz ai4
- or com_status,OVERRUN_ERR
- ai4:
- test al,PARITY
- jz ai5
- or com_status,PARITY_ERR
- ai5:
- test al,FRAMING
- jz ai6
- or com_status,FRAMING_ERR
- ai6:
- test al,BREAK
- jz ai_out
- or com_status,BREAK_ERR
-
- ai_out:
- ; this is where we check for simultaneous interrupts
- mov dx,com_port ; get com port address
- add dx,INT_ID ; point to interrupt ident reg
- in al,dx ; read register
- test al,01h ; check for pending interrupt
- jz ai1 ; and if so, process it
-
- ; no pending interrupts
- mov dx,com_port ; re-set Int. Enable Reg.
- add dx,INT_ENABLE
- mov al,int_enable_mask
- out dx,al
-
- mov al,PIC_EOI ; re-enable the 8259
- out 20h,al
-
- pop si
- pop es
- pop dx
- pop ds
- pop di
- pop cx
- pop bx
- pop bp
-
- ; restore the stack
- cli
- mov ss,word ptr cs:old_stack + 2
- mov sp,word ptr cs:old_stack
- mov ax,cs:save_ax
- sti
- iret
- async_isr endp
-
-
- ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ;* RECV_CHAR first inputs the character received and then checks
- ;* for handshaking. If handshaking is enabled then the character
- ;* received is passed to the hand-shaking routine. The hand-shaking
- ;* function will clear AH if the byte passed to it should be saved
- ;* otherwise AH will be non-zero.
- ;* If byte is to be kept then a test for buffer overflow is made.
- ;* If the buffer is full an error flag is set and the character is
- ;* thrown away.
- ;* Provided the above tests have been passed, the character is
- ;* saved at the tail of the local receive buffer and a flag is set
- ;* indicating that there are characters in the receive buffer.
- ;*
- recv_char proc near
- mov dx,com_port ; get com port address
- in al,dx ; & read character
-
- test com_status,HAND_SHAKING ; check for hand-shaking
- jz rc1 ; no hand-shaking so continue
- ; else
- mov ah,RECV_TEST ; set ah to function code
- push ax ; (al = character)
- if @codesize ; large or compact model
- call far ptr [hand_shake]
- else ; small or medium model
- call word ptr [hand_shake]
- endif
- add sp,2 ; adjust stack
- test ah,0ffh ; see if ah is zero
- jz rc1 ; if it is, continue
- ; else
- jmp rc_out ; exit
-
- rc1:
- ; make sure recv_tail is less than the receive buffer's length
- mov dx,recv_tail
- cmp dx,recv_len
- jl rc2
- or word ptr com_status,OVERFLOW
- jmp short rc_out
-
- rc2:
- ; save the byte
- push es
- les di,recv_buffer ; es:di = receive buffer
- add di,recv_tail ; point to current end of buffer
- mov es:[di],al ; save character
- inc word ptr recv_tail ; increment tail
- or com_status,RECVD_CHAR ; and set receive character flag
- pop es
-
- rc_out:
- ret
- recv_char endp
-
-
- ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ;* SEND_CHAR first loads the next character to send into AL and then
- ;* checks to see if hand-shaking is enabled. If so the hand-shaking
- ;* function is called. The hand-shaking function will clear AH if the byte
- ;* passed to it should be sent (and send_tail incremented) otherwise AH
- ;* will be non-zero.
- ;*
- send_char proc near
- ; first get the next byte in the buffer
- push es
- les di,send_buffer
- add di,send_tail ; point to next character
- mov al,es:[di] ; move character into al
- pop es
-
- test com_status,HAND_SHAKING ; check protocol
- jz sc1
- mov ah,SEND_TEST ; set ah to function code
- push ax ; al = next send character
- if @codesize ; large or compact model
- call far ptr [hand_shake]
- else ; small or medium model
- call word ptr [hand_shake]
- endif
- add sp,2 ; adjust stack
- ; if HAND_SHAKE returns with ah > 0 then it has replaced the character in
- ; al in which case send_tail is not changed, otherwise it is incremented.
- ; note that since the byte is not re-loaded from the buffer hand_shake
- ; can substitute another byte and still force send_tail to be incremented.
- test ah,0ffh
- jnz sc2
- sc1:
- inc send_tail
-
- sc2: ; loop until Trans Holding Reg
- ; this test shouldn't be necessary but at least one supposed 8250 clone
- ; (I don't recall whose) interrupts when the transmit shift register is
- ; empty and not the transmit hold register
- mov ah,al ; save send character in ah
- mov dx,com_port ; get port base address
- add dx,LINE_STATUS ; point to Line Status Register
- sc3:
- in al,dx
- test al,40h
- jz sc3
-
- sub dx,LINE_STATUS ; point back to base address
- mov al,ah ; put character back in al
- out dx,al ; and send character
-
- mov ax,msg_len ; get message length
- cmp ax,send_tail ; & compare to see if
- ; we're at the end of the message
- jne short sc_out
-
- ; we've sent the entire message so re-initialize the variables and turn
- ; off the transmit interrupt
- mov word ptr send_tail,0 ; reset send tail
- mov word ptr msg_len,0
- and com_status,not SNDNG_PCKT ; turn sending flag off
- and int_enable_mask,not TRANS_EMPTY_INT ; reset interrupt status
- mov dx,com_port ; re-set Int. Enable Reg.
- add dx,INT_ENABLE ; point to Interrupt Enable Reg
- mov al,int_enable_mask ; clear the transmit bit
- out dx,al
-
- sc_out:
- ret
- send_char endp
-
- ;******************************************************************************
- ;* int com_open(int port,unsinged int params);
- ;*
- ;* Only com1 and com2 are supported using IRQ4 and IRQ3 respectively.
- ;* Once the port has been determined the BIOS (int 14h) is used to set
- ;* it up. The current interrupt vector is saved for later restoration and
- ;* ASYNC_ISR is substituted. DTR and RTS are pulled high. The UART's
- ;* receive buffer is cleared, and interrupts are enabled on the UART and
- ;* the 8259 Programmable Interrupt Controller (PIC).
- ;*
- ;* Returns: -1 if error, otherwise 0.
- ;*
- _com_open proc
- push bp
- mov bp,sp
- push bx
- push ds
- push dx
-
- if @datasize ; large data model
- mov ax,seg com_status ; change to local data segment
- mov ds,ax ; if necessary
- endif
- test com_status,PORT_OPEN ; see if the port is already open
- jz co1 ; if not, continue
- jmp co_err ; otherwise, return an error
- co1:
- ;* find out which com port - set up first for com2 and then if not
- ;* modify the settings
- mov PIC_mask,08h ; 8259 PIC mask for IRQ3
- mov com_int,0bh ; set interrupt to com2
- mov bx,0402h ; set si to BIOS com2 address
- mov dx,[bp + bp_ofs] ; get com port
- cmp dx,1 ; check for com2
- je co2 ; and if true test port
- ; else
- mov PIC_mask,10h ; 8259 PIC mask for IRQ4
- inc com_int ; reset interrupt to com1
- sub bx,2 ; set si to BIOS com1 address
- cmp dx,0 ; & check for com1
- je co2
- or com_status,INVALID_PORT
- jmp co_err ; only com1 & com2 are supported
-
- co2:
- mov ax,0
- push ds
- mov ds,ax ; set ds to bios segment
- mov ax,[bx] ; get port address from BIOS area
- pop ds
- cmp ax,0 ; if BIOS address is not 0 then
- jne co3 ; initialize port
- ; else
- or com_status,PORT_NOT_FND
- jmp co_err ; return an error
-
- co3:
- mov com_port,ax ; save com port address
- mov ax,[bp + bp_ofs + 2] ; get com parameters
- int 14h ; call bios to set com port
-
- ;* now we're ready to save the existing com interrupt vector and
- ;* substitute async_isr for it
- push es
- mov al,com_int ; vector address
- mov ah,35h ; DOS Get Vector function
- int 21h ; call DOS
- mov word ptr old_vector,bx ; and save the old
- mov word ptr old_vector + 2,es ; vector
- pop es
-
- mov dx,offset cs:async_isr ; move relative offset of
- ; interrupt routine to dx
- push ds
- push cs ; move code segment address
- pop ds ; to ds
- mov ah,25h ; DOS Set Vector function
- int 21h ; call dos
- pop ds
-
- ;* the only thing left to do is set up the various com port registers
- mov dx,com_port ; get port address
- mov al,DTR + OUT2 + RTS ; set DTR, Out2, & RTS mask
- add dx,MODEM_CONTROL
- out dx,al ; set register
- sub dx,MODEM_CONTROL ; point back to base
-
- co4:
- ; loop until the UART's receive buffer is empty
- add dx,LINE_STATUS ; point to Line Status Register
- in al,dx ; read it
- test al,01h ; & check for a waiting char
- jz co5 ; if no character continue
- ; otherwise
- sub dx,LINE_STATUS ; point back to base
- in al,dx ; read the character
- jmp short co4 ; and check it again
-
- co5:
- ; set the UART to interrupt on received character or line status error
- mov int_enable_mask,DATA_AVAIL_INT + LINE_STATUS_INT
- mov dx,com_port ; get base address
- add dx,INT_ID ; point to Inter. ID Register
- in al,dx ; clear it
- sub dx,INT_ID
- mov al,int_enable_mask
- add dx,INT_ENABLE
- out dx,al ; enable UART interrupts
-
- or com_status,PORT_OPEN ; set status flag
-
- ; now set up the Programable Interrupt Control (PIC) register
- cli
- in al,PIC_MASK_REG ; read 8259 mask register
- mov ah,PIC_mask ; move mask to ah
- not ah ; flip the bits
- and al,ah ; reset mask for this port
- out PIC_MASK_REG,al
- sti
- mov ax,OK
- jmp short co_out
-
- co_err:
- mov ax,ERROR ; set zero flag and clear ax
- co_out:
- pop dx
- pop ds
- pop bx
- pop bp
- ret
- _com_open endp
-
- ;**************************************************************************
- ;* void com_close(void);
- ;*
- ;* com_close() restores the original interrupt vectors, disables the
- ;* com interrupts, and restores the com registers.
- ;*
- _com_close proc
- push bp
- mov bp,sp
- push ax
- push ds
- push dx
-
- if @datasize ; large data model
- mov ax,seg com_status ; change to local data segment
- mov ds,ax ; if necessary
- endif
- test com_status,PORT_OPEN
- jz cc_out
-
- ;* restore the 8259 PIC
- cli
- in al,PIC_MASK_REG
- xor al,PIC_mask
- out PIC_MASK_REG,al
- sti
-
- ;* restore the UART registers
- mov al,00h ; turn off DTR, RTS, and OUT2
- mov dx,com_port
- add dx,MODEM_CONTROL
- out dx,al ; reset register
- sub dx,MODEM_CONTROL ; point back to base
- add dx,INT_ENABLE ; and then to Inter. ID Register
- out dx,al ; and clear it
-
- ;* restore the original com interrupt vector
- push ds
- lds dx,old_vector
- mov al,com_int
- mov ah,25h
- int 21h
- pop ds
-
- mov com_status,0 ; clear the status word
- mov recv_tail,0 ; and initialize the buffers
- mov send_tail,0
-
- cc_out:
- pop dx
- pop ds
- pop ax
- pop bp
- ret
- _com_close endp
-
- ;**************************************************************************
- ;* int com_write(int length,void *message);
- ;*
- ;* This routine is passed the application program's send buffer and the
- ;* the message length. The buffer address is saved and then the UART is set
- ;* to interrupt whenever the Transmitter Holding Register is empty.
- ;*
- ;* Returns: -1 if error detected or already sending otherwise 0
- ;*
- _com_write proc
- push bp
- mov bp,sp
- push di
- push ds
- push dx
- push es
- push si
-
- if @datasize ; large data model
- mov ax,seg com_status ; change to local data segment
- mov ds,ax ; if necessary
- endif
- test com_status,PORT_OPEN ; see if port is open
- jz cw_err ; if not then return error
- ; else
- test com_status,SNDNG_PCKT ; see if we're already sending
- jz cw1 ; if not continue
- ; else
- jmp cw_err ; return error
-
- cw1:
- ; copy the message into the local send buffer
- mov ax,[bp + bp_ofs] ; get message length
- mov msg_len,ax ; & save it
- mov cx,ax
- les di,send_buffer
- mov si,[bp + bp_ofs + 2] ; get offset of send buffer
- push ds
- if @datasize ; large data model
- mov ds,[bp + bp_ofs + 4] ; get segment of send buffer
- endif
- cld
- rep movsb ; copy the message
- pop ds
-
- ; now enable transmit interrupts
- cli
- or int_enable_mask,TRANS_EMPTY_INT ; set mask
- mov dx,com_port ; put port address in dx
- add dx,INT_ENABLE ; Interrupt Enable Register
- mov al,int_enable_mask
- out dx,al ; enable interrupt
- or com_status,SNDNG_PCKT ; set the status flag
- sti
- mov ax,OK
- jmp short cw_out
-
- cw_err:
- mov ax,ERROR ; set error return
-
- cw_out:
- pop si
- pop es
- pop dx
- pop ds
- pop di
- pop bp
- ret
- _com_write endp
-
- ;*****************************************************************************
- ;* int com_read(void *recv_buf)
- ;*
- ;* This routine is passed the application program's receive buffer.
- ;* The contents (if any) of the local receive buffer are transferred to it.
- ;* If hand-shaking is enabled then HAND_SHAKE is called and passed the
- ;* BUF_EMPTY function code so that it can re-start receving if necessary.
- ;*
- ;* Returns: Length of received message or -1 if error.
- ;*
- _com_read proc
- push bp
- mov bp,sp
- push cx
- push di
- push ds
- push es
- push si
-
- if @datasize ; large data model
- mov ax,seg com_status ; change to local data segment
- mov ds,ax ; if necessary
- endif
- push ds
- test com_status,PORT_OPEN ; make sure the port's open
- jnz cr1
- jmp cr_err
- cr1:
- mov di,[bp + bp_ofs] ; get offset of program's buffer
- if @datasize ; large data model
- mov ax,[bp + bp_ofs + 2] ; get segment of program's buffer
- mov es,ax ; & put it in es
- else ; else
- mov ax,ds
- mov es,ax
- endif
- lds si,recv_buffer
- mov cx,recv_tail ; set cx to length of string recd
- inc cx
- cld
- rep movsb ; copy the message
-
- ; now re-initialize the buffer and flags
- pop ds
- and com_status,not RECVD_CHAR ; reset status
- and com_status,not OVERFLOW
- mov cx,recv_tail ; return length of string
- mov recv_tail,0
-
- test com_status,HAND_SHAKING ; is hand-shaking is enabled?
- jz cr_2 ; if not then exit
- ; else
- mov ah,BUF_EMPTY ; set the function code
- push ax
- if @codesize ; large or compact model
- call far ptr [hand_shake]
- else ; small or medium model
- call word ptr [hand_shake]
- endif
- add sp,2 ; adjust stack
-
- cr_2:
- mov ax,cx
- sti
- jmp short cr_out
-
- cr_err:
- mov ax,ERROR ; set zero flag and clear ax
-
- cr_out:
- pop si
- pop es
- pop ds
- pop di
- pop cx
- pop bp
- ret
- _com_read endp
-
- ;**************************************************************************
- ;* int com_read_char(void);
- ;*
- ;* Returns the oldest character in the receive buffer. If there are
- ;* no characters then an error is returned. Note that the return value is
- ;* an integer. This means that a return value of 0 to 255 is the character
- ;* received while -1 is an error.
- ;*
- ;* Returns: 0 if successful or -1 if error occurs.
- ;*
- _com_read_char proc
- push bp
- mov bp,sp
- push cx
- push di
- push ds
- push es
- push si
-
- if @datasize ; large data model
- mov ax,seg com_status ; change to local data segment
- mov ds,ax ; if necessary
- endif
- test com_status,PORT_OPEN ; make sure port's open
- jnz crc1
- jmp crc_err
-
- crc1:
- cmp recv_tail,0 ; anything in the buffer?
- je crc_err ; no, so exit
- mov cx,recv_tail ; set cx for subsequent movsb
- push ds
- lds si,recv_buffer ; point ds:si to recv buffer
- mov al,[si] ; get 1st character in buffer
- mov ah,0 ; clear high byte
- inc si ; point si to next character
- les di,recv_buffer ; es:di = beginning of buffer
- cld
- rep movsb ; shift remaining characters down
-
- pop ds
- dec recv_tail ; adjust tail
- cmp recv_tail,0 ; check for empty buffer
- jne crc_out ; if not exit
- ; else
- and com_status,not RECVD_CHAR ; reset status
- and com_status,not OVERFLOW
-
- crc_err:
- mov ax,ERROR ; set error flag and clear ax
-
- crc_out:
- pop si
- pop es
- pop ds
- pop di
- pop cx
- pop bp
- ret
- _com_read_char endp
-
- ;**************************************************************************
- ;* int com_write_char(char chr);
- ;*
- ;* This function sends a character out the com port immediately.
- ;* If a message is currently being sent an error code is returned.
- ;*
- _com_write_char proc
- push bp
- mov bp,sp
- push cx
- push di
- push ds
- push es
- push si
-
- if @datasize ; large data model
- mov ax,seg com_status ; change to local data segment
- mov ds,ax ; if necessary
- endif
- test com_status,SNDNG_PCKT ; see if we're sending
- jnz cwc_err ; if so, return an error
- ; else
- mov dx,com_port ; get port base address
- add dx,LINE_STATUS ; point to Line Status Register
- cwc1:
- ; loop until the transmitter holding register is empty
- in al,dx
- test al,40h
- jz cwc1
-
- sub dx,LINE_STATUS ; point back to base address
- mov al,[bp + bp_ofs] ; get character to send
- out dx,al ; and send character
- mov ax,OK ; indicate no error
- jmp short cwc_out ; and exit
-
- cwc_err:
- mov ax,ERROR
-
- cwc_out:
- pop si
- pop es
- pop ds
- pop di
- pop cx
- pop bp
- ret
- _com_write_char endp
-
- ;**************************************************************************
- ;* void com_stop_sending(void);
- ;*
- ;* Stop sending disables the the Transmit Buffer Empty interrupt.
- ;*
- _com_stop_sending proc
- push ax
- push ds
- push dx
-
- if @datasize ; large data model
- mov ax,seg com_status
- mov ds,ax
- endif
- test com_status,SNDNG_PCKT ; are we in send mode?
- jz css1_out ; no, so just return
- cli ; make sure we're not interrupted
- and int_enable_mask,not TRANS_EMPTY_INT ; reset interrupt status
- mov dx,com_port ; re-set Int. Enable Reg.
- add dx,INT_ENABLE
- mov al,int_enable_mask ; disable interrupt
- out dx,al
- sti
-
- css1_out:
- pop dx
- pop ds
- pop ax
- ret
- _com_stop_sending endp
-
- ;**************************************************************************
- ;* void com_start_sending(void);
- ;*
- ;* Start sending is the complement to stop sending. It checks to see
- ;* if the SNDNG_PCKT flag is true and if so re-enables the transmit
- ;* interrupt. Ohterwise it simply returns.
- ;*
- _com_start_sending proc
- push bp
- mov bp,sp
- push ax
- push ds
- push dx
-
- if @datasize ; large data model
- mov ax,seg com_status
- mov ds,ax
- endif
- test com_status,SNDNG_PCKT ; are we in send mode?
- jz css2_out ; no, so just return
- cli ; make sure we're not interrupted
- or int_enable_mask,TRANS_EMPTY_INT ; set status to send interrupts
- mov dx,com_port ; put port address in dx
- add dx,INT_ENABLE ; Interrupt Enable Register
- mov al,int_enable_mask
- out dx,al ; enable register
- sti
-
- css2_out:
- pop dx
- pop ds
- pop ax
- pop bp
- ret
- _com_start_sending endp
-
- ;**************************************************************************
- ;* unsigned int com_get_status(void);
- ;*
- ;* This function returns a copy of the com_status word maintained
- ;* by this module. The status word consists of a sset of bit flags. See
- ;* SERIAL.HPP for the bit structure that defines them.
- ;*
- _com_get_status proc
- push ds
-
- if @datasize ; large data model
- mov ax,seg com_status
- mov ds,ax
- endif
- mov ax,com_status
-
- pop ds
- ret
- _com_get_status endp
-
- ;**************************************************************************
- ;* int com_chars_recvd(void);
- ;*
- ;* Returns the number of characters currently in the receive buffer.
- ;*
- _com_chars_recvd proc
- push ds
-
- if @datasize ; large data model
- mov ax,seg com_status
- mov ds,ax
- endif
- mov ax,recv_tail
-
- pop ds
- ret
- _com_chars_recvd endp
-
- ;**************************************************************************
- ;* int com_chars_sent
- ;*
- ;* Returns the number of characters that have been sent.
- ;*
- _com_chars_sent proc
- push ds
-
- if @datasize ; large data model
- mov ax,seg com_status
- mov ds,ax
- endif
- mov ax,send_tail
-
- pop ds
- ret
- _com_chars_sent endp
-
- ;**************************************************************************
- ;* void com_set_buffers(void *recv_buffer, void *send_buffer, int len);
- ;*
- ;* Sets the local send and receive buffers to be used by this module.
- ;*
- _com_set_buffers proc
- push bp
- mov bp,sp
- push ax
- push ds
-
- if @datasize ; large data model
- mov ax,seg com_status ; change to local data segment
- mov ds,ax ; if necessary
- mov ax,[bp + bp_ofs] ; receive buffer offset
- mov word ptr recv_buffer,ax
- mov ax,[bp + bp_ofs + 2] ; receive buffer segment
- mov word ptr recv_buffer + 2,ax
- mov ax,[bp + bp_ofs + 4] ; send buffer offset
- mov word ptr send_buffer,ax
- mov ax,[bp + bp_ofs + 6] ; send buffer segment
- mov word ptr send_buffer + 2,ax
- mov ax,[bp + bp_ofs + 8] ; buffer length
- else
- mov ax,[bp + bp_ofs] ; receive buffer offset
- mov word ptr recv_buffer,ax
- mov word ptr recv_buffer + 2,ds
- mov ax,[bp + bp_ofs + 2] ; send buffer offset
- mov word ptr send_buffer,ax
- mov word ptr send_buffer + 2,ds
- mov ax,[bp + bp_ofs + 4] ; send buffer length
- endif
- mov send_len,ax
- mov recv_len,ax
-
- pop ds
- pop ax
- pop bp
- ret
- _com_set_buffers endp
-
- ;**************************************************************************
- ;* void com_clr_recv_buf(void);
- ;*
- ;* Effectively clears all characters from the receive buffer by
- ;* resetting recv_tail to 0.
- ;*
- _com_clr_recv_buf proc
- push ds
-
- if @datasize ; large data model
- mov ax,seg com_status
- mov ds,ax
- endif
- cli
- mov recv_tail,0
- sti
-
- pop ds
- _com_clr_recv_buf endp
-
- ;**************************************************************************
- ;* void com_clr_recv_buf(void);
- ;*
- ;* Effectively clears all characters from the send buffer by
- ;* resetting send_tail and msg_len to 0. Note: if we're currently
- ;* sending then sending is stopped.
- ;*
- _com_clr_send_buf proc
- push ds
-
- if @datasize ; large data model
- mov ax,seg com_status
- mov ds,ax
- endif
- test com_status,SNDNG_PCKT ; are we sending now?
- jz ccsb1 ; no, continue
- ; else
- call _com_stop_sending ; stop sending
-
- ccsb1:
- cli ; avoid interruptions
- and com_status,not SNDNG_PCKT
- mov word ptr send_tail,0
- mov word ptr msg_len,0
- sti
-
- pop ds
- _com_clr_send_buf endp
-
-
- ;**************************************************************************
- ;* void _com_set_handshake(HANDSHAKE hs);
- ;*
- ;* Sets a pointer to the hand-shaking routine and sets the status
- ;* flag indicating that hand-shaking is enabled. If the pointer passed
- ;* to this routine is NULL then hand-shaking is disabled.
- ;*
- _com_set_handshake proc near
- push bp
- mov bp,sp
- push ax
- push bx
- push ds
-
- if @datasize ; large data model
- mov ax,seg com_status ; change to local data segment
- mov ds,ax ; if necessary
- endif
-
- mov ax,[bp + bp_ofs] ; get offset address of hand-
- ; shaking function
- mov word ptr hand_shake,ax ; save it
- if @codesize ; large or compact model
- mov bx,[bp + bp_ofs + 2] ; get segment address
- or ax,bx ; see if we were passed a NULL
- jz csh1 ; if so, disable hand-shaking
- ; else
- mov word ptr hand_shake + 2,bx ; save the segment
- or com_status,HAND_SHAKING ; set the enable flag
- jmp short csh_out
- else ; small or medium model
- test ax,0ffffh ; were we passed a NULL?
- jz csh1 ; yes, so disable hand-shaking
- ; else
- mov word ptr hand_shake + 2,cs ; set hand-shake segment to cs
- or com_status,HAND_SHAKING ; set the enable flag
- jmp short csh_out
- endif
-
- csh1:
- mov word ptr hand_shake + 2,0
- and com_status,not HAND_SHAKING ; disable hand-shaking
-
- csh_out:
- pop ds
- pop bx
- pop ax
- pop bp
- ret
- _com_set_handshake endp
-
-
- end
-