; B3SM51-4.ASM - SMARTMODEM DRIVER WITH 8251 I/O FOR BYE3 ; ; 04/04/84 Updated for BYE3-20 - Paul Traina ; ; 12/22/83 Revised to work with BYE3, renamed to be consistent with ; other BYE3 names. - Irv Hoff ; ; Steve Holtzclaw Version 1.1 12/16/83 ; SYSOP - Metroplex RCP/M ; Dallas Texas ; (214) 739-1935 ; ; This BYE3 driver supports both the Smartmodem 300 and the Smartmodem ; 1200. It was written in an attempt to correct the problems found in ; other Smartmodem drivers and also compensates for a flaw found in the ; Smartmodem 1200 (and possibly Smartmodem 300 as well). The flaw oc- ; curs when a command string is being sent to the Smartmodem. If the ; phone rings during the transmission of a command string, more often ; than not, one or more of the characters in the command string will be ; corrupted. The result of this error generally causes the Smartmodem ; to become 'confused' and it will reset to its initial command state. ; There is a possibility, however, that the error will go un-noticed by ; the Smartmodem and be accepted as a valid command. If an error is ; accepted by the Smartmodem as a valid command, the result will be un- ; predictable because the value of one character may have been changed. ; The command 'S2=128' (escape code character) could be changed to 'S2= ; 028' for example. This driver eliminates these problems by monitor- ; ingtoring the echoed characters in each command string that is sent to ; the Smartmodem. ; ; This driver is configured for an intel 8251 however it is structured ; so that it can be easily modified for any system by simply changing ; the port equates. ; ; The following hardware (your computer) configuration is assumed: ; ; DTR (pin 20) is supported ; DCD (pin 8) is supported ; RI (pin 22) is not supported ; ; The following software (your BYE3) configuration is assumed: ; ; CLOSS EQU 5 ;if carrier lost wait 5 sec. to hang-up ; NORING EQU NO ;yes, uart ring indicator not available ; ; The following Smartmodem default switches are assumed: ; ; 1=UP DTR supported, do not force to always logic true ; 2=DOWN send result codes as digits when in command state ; 3=UP result codes are not sent to the terminal ; 4=UP do not echo characters when in command state ; 5=DOWN do not answer the telephone automatically ; 6=UP DCD supported, do not force to always logic true ; 7=UP single line RJ11 telephone connection to Smartmodem ; 8=DOWN enables modem command recognition, when in command state ; ; ;======================================================================= ; LISTED BELOW IS A PATCH THAT ELIMINATES THE "CWAIT" WAIT FOR CARRIER. ; (SMARTMODEM DOES THAT SO BYE DOESNT NEED TO.) ;======================================================================= ; ;----------------------------------------------------------------------- ; PATCH #1 ------------------------------------------------------------- ;----------------------------------------------------------------------- ; ;FRSTCR:CALL MDCARCK ;carrier there? ; JNZ CARCK2 ;yes, jump to regular routine ; STC ;<=== add this line ; RET ;<=== add this line ; ;===> PUSH B ;<=== remove this line ;===> MVI B,CWAIT*5 ;<=== remove this line ;===> JMP CARLP ;<=== remove this line ; ;======================================================================= ; LISTED BELOW IS A PATCH THAT ELIMINATED THE RELAY BOUNCE TEST IN BYE. ; THIS PATCH MUST BE MADE FOR PROPER OPERATION OF THIS DRIVER. ;======================================================================= ; ;----------------------------------------------------------------------- ; PATCH #2 ------------------------------------------------------------- ;----------------------------------------------------------------------- ; ;RINGW2:CALL MDRING ;call ring-check routine ; JZ RINGWT ;not ringing... ; ; The phone may be ringing. wait .1 sec and look again to make sure it ; is not just relay bounce. ; ;===> CALL DELAY ;<=== remove this line ;===> CALL MDRING ;<=== remove this line ;===> JZ RINGFWT ;<=== remove this line ; ; The phone is definitely ringing, now wait until ring is finished. ; ;----------------------------------------------------------------------- ;----------------------------------------------------------------------- ; ; ; E Q U A T E S ; VERBOS: EQU YES ;yes for wordy status messages Z80: EQU YES ;yes if running z80, false otherwise SNDBRK: EQU YES ;yes to send break before dis-connect TESTING:EQU NO ;yes is you want to see Smartmodem ;command character echo ; ;'NOTE' - you must code your own console ;output routines at 'KONOUT' if you want ;to use this function. ; ; This routine should turn off everything on the modem, and get it ready ; to wait for a ring. (Also hang it up.) ; ; M D I N I T ; ; Save BYE3 registers ; MDINIT: IF Z80 ;if running Z80 CPU DB 0D9H ;use the Z80 'EXX' instruction ENDIF ;Z80 ; IF NOT Z80 ;if running 8080 CPU PUSH B ;save BC PUSH D ;save DE PUSH H ;save HL ENDIF ;NOT Z80 ; ; ; S M I N I T ; ; Force the Smartmodem to hang up the phone and initialize. ; SMINIT: CALL SMDIS ;disable Smartmodem CALL SILENC ;wait for line silence (waste time) CALL SET300 ;set modem to 300 bps IN DATPORT ;collect garbage CALL SMENBL ;enable the Smartmodem CALL DELAY ;wait .1 seconds for DTR to stabilize CALL MDSEND DB 'ATZ',CR,0 ;do Smartmodem default reset JC SMDERR ;if an error in sending the command CALL SILENC ;wait for line silence CALL MDSEND ;send the command sequence DB 'AT' ;bring Smartmodem to attention. DB 'S0=0' ;Smartmodem won't answer incoming ; calls - overrides switch 5 DB 'V0' ;codes sent as digits - overrides SW2 DB 'Q0' ;result codes enabled - overrides SW3 DB 'E1' ;Smartmodem echoes characters in the ; local command state - overrides SW4 DB 'M0' ;turn/keep the speaker off DB 'S2=128' ;disable the escape char. so Smartmodem ; can not be accidentally brought off ; line to local command state. DB 'S7=15' ;seconds to wait for 1st carrier before ; hanging up. DB 'S10=60' ;time delay between loss of carrier and ; Smartmodem hang-up. This value is ; in 1/10th secs., i.e., 60=60/10th ; (6 seconds). Tthis function is per- ; formed by BYE3byeii so the value ; should be greater than 'CLOSS'. DB CR,0 ; JC SMDERR ;if error in sending the command string CALL SILENC ;wait for line silence ; IF TESTING CALL KRLF ;send a CRLF to locat CRT ENDIF ;TESTING ; IF VERBOS LXI D,OKMSG ;index to message MVI C,9 CALL 5 ENDIF ;VERBOS ; ; ; Restore BYE3 registers ; IF Z80 ;if running Z80 CPU DB 0D9H ;use the Z80 'EXX' instruction ENDIF ;Z80 ; IF NOT Z80 ;if running 8080 CPU unning 8080 CPU POP H ;restore hl POP D ;restore de POP B ;restore bc ENDIF ;NOT Z80 ; RET ; IF VERBOS OKMSG: DB 'Modem ready...',CR,LF,'$' ENDIF ;VERBOS ; ; ; S M D E R R ; ; Handle a Smartmodem send character error condition. ; SMDERR: CALL MDSEND ;since the command could be garbage, DB CR,0 ; send a CR to complete the command CALL SILENC ; and give Smartmodem time to complain JMP SMINIT ;try it again ; ; M D S E N D ; ; Routine to control the sending of a command string to the Smartmodem. ; If the echo of each character sent is not received within 2 character ; time periods, or, if a bad echo character is received, an error flag ; is set... ; MDSEND: XTHL ;save HL, get address of message CALL MDINP ;clear any garbage characters ; MDSEN1: CALL MDOUTST ;get modem output status JZ MDSEN1 ;not ready to send yet... MOV A,M ;ready, get the character.. CALL MDOUTP ;send the character LXI D,840*MHZ ;2 character periods at 300 bps ; MDSEN2: DCX D ;count down MOV A,E ;test for timeout ORA D JZ MDSEN4 ;if an echo character timeout CALL MDINST ;get modem port input status JZ MDSEN2 ;wait for character ready CALL MDINP ;get the echo character ; IF TESTING CALL KONOUT ;print ENDIF ;TESTING ; CMP M ;same as character sent? JNZ MDSEN4 ;bad echo back - set error flag INX H ;point to next character MOV A,M ;get next character ORA A ;delimiter ? all sent ? JNZ MDSEN1 ;..no, go send another XTHL ;...restore hl, get return address XRA A ;clear error flag status RET ; MDSEN4: MOV A,M ;get next character ORA A ;end of string yet ? JZ MDSEN5 ;yes - return from this routine INX H ;else bump character pointer JMP MDSEN4 ; and loop for more ; MDSEN5: XTHL ;restore HL/stack STC ;set error condition RET ;return to caller ; ; M D G E T C ; ; Get an ascii character ('0'-'9') from Smartmodem ; CY=0 - no error, 'A' has a valid ascii character ; CY=1 - error, something is wrong with Smartmodem ; MDGETC: PUSH H ;save CALL MDINP ;gobble garbage characters LXI H,6250*MHZ ;.5 second wait ; MDGET1: DCX H ;bump counter MOV A,L ;check for count down ORA H JZ MDGET2 ;something bad is happening... CALL MDINST ;look for char ready from modem JZ MDGET1 ;if no character ready CALL MDINP ;get char from modem ANI 07FH ;make sure its ASCII CPI 030H ;ASCII zero JC MDGET1 ;if less CPI 03AH ;ASCII nine + 1 JNC MDGET1 ;if greater ; IF TESTING CALL KONOUT ;test ENDIF ;TESTING ; ORA A ;clear carry/error condition POP H RET ;return to caller ;... ; ; MDGET2: STC ;set carry/error condition POP H RET ;return to caller ; ; S I L E N C ; ; Wait for 500 ms of line silence. ; SILENC: CALL MDINP ;gobble up garbage characters MVI B,10 ; SILEN1: CALL MDINST ;character in receiver ? JNZ SILENC ;yes - gobble it up and restart CALL KDELAY ;wait 50 ms DCR B ;bump counter JNZ SILEN1 ;if more counts left RET ;return - no chars for b * 50ms ; ; M D R I N G ; ; Routine that will check to see if the phone is ringing. If not, it ; it will return with zero set, otherwise zero will be cleared. Since ; the Smartmodem can not hold the ring indicator (it sends a result ; code) we have to test for the '2' result code. A 1/2 second test ; period was chosen because bye can not stay in this loop. ; MDRING: LXI D,6250*MHZ ;.50 second test period ; MDRIN1: DCX D MOV A,E ORA D RZ ; CALL MDINST ;result code from Smartmodem ? JZ MDRIN1 ;no CALL MDINP ;get character CPI '2' ;Smartmodem 'RING' result code JNZ MDRIN1 ;no ; IF VERBOS LXI D,RNGMSG ;index 'RINGING' message MVI C,9 ;BDOS print string function CALL 5 ;do BDOS call ENDIF ;VERBOS ; MVI A,0FFH ;set flag - phone ringing ORA A ;clear any zero flag RET ;return to BYE3 with Zero flag clear ; IF VERBOS RNGMSG: DB 'Ringing...',CR,LF,'$' ENDIF ;VERBOS ; RNGCNT: DB 0 ; ; M D A N S W ; ; Routine to make the modem answer the phone. ; MDANSW: CALL MDSEND ;send a string of chars DB 'ATA',CR,0 ;tell modem to answer - send no more ;result codes JC MDANS2 ;if an error while sending string ; IF TESTING CALL KRLF ENDIF ;TESTING ; IF VERBOS LXI D,ANSMSG MVI C,9 CALL 5 ENDIF ;VERBOS ; MDANS1: CALL MDGETC ;wait for any result code JC MDANS1 ;loop until character received ; IF TESTING CALL KRLF ENDIF ;TESTING ; ; ; W A I T C R ; ; Wait for the CR from the result code - if we dont, BYE3 will think ; that it has received a CR from the caller. ; WAITCR: CALL MDINST ;is a character ready? JZ WAITCR ;...no - loop again CALL MDINP ;get the character RET ; MDANS2: CALL SILENC ;wait for line silence CALL MDSEND DB CR,0 ;send a CR to Smartmodem CALL SILENC ;wait for line silence JMP MDANSW ;try again IF VERBOS ANSMSG: DB 'Answering..',CR,LF,'$' ENDIF ;VERBOS ; ; ;----------------------------------------------------------------------- ;----------------------------------------------------------------------- ; H A R D W A R E D E P E N D E N T S U B R O U T I N E S ; ; These subroutines are hardware dependent - you must code these subrou- ; tines to fit your specific hardware requirements. ; ;----------------------------------------------------------------------- ;----------------------------------------------------------------------- ; ; Baud rate port equates ; BDPORT: EQU 00BH BD300: EQU 005H ;300 bps setting BD1200: EQU 007H ;1200 bps setting ; ; ; Modem port I/O equates ; DATPORT:EQU 6 ;data port STPORT: EQU DATPORT+1 ;data port status CTLPORT:EQU DATPORT+1 ;control port ; ; ; Modem port status equates ; RRDY: EQU 00000010B ;character ready mask FE: EQU 00100000B OE: EQU 00010000B PE: EQU 00001000B TRDY: EQU 00000001B ;send ready mask CDET: EQU 10000000B ;carrier detect mask ; ; ; Modem port command instruction bit equates ; HNTSET: EQU 10000000B ;enter hunt mode (this is a peculiar ; flaw in some 8251's and is sometimes ; times required for proper initiali- ; zation INTRES: EQU 01000000B ;internal reset RTSSET: EQU 00100000B ;force RTS when set ERESET: EQU 00010000B ;reset 8251 error flags BRKSET: EQU 00001000B ;force TXD low when set (send break) RCVSET: EQU 00000100B ;enable RXD when set DTRSET: EQU 00000010B ;enable DTR when set TXESET: EQU 00000001B ;enable TXD when set ; ; ; Modem port mode instruction bit equates ; S2SET: EQU 10000000B ;controls number of stop bits S1SET: EQU 01000000B ;controls number of stop bits EPSET: EQU 00100000B ;even parity when set PESET: EQU 00010000B ;parity enable when set L2SET: EQU 00001000B ;controls character length L1SET: EQU 00000100B ;controls character length B2SET: EQU 00000010B ;controls baud rate divisor B1SET: EQU 00000001B ;controls baud rate divisor ; RESCM1: EQU HNTSET+RTSSET+ERESET+RCVSET+DTRSET+TXESET RESCM2: EQU INTRES+RTSSET+ERESET+RCVSET+DTRSET+TXESET MODCMD: EQU S1SET+L2SET+L1SET+B2SET CMDCM1: EQU RTSSET+ERESET+RCVSET+DTRSET+TXESET ; modem enabled CMDCM2: EQU RTSSET+ERESET+RCVSET+TXESET ; modem disabled ; ; ; M D I N S T ; ; The following is a routine to determine if there is a characterr wait- ; ing to be received. If not, the zero flag will be set, otherwise, 255 ; (0FFH) will be returned in register 'A'. Remember that the system may ; like you a little more if you also mask out framing, parity, and over- ; run errors. (On some modems, you cannot do this because of problems ; with the baud rate selection.) ; MDINST: IN STPORT ANI PE+FE+OE ;any error flags? CNZ RESERR ;yes - reset error flags IN STPORT ;get status byte again ANI RRDY RZ ORI 0FFH ;we got something... RET ; ; R E S E R R ; ; Reset framing, parity, and overrun errors. ; RESERR: MVI A,CMDCM1 OUT STPORT ;reset error flags RET ; ; M D O U T S T ; ; The following is a routine to determine if the transmit buffer is em- ; pty. If not it will return with the Zero flag set. If the transmitter ; is not empty, it will return with zero clear. ; MDOUTST:IN STPORT ;get status byte again ANI TRDY RZ ORI 0FFH RET ; ; M D C A R C K ; ; The following is a routine that will check to make sure we still have ; carrier. If no carrier, it will return with the zero flag set. ; MDCARCK:IN CTLPORT ANI CDET RET ; ; M D I N P ; ; The following is a routine that will input one character from the modem ; port. If there is nothing there, it will return garbage... so use the ; MDINST routine first. ; MDINP: IN DATPORT ANI 07FH RET ; ; M D O U T P ; ; The following is a routine that will output one character in the 'A' ; register to the modem. Remember, that is the 'A' register, not in the ; 'C' register. ; ; ** use MDOUTST first to see if the buffer is empty ** ; MDOUTP: ANI 07FH OUT DATPORT RET ; ; S M D I S ; ; The following is a routine that forces the Smartmodem to hang up the ; phone and disables command recognition. its also a good time to re- ; initialize the modem port. ; ; NOTE: This subroutine is hardware dependent - you must code this ; subroutine to fit your specific hardware requirements. ; ; Initialize the 8151 USART ; SMDIS: MVI A,RESCM1 ;reset instruction 1 OUT CTLPORT ;send it NOP ;the NOPS are for slow 8251 units NOP NOP MVI A,RESCM2 ;reset instruction 2 OUT CTLPORT ;send it NOP ;the NOPS are for slow 8251 units NOP NOP MVI A,MODCMD ;mode instruction OUT CTLPORT ;send it NOP ;the NOPS are for slow 8251 units NOP NOP ; ; ; Send break before disconnect (optional) ; IF SNDBRK ;send break before disconnect MVI A,RESCM1 ;reset instruction 1 OUT CTLPORT ;send it NOP ;the NOPS are for slow 8251 units NOP NOP MVI A,RESCM2 ;reset instruction 2 OUT CTLPORT ;send it NOP ;the NOPS are for slow 8251 units NOP NOP MVI A,MODCMD+BRKSET ;mode instruction OUT CTLPORT ;sent it NOP ;the NOPS are for slow 8251 units NOP NOP CALL SILENC ;wait .5 seconds CALL SILENC ;wait another .5 seconds MVI A,RESCM1 ;reset instruction 1 OUT CTLPORT ;send it NOP ;the NOPS are for slow 8251 units NOP NOP MVI A,RESCM2 ;reset instruction 2 OUT CTLPORT ;send it NOP ;the NOPS are for slow 8251 units NOP NOP MVI A,MODCMD ;mode instruction OUT CTLPORT ;sent it NOP ;the NOPS are for slow 8251 units NOP NOP ENDIF ;SNDBRK ; ; ; Force the Smartmodem to hang up the phone ; MVI A,CMDCM2 ;modem port reset (disable Smartmodem) OUT CTLPORT RET ; ; S M E N B L ; ; The following is a routine that enables Smartmodem command recognition ; ; NOTE: This subroutine is hardware dependent - you must code this sub- ; routine to fit your specific hardware requirements. ; SMENBL: MVI A,CMDCM1 ;modem port reset (enable Smartmodem) OUT CTLPORT RET ; ;----------------------------------------------------------------------- ;----------------------------------------------------------------------- ; These next routines set the proper baud rates for the modem. If you ; do not support the particular rate, then simply put in a MMP to SETINV. ; If the baud rate change was successful, make sure the zero flag is set. ;----------------------------------------------------------------------- ;----------------------------------------------------------------------- ; ; The following routines returns a 0FFH because we were not able to set ; to the proper baud rate because either the serial port or the modem ; cannot handle it. ; SET110: DS 0 SET450: DS 0 SET600: DS 0 SET710: DS 0 SETINV: MVI A,0FFH ORA A ;make sure the zero flag is not set RET ; SET300: MVI A,BD300 ;setup for 300 bps OUT BDPORT XRA A RET ; SET1200:MVI A,BD1200 ;setup for 1200 bps OUT BDPORT XRA A RET ; ;----------------------------------------------------------------------- ; T E S T I N G R O U T I N E S ;----------------------------------------------------------------------- ; IF TESTING ; ; A little direct console output routine to monitor echo characters from ; the Smartmodem - converts a CR to a space. You will have to code this ; for your system. ; ; (IT MUST NOT DESTROY ANY REGISTERS !!!) ; KONOU3: PUSH PSW JMP KONOU1 ; KONOUT: PUSH PSW CPI CR JNZ KONOU1 MVI A,' ' ; KONOU1: PUSH PSW ; KONOU2: IN 1 ANI 1 JZ KONOU2 POP PSW OUT 0 POP PSW RET ;..... ; ; KRLF: PUSH PSW ;don't destroy 'A' or flags MVI A,CR CALL KONOU3 MVI A,LF CALL KONOU3 POP PSW RET ; ENDIF ;TESTING ;