Title 'MEX overlay for the PMMI version 2.2' ; ; Ignore the Title error message if using ASM. ; REV equ 22 ; overlay revision number LVL equ 'c' ; overlay level ( as in Revision 2.2a ) ; ; MEX PMMI OVERLAY VERSION 1.0: written 04/27/84 by Ron Fowler ; ; " " " " 2.0: generally rewritten 9/18/84 by Fred M. Spinner ; " " " ' 2.1: rewritten 09/27/84 by Bill Norris ; " " " " 2.2: " 10/30/84 by Bill Norris ; ; ; Version 2.2 notes: Added 'SET EXTRA' command. This is a toggle ; that allows you to see on the console when ; certain overlay functions are invoked. ; Corrected a minor bug in the clear screen and ; clear to end of screen functions. ; Added 15 to SET PPS command. ; Added SET ONLINE ( SET OFFHOOK synonym ) ; OFF-HOOK and ON-HOOK have been changed from ; scattered in-line calls to subroutines. ; Renamed SET FIDGET to SET ICD (intercall delay) ; Renamed SET IDG to SET IDD (interdigit delay) ; The default PMMI base port was changed to 80h ; in version 2.1 due to conflicts with several ; disk controller boards. If your PMMI is not ; addressed at this port, just use the SET BASE ; command (and CLONE) if you don't want to edit ; and re-assemble this file. ; Speeded up keyboard abort (^X and ^C). ^S also ; accepted here (during dialing of a number). ; Phone number '#' is replaced at dial time from ; the keyboard. ; ; ; Version 2.1 notes: Unifies scattered PMMI I/O; allows modification ; of the PMMI base port with SET BASE command. ; No PMMI I/O is done in-line. It is all done ; using subroutine calls. This should make all ; modifications simpler (including future ; changes to support MEX 2.x). ; Base port address is printed in signon message. ; SET FIDGET added (delay between calls). ; BASE/FIDGET changes are preserved through CLONEs. ; Uses BDOS 6 to force BUSY instead of using hard ; coded keyboard I/O for the CTRLX function. (See ; description in Version 2.0 notes below). ; ; ; Version 2.0 9/18/84: Numerous bugs repaired. The offhook command ; now actually takes the modem off hook. The DTR bytes were swapped ; in 1.1 so that baud rates over 300 would barf. This has been repaired ; The SET MODE command is no longer available. Use SET ORIG, ORG, or ; ORIGINATE and SET ANS or ANSWER to switch modes. The actual routine ; to switch modes has been re-written from scratch, also. Overlay version ; message more verbose (better looking, also) now. If your know your ; keyboard (terminal)'s Status and Data Port and also know the value ; (bit) to check for for keyboard input, you can also implement the CTRLX ; feature which is handy to have if you know a number is busy and you ; want to call the next, etc. without further delays. The keyboard info ; goes under KSTAT, KPORT, KBIT, and KVAL which mean Keyboard/Terminal status ; port, Keyboard data port, AND bit to status input, and value to check for ; after status is ANDed, respectively. Set CTRLX to YES if you have ; this information and want to use this feature, or set it to NO to use ; the standard MEX keyboard trap. ; ; Fred M. Spinner ; ; ; (V1.1) 05/17/84 (Jim Byram) : Small bugs repaired. Answer-mode ; bit (ANBIT) and originate-mode bit (ORBIT) were reversed; fixed ; SET MODE help message. ; ; This is a MEX overlay file for the PMMI modem. You can use it as ; a model for designing your own modem overlay (or you can use any ; existing MDM7 overlay, if available). ; ; If you use this as a template for writing your own overlay, and ; distribute it to others, please pare down these comments as much ; as possible (to keep the overlays small). I'll maintain this file ; with as many notes and references as possible, but this will hope- ; fully be the only "big" overlay. ; ; There are advantages to recoding your overlay to conform to the ; techniques presented here: MEX 2.0 will likely have a much simpler ; overlay structure; if you stick to the label names and coding ; suggestions used here, you'll easily be able to follow the overlay ; upgrade instructions when MEX 2.0 hits the streets. Also, you can ; make use of the MEX service processor to write a very versatile ; SET command (as done here). ; ; Note that all overlays may freely use memory up to 0CFFH. If your ; overlay must work with the MEX Smartmodem overlay (MXO-SMxx.ASM), ; the physical modem overlay should terminate by 0AFFH. ; ; For purposes of example, this is a "full-featured" MEX overlay. In ; practice, your overlay may be much simpler (all that is really re- ; quired is the modem I/O code; fancy stuff like the SET command, and ; even the disconnect routine, may be left open. You will need DIAL ; code, though, unless your modem doesn't support autodialing). ; ;------------------------------------------------------------ ; ; Misc equates ; NO equ 0 YES equ 0FFh TPA equ 100h CR equ 13 LF equ 10 BS equ 8 TAB equ 9 ESC equ 27 CTRLX equ YES ;YES, if use ^X for fake "BUSY" CONTX equ 'X'-40h ; ; Equates used only by PMMI routines grouped together here. ; ; ; PMMI port definitions ; PORT equ 080h ;PMMI base port (data or status) ; PORT now also used by NITMOD. MODCT1 equ 0 ;modem control port (added to base port). MODDAT equ MODCT1+1 ;modem data port " BAUDRP equ MODCT1+2 ;modem baud rate port " MODCT2 equ MODCT1+3 ;modem status port " ; ; PMMI bit definitions ; MDRCVB equ 02h ;modem receive bit (DAV) MDRCVR equ 02h ;modem receive ready MDSNDB equ 01h ;modem send bit MDSNDR equ 01h ;modem send ready bit ; ; CTSMSK equ 4 ;mask for CTS bit BRKMSK equ 0FBh ;mask to set break PARMSK equ 0CFh ;mask to remove parity bits OPARIT equ 00h ;odd-parity bits EPARIT equ 20h ;even-parity bits NPARIT equ 10h ;no-parity bits MODEMK equ 0FCh ;mode mask ANMODE equ 1Eh ;answer mode ANBIT equ 2 ;answer-mode bit ORIGMD equ 1Dh ;originate mode ORBIT equ 1 ;originate-mode bit WTCTS equ 150 ;number of seconds (x5) to wait for the ;computer to answer after PMMI auto-dial ;100=20 sec, 150=30 sec, 255=51 sec. ;any number 0-255 acceptable ; ; ; Modem control command words ; BRKMASK equ 0 ;tele line on hook (break while dialing) CLEAR equ 3Fh ;idle mode DTMSK equ 1 ;dial tone mask MAKEM equ 1 ;tele line make (off hook) RBLMT equ 35 ;7 seconds to wait til no-ring-heard msg RBWAIT equ 50 ;5 second delay before redialing PMMI SMRWT equ 15 ;1.5 sec delay before redialing HAYES TMPUL equ 80h ;timer pulses mask bit TRATE equ 250 ;value for 0.1 second ; ; ; MEX service processor stuff ... MEX supports an overlay service ; processor, located at 0D00H (and maintained at this address from ; version to version). If your overlay needs to call BDOS for any ; reason, it should call MEX instead; function calls below about ; 240 are simply passed on to the BDOS (console and list I/O calls ; are specially handled to allow modem port queueing, which is why ; you should call MEX instead of BDOS). MEX uses function calls ; above about 244 for special overlay services (described below). ; ; Some sophisticated overlays may need to do file I/O; if so, use ; the PARSFN MEX call with a pointer to the FCB in DE to parse out ; the name. This FCB should support a spare byte immediately pre- ; ceeding the actual FCB (to contain user # information). If you've ; used MEX-10 for input instead of BDOS-10 (or you're parsing part ; of a SET command line that's already been input), then MEX will ; take care of DU specs, and set up the FCB accordingly. There- ; after all file I/O calls done through the MEX service processor ; will handle drive and user with no further effort necessary on ; the part of the programmer. ; 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 ; ; CONOUT equ 2 ;simulated BDOS function 2: console char out PRINT equ 9 ;simulated BDOS function 9: print string INBUF equ 10 ;input buffer, same structure as BDOS 10 ; 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 YES ;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 55 ;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 5 ;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 5 ;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 NO ;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 YES ;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 NO ;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 PRATE: db 167 ;125=20pps dialing, 250=10pps db 0 ;not used ; ; Low-level modem I/O routines: this will be replaced with ; a jump table in MEX 2.0 (you can insert jumps here to longer ; routines if you'd like ... I'd recommend NOT putting part of ; a routine in this area, then jumping to the rest of the routine ; in the non-fixed area; that will complicate the 2.0 conversion) INCTL1: jmp iCTL1 ;in modem control port db 0,0,0,0,0,0,0 OTDATA: jmp oDATA db 0,0,0,0,0,0,0 INPORT: jmp iDATA db 0,0,0,0,0,0,0 ; Bit-test routines. These will be merged with the above ; routines in MEX 2.0 to provide a more reasonable format ; MASKR: ani MDRCVB ;bit to test for receive ready ret TESTR: cpi MDRCVR ;value of receive bit when ready ret MASKS: ani MDSNDB ;bit to test for send ready ret TESTS: cpi MDSNDR ;value of send bit when ready ret ; ; 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 jump table: if your overlay cannot handle ; some of these, change the jump to "DS 3", so the code present in ; MEX will be retained. Thus, if your modem can't dial, change the ; JMP PDIAL at DIALV to DS 3, and MEX will print a "not-implemented" ; diagnostic for any commands that require dialing. ; ; DIALV dials the digit in A. See the comments at PDIAL for specs. ; ; DISCV disconnects the modem ; ; GOODBV is called just before MEX exits to CP/M. If your overlay ; requires some exit cleanup, do it here. ; ; INMODV is called when MEX starts up; use INMODV to initialize the modem. ; ; NEWBDV is used for phone-number baud rates and is called with a baud-rate ; code in the A register, value as follows: ; ; A=0: 110 baud A=1: 300 baud A=2: 450 baud ; A=3: 600 baud A=4: 710 baud A=5: 1200 baud ; A=6: 2400 baud A=7: 4800 baud A=8: 19200 baud ; ; If your overlay supports the passed baud rate, it should store the ; value passed in A at MSPEED (107H), and set the requested rate. If ; the value passed is not supported, you should simply return (with- ; out modifying MSPEED) -or- optionally request a baud-rate from the ; user interactively. ; ; NOPARV is called at the end of each file transfer; your overlay may simply ; return here, or you may want to restore parity if you set no-parity ; in the following vector (this is the case with the PMMI overlay). ; ; PARITV is called at the start of each file transfer; your overlay may simply ; return here, or you may want to enable parity detection (this is the ; case with the PMMI overlay). ; ; SETUPV is the user-defined command ... to use this routine to build your own ; MEX command, set the variable SETFL (117H) non-zero, and add your SET ; code. You can use the routine presented in the PMMI overlay as a ; guide for parsing, table lookup, etc. ; ; SPMENU is provided only for MDM compatibility, and is not used by MEX 1.0 for ; any purpose (it will be gone in MEX 2). ; ; VERSNV is called immediately after MEX prints its sign-on message at cold ; startup -- use this to identify your overlay in the sign-on message ; (include overlay version number in the line). ; BREAKV is provided for sending a BREAK (<ESC>-B in terminal mode). If your ; modem doesn't support BREAK, or you don't care to code a BREAK rou- ; tine, you may simply execute a RET instruction. ; 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: jmp DUMMY ;called before exit to CP/M INMODV: jmp NITMOD ;initialization. Called at cold-start NEWBDV: jmp PBAUD ;set baud rate NOPARV: jmp NOPAR ;set modem for no-parity PARITV: jmp PARITY ;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 ; ; The following jump vector provides the overlay with access to special ; routines in the main program (retained and supported in the main pro- ; gram for MDM overlay compatibility). These should not be modified by ; the overlay. ; ; Note that for MEX 2.0 compatibility, you should not try to use these ; routines, since this table will go away with MEX 2.0 (use the MEX ; service call processor instead). ; 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). ; ; These routines (and other screen routines that MEX 2.0 will sup- ; port) will be accessed through a jump table in 2.0, and will be ; located in an area that won't tie the screen functions to the ; modem overlay (as the MDM format does). ; CLREOS: lxi h,SCRTST lxi d,EOSMSG jmp PRMAYBE CLS: lxi h,SCRTST lxi d,CLSMSG jmp PRMAYBE ; ;------------------------------------------------------------ ; ; *** END OF FIXED FORMAT AREA *** ; ;------------------------------------------------------------ ; ; Data area ERRFLG: db 0 ;connection error code UCTLB: db ORIGMD ;uart-control byte image BAUDSV: db 52 ;current baud rate (dflt 300) MODCTB: db 07FH ;modem control byte INTERD: db 2 ;inter-digit delay in 100's of ms PRXTRA: db YES ; Diagnostic prints upon function usage WTNUM: db WTCTS ; OFFHK: db 0 ; ; BPTAB: db '0123456789ABCDEF', 80h NITBYT: db PORT ; Should be the PMMI base port. Original port ; is C0 hex. Recommended alternate is 80 hex. DIALFLG: db 0 ; ABOBYT: db 0 ; TEMP: dw 0 ; PRMAYBE: mov a,m ora a rz PRMBOK: mvi c,PRINT jmp MEX iCTL1: mvi a,MODCT1 jmp BPIN iCTL2: mvi a,MODCT2 jmp BPIN iDATA: mvi a,MODDAT ;in modem data port jmp BPIN iBDRP: mvi a,BAUDRP jmp BPIN oCTL1: push psw mvi a,MODCT1 jmp BPOUT oCTL2: push psw mvi a,MODCT2 jmp BPOUT oDATA: push psw ;out modem data port mvi a,MODDAT jmp BPOUT oBDRP: push psw mvi a,BAUDRP jmp BPOUT BPIN: push b mov b,a lda NITBYT add b sta BPINX+1 BPINX: in $-$ pop b ret BPOUT: push b mov b,a lda NITBYT add b sta BPOUTX+1 pop b pop psw BPOUTX: out $-$ ret ; Modem initialization. This overlay doesn't do any initialization. ; (if we did, we'd disconnect a call already in progress). NITMOD: lda NITBYT ; Convert hex byte to ascii nibble. rar rar rar rar ani 0Fh mvi d,0 mov e,a lxi h,BPTAB dad d mov a,m sta BPMSG ; Store base port in sign-on message. mvi a,LVL sta LEVEL ret ; PMMI send-break routine PBREAK: lda MODCTB ;get the last modem control byte ani BRKMSK ;set the transmit break bit low call oCTL2 ;send it to the modem mvi b,2 call TIMERV ;send a space tone for 200 ms. lda MODCTB ;get the last modem control byte call oCTL2 ;restore to normal lxi h,PRXTRA lxi d,BRKMSG jmp PRMAYBE BRKMSG: db '.break. $' ; Setup PMMI for odd/even parity. PARITY: lda UCTLB ;send what's in the image byte jmp oCTL1 ; set no-parity NOPAR: lda UCTLB ;get uart/modem control byte ani PARMSK ;reset parity bits ori NPARIT ;add no-parity bits jmp oCTL1 ; disconnect the modem PDISC: call HUKONN ; Hang up call oCTL2 ; clear DAV, ESD, etc push b ; lxi h,PRXTRA ; lxi d,DSC1MSG ; call PRMAYBE ; mvi b,20 ;wait for PMMI to disconnect (2 sec) %%* 1 to 2 mvi c,TIMER ;0.1 second per timer interval call MEX ; lxi h,PRXTRA ; lxi d,DSC2MSG ; call PRMAYBE ; pop b ; ret ; DSC1MSG: db '.di$' DSC2MSG: db 'sc. $' ; exit routine DUMMY: ret ;we don't need one ; ; ;------------------------------------------------------------ ; ; <PMMI DIALING ROUTINES BEGIN> ; ; This is the DIAL routine called by MEX to dial a digit. The digit ; to be dialed is passed in the A register. Note that two special ; codes must be intercepted as non-digits: 254 (start dial sequence) ; and 255 (end-dial sequence). Mex will always call DIAL with 254 ; in the accumulator prior to dialing a number. Mex will also call ; dial with 255 in A as an indication that dialing is complete. Thus, ; the overlay may use these values to "block" the number, holding it ; in a buffer until it is completely assembled (we don't do this with ; the PMMI, however; we just dial the digits as they come in). ; ; After the 254-start-dial sequence, MEX will call the overlay with ; digits, one-at-a-time. MEX will make no assumptions about the dig- ; its, and will send each to the DIAL routine un-inspected (some modems, ; like the Smartmodem, allow special non-numeric characters in the ; phone number, and MEX may make no assumptions about these). This ; dialing routine validates digits, and ignores any except 0-9 and ; comma (uses comma to simulate Smartmodem delay). ; ; After receiving the end-dial sequence (255) the overlay must take ; whatever end-of-dial actions are necessary *including* waiting for ; carrier at the distant end. The overlay should monitor the keyboard ; during this wait (using the MEX keystat service call), and return ; an exit code to MEX in the A register, as follows: ; ; 0 - Carrier detected, connection established ; 1 - Far end busy (only for modems that can detect this condition) ; 2 - No answer (or timed out waiting for modem response) ; 3 - Keyboard abort (^C only: all others should be ignored) ; 4 - Error reported by modem ; ; <No other codes should be returned after an end-dial sequence> ; ; The overlay should not loop forever in the carrier-wait routine, but ; instead use either the overlay timer vector, or the INMDMV (timed 100 ; ms character wait) service call routine. ; ; The DIAL routine is free to use any of the registers, but must return ; the above code after an end-dial sequence ; ; PDIAL: cpi 254 ;start-dial? jz STDIAL ; cpi 255 ;end-dial jz ENDIAL ; ; push psw ; mvi a,7 ; sta DIALFLG ; pop psw ; ; PDIAL1: cpi ',' ;smartmodem pause command jnz PDIAL2 ;if not pause, continue mvi b,10 ;delay 1 second jmp TIMOUT ; PDIAL2: cpi '#' ; jnz CKDIG ; mvi a,BS ; call PUT1C ; PDIAL3: call GET1C ; jz PDIAL3 ; call PUT1C ; jmp PDIAL1 ; CKDIG: cpi '9'+1 ; digits are 0-9 rnc ; too big... sui '0' ; rc ; too small.... jnz DIALIT ; just right... mvi a,10 ; convert zero to 10 pulses ; Send a digit to the modem. DIALIT: mov c,a ; save the digit lda ERRFLG ; before we try to dial... ora a ; ...check dialtone error flag rnz ; ...if no DT, exit now lda PRATE ; value for dial speed call oBDRP ; call WAITLO ; wait for timer lo call WAITHI ; wait for timer hi call GET1C ; DIAL1: cpi 3 ; ^C ? jz DIALX ; cpi 24 ; ^X ? jz DIALX ; cpi 19 ; ^S ? jnz DIGLP ; DIALP: call GET1C ; Wait for a character jz DIALP ; cpi 19 ; jmp DIGLP ; ; DIALX: sta ABOBYT ; DIGLP: lda ABOBYT ; ora a ; jnz DIGLP2 ; ; call HUKOFF ; Go off-hook call WAITLO ; call HUKONN ; call WAITHI ; DIGLP2: dcr c ; jnz DIGLP ; send rest of digit lda ABOBYT ; ora a ; rnz ; ; call HUKOFF ; lda INTERD ; get inter-digit delay mov b,a ; jmp TIMOUT ; ; Wait for negative edge of timer pulse WAITLO: call iBDRP ani TMPUL jnz WAITLO ret ; Wait for positive edge of timer pulse WAITHI: call iBDRP ani TMPUL jz WAITHI ret ; Start-dial sequence: disconnect, wait for dial-tone STDIAL: xra a ; reset error flag sta ERRFLG ; call PDISC ; on-hook call HUKOFF ; call PROFFH ; (possibly) print .off hook. message ; Wait routine will return with carry set if unable to get dialtone. mvi d,DTMSK ;dial tone mask mvi e,50 ;waits up to 10 sec. for dial tone call WAIT ;wait for dial tone rnc ;if dial tone within 10 seconds sta ERRFLG ;(action on error deferred until call PDISC ;no tone, hang up ret ; dialing is completed) ; End-dial sequence ENDIAL: call ENDIT ;close out dialing push psw ; xra a ; sta DIALFLG ; sta ABOBYT ; pop psw ; ora a ;successfully connected? rz ;exit now if so push psw ;nope, save the error code call PDISC ;shut down the modem pop psw ; ret ; ENDIT: lda ERRFLG ;no-dialtone error from STDIAL? ora a rnz ;if so, return the error here call OFF ;go off-hook lda UCTLB ;get uart/modem control byte call oCTL1 ;send it mvi d,4 ;clear-to-send mask ; lda WTNUM ; mov e,a ; call WAIT ; rnc ;return A=0 if good ; cpi 'C'-40h ;keyboard abort? rz ;if so return it ; if CTRLX ; cpi 1 ;Fake busy? rz ;Return if so endif ;CTRLX ; mvi a,2 ;nope, convert error to "no answer" ret ; ; <end of PMMI dialing routines> ;------------------------------------------------------------ ; Go Off-Hook OFF: lda BAUDSV ;set current baud rate call oBDRP ; lda MODCTB ;Load current DTR call oCTL2 ; call HUKOFF ; lda UCTLB ; call oCTL1 ; mvi b,2 ;wait 200 ms %%* changed from 1 to 2. call TIMOUT ; lda DIALFLG ; ora a ; jz PRONLN ; xra a ; sta DIALFLG ; PRWAIT: lxi h,PRXTRA ; lxi d,WAITMSG ; jmp PRMAYBE ; PROFFH: lxi h,PRXTRA ; lxi d,OFFHMSG ; jmp PRMAYBE ; PRONLN: lxi h,PRXTRA ; lxi d,ONLNMSG ; jmp PRMAYBE ; OFFHMSG: db '.off-h. $' ; Force PMMI to on-line status. ONLNMSG: db '.on-line. $' ; Force PMMI to on-line status. WAITMSG: db '.wait. $' ; Force PMMI to " " and wait ; for either a carrier or timeout. HUKOFF: mvi a,255 ; Go Off-Hook sta OFFHK ; mvi a,MAKEM ; jmp oCTL1 ; HUKONN: xra a ; Go On-Hook sta OFFHK ; mvi a,BRKMASK ; jmp oCTL1 ; ; Time-out routine. Must be called with mask in D reg. for input at ; relative port 2 and number of seconds (times 10) in E reg. WAIT: mvi b,2 ; 200 ms call TIMOUT ; wait for timer to go high then low call iBDRP ; pmmiaddr+2 (modem status port) ana d ; (cts or dialtone mask) rz ; active low, so return on 0 if not CTRLX ; mvi c,CHEKCC ;not yet, check for console-abort call MEX ;abort? mvi a,3 ;set error code 3 if abort active stc ; rz ;return if aborted endif ;not CTRLX if CTRLX ; lda ABOBYT ; ora a ; jz WAIT0 ; push psw ; xra a ; sta ABOBYT ; pop psw ; jmp WAIT1 ; WAIT0: call GET1C ; jz WAITOR ; ; WAIT1: cpi CONTX ;'^X?' jnz WAIT2 ;no, check for ^C call GET1C ;Clear out garbage mvi a,1 ;yes, return fake error code stc ; ret ; WAIT2: cpi 3 ;Duplicate MEX ^C trap jnz WAITOR ;Not ^C, continue call GET1C ;Clear out garbage mvi a,3 ;"ABORT" error stc ;Yes, pass error ret ;code and return endif ;CTRLX WAITOR: dcr e ; jnz WAIT ; nope, downcount inr a ; set error=4 (modem error); cy already set ret ; GET1C: push h push d push b mvi c,6 mvi e,0FFh call 5 pop b pop d pop h ani 7Fh ret PUT1C: push h push d push b mvi c,6 mov e,a call 5 pop b pop d pop h ret ; Set baud-rate code in A (if supported by your modem overlay). PMMI ; supports only five rates, which are validated here. NOTE: this routine ; (ie, the one vectored through NEWBDV) should update MSPEED with the ; passed code, but ONLY if that rate is supported by the hardware. PBAUD: push h ;don't alter anybody push d push b mov e,a ;code to DE mvi d,0 lxi h,BAUDTB ;offset into table dad d mov a,m ;fetch code ora a ;0? (means unsupported code) stc ;return error for STBAUD caller jz PBEXIT ;exit if so call oBDRP ;good rate, set it sta BAUDSV ;save it mov a,e ;get speed code back sta MSPEED ;make it current call GETDTR ;get correct DTR based on baud rate sta MODCTB ;save the code call CARRCK ;is a connection in progress? jnz PBEXIT ;skip this if not lda MODCTB ;yep, set up DTR call oCTL2 PBEXIT: lxi h,PRXTRA lxi d,BDSTMSG call PRMAYBE pop b ;all done pop d pop h ret BDSTMSG: db '.bd-rt. $' ; table of baud rate divisors for supported rates BAUDTB: db 142,052,035,026,022 ;110,300,450,610,710 db 0,0,0,0,0 ;1200,2400,4800,9600,19200 ; Sign-on message SYSVER: lxi d,LINMSG mvi c,PRINT call MEX lxi d,SOMESG mvi c,PRINT call MEX lxi d,bpmess mvi c,PRINT call MEX CARRSH: lxi d,NOMESG ;tell about carrier call CARRCK ;check for it mvi c,PRINT cz CMSG cnz MEX lxi d,LINMSG mvi c,PRINT call MEX lxi d,GRBMSG mvi c,PRINT call MEX ret CMSG: push psw mvi c,PRINT lxi d,CARMSG call MEX pop psw ret SOMESG: db '* PMMI overlay version - ' db REV/10+'0' db '.' db REV MOD 10+'0' LEVEL: db ' *',CR,LF,'$' BPMESS: db '* Base port = ' BPMSG: db 'x0 hex. *' NLMSG: db cr,lf,'$' NOMESG: db '* No carrier present. *$' CARMSG: db '* Carrier IS present. *$' LINMSG: db CR,LF,'********************************',CR,LF,'$' GRBMSG: db CR,LF,'$' ; ; ; get DTR port value based on baud rate ; GETDTR: lda BAUDSV cpi 52 ;>300? mvi a,05Fh ;set speed configuration (ARRRRRRGGGGHHHH.) rc ;done if so (Swapped in version 2.0) mvi a,07Fh ;reset speed config bit (ARRRRRRGGGGGHHHH.) ret ; check the PMMI for carrier-present (NZ=no) CARRCK: call iBDRP ;get status byte ani CTSMSK rnz push psw mvi a,255 sta OFFHK pop psw ret ; Newline on console CRLF: mvi a,CR call TYPE mvi a,LF ;fall into TYPE ; type char in A on console TYPE: push h ;save 'em push d push b mov e,a ;align output character mvi c,CONOUT ;print via MEX call MEX pop b pop d pop h ret ; strings to clear-to-end-of-screen, and clear-screen ; Note: these are dummy strings, not intended to be displayed... EOSMSG: db ' -clr eos- $' ;clear to end-of-screen CLSMSG: db ' -clr all- $' ;clear whole screen ; ;------------------------------------------------------------ ; ; The remainder of this overlay implements a very versatile ; SET command -- if you prefer not to write a SET for your ; modem, you may delete the code from here to the END statement. ; ; ; 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,'$' ; ; SET command table ... note that tables are constructed of command- ; name (terminated by high bit=1) followed by word-data-value returned ; in HL by MEX service processor LOOKUP. Table must be terminated by ; a binary zero. ; ; Note that LOOKUP attempts to find the next item in the input stream ; in the table passed to it in HL ... if found, the table data item is ; returned in HL; if not found, LOOKUP returns carry set. ; CMDTBL: db '?'+80h ; "set ?" dw STHELP ; db 'BAU','D'+80h ; "set baud" dw STBAUD ; db 'ID','D'+80h ; "set id" dw SETIDD ; db 'ANSWE','R'+80h ; "set answer" dw STANSW ; db 'AN','S'+80h ; "set ans" (same as above) dw STANSW ; db 'ORIGINAT','E'+80h ; "set originate" dw STORIG ; db 'ORI','G'+80h ; "set orig" (same as above) dw STORIG ; db 'OR','G'+80h ; "set org" (same as above) dw STORIG ; db 'OFFHOO','K'+80h ; "set offhook" dw OFF ; db 'ONLIN','E'+80h ; "set online" (same as offhook) dw OFF ; db 'ONHOO','K'+80h ; "set onhook" dw PDISC ; db 'OFFLIN','E'+80h ; "set offline" (same as onhook) dw PDISC ; db 'PP','S'+80h ; "set pps" dw SETPPS ; db 'BAS','E'+80h ; "set PMMI base port." dw SETBP ; db 'IC','D'+80h ; "set delay between calls" dw SETICD ; db 'EXTR','A'+80h ; "set extra print mode" dw SETXTRA ; db 'XYZZ','Y'+80h ; dw XYZZY ; ; db 0 ; <<=== table terminator ; ; SET <no-args>: print current statistics ; SETSHO: call SYSVER ;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 call CRLF ;print newline mvi c,CHEKCC ;check for console abort call MEX pop h ;it's done jnz SETSLP ;continue if no abort call CRLF ret GOHL: pchl ; table of SHOW subroutines SHOTBL: dw BDSHOW dw MDSHOW dw SHOICD dw SHOIDD dw SHOPPS dw SHOXTRA dw CRLF 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, for the PMMI S-100 modem (r.i.p.)' db cr,lf db cr,lf,'SET ANSWER <or> SET ANS ... put PMMI in answer mode' db cr,lf,'SET BASE <hex #> ... set new PMMI base port' db cr,lf,'SET BAUD <value> ... set baud rate' db cr,lf,' BAUD values allowed are: 110, 300, 450, 600, and 710' db cr,lf,'SET EXTRA <value> ... OFF if <value> == 0, else ON' db cr,lf,' EXTRA function diagnostics displayed: BAUD RATE, BREAK,' db cr,lf,' DISCONNECT, OFF-HOOK, and WAIT (for answer tone)' db cr,lf,'SET ICD <value>' db ' ... intercall delay; 150 == 30 seconds' db cr,lf,'SET IDD <value> ... interdigit delay in 100''s msec' db cr,lf,'SET OFFHOOK <or> SET ONLINE ... force PMMI online' db cr,lf,'SET ONHOOK <or> SET OFFHOOK ... disconnect without message' db cr,lf,'SET ORIGINATE <or> SET ORIG ... put PMMI in originate mode' db cr,lf,'SET PPS <value> ... may be 10, 15 or 20 pulses/sec.' db cr,lf db cr,lf, '$' ; SET BAUD processor STBAUD: mvi c,BDPARS ;function code call MEX ;let MEX look up code jc SETERR ;invalid code call PBAUD ;no, try to set it jc SETERR ;not-supported code BDSHOW: call ILPRT ;display baud db 'Baud rate: ', tab, ' ', 0 lda MSPEED mvi c,PRBAUD ;use MEX routine call MEX ret ; SET MODE processor MDSHOW: call ILPRT ;show mode db 'Mode:', tab, tab, ' ', 0 lda UCTLB ;get UART B image ani ORBIT ;orig? jz MDORIG call ILPRT db 'Originate', 0 ret MDORIG: call ILPRT db 'Answer', 0 ret STORIG: mvi l,ORBIT jmp CHGAO STANSW: mvi l,ANBIT CHGAO: lda UCTLB ani MODEMK ora l sta UCTLB call OHKBYT jnz MDSHOW call oCTL1 call OFF jmp MDSHOW OHKBYT: lda OFFHK cma ora a ret ; ; SET PPS command processor ; SETPPS: lxi d,PPSTBL ;get value call TSRCH jc SETERR ;not found in table? error out mov a,l ;yep, set it sta PRATE SHOPPS: call ILPRT db 'PPS rate: ', tab, ' ', 0 lda PRATE ;display PPS cpi 250 jnz SHO2 call ILPRT db '10', 0 ret SHO2: cpi 125 jnz SHO3 call ILPRT db '20',0 ret SHO3: call ILPRT db '15',0 ret PPSTBL: db '1','0'+80H ;"set pps 10" dw 250 db '1','5'+80h ;"set pps 15" dw 167 db '2','0'+80H ;"set pps 20" dw 125 db 0 ;<<=== table terminator ; ; SET IDIG command processor ; SETIDD: mvi c,EVALA call MEX ;get numeric mov a,h ;validate ora a jnz SETERR mov a,l sta INTERD ;set new rate SHOIDD: call ILPRT db 'Inter-digit delay: ', 0 lda INTERD ;get value mov l,a ;move delay to HL mvi h,0 mvi c,DECOUT ;print it call MEX call ILPRT db '00 ms',0 ret ; Set BASE PORT command processor. SETBP: mvi c,SBLANK call MEX mvi c,GNC ;get char from input, cy=1 if none call MEX call UPPER mov l,a ; Character to test is in L. shld TEMP lxi b,BPTAB-1 lxi d,10h lxi h,-10h SETLP: inx b ; Advance to next allowable character. dad d ; Add 10 hex to base port address. ldax b ; ora a ; jm SETNG ; Jump if character typed not in allowable set. push h ; lhld TEMP ; cmp l ; Valid port requested? shld TEMP ; pop h ; Restore new base port. jnz SETLP ; No match, try again. sta BPMSG ; Patch sign-on message with Port # (ascii). mov a,l ; sta NITBYT ; Save base port (hex) for I/O and for CLONING. ret BPNOGO: db 7, ' **** Invalid port ****', cr, lf, '$' SETNG: lxi d,BPNOGO mvi c,PRINT jmp MEX SETICD: mvi c,EVALA call MEX ;get numeric mov a,h ;validate ora a jnz SETERR mov a,l sta WTNUM ;set new rate SHOICD: call ILPRT db 'Inter-call delay: ', 0 lda WTNUM ;get value mov l,a ;move delay to HL mvi h,0 mvi c,DECOUT ;print it call MEX call ILPRT db ' ticks. (150 ticks=30 seconds)', 0 ret SETXTRA: mvi c,EVALA call MEX mov a,h ora a jnz SETERR mov a,l sta PRXTRA SHOXTRA: call ILPRT db 'Extra print mode: ',0 lda PRXTRA ora a lxi d,ONNMSG jnz SHOXT2 lxi d,OFFMSG SHOXT2: jmp PRMBOK ONNMSG: db 'ON$' OFFMSG: db 'OFF$' ; 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 XYZZY: call ILPRT db 'Nothing happens...', 0 ret ; Print in-line message ILPRT: mvi c,ILP ;get function code jmp MEX ;go do it TIMOUT: mvi c,TIMER ; jmp MEX ; UPPER: cpi 'a' rc cpi 'z'+1 rnc sui 'a'-'A' ret ;------------------------------------------------------------ ; ; End of PMMI MEX modem overlay ; ;------------------------------------------------------------ end