[net.sources] Talking PC6300 For The Blind, part 7 of 11

eklhad@ihuxv.UUCP (02/11/87)

;------------------------------------------------------------------------------
;	Talking console device driver for the AT&T PC6300.
;	Written by Karl Dahlke, September 1986.
;	Property of AT&T Bell Laboratories, all rights reserved.
;	This software is in the public domain and may be freely
;	distributed to anyone, provided this notice is included.
;	It may not, in whole or in part, be incorporated in any commercial
;	product without AT&T's explicit permission.
;------------------------------------------------------------------------------

;	synth.asm: speech synthesizer routines for talking device driver

;	currently designed to control a Votrax Type & Talk speech unit
;	via com1
;	application programs should not use com1 when this driver is installed
;	we use an interrupt driven system, bypassing bios.

	include parms.h

;	synthesizer can be on com1 or com2
COM	equ 1

RSBASE equ 4f0h-COM*100h    ;base of address of aux. port registers
DATREG equ RSBASE + 8     ;data register
LDL equ RSBASE + 8        ;low divisor latch
HDL equ RSBASE + 9        ;high divisor latch
IER equ RSBASE + 9        ;interrupt enable register
IIR equ RSBASE + 0ah        ;interrupt identification register
LCR equ RSBASE + 0bh        ;line control register
MCR equ RSBASE + 0ch        ;modem control register
LSR equ RSBASE + 0dh        ;line status register
MSR equ RSBASE + 0eh        ;modem status register


PGROUP	group	PROG, DATA
	assume cs:PGROUP, ds:PGROUP

DATA	segment	word public 'DATA'

	extrn rdflag:byte, inspeech:byte
	extrn buzzfc:byte

xmit_ptr dw 0 ; pointer to the next character to be transmitted
novo	db 0 ; no votrax present
crticks	db 0 ; number of ticks to wait after sending return
inxmit	db 0 ; flag indicating transmission in progress

DATA	ends


PROG	segment	byte public 'PROG'

	extrn putfifo:near
	public ss_ready, ss_text, ss_shutup
	public ss_init

;	init synthesizer, in this case the serial port
ss_init	proc near
;	reset the UART
	mov dx,MCR
	mov al,0
	out dx,al
	mov dx,LSR         ;reset line status
	in al,dx
	mov dx,DATREG      ; clear any input
	in al,dx
	mov dx,MSR
	in al,dx

;	set baud rate to 9600 baud
	mov dx,LCR
	mov al,80h ; access divisor latch
	out dx,al
	mov dx,LDL
	mov al,12       ;low byte of divisor
	out dx,al
	mov dx,HDL
	mov al,0       ;high byte of divisor
	out dx,al

	mov dx,LCR
	mov al,3 ; 8 bits, no parity
	out dx,al

;	set interrupt vector
	mov word ptr [bx+34h-COM*4],ADDR: ih_com
	mov [bx+36h-COM*4],cs

	mov dx,IER                 ;enable interrupts on 8250
	mov al,0 ; no transmit interrupt initially
	out dx,al

	in al,21h                     ;set enable bit on 8259
	and al,0e7h+COM*8 ; bit 4/3 is serial interrupt
	nop ; timing
	nop
	out 21h,al

	mov dx,MCR
	mov al,7+COM*4 ; dtr and rts set
;	extra bit (8[4]) is needed to generate interrupts.
	out dx,al

	ret
ss_init	endp

;	interrupt handler for serial interrupts
ih_com	proc far
	cld
	push ds
	push cs
	pop ds
	push ax
	push bx
	push dx

repoll:
;	When determining what actions to take, I find the IIR nigh unto
;	useless.  We have to look at LSR and MSR anyways, 
;	so why bother with IIR?
;	we read IIR, only because the interrupt system requires it.
	mov dx,IIR
	in al,dx
	nop
	nop
	mov dx,LSR
	in al,dx
	test al,20h
	jnz txint

intend:	mov al,65h-COM
	out 20h,al
	pop dx
	pop bx
	pop ax
	pop ds
	iret

	;if no data to send then reset tx interrupt and return
txint:	mov bx,xmit_ptr
	or bx,bx
	jnz oktx
	mov dx,IER
	mov al,0
	out dx,al
	dec inxmit
	jmp intend

oktx:	mov al,[bx]    ;get data from buffer
	inc bx
	mov dx,DATREG
	or al,al
	jnz more
;	end of string, sen return byte
	mov al,13
	xor bx,bx
more:	out dx,al                     ;send data
	mov xmit_ptr,bx
	jmp intend

ih_com	endp

;	return status of synthesizer,  ready for more or not
;	ideally, the unit is ready when it has spoken everything
;	previously sent to it.  the Type & Talk has an
;	annoying delay of about 10 seconds between ready indicated
;	and all input spoken.  There is nothing I can do
;	about this.  Other units, such as the echo,
;	are out of the question, since their delay is measured
;	in minutes.  Someday, a speech unit will indicate clearly when
;	it has spoken all input.
ss_ready proc near
;	sending a string?
	cmp inxmit,0
	jnz ss_busy
;	a real time delay, after sending return
	cmp crticks,0
	jz crok
	dec crticks
ss_busy:	xor ax,ax
	ret
crok:
	mov dx,MSR
	in al,dx
;	check to see if votrax is even there (dsr)
	test al,20h
	jnz alive
	cmp novo,0
	jnz nobuzz
	inc novo
	mov rdflag,0
	mov inspeech,0
	mov bx,ADDR: buzzfc
	call putfifo
nobuzz:	or al,10h
alive:	and ax,10h ; clear to send indicates Votrax is ready
	ret
ss_ready endp

;	send text string to the speech synthesizer
;	routine assumes the text is to be spoken immediately
;	once the text is spoken, cts will indicate ready for more
ss_text	proc near
	mov novo,0
	mov xmit_ptr,bx ; set pointer to buffer
;	set delay, after text is transmitted, so votrax can disable cts
	inc crticks
	inc inxmit ; in transmit state
;	enable transmit register empty interrupt, to transmit the text
	mov dx,IER
	mov al,2
	out dx,al
	ret
ss_text endp

;	shut up, and discard accumulated text
;	annoyingly, type & talk must be "ready" for text,
;	before it will honor the shut up command (break on rs232).
ss_shutup	proc near
;	wait a few miliseconds, votrax needs this
	sti
	mov cx,62*CLKRATE
	loop $
	cli
	mov dx,LCR         ;get the line control register
	in al,dx
	or al,40h       ;set break condition
	nop
	out dx,al
;	wait a while, in break
;	sorry to take real time for this, but, it is easier
	mov cx,57*CLKRATE
	loop $
	and al,0bfh
	out dx,al
	sti
	ret
ss_shutup	endp

PROG	ends

	end

-- 
	You know  ...  if it ain't patina, it's verdigris.
	Karl Dahlke   ihnp4!ihnet!eklhad