Title 'MEX overlay for Epson PX-8 version 1.0' ; ; ; (delete above title line if not assembling with MAC) ; ; REV EQU 10 ;overlay revision level ; ; MEX overlay for Epson PX-8 with MFU, Direct Connect modem, or ; external modem. Support is provided for an external dialing overlay ; such as MXO-SM. For details see MXO-PX8.DOC. ; ; Written 3/10/85 by David B. Kozinn ; ; Copyright (C) 1985 by David B. Kozinn ; ; This program (in source or object code form) may be copied and distributed ; for non-commercial purposes. Sale of this program is forbidden without ; written consent of the author. ; ; The author can be contacted on CompuServe [76703,565] via Easyplex, or ; (preferably) in CP-MIG (PCS-47) or EpsOnline (PCS-19). ; ; PLEASE READ THE FOLLOWING IF YOU INTEND TO MODIFY THIS OVERLAY: ; --------------------------------------------------------------- ; Much of the commentary has been removed in order to save space. For ; complete documentation of how an overlay is structured, see the original ; overlay, MXO-PM.ASM, written by Ron Fowler. Please be sure to read the ; comments in that overlay if you intend to change this one. ; ; Version Date Changes ; ------- ------- ------- ; 1.0 850310 First general release version ;------------------------------------------------------------ ; ; Misc equates ; NO EQU 0 YES EQU (NOT NO) AND 0FFH TPA EQU 100H CR EQU 13 LF EQU 10 TAB EQU 9 BELL EQU 7 ESC EQU 01BH CUROFF EQU 032H CURON EQU 033H XON EQU 011H XOFF EQU 013H ; ; PX-8 port definitions ; MCTLR2 EQU 002H ;Misc control signals (output) CCR EQU 00DH ;8251 command port DCRREG EQU 084H ;Modem tone dialer control port (output) OCR EQU 085H ;Modem control register (output) STR EQU 086H ;Modem status register (input) OMR EQU 087H ;Modem port setup (output) ; ; PX-8 Special locations (see code for use) ; WBLOC EQU 0EC03H ;BIOS call Warm Boot location DRSDAT EQU 0F00FH ;Default RS-232 data CTLR1 EQU 0F0B0H ;CTLR1 register value CTLR2 EQU 0F0B2H ;CTLR2 register value RSMODE EQU 0F6D0H ;8251 Mode byte location RSCMD EQU 0F6D1H ;8251 Command byte location RSOPN EQU 0F2C8H ;RS-232 open flag (00=Open) SLVFLG EQU 0F358H ;Slave cpu (6301) flag INTBUF EQU 0FB90H ;Internal rs232 buffer INTBUFL EQU 0160H ;Internal buffer length ; ; bit definitions ; MDMINIT EQU 089H ;8251 initialization string BRKBIT EQU 008H ;8251 bit to turn break on MDRCVB EQU 001H ;modem receive bits MDRCVR EQU 001H ;modem recieve ready MDSNDB EQU 002H ;modem send bits MDSNDR EQU 002H ;modem recieve ready USEINT EQU 020H ;set to 0, send this to CTLR2 to use int. DCD EQU 008H ;Use with RSIOX CTLIN ; ; bit definitions for OCR ; OHC EQU 001H ;off hook HSC EQU 002H ;handset control MON EQU 004H ;enable speaker TXC EQU 008H ;transmit carrier ANS EQU 010H ;Answer mode TEST EQU 020H ;Test function PWR EQU 040H ;Modem Power CCT EQU 080H ;connect to phone lne ; ; bit definitions for STR ; BDS EQU 001H ;Bell Detect Signal. 0 if ringing CTSMSK EQU 004H ;Clear to send. (carrier det) =0 if clear MII EQU 080H ;Modem Installation Indicator 0=installed ; ; ; Special BIOS call locations ; CONIN EQU WBLOC+006H ;Direct console input CONOUT EQU WBLOC+009H ;Direct console output RSOPEN EQU WBLOC+039H ;Open RS-232 port RSCLOSE EQU WBLOC+03CH ;Close RS-232 port RSINST EQU WBLOC+03FH ;Check for input RSOUTST EQU WBLOC+042H ;Check for output RSIN EQU WBLOC+045H ;Get a character RSOUT EQU WBLOC+048H ;Send a character RSIOX EQU WBLOC+051H ;Special RS-232 calls SLAVE EQU WBLOC+072H ;Use slave CPU ; ; Equates for use with RSIOX ; OPNIOX EQU 010H ;Open using RSIOX CLSIOX EQU 020H ;Close using RSIOX INSTS EQU 030H ;Check for data in recieve buffer CTLIN EQU 070H ;Check carrier & DSR ; ; Mex locations ; QUEUE EQU 00D51H ;Queued I/O variable MODE EQU 00D54H ;Terminal mode byte (01 = in terminal mode) SMART EQU 00B00H ;Entry point for smart modem overlay ; ; Other equates ; WTCTS EQU 150 ;How long to wait for carrier. 150=30 seconds ; ; MEX service processor stuff ; MEX EQU 0D00H ;address of the service processor INMDM EQU 255 ;get char from port to A, CY=no more in 100 ms TIMER EQU 254 ;delay 100ms * reg B TMDINP EQU 253 ;B=# secs to wait for char, cy=no char CHEKCC EQU 252 ;check for ^C from KBD, Z=present SNDRDY EQU 251 ;test for modem-send ready RCVRDY EQU 250 ;test for modem-receive ready SNDCHR EQU 249 ;send a character to the modem (after sndrdy) RCVCHR EQU 248 ;recv a char from modem (after rcvrdy) LOOKUP EQU 247 ;table search: see CMDTBL comments for info PARSFN EQU 246 ;parse filename from input stream BDPARS EQU 245 ;parse baud-rate from input stream SBLANK EQU 244 ;scan input stream to next non-blank EVALA EQU 243 ;evaluate numeric from input stream LKAHED EQU 242 ;get nxt char w/o removing from input GNC EQU 241 ;get char from input, cy=1 if none ILP EQU 240 ;inline print DECOUT EQU 239 ;decimal output PRBAUD EQU 238 ;print baud rate ; ; PRINT EQU 9 ;simulated BDOS function 9: print string INBUF EQU 10 ;input buffer, same structure as BDOS 10 ; ORG SMART ;Put code in in case he calls smartmodem CPI 255 ;without installing the overlay first RNZ ;Only do it once, at the end CALL ILPRT DB '** You have not installed a dialing overlay **' DB BELL,CR,LF,0 XRA A ;Set zero flag MVI A,3 ;Tell him dialing has been aborted RET ORG QUEUE ;Set to Queued I/O flag location DB 0 ;Don't allow queued I/O (it interferes ;with the stuff we're doing) ORG TPA ;we begin ; ; DS 3 ;MEX has a JMP START here ; ; The following variables are located at the beginning of the program ; to facilitate modification without the need of re-assembly. They will ; be moved in MEX 2.0. ; PMODEM: DB NO ;yes=PMMI modem \ / These 2 locations are not SMODEM: DB NO ;yes=Smartmodem / \ referenced by MEX TPULSE: DB 'T' ;T=touch, P=pulse (not referenced by MEX) CLOCK: DB 20 ;clock speed x .1, up to 25.5 mhz. MSPEED: DB 1 ;sets display time for sending a file ;0=110 1=300 2=450 3=600 4=710 ;5=1200 6=2400 7=4800 8=9600 9=19200 BYTDLY: DB 0 ;default time to send character in ;terminal mode file transfer (0-9) ;0=0 delay, 1=10 ms, 5=50 ms, 9=90 ms CRDLY: DB 0 ;end-of-line delay after CRLF in terminal ;mode file transfer for slow BBS systems ;0=0 delay, 1=100 ms, 5=500 ms, 9=900 ms COLUMS: DB 5 ;number of directory columns SETFL: DB YES ;yes=user-defined SET command SCRTST: DB YES ;yes=if home cursor and clear screen ;routine at CLRSCRN DB 0 ;was once ACKNAK, now spare BAKFLG: DB NO ;yes=make .BAK file CRCDFL: DB YES ;yes=default to CRC checking ;no=default to Checksum checking TOGCRC: DB YES ;yes=allow toggling of Checksum to CRC CVTBS: DB NO ;yes=convert backspace to rub TOGLBK: DB YES ;yes=allow toggling of bksp to rub ADDLF: DB NO ;no=no LF after CR to send file in ;terminal mode (added by remote echo) TOGLF: DB YES ;yes=allow toggling of LF after CR TRNLOG: DB NO ;yes=allow transmission of logon ;write logon sequence at location LOGON SAVCCP: DB YES ;yes=do not overwrite CCP LOCNXT: DB NO ;yes=local cmd if EXTCHR precedes ;no=not local cmd if EXTCHR precedes TOGLOC: DB YES ;yes=allow toggling of LOCNXTCHR LSTTST: DB YES ;yes=allow toggling of printer on/off ;in terminal mode. Set to no if using ;the printer port for the modem XOFTST: DB YES ;yes=allow testing of XOFF from remote ;while sending a file in terminal mode XONWT: DB NO ;yes=wait for XON after sending CR while ;transmitting a file in terminal mode TOGXOF: DB YES ;yes=allow toggling of XOFF testing IGNCTL: DB NO ;yes=do not send control characters ;above CTL-M to CRT in terminal mode ;no=send any incoming CTL-char to CRT EXTRA1: DB 0 ;for future expansion EXTRA2: DB 0 ;for future expansion BRKCHR: DB '@'-40H ;^@ = Send a 300 ms. break tone NOCONN: DB 'N'-40H ;^N = Disconnect from phone line LOGCHR: DB 'L'-40H ;^L = Send logon LSTCHR: DB 'P'-40H ;^P = Toggle printer UNSVCH: DB 'R'-40H ;^R = Close input text buffer TRNCHR: DB 'T'-40H ;^T = Transmit file to remote SAVCHR: DB 'Y'-40H ;^Y = Open input text buffer EXTCHR: DB '^'-40H ;^^ = Send next character ; ; The next two are for PMMI, we don't use them, but they have to hang ; around anyway. ; DB 250 DB 0 ; ; Low-level modem I/O routines ; INCTL1: JMP MODSTAT ;in modem control port DB 0,0,0,0,0,0,0 ;spares ; OTDATA: JMP MODOUT ;out modem data port DB 0,0,0,0,0,0,0 ;spares ; INPORT: JMP MODIN ;in modem data port DB 0,0,0,0,0,0,0 ;spares ; ; Bit-test routines. These will be merged with the above ; routines in MEX 2.0 to provide a more reasonable format ; MASKR: ANI MDRCVB ! RET ;bit to test for receive ready TESTR: CPI MDRCVR ! RET ;value of receive bit when ready MASKS: ANI MDSNDB ! RET ;bit to test for send ready TESTS: CPI MDSNDR ! RET ;value of send bit when ready ; ; ; Unused area: was once used for special PMMI functions, ; Now used only to retain compatibility with MDM overlays. ; You may use this area for any miscellaneous storage you'd ; like but the length of the area *must* be 12 bytes. ; DS 12 ; ; Special modem function table ; LOGON: DS 2 ;needed for MDM compat, not ref'd by MEX DIALV: JMP PDIAL ;dial digit in A (see info at PDIAL) DISCV: JMP PDISC ;disconnect the modem GOODBV: DS 3 ;called before exit to CP/M INMODV: JMP NITMOD ;initialization. Called at cold-start NEWBDV: JMP PBAUD ;set baud rate NOPARV: DS 3 ;set modem for no-parity PARITV: DS 3 ;set modem parity SETUPV: JMP SETCMD ;SET cmd: jump to a RET if you don't write SET SPMENV: DS 3 ;not used with MEX VERSNV: JMP SYSVER ;Overlay's voice in the sign-on message BREAKV: JMP PBREAK ;send a break ; ; Entry points here are for compatibility with MDM7. They will be gone ; in MEX 2.0, so avoid using them. ; ILPRTV: DS 3 ;replace with MEX function 9 INBUFV: DS 3 ;replace with MEX function 10 ILCMPV: DS 3 ;replace with table lookup funct. 247 INMDMV: DS 3 ;replace with MEX function 255 NXSCRV: DS 3 ;not supported by MEX (returns w/no action) TIMERV: DS 3 ;replace with MEX function 254 ; ; ; Clear/screen and clear/end-of-screen. Each routine must use the ; full 9 bytes alloted (may be padded with nulls). ; CLREOS: LXI D,EOSMSG MVI C,PRINT CALL MEX RET ; ; CLS: LXI D,CLSMSG ;null unless patched MVI C,PRINT CALL MEX RET ; ;------------------------------------------------------------ ; ; *** END OF FIXED FORMAT AREA *** ; ;------------------------------------------------------------ ; ; Modem initialization. First make sure that the dialing overlay ; address is correct (some overlays ORG the dial vector and stick a ; JMP B00 there.) We have to make sure that we get control first. ; Also, store away the current value in the DISCV address, because it ; might be the address of the dialing overlay disconnect vector. We'll ; use this to disconnect along with the regular disconnect code if an ; external modem is being used. Then, set up the default communications ; parameters. Then, if the port is already open, just return, else set ; up to use the built-in modem. ; NITMOD: LXI H,PDIAL ;Get address of our dialing routine SHLD DIALV+1 ;Store it as the address to jump to LHLD DISCV+1 ;Get address of disconnect vector SHLD SMDISCV+1 ;Save it in case it's needed LXI B,PDISC ;Get our disconnect routine address XRA A ;Clear carry flag DB 0EDH,042H ;SBC HL,BC If zero, then the same JZ NIT0 ;Don't do anything special DCR A ;Get 0FFH to store STA GOTDISC ;Indicate that we've got external disc LXI H,PDISC ;Get the address of our disconnect routine SHLD DISCV+1 ;Store it in the proper place NIT0: LXI H,DRSDAT ;Get default rs232 data LXI D,BAUDRATE LXI B,4 DB 0EDH,0B0H ;LDIR LDA BAUDRATE ;Find out what baud we're set to LXI H,BAUDTBL MVI B,0 NIT1: CMP M ;Do we match this table entry? JZ NIT2 ;Yes INX H INR B JMP NIT1 NIT2: MOV A,B ;Store the table entry locally STA MDMSPD CALL SMSPEED ;Set modem speed for time for xfer LDA RSOPN ;See if the port is already open ORA A RZ ;Don't do anything if so CALL RSOPEN ;Turn the port on CALL PWRON ;Try to turn the modem on IN STR ;Read status register ANI MII ;Is modem installed? JNZ OPENIT ;No, open the RS-232 port normally CALL STPORT ;Set up to use the direct connect LDA OCRVAL ;Turn off modem power to conserve ANI (NOT PWR) AND 0FFH STA OCRVAL OUT OCR MVI A,0FFH ;Indicate we're using the internal modem STA MDMTYPE RET OPENIT: CALL RSCLOSE ;Close the port to clean things up CALL RSOPEN ;Open it up for the regular port RET ; ; send-break routine ; PBREAK: LDA RSCMD ;Get the current command for the 8251 ORI BRKBIT ;turn break on OUT CCR ;Send it to the 8251 MVI B,3 ;Wait 300 ms. MVI C,TIMER CALL MEX LDA RSCMD ;Restore the 8251 to normal OUT CCR RET ; ; disconnect the modem ; PDISC: LDA MDMTYPE ;See if we're using an external modem ORA A ;This will be zero if so JNZ PDISC0 ;If not, don't worry about it LDA GOTDISC ;See if we had an external routine ORA A ;This will be non-zero if so JNZ SMDISCV ;Call it if it's there PDISC0: CALL RSCLOSE LDA OCRVAL ;get current modem control values ANI 0FFH-(CCT+TXC+OHC) ;On-hook, carrier off,disconnect OUT OCR ;send it ANI (NOT PWR) AND 0FFH ;now turn power off too OUT OCR STA OCRVAL ;Save this as current mod. ctl. value CALL RESPORT ;Reset to use internal CALL SPKROFF ;Turn the speaker off CALL RSOPEN RET ; ; External dialing routine disconnect code is called through here. ; SMDISCV:JMP PDISC ;<-----This may be modified ; ; ;------------------------------------------------------------ ; ; DIALING ROUTINES ; ; ; The DIGITS table is a translation for digit to register value for ; all of the possible legal digits. Not many people will likely have ; use for A-D, since they are kind of hard to dial on a normal phone, ; but since the modem supports them, I've included them here. If you do ; want to use A-D, be sure to specify them as UPPER CASE or they'll be ; treated as they were one of the non-special characters. The modem ; also understands that a comma (,) means to wait for n seconds before ; continuing (for compatability with various intelligent modems.) Any other ; values (such as -, (, or ) ) are ignored. (Values have been OR'd with ; the tone-on bit already.) ; DIGITS: DB 1DH,10H,11H,12H ; 0, 1, 2, 3 DB 14H,15H,16H,18H ; 4, 5, 6, 7 DB 19H,1AH ; 8, 9 SPLAT: DB 1CH ; * CRUNCH: DB 1EH ; # CHARS: DB 13H,17H,1BH,1FH ;A, B, C, D ; PDIAL: MOV B,A ;Save the digit LDA MDMTYPE ;See if we're using an external modem ORA A MOV A,B ;Restore the digit JZ SMART ;If so, jump to the Hayes routines CPI 254 ;start-dial? JZ STDIAL CPI 255 ;end-dial JZ ENDIAL CPI ',' ;smartmodem pause command JNZ CKDIG ;if not pause, continue LDA COMDLY ;delay n seconds MOV B,A ADD A ; x 2 ADD A ; x 4 ADD A ; x 8 ADD B ; x 9 ADD B ; x 10 MOV B,A MVI C,TIMER CALL MEX RET ; CKDIG: CPI '9'+1 ;digits are 0-9 JNC CKALFA ;too big...check if it's A-D SUI '0' JC CKSPEC ;too small....check if it's * or # LXI H,DIGITS ;get start of digits table JMP DIALIT ; CKALFA: CPI 'D'+1 ;legal alpha are A-D RNC ;too big, ignore it SUI 'A' RC ;too small LXI H,CHARS ;get start of character table JMP DIALIT ; CKSPEC: LXI H,SPLAT ;Check for specials CPI ('*'-'0') AND 0FFH ;..is it *? JZ DIALIT1 ;Yup, go dial INX H ;point to CRUNCH CPI ('#'-'0') AND 0FFH ;..is it #? RNZ ;No, forget it JMP DIALIT1 ;Yup, go dial ; ; First get the value to send to the tone control register. At DIALIT, ; HL contains the proper table, and A contains the offset into that table. ; DIALIT: MVI B,0 MOV C,A ;Get offset into BC DAD B ;Get real byte location into HL ; DIALIT1:MOV A,M ;Get value to dial into A OUT DCRREG ;Start sending the tone MVI B,1 ;Send it for 100ms (which is kinda long MVI C,TIMER ;but it's easier than coding my own timing CALL MEX ;routine.) XRA A OUT DCRREG ;Turn tone off MVI B,1 ;Wait for 100ms for the inter-digit delay MVI C,TIMER CALL MEX RET ; ; Start-dial sequence: Go thru normal init sequence, assuming that ; the guy is not trying to dial while connected. (This should ; disconnect him anyway. ; STDIAL: CALL PDISC ;Disconnect LDA OCRVAL ;Turn on monitor soon ORI MON STA OCRVAL CALL RESPORT ;I don't know why, but I gotta do this CALL PWRON ;Init modem and ports CALL SPKRON ;turn power to speaker on LDA OCRVAL ;Get current value for OCR ANI (NOT ANS) AND 0FFH ;Set originate mode STA OCRVAL OUT OCR OFFHK: LDA OCRVAL ;Have to reload 'cause we're called directly ORI CCT ;Connect to phone OUT OCR ORI OHC ;go off hook OUT OCR STA OCRVAL MVI B,20 ;Wait 2 seconds for dial tone MVI C,TIMER CALL MEX RET ;dialing init done ; ; End-dial sequence: Watch to see if CTS goes on within 30 seconds. If ; so, turn on carrier, turn speaker off, and connect to the line. ; ENDIAL: LDA OCRVAL ;Turn on carrier ORI TXC OUT OCR STA OCRVAL CALL STPORT MVI E,WTCTS ;# of ms * 5 to wait LP1: MVI B,2 ;200 ms. MVI C,TIMER CALL MEX IN STR ;Check modem status register ANI CTSMSK ;See if we've got carrier yet JZ GOTCAR ;If it's zero, then we've got carrier MVI C,CHEKCC ;Not yet, see if he hit ctl-c CALL MEX MVI A,3 ;Get ready to return code JZ NOCAR ;Yup, return DCR E ;Nope, count down JNZ LP1 ;Keep going if more time MVI A,2 ;Set code in A to 2 (no answer) NOCAR: PUSH PSW ;Save the return code CALL PDISC ;Hang up POP PSW ;Get the return code back RET ; ; GOTCAR - Come here to go on-line, we've got a carrier from remote ; GOTCAR: CALL SPKROFF ;Turn the speaker off XRA A ;Report that we got carrier RET ; ; ;------------------------------------------------------------ ; PBAUD: RET ;use SET COMM for this ; ; Sign-on message ; SYSVER: LXI D,SOMESG MVI C,PRINT CALL MEX RET ; SOMESG: DB 'Epson PX-8 overlay V' DB REV/10+'0' DB '.' DB REV MOD 10+'0' DB '$' ; ; input from the status port. Since the PX-8 has 2 status ports, and ; we can't tell why we're being call (for input or output), we have to ; kludge here. We'll call both in & out status, and fake a 1 byte status ; word. See the MOD??? bytes for the values. Also, we check here to see ; if carrier has been lost (only if we were using the modem.) If so, then ; we'll disconnect from the phone line, reset the port, and tell the user. ; ; NOTE: It was observed that there was really no need for output status, ; so these routines always return "ready to output". However, the ; basic code structure to support both input and output status has ; been left in should it ever be necessary. ; ; Automatic X-ON/X-OFF flow control is also done from this point. ; MODSTAT: PUSH B ;push all registers (except A) PUSH D PUSH H LDA CTLR2 ;See if we're using an MFU ANI USEINT JNZ MDSTAT1 ;If not, forget about it IN STR ;Else check modem status register ANI CTSMSK JZ MDSTAT1 ;Everything Ok if it's there CALL PDISC ;Otherwise hang up CALL ILPRT ;and say something about it DB CR,LF,'** Carrier Lost **',BELL,CR,LF,0 MDSTAT1:LDA MODE ;Get terminal mode CPI 1 ;01 means in terminal mode JNZ MDSTAT4 ;If not, then don't worry about it MDSTAT2:MVI B,INSTS ;Check for characters in input buffer LXI H,WIPEOUT ;Here's where to put the returned info CALL RSIOX JNZ MDSTAT2 ;Wait until we get good status XRA A ;Clear carry LXI H,264 ;3/4 full buffer DB 0EDH,042H ;SBC HL,BC JNC MDSTAT3 ;Continue if < 264 chars in buffer LDA PENDXOFF ;is there an XOFF outstanding already? ORA A ;It'll be 0 if not JNZ MDSTAT4 ;If so, then just go ahead MVI C,XOFF ;Send out an XOFF CALL RSOUT XRA A DCR A STA PENDXOFF ;Indicate a pending XOFF JMP MDSTAT4 ;Continue MDSTAT3:MVI B,INSTS ;Check input again, this time we're LXI H,WIPEOUT ;seeing if it's time to send an XON CALL RSIOX JNZ MDSTAT3 XRA A LXI H,50 DB 0EDH,042H ;SBC HL,BC JC MDSTAT4 ;Don't send XON until < 50 chars in buffer LDA PENDXOFF ;Ok, we've got < 50, did we send an XOFF? ORA A JZ MDSTAT4 ;No, so don't do anything MVI C,XON CALL RSOUT ;Send the XON XRA A STA PENDXOFF MDSTAT4:CALL RSINST ;Now get status ANI MDRCVB ;Mask off what we don't care about ORI MDSNDB ;Always say that output is ready POPEM: POP H POP D POP B RET ; ; Get a character ; MODIN: PUSH B PUSH D PUSH H MVI B,INSTS LXI H,STATBLK CALL RSIOX ;Make sure there is really data so we ORA A ;don't ever hang waiting JZ MODIN1 CALL RSIN MODIN1: POP H POP D POP B RET ; ; Send a character ; MODOUT: PUSH B PUSH D PUSH H MOV C,A CALL RSOUT POP H POP D POP B RET ; ; type char in A on console ; TYPE: PUSH H ;save 'em PUSH D PUSH B MOV C,A ;align output character CALL CONOUT POP B POP D POP H RET ; ; SETPORT - set up to use internal modem ; STPORT: LDA CTLR2 ;Get current port info ANI (NOT USEINT) AND 0FFH ;Use internal modem SPORT: STA CTLR2 OUT MCTLR2 RET ; ; RESPORT - set up to use external modem ; RESPORT:LDA CTLR2 ;Get current port info ORI USEINT ;Use external modem JMP SPORT ;Store & send to modem ; ; PWRON - Turn power on to the modem (& some other initialization stuff) ; PWRON: MVI A,MDMINIT ;Initialize the 7508 OUT OMR LDA OCRVAL ;Get current parameters ORI PWR ;Turn the power on OUT OCR STA OCRVAL ;Save the parameters MVI B,1 ;Wait a while to let things settle MVI C,TIMER CALL MEX RET ; ; SPKRON - Turn the speaker on ; SPKRON: MVI A,0FFH STA SLVFLG LXI D,SLVPRAM1 CALL SLAVE RET ; ; SPKROFF - Turn speaker off ; SPKROFF:LDA OCRVAL ;Get current params ANI (NOT MON) AND 0FFH ;We're not monitoring anymore OUT OCR STA OCRVAL MVI A,0FFH STA SLVFLG LXI D,SLVPRAM2 CALL SLAVE RET ; ; Print in-line message ... blows away C register ; ILPRT: MVI C,ILP ;get function code JMP MEX ;go do it ; ; PLACECUR - Place cursor at row/col specified by BC. ; PLACECUR: PUSH PSW MOV A,B ADI 01FH ;Add in offset STA ROW MOV A,C ADI 01FH ;Add in offset STA COL CALL ILPRT DB ESC,'=' ROW: DS 1 COL DS 1 DB 0 POP PSW RET ; ; Keyin - get a character into A ; KEYIN: PUSH B PUSH D PUSH H CALL CONIN ;Direct console input POP H POP D POP B RET ; ; UCASE - Convert character in A to uppercase ; UCASE: CPI 'a' RC ;Return if not lower case CPI 'z'+1 RNC ;Return if > lower case z ANI 05FH ;Else change to upper case RET ; ; SMSPEED - Set time to transfer speed ; SMSPEED:LDA MDMSPD ;Get locally stored speed value MOV C,A ;Put in lower half of BC MVI B,0 ;Zap upper half of BC LXI H,XSPDTBL ;Get address of xfer speed table DAD B ;Get address of time for xfer byte MOV A,M ;Get the value STA MSPEED ;Store it RET ; ; Data area ; ; ; XSPDTBL - transfer speed table. The number in parenthesis is the value ; given to MEX. This differs from the actual baud rate in some ; cases due to the baud rates available on the PX-8. ; XSPDTBL:DB 0 ;Unused DB 0 ;110 Baud (110) DB 0 ;150 Baud (110) DB 1 ;300 Baud (300) DB 3 ;800 Baud (600) DB 5 ;1200 Baud (1200) DB 6 ;2400 Baud (2400) DB 7 ;4800 Baud (4800) DB 8 ;9600 Baud (9600) DB 9 ;19200 Baud (19200) EOSMSG: DB ESC,'Y','$' ;clear to end-of-screen CLSMSG: DB ESC,'*','$' ;clear whole screen OCRVAL: DB 0 ;OCR register value MDMTYPE:DB 0 ;modem type, 0FFH=external, 0=internal GOTDISC:DB 0 ;got external disconnect routine, FF=Yes MDMSPD: DS 1 ;current port speed COMDLY: DB 2 ;#secs to wait for , in dial string PENDXOFF: DB 0 ;0FFH if XOFF pending, 0 otherwise STATBLK:DS 9 ;Returned info from RSIOX INSTS call ; ; The following group of data items are for using the slave CPU. ; DO NOT ADD OR REMOVE ANYTHING IN THIS AREA!!! ;---------------Start of slave CPU data------------------ SLVPRAM1: DW ONSNDCMD DW ONSNDLEN DW ONRETVAL DW ONRETLEN ONSNDCMD: DB 072H,080H ONSNDLEN: DB 2 ONRETVAL: DB 1 ONRETLEN: DB 1 SLVPRAM2: DW OFFSDCMD DW OFFSDLEN DW OFFRTVAL DW OFFRTLEN OFFSDCMD: DB 072H,0 OFFSDLEN: DB 2 OFFRTVAL: DB 1 OFFRTLEN: DB 1 ; ;-----------------End of Slave CPU data---------------------- ; ; ;------------------------------------------------------------ ; ; ; Control is passed here after MEX parses a SET command. ; SETCMD: MVI C,SBLANK ;any arguments? CALL MEX JC SETSHO ;if not, go print out values LXI D,CMDTBL ;parse command CALL TSRCH ;from table PUSH H ;any address on stack RNC ;if we have one, execute it POP H ;nope, fix stack SETERR: LXI D,SETEMS ;print error MVI C,PRINT CALL MEX RET ; SETEMS: DB CR,LF,'SET command error',CR,LF,'$' ; ; CMDTBL: DB '?'+80H ;"set ?" DW STHELP DB 'OFFHOO','K'+80H ;"set offhook" DW SETOFF DB 'COM','M'+80H ;"set comm" DW SETCOMM DB 'DELA','Y'+80H ;"set delay" DW SETDLY ; DB 0 ;<<=== table terminator ; ; SET : print current statistics ; SETSHO: CALL CARRSH ;show carrier present/not present LXI H,SHOTBL ;get table of SHOW subroutines SETSLP: MOV E,M ;get table address INX H MOV D,M INX H MOV A,D ;end of table? ORA E RZ ;exit if so PUSH H ;save table pointer XCHG ;adrs to HL CALL GOHL ;do it MVI C,CHEKCC ;check for console abort CALL MEX POP H ;it's done JNZ SETSLP ;continue if no abort RET ; GOHL: PCHL ; ; table of SHOW subroutines ; SHOTBL: DW SHHOOK ; DW SHSTAT DW SHDLY DW 0 ;<<== table terminator ; ; SET ? processor ; STHELP: LXI D,HLPMSG MVI C,PRINT CALL MEX RET ; ; The help message ; HLPMSG: DB CR,LF,'SET command, PX-8 version:',CR,LF,LF DB CR,LF,'SET COMM set/display comm parameters' DB CR,LF,'SET DELAY n set delay for comma in dial string' DB CR,LF,' to n seconds' DB CR,LF,'SET OFFHOOK go offhook' DB CR,LF,'$' ; ; Show carrier status ; CARRSH: CALL CARRCK ;check for it LXI D,NOMESG ;tell about carrier MVI C,PRINT CZ MEX ;print the "NO" if no carrier LXI D,CARMSG ;print "carrier present" MVI C,PRINT CALL MEX RET ; NOMESG: DB 'no $' CARMSG: DB 'carrier present',CR,LF,'$' ; ; check the PX-8 for carrier-present (Z=no) ; CARRCK: MVI B,CTLIN ;get status byte CALL RSIOX ANI DCD ;Check for carrier detect RET ; ; Set OFFHOOK processor ; SETOFF: CALL PDISC ;Disconnect if anything was there CALL PWRON ;Fire up the modem CALL OFFHK SHHOOK: CALL ILPRT DB 'Modem is ',0 LDA OCRVAL ANI OHC JZ SHONHK CALL ILPRT DB 'off-hook',CR,LF,0 RET SHONHK: CALL ILPRT DB 'on-hook',CR,LF,0 RET ; ; Set delay for comma ; SETDLY: MVI C,EVALA ;Get the number CALL MEX MOV A,H ;Validate ORA A JNZ SETERR MOV A,L STA COMDLY ;Store new rate ; ; Show dialing delay ; SHDLY: CALL ILPRT DB 'Delay time for dialing:',0 LDA COMDLY MOV L,A MVI H,0 MVI C,DECOUT CALL MEX CALL ILPRT DB ' seconds',CR,LF,0 RET ; ; Compare next input-stream item in table @DE; CY=1 ; if not found, else HL=matched data item ; TSRCH: MVI C,LOOKUP ;get function code JMP MEX ;pass to MEX processor ; ; SET COMM routines - With thanks to Mike Hoffman and Christopher Rhodes ; of Epson. These are from EPPXMDM3.MAC ; SETCOMM:CALL CLS ;Clear the screen LXI D,MENU MVI C,PRINT CALL MEX ;Display the setup menu ; DISPLAY CURRENT VALUES ON SETUP SCREEN CALL DBAUD CALL DDBITS CALL DPARITY CALL DSTP CALL DMODEM ; GET USERS RESPONSE AND SET PARAMITERS SETUP0: CALL KEYIN CALL UCASE CPI ESC JZ SETUP CPI '9'+1 ;GREATER THAN BAUD SELECTION JNC SDBITS ;CHECK FOR DATA BITS CPI '1' ;LESS THAN 1? JC SETUP0 ;GET ANOTHER RESPONSE ANI 0FH MOV E,A MVI A,10 SUB E STA MDMSPD MOV C,A MVI B,0 LXI H,BAUDTBL DAD B MOV A,M STA BAUDRATE CALL DBAUD JMP SETUP0 SDBITS: CPI 'B'+1 ;GREATER THAN DATA BITS JNC SPARITY ;CHECK FOR PARITY CPI 'A' ;LESS THAN 'A' JC SETUP0 ;GET ANOTHER RESPONSE SUI 3FH ;MAKE 2 OR 3 STA DBITS CALL DDBITS JMP SETUP0 SPARITY:CPI 'E'+1 ;GREATER THAN PARITY JNC SSTOP ;CHECK FOR STOP BITS SUI 'C' SPAR1: STA PARBITS CALL DPARITY JMP SETUP0 SSTOP: CPI 'G'+1 ;GREATER THAN STOP BITS JNC SMOD ;CHECK FOR MODEM SUI 'F'-1 CPI 1 JZ SSTOP1 ADI 2 SSTOP1: STA STP CALL DSTP JMP SETUP0 SMOD: CPI 'I'+1 ;GREATER THAN BAUD JNC SETUP0 ;BAD SELECTION GET ANOTHER RESPONSE SUI 'H' JZ SMOD1 CALL PWRON ;Try to turn the modem on IN STR ;Read status register ANI MII ;Is modem installed? JNZ SMOD2 MVI A,0FFH SMOD1: STA MDMTYPE CALL DMODEM JMP SETUP0 SMOD2: MVI A,BELL CALL TYPE SMOD3: LXI B,0201H CALL PLACECUR CALL ILPRT DB TAB,'*** NO MODEM ***',0 XRA A STA MDMTYPE CALL DMODEM JMP SETUP0 ; ; Display baud rate ; DBAUD: LXI B,30DH CALL PLACECUR LXI H,BAUDSPD MVI D,0 LDA MDMSPD ;get baud rate code CPI 0FFH RZ ;unknown baud rate MOV E,A ;x1 ADD A ;x2 ADD A ;x4 ADD E ;x5 ADD E MOV E,A DAD D ;point to correct rate XCHG MVI C,PRINT CALL MEX CALL ILPRT DB ' bps ',CR,LF,0 RET ; ; Display data bits ; DDBITS: LXI B,50DH CALL PLACECUR LDA DBITS CPI 2 MVI A,'7' JZ DDBITS1 MVI A,'8' DDBITS1:CALL TYPE RET ; ; Display parity ; DPARITY:LXI B,60DH CALL PLACECUR LDA PARBITS ORA A JNZ DPAR1 CALL ILPRT DB 'none',0 RET DPAR1: CPI 1 JNZ DPAR2 CALL ILPRT DB 'odd ',0 RET DPAR2: CALL ILPRT DB 'even',0 RET ; ; Display stop bits ; DSTP: LXI B,70DH CALL PLACECUR LDA STP CPI 1 MVI A,'1' JZ DSTP1 MVI A,'2' DSTP1: CALL TYPE RET ; ; Display modem type ; DMODEM: LXI B,80DH CALL PLACECUR LDA MDMTYPE ORA A JNZ DMODEM1 CALL ILPRT DB 'external',0 RET DMODEM1:CALL ILPRT DB 'internal',0 RET SETUP: CALL STPORT ;Set up for internal mode just in case CALL SMSPEED ;Set time to xfer speed LDA MDMTYPE ;See what kind of modem we're using INR A ;If FF, then it's internal JZ SETUP1 ;yep, it's internal CALL RESPORT ;Using external, do setup SETUP1: LXI H,PARAMS LXI D,WIPEOUT LXI B,9 DB 0EDH,0B0H ;LDIR MVI B,CLSIOX CALL RSIOX ; close port first MVI B,OPNIOX LXI H,WIPEOUT CALL RSIOX ; open with new parameters CALL CLS CALL ILPRT DB ESC,CURON DB CR,LF,LF,LF DB TAB,'Communication initialization completed.',CR,LF,0 RET BAUDSPD: DB '50 $110 $150 $300 $600 $' DB '1200 $2400 $4800 $9600 $19200$' BAUDTBL: DB 0FFH ; 50 baud not supported DB 2 ; 110 baud DB 4 ; 150 baud DB 6 ; 300 baud DB 8 ; 600 baud DB 0AH ; 1200 baud DB 0CH ; 2400 baud DB 0DH ; 4800 baud DB 0EH ; 9600 baud DB 0FH ; 19.2 baud MENU: DB ESC,CUROFF DB ' Select alphanumeric or ESC to return.',CR,LF,LF DB 'bit rate : 1=19200 2=9600 3=4800 4=2400' DB ' 5=1200',CR,LF DB ' 6=600 7=300 8=150 9=110',CR,LF DB 'data bits : A=7 B=8',CR,LF DB 'parity : C=none D=odd E=even',CR,LF DB 'stop bits : F=1 G=2',CR,LF DB 'modem type: H=external I=internal$' PARAMS: DW INTBUF DW INTBUFL BAUDRATE: DS 1 DBITS: DS 1 PARBITS: DS 1 STP: DS 1 SPECIAL: DB 0FFH ;Not XON/XOFF, not SI/SO, DTR on, RTS on WIPEOUT:DS 9 ; this area gets overwritten by BIOS call COPYRITE: DB 'Copyright (C) 1985 by David B. Kozinn' ; ;------------------------------------------------------------ ; ; End of PX-8 MEX modem overlay ; ;------------------------------------------------------------ ; END