home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
simtel
/
sigm
/
vols200
/
vol216
/
mdm840.a86
< prev
next >
Wrap
Text File
|
1994-07-13
|
184KB
|
8,066 lines
pagesize 51
VERSION EQU 840 ;MDM840a(10/27/84) -- CP/M MODEM PROGRAM *
;
; MDM841.A86
;
;
; 840A 10/27/84 - Fixed Timing Loops Alex Soya
; 840 10/23/84 - Added stuff from MDM740 Dennis Vallianos
; 830 - Translation from MDM730 Alex Soya
;------------------------------------------------------------------------
; Translation of MDM740.ASM for CPM86 and MPM86.
;
; This translation follows the same principle of using overlays
; to adapt MDM8xx to different hardware environments as was so
; successfully done with MDM7xx.
;
; The procedure to adapt MDM8xx to specific hardware has changed
; somewhat due to the facts that DDT86 can not be used to overlay
; H86 (HEX) files and no SAVE command beeing available in CPM86.
;
; The Procedure is now as follows:
;
; Required Files: MDM8xx.H86 (xx is Version Number)
; The Main Program in Hex Form.
;
; M8GP.A86 (The General None Specific
; Overlay.
; or
; One of the available Overlays
; for your hardware.)
;
;
;
; After Editing your Overlay Source File to conform to your
; Hardware environment, proceed as follows:
;
;
; ASM86 M8GP (Assemble the Overlay File )
; PIP MDM.H86=MDM840.H86,M8GP.H86 (Append the Overlay to the
; main program)
; GENCMD MDM 8080 CODE[MFF0] ( Run GENCMD to produce MDM.CMD )
;
; Now you can run MDM.CMD
;
;
;
; The Translation was MAINLY done be hand as XLT86 ( DRs 8080 -> 8086 translator)
; is virtualy useless with large files.
; Various routines had to be changed to work properly with CPM86 and MPM86
; When making mods to MDM8xx keep in mind that they should work on CPM86 as
; well as MPM86, so dont use BIOS calls and stuff as such...
;
; Alex Soya
; Sysop Melbourne RCPM
;
; P.O. Box 121
; Melbourne Beach
; Fl. 32951
;
;
; MDM8xx COPYRIGHTED 1984 BY ALEX K. SOYA
; MDM7xx COPYRIGHTED 1984 BY IRVIN M. HOFF
;
; THIS TELEPHONE MODEM PROGRAM USES THE CHRISTENSEN PROTOCOL. IT HAS
; BOTH 'CRC' AND CHECKSUM CAPABILITY FOR ERROR-DETECTION. IT SUPPORTS
; DIALING AND AUTO-REDIALING FOR THE ANCHOR AUTOMATION SIGNALMAN MARK
; XII, US ROBOTICS MODEMS, THE HAYES SMARTMODEM 300 AND 1200 AND PMMI
; S-100 MODEMS. IT SUPPORTS UP TO TWO ALTERNATE DIALING SYSTEMS SUCH
; AS 'MCI', 'SPRINT', ETC. IT IS COPYRIGHTED TO DETER COMMERCIALISM.
;
; OTHER EXTERNAL MODEMS MAY BE READILY USED, ALTHOUGH MANUAL DIALING
; MAY BE NECESARY. OVERLAYS HAVE BEEN MADE ALLOWING RAPID ADAPTATION
; TO VARIOUS COMPUTERS. THE PROGRAM CONFORMS READILY TO NUMEROUS I/O
; DEVICES INCLUDING THE 2661, 8250, 8251, Z80-SIO, ETC.
;
;
;***********************************************************************
;
; GENERAL INTEREST: When transferring files modem-to-modem, the batch
; mode is extremely useful. It allows automatic transmission of nu-
; merous files while the operator at the receiving end does virtually
; nothing. It can be used for single files or with wildcards. With
; normal single program transfer, the receiving end switches from CRC
; to checksum in one minute and times out completely in 120 seconds.
; (In batch mode it times out in 3 minutes for receive.) This offers
; ample opportunity to transfer programs between individuals.
;
;
; M8LIB.CMD can be used to very easily and very quickly change
; any of the telephone overlay numbers.
;
; M8FNK.CMD can be used to quickly and easily change any of the
; 10 function key assignments (or the function key intercept
; character itself, which is currently the '^' character.
;
;
; This program may be used freely for any non-commercial purpose,
; provided that the user does not remove or alter this notice or
; the copyright statement. It is not covered by a warranty either
; express or implied. No changes or alterations are authorized.
; If desirious of modifying the program for national release, it
; may be used for such purposes only if the name is changed and
; credit given where appropriate.
;
; Many people have contributed in the past to make MODEM7 what it
; was when I renamed the program to MDM700 and began this series.
; Their achievements range from modest changes to significant ma-
; jor additions:
;
; Ward Christensen, Jim Mills, Mark Zeigler, Keith Petersen,
; Paul Kelly, Bruce Ratoff, Ron Fowler, Rich Berg, Bob Clyne,
; Bill Earnest, Ben Bronson, Paul Hansknecht, John Mahr, Bob
; Plouffe, Sigi Kluger, Frank Gaude' and others.
;
; I do not mean to slight anyone, and hope I have included those
; who made the most significant advancements to the program.
; - Irv Hoff W6FFC
;
;***********************************************************************
;
;
PORT EQU 0C0H ;your base port (data or status)
;
MODCTL1 EQU PORT ;modem control port
MODDATP EQU PORT+1 ;modem data port
MODRCVB EQU 02H ;modem receive bit (DAV)
MODRCVR EQU 02H ;modem receive ready
MODSNDB EQU 01H ;modem send bit
MODSNDR EQU 01H ;modem send ready bit
;
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; SPECIAL EQUATES FOR PMMI
;
MODCTL2 EQU PORT+3 ;modem status port
;
BAUDRP EQU PORT+2 ;modem baud rate port
BRKMSK EQU 0FBH ;mask to set break
EVPARMSK EQU 20H ;mask to set even parity
NOPARMSK EQU 10H ;mask to reset to no parity
ODPARMSK EQU 0CFH ;mask to set odd parity
;
ANSWMOD EQU 1EH ;answer mode
ORIGMOD EQU 1DH ;originate mode
WAITCTS 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
;
; (END OF SPECIAL PMMI EQUATES)
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;
YES EQU 0FFH
NO EQU 0
;
;
BUFSIZ EQU 16 ;buffer size in Kbytes for ASCII capture to disk
;(16k is one file extent)
XFRSIZ EQU 4 ;file transfer buffer in Kbytes. Do not make
;any larger than BUFSIZ. 16k works fine on all
;but very slowest systems
;
BDNMCH EQU 75H ;bad name match
ERRLIM EQU 10 ;maximum allowable consecutive errors
ERRCRC EQU 6 ;CRC tries, then switches to CHECKSUM
LIBLEN EQU 34 ;length of each phone library entry
SHOWHEX EQU NO ;yes, show both decimal and hex record counts
;no, show just standard decimal record count
RUB EQU 7FH ;rub
CRC EQU 'C' ;requests 'CRC' instead of 'CKSUM'
ESC EQU '['-40H ;^[ = escape
SOH EQU 'A'-40H ;^A = start of header
EOT EQU 'D'-40H ;^D = end of text
EXITCHR EQU 'E'-40H ;^E = exit character
ACK EQU 'F'-40H ;^F = acknowledge
OKNMCH EQU 'F'-40H ;^F = ok name match
BELL EQU 'G'-40H ;^G = bell character
BKSP EQU 'H'-40H ;^H = backspace
LF EQU 'J'-40H ;^J = linefeed
CR EQU 'M'-40H ;^M = carriage return
XON EQU 'Q'-40H ;^Q = XON character
XOFF EQU 'S'-40H ;^S = XOFF character
NAK EQU 'U'-40H ;^U = not acknowledge
CANCEL EQU 'X'-40H ;^X = cancel send or receive
EOFCHAR EQU 'Z'-40H ;^Z = end of file
;
;
ORG 0100H
;
;
JMP START ;skip the data area below
;
;
;
; THESE ROUTINES AND EQUATES ARE AT THE BEGINNING OF THE PROGRAM SO
; THEY CAN BE PATCHED BY A MONITOR OR OVERLAY FILE WITHOUT RE-ASSEMBLING
; THE PROGRAM.
;
PMMIMODEM DB YES ;yes=PMMI modem
AUTODIAL DB NO ;yes=Hayes-type autodial modem
TOUCHPULSE DB 'T' ;T=touch, P=pulse (autodial-only)
;
CLOCK DB 40 ;clock speed in MHz x 10, 25.5 MHz max.
;2 MHz=20, 3.68 MH=37, 4 MHz=40, etc.
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 ;0=0 delay 1=10 ms 5=50 ms - 9=90 ms
;defaut time to send character in ter-
;minal mode file transfer for slow BBS
CRDLY DB 5 ;0=0 delay 1=100 ms 5=500 ms - 9=900 ms
;default time for extra wait after CRLF
;in terminal mode file transfer
NOOFCOL DB 5 ;number of directory columns
SETUPTST DB NO ;yes=non-PMMI setup routine
SCRNTEST DB NO ;yes=if home cursor and clear screen
;routine at CLRSCRN
RETRY DB YES ;yes=reset the error limit to try again
;no=abort after 10 consecutive errors
;(ARPANET users should select yes)
BAKUPBYTE DB NO ;yes=make .BAK file
CRCDFLT DB YES ;yes=default to CRC checking
;no=default to Checksum checking
TOGGLECRC DB YES ;yes=allow toggling of Checksum to CRC
CONVRUB DB YES ;yes=convert rub to backspace
TOGGLERUB DB YES ;yes=allow toggling of rub to backspace
ADDLF DB NO ;no=no LF after CR to send file in
;terminal mode (added by remote echo)
TOGGLELF DB YES ;yes=allow toggling of LF after CR
TRANLOGON DB NO ;yes=allow transmission of logon
;write logon sequence at location LOGON
RESERVED DB NO ;Reserved for Future releases
LOCNXTCHR DB NO ;yes=local cmd if EXTCHR precedes
;no=not local cmd if EXTCHR precedes
TOGGLELOC 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
XOFFTST DB NO ;yes=allow testing of XOFF from remote
;while sending a file in terminal mode
XONWAIT DB NO ;yes=wait for XON after sending CR while
;transmitting a file in terminal mode
TOGXOFF DB YES ;yes=allow toggling of XOFF testing
IGNORCTL DB YES ;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
NOCONNCT DB 'N'-40H ;^N = Disconnect from phone line
LOGCHR DB 'L'-40H ;^L = Send logon
LSTCHR DB 'P'-40H ;^P = Toggle printer
UNSAVECHR DB 'R'-40H ;^R = Close input text buffer
TRANCHR DB 'T'-40H ;^T = Transmit file to remote
SAVECHR DB 'Y'-40H ;^Y = Open input text buffer
EXTCHR DB '^'-40H ;^^ = Send next character
;
;
; Equates used only by PMMI routines grouped together here.
;
PULSERATE DB 250 ;125=20pps dialing, 250=10pps
CHGBAUD DB 'B'-40H ;^B = Used with PMMIMODEM in terminal
;mode to change baud rate on fly
PMMIPORT DB MODCTL1 ; Pmmi Port location
;
; Handles in/out ports for data and status
;
IN_MODCTL1: IN AL,MODCTL1 ! RET
DB 0,0,0,0,0,0,0 ;spares if needed for non-PMMI
OUT_MODDATP: OUT MODDATP,AL ! RET ;out modem data port
DB 0,0,0,0,0,0,0 ;spares if needed for non=PMMI
IN_MODDATP: IN AL,MODDATP ! RET ;in modem data port
DB 0,0,0,0,0,0,0 ;spares if needed for non-PMMI
ANI_MODRCVB: AND AL,MODRCVB ! RET ;bit to test for receive ready
CPI_MODRCVR: CMP AL,MODRCVR ! RET ;value of receive bit when ready
ANI_MODSNDB: AND AL,MODSNDB ! RET ;bit to test for send ready
CPI_MODSNDR: CMP AL,MODSNDR ! RET ;value of send bit when ready
;
;
;====================== SPECIAL PMMI PORTS =============================
;
IN_BAUDRP: IN AL,BAUDRP ! RET ;in baudrate port
OUT_BAUDRP: OUT BAUDRP,AL ! RET ;out baudrate port
OUT_MODCTL1: OUT MODCTL1,AL! RET ;out modem control port #1
OUT_MODCTL2: OUT MODCTL2,AL! RET ;out modem control port #2
;
;================== END OF SPECIAL PMMI PORTS ==========================
;
;
LOGONPTR DW (Offset LOGON)
JMP_DIAL: JMP DIAL
JMP_DISCONNT: JMP DISCONNT
JMP_GOODBYE: JMP GOODBYE
JMP_INITMOD: JMP INITMOD
JMP_NEWBAUD: JMP NEWBAUD
JMP_NOPARITY: JMP NOPARITY
JMP_PARITY: JMP PARITY
JMP_SETUPR: JMP SETUPR
JMP_SPCLMENU: JMP SPCLMENU
JMP_SYSVER: JMPS SYSVER
JMP_BREAK: JMP SENDBRK
;
;
; NEXT EIGHT LINES SHOULD NOT BE CHANGED BY USER OVERLAY AS THESE GO TO
; SPECIFIC LOCATIONS IN THE MAIN PROGRAM, NOT IN THE OVERLAY.
;
JMP_ILPRT: JMP ILPRT
JMP_INBUF: JMP INBUF
JMP_INLNCOMP: JMP INLNCOMP
JMP_INMODEM: JMP INMODEM
JMP_NXTSCRN: JMP NXTSCRN
JMP_TIMER: JMP TIMER
JMP_CTYPE: JMP CTYPE
JMP_KEYIN: JMP KEYIN
;
;
; Clear sequences are for Televideo, Lear Siegler, etc. Change to match
; your terminal. (Heath uses ESC 4AH for clear to end of screen, ESC 45H
; to clear screen. Lear Siegler and others use ESC 79H for clear to end
; of screen and ESC 3AH to clear screen.) Room allowed for four bytes.
; (Last zero needed for stopping the string display. Any extra 0's just
; act as NOP's.)
;
CLREOS: CALL ILPRT
DB ESC,79H,0,0,0
RET
;.....
;
;
CLRSCRN: CALL ILPRT
DB ESC,3AH,0,0,0
RET
;.....
;
;
;======================= SIGN-ON MESSAGE ==============================
;
; Send version number and date
;
SYSVER: MOV AL,Byte Ptr PMMIMODEM ;using the PMMI S-100 modem?
OR AL,AL
JZ SYSVER1 ;go if not
CALL ILPRT
DB 'Version for PMMI S-100 modem starting at port: ',0
MOV AL,Byte Ptr PMMIPORT
CALL HEXO ; put in PMMI control port number
CALL ILPRT
DB 'H',CR,LF,0
RET
;.....
;
;
SYSVER1:CALL ILPRT ;if not using the PMMI S-100 board
DB 'Version for Non-PMMI modem',CR,LF,0
RET
;.....
;
;
;==================== LOGON MESSAGE (IF ANY) ===========================
;
; Insert your logon message here. End with a 0 (for"CALL ILPRT").
; PMMIusers have 59 bytes available, non-PMMI users have approximately
; 2K bytes available as they can overwrite all the following PMMI rou-
; tines if they wish. This method allows the external overlays to have
; plenty of room. It keeps the phone number library at a fixed location.
;
LOGON RB 59 ;up to 59 characters allowed
DB 0 ;to terminate the logon message
;.....
;
;
;=============== NON-PMMI INITIALIZATION (IF ANY) ======================
;
; Insert your initialization routine here if needed. Can replace the
; following special PMMI area to set speed and auto-dial. Over 950
; bytes are available for this purpose. (End your routine with a RET.)
;
;
INITMOD: RET
;
;========== NON-PMMI SETUP (SPEED CHANGE, ETC.) IF ANY ==============
;
; Insert your speed change and/or auto-dialing routines here.
; Over 950 bytes are available (INCLUDING INITMOD, above).
; End your routine with a RET.
;
SETUPR: RET
;
;
; Not needed if using the PMMI board, as it has its own break routine
;
SENDBRK: RET
;
;
;**************** START OF SPECIAL PMMI ROUTINES **********************
;
;
;=======================================================================
;
; SETS THE BAUD RATE
;
;=======================================================================
;
;
SETBAUD:MOV AL,Byte Ptr ANSWFLG ;if 'O' or 'A' not requested and
OR AL,AL ; baudrate not specified, returns
JZ FIXBAUD ; with current mode and rate
MOV AL,Byte Ptr ORIGFLG ;if option requested, a blank returns
OR AL,AL ; with current mode and rate
JZ FIXBAUD
RET ;no change if neither 'O' or 'A' shown
;
FIXBAUD:CALL GETBAUD ;calculate PMMI baud rate divisor
CALL SETMSPD ;set the file time transfer value
CALL OUT_BAUDRP ;set the PMMI board to that baudrate
CMP AL,52
MOV AL,5FH ;DTR (filter for over 300 baud)
JB GT300 ;yes, greater than
MOV AL,7FH ;DTR (filter for 300 and less baud)
;
GT300: CALL OUT_MODCTL2
MOV Byte Ptr MODCTLB,AL ;save modem control byte
;
OFFHOOK:MOV BX,7500 ;throw in some delay
;
OFFDLY: DEC BL
JNZ OFFDLY
DEC BH
JNZ OFFDLY
MOV AL,Byte Ptr UARTCTLB ;UART control byte for 'A' or 'O'
CALL OUT_MODCTL1 ;now set to answer or originate
MOV AL,CL
MOV Byte Ptr MSPEED,AL ;set the file transfer time value
XOR AL,AL ;clear the flags
RET
;.....
;
;
;=======================================================================
; CALCULATES THE BAUD RATE DIVISOR
;
; Returns with current baud rate intact if a blank or null in the speed
; field (extent area).
;
GETBAUD:MOV AL,Byte Ptr FCB+9 ;get 1st digit of requested baudrate
CMP AL,' ' ;if a space, return with current speed
MOV AL,Byte Ptr CURRENT
JNZ LA14
RET
LA14:
MOV AL,Byte Ptr FCB+9
OR AL,AL ;if a null, return with current speed
MOV AL,Byte Ptr CURRENT
JNZ LA15
RET
LA15:
;
MOV DX, FCB+9 ;get the requested speed
MOV BX,0
;
DECLP: MOV SI,DX ;get the ASCII digit
MOV AL,[SI]
INC DX
CMP AL,' '
JZ DECLP
CMP AL,'0' ;numerals are 0-9
JB BADRATE
CMP AL,'9'+1
JNB BADRATE
SUB AL,'0'
MOV CH,BH
MOV CL,BL
SHL BX,1
SHL BX,1
ADD BX,CX
SHL BX,1
ADD AL,BL
MOV BL,AL
JNZ DIGNC
INC BH
;
DIGNC: MOV AL,DL
CMP AL,FCB+12
JNZ DECLP
MOV AL,BH
NOT AL
MOV DH,AL
MOV AL,BL
NOT AL
MOV DL,AL
INC DX
MOV BX,15625 ;250000/16
MOV CX,-1
;
DIVLP: INC CX
ADD BX,DX
JB DIVLP
MOV AL,CH
OR AL,AL
MOV AL,CL
MOV Byte Ptr CURRENT,AL ;can use this the next time by default
JNZ BADRATE
RET
;
BADRATE:CALL ERXIT
DB '++ INVALID BAUDRATE ++$'
;.....
;
;
;=======================================================================
; SETS 'MSPEED' TO BAUD RATE
;
;
SETMSPD:MOV CL,0 ;changes PMMI mspeed for 110-710 baud
CMP AL,100 ;<300 baud
JNAE LA17
RET
LA17:
INC CL ;c=1 for 300 baud
CMP AL,40 ;<450 baud
JNAE LA18
RET
LA18:
INC CL ;c=2 for 450 baud
CMP AL,30 ;<600 baud
JNAE LA19
RET
LA19:
INC CL ;c=3 for 600 baud
CMP AL,24 ;<710 baud
JNAE LA20
RET
LA20:
INC CL ;c=4 for 710 baud
RET
;.....
;
;
; Change baudrate on-the-fly with CTL-B (while in terminal mode)
;
NEWBAUD:MOV AL,Byte Ptr PMMIMODEM
OR AL,AL
JNZ LA21
RET
LA21:
CALL ILPRT
DB CR,LF,'Enter new Baudrate: ',0
MOV BX, FCB+9
MOV Byte ptr [BX],' ' ;keep current baud if none included
;
NEWBAUD1:
CALL KEYIN ;get the baud rate
CMP AL,CR ;carriage ret finishes baud rate entry
JNZ LA22
CALL CRLF ;if a 'CR', baud rate has been entered
LA22:
JNZ LA23
JMP FIXBAUD ;go change the baud rate
LA23:
;.....
;
;
NEWBAUD2:
CMP AL,'0' ;numerals are 0-9
JB NEWBAUD1
CMP AL,'9'+1
JNB NEWBAUD1 ;if not a numeral, ignore, ask again
MOV Byte Ptr [BX],AL ;store answer starting at FCB+9
CALL STYPE ;show the numeral on the CRT
INC BX ;next storage location in FCB
JMPS NEWBAUD1 ;get the next numeral
;.....
;
;
;======================= PARITY ROUTINES ===============================
;
;--->PARITY: Routine to setup PMMI for odd/even parity.
;
PARITY: MOV AL,Byte Ptr PMMIMODEM ;is modem a PMMI?
OR AL,AL ;set flags
JNZ LA24
RET ;no, return
LA24:
MOV AL,Byte Ptr OPARITY ;get odd parity request byte
OR AL,AL ;set flags
JNZ EVENPAR ;if not odd see if it is even
MOV AL,Byte Ptr UARTCTLB ;get uart/modem control byte
AND AL,ODPARMSK
JMPS PARITY1
;...
;
;
EVENPAR:MOV AL,Byte Ptr EPARITY ;get even parity request byte
OR AL,AL ;set flags
JZ LA25
RET ;if even parity not specified return
LA25:
MOV AL,Byte Ptr UARTCTLB ;get uart/modem control byte
AND AL,ODPARMSK ;set for parity
OR AL,EVPARMSK ;now set for even parity
;
PARITY1:MOV Byte Ptr UARTCTLB,AL
JMP OUT_MODCTL1 ;send to PMMI -
; ;when OUT$MODCTL1 does return, it
;..... ;will go back to calling routine
;
;
NOPARITY:
MOV AL,Byte Ptr PMMIMODEM
OR AL,AL
JNZ LA26
RET
LA26:
MOV AL,Byte Ptr UARTCTLB ;get UART/modem control byte
OR AL,NOPARMSK ;reset parity bit on PMMI
JMP OUT_MODCTL1
;.....
;
;
;==================== END OF PARITY ROUTINES ===========================
;
;
;=======================================================================
;
; HAYES/PMMI DIALING ROUTINES
;
;=======================================================================
;
;
RB 640 ;FOR EXPANSION
;
; 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
SMRWAIT EQU 15 ;1.5 sec delay before redialing HAYES
TMPUL EQU 80H ;timer pulses mask bit
TRATE EQU 250 ;value for 0.1 second
;.....
;
;
; Dialing routine
;
DIAL: MOV AL,Byte Ptr PMMIMODEM ;using a PMMI modem?
OR AL,AL
JNZ DIAL1
MOV AL,Byte Ptr AUTODIAL
OR AL,AL
JNZ LA29
RET ;return if neither modem
LA29:
CALL SMNOISEY ;make sure autodial modem speaker is on
;
DIAL1: XOR AL,AL
MOV BYTE PTR AUTODIR,AL ;zero the direct to terminal mode flag
MOV BYTE PTR AUTOFL,AL ;zero the auto-linking flag
MOV Byte Ptr CRFLAG,AL ;zero the continuous dial flag
MOV BX,0
MOV Word Ptr DIALCT,BX ;zero the dial count
MOV BX, Offset CMDBUF+1 ;point to the number of characters in..
MOV AL, Byte Ptr [BX] ;..the buffer, then get the number
CMP AL,3+1 ;anything typed after 'CAL'?
JB DIAL2 ;if not, go through library routine
;
;
; If there were only 3 characters, then "CAL<RET>" was typed -- the user
; obviously expecting to get a phone number (or letter) from the library
; file. If 4 or more, a number (or letter) was typed in from the menu
; command line, so move the characters down 4 to compensate. Needed for
; auto-redialing of menu command line entries.
;
MOV CL,AL ;put into the 'C' reg.
MOV CH,0 ;will move original number down 4
SUB AL,4 ;eliminate the 'CAL' portion
MOV Byte Ptr [BX],AL ;store new count at cmdbuf+1
INC BX ;CMDBUF+2 (first character of string)
XCHG BX,DX ;'DE' now has CMDBUF+2
MOV BX, Offset CMDBUF+6 ;point to number (or letter) to dial
CALL MOVER ;move the group down 4 places
JMP DIAL4 ;check if library number, then dial
;...
;
;
; Comes here if no phone number was manually entered after 'CAL' and if
; no phone library code was entered. Displays the phone number library
; then asks for an entry.
;
DIAL2: MOV CL,18 ;number of lines to move
MOV BX, Offset NUMBLIB ;start of phone number library
MOV DX, Offset BUFFER ;buffer add. to store them temporarily
CALL NEWLINE ;start with CR/LF
MOV SI,DX ;+LF
MOV [SI],AL
INC DX ;and bump it
;
DIAL3: MOV CH,LIBLEN ;number of bytes to move
CALL MOVE ;move to buffer
CALL SPACES ;2 entries + 3 spaces = 71 characters
PUSH BX ;save source address
PUSH DX ;save destination address
MOV DX,(17*LIBLEN) ;get offset of 17 times entry length
ADD BX,DX ;add it to source address
POP DX ;restore destination address
MOV CH,LIBLEN ;get length of library entry
CALL MOVE ;move another entry
POP BX ;restore source address
CALL NEWLINE
DEC CL ;one less line to print
JNZ DIAL3 ;if not zero, print another
MOV AL,'$' ;BDOS print routine terminate character
MOV SI,DX ;store in buffer
MOV [SI],AL
CALL CLRTST
MOV CL,PRINT
MOV DX, Offset BUFFER ;print the library on the CRT
INT 224
CALL JMP_ILPRT ;ask which one is wanted
DB CR,LF,'Enter library code or phone number,',CR,LF
DB 'Hit RET to abort this function now or',CR,LF
DB 'CTL-X quits while dialing or ringing: ',0
MOV DX, Offset CMDBUF
CALL INBUF ;get the answer from the keyboard
;
;
; You now have either a library code or a manually entered phone num-
; ber. These either came from the menu command line or from the library
; command line. Next we see if a code, if so, get the corresponding
; line with phone number from the library. If a number greater than
; one digit, we ignore the library look-up. (Ringback numbers must end
; with letter 'R'.)
;
DIAL4: MOV BX,Offset CMDBUF+1 ;number of characters in buffer
MOV AL,Byte ptr [BX]
OR AL,AL ;null means CR was typed
JNZ LA30
JMP DIALEXIT2 ;abort dialing, return to menu
LA30:
MOV Byte Ptr NUMBER,AL
MOV BX,OFFSET CMDBUF+3
MOV AL,BYTE PTR [BX] ;see if at least two chars. entered
CMP AL,'/' ;slash for linking, direct to terminal.
JNZ LA30A
CALL AUTO ;..mode on answer
LA30A: CMP AL,',' ;comma used for linking
JNZ DIAL5
CALL AUTO1 ;if so, set it up for auto-linking
;
;
; Check to see how many characters were typed. If more than one, then
; was a hand-entered phone number, so exit.
;
DIAL5: CALL DIALBGN ;disconnect, reconnect, wait for tone
MOV AL,BYTE PTR AUTOFL ;auto-link flag set?
OR AL,AL
JZ LA30B
JMP AUTO2 ;if yes, exit
LA30B: MOV AL,BYTE PTR NUMBER ;number of chars. in buffer
MOV BX,OFFSET CMDBUF+1
MOV BYTE PTR [BX],AL ;reset the character count, if needed
CMP AL,1 ;more than 1 character
JNA LA32
JMP DIAL14 ;if more than one, hand-entered number
LA32:
MOV BX, Offset CMDBUF+2 ;first character in phone number line
;
;
; If just one character entered, see if a (A-Z) letter
;
DIAL6: MOV AL,Byte ptr [BX]
MOV CH,'A' ;first letter of alphabet
MOV DL,0 ;counts number of letters to match
MOV CL,26 ;number of letters in alphabet
;
DIAL7: CMP AL,CH ;letter from table?
JNZ LA33
JMP DIAL9 ;if yes, get phone number, else
LA33:
INC CH ;make next letter (A-Z)
INC DL ;count up
DEC CL ;count down
JNZ DIAL7 ;try next one in (A-Z) table
;
;
; If not (A-Z) then should be (0-9)
;
MOV CH,'0' ;first digit to check
MOV DL,26 ;point past alpha codes
MOV CL,10 ;number of digits in table
;
DIAL8: CMP AL,CH ;number from table?
JZ DIAL9 ;if yes, go dial, else
INC DL ;make next table line number
INC CH ;make next digit to compare
DEC CL ;count down - loop counter
JNZ DIAL8 ;loop
JMP DIALBAD ;error if not a number or a letter
;
;
; Now have a match between the requested code and one in the library.
; E-reg. holds the library line number (1-36) that matches the requested
; code (A-Z or 0-9).
;
DIAL9: MOV BX,(Offset NUMBLIB) ;phone number library
MOV CX,LIBLEN ;length of library entry
MOV AL,DL ;number of times to library length to BX
OR AL,AL ;set flags
JZ DIAL11
;
DIAL10: MOV AL,Byte Ptr [BX] ;get first char of selected lib entry
OR AL,AL ;set flags
JNZ LA2
JMP DIALBAD ;send bad library msg and abort
LA2:
ADD BX,CX ;increment 'BX' by library length
DEC DL ;countdown
JNZ DIAL10 ;not there yet, loop
;
;
; Now have the line in the phone number library matching the requested
; letter so store that line starting at 'CMDBUF+1'
;
DIAL11: MOV CH,LIBLEN ;number of characters to get from table
MOV DX, Offset CMDBUF+1 ;point to buffer
XCHG BX,DX ;'BX' points to CMDBUF+1
MOV Byte Ptr [BX],CH ;length of each table entry
XCHG BX,DX ;restore the registers
INC DX ;point to first char position in buffer
CALL MOVE ;move the table entry to the buffer
;
;
; Now have the full line including phone number in 'CMDBUF' area. Scan
; past the descriptive portion of library entry - terminate scan at the
; first '.' This allows commas and numbers to be part of the text, such
; as:
; 'A=DataTech, Node 7..1-408-238-9621'
;
DIAL12: MOV AL,Byte Ptr AUTODIAL ;using a Hayes-type modem?
OR AL,AL
JZ DIAL12A
CALL SMINIT ;if yes, initialize
;
DIAL12A:
MOV BX, Offset CMDBUF+1
MOV DL,Byte Ptr [BX] ;number of chars in buffer
INC BX ;point to 1st character in buffer
;
DIAL13: MOV AL,Byte ptr [BX] ;get next character
CALL STYPE ;show it
INC BX ;bump pointer
DEC DL ;decrement count
JNZ L2A4
JMP DIALEXIT ;exit if no '.' (bad lib entry)
L2A4:
CMP AL,'.' ;dot?
JZ DIAL15 ;yes, go dial the phone
JMPS DIAL13 ;no, loop for next character
;.....
;
;
; There is a user entered phone number in 'CMDBUF' area
;
DIAL14: MOV AL,Byte Ptr AUTODIAL ;using a Hayes-type modem?
OR AL,AL
JZ L2A5
CALL SMINIT ;if yes, initialize
L2A5:
MOV BX, Offset CMDBUF+1
MOV DL,Byte Ptr [BX] ;get number of chars in buffer
INC BX ;point to 1st character to dial
;.....
;
;
; Loop to dial the phone number pointed to by 'BX', character count in
; the 'DL' register.
;
DIAL15: MOV AL,Byte Ptr [BX] ;get first number from the buffer
OR AL,AL ;set flags
JNZ L2A6
JMP DIALBAD ;bad number if a null
L2A6:
;
;
; Dial a digit, check keyboard for abort
;
CALL DIALA ;dial a digit, show on CRT
CALL STAT ;keypress?
JZ DIAL17 ;if not, exit
CALL KEYIN ;yes, go get it
CMP AL,CANCEL ;CTL-X?
JNZ DIAL17 ;if not, exit
MOV AL,Byte Ptr AUTODIAL ;using a Hayes-type modem?
OR AL,AL
JNZ L2A7
JMP DIALEXIT ;if not, exit now, otherwise clear line
L2A7:
;
;
; If using an autodial modem, backspace 30 times to make sure the entire
; number plus "DT" part of "ATDT" is erased.
;
MOV CL,30
;
DIAL16: MOV CH,BKSP
CALL SENDCHR ;send to the modem to cancel call
DEC CL
JNZ DIAL16 ;if not zero, do another
MOV CH,CR
CALL SENDCHR
MOV AL,' '
CALL STYPE ;show on CRT
JMP DIALEXIT ;now go abort
;
DIAL17: INC BX ;bump pointer
DEC DL ;one less character to go
JNZ DIAL15 ;if not done, send the next digit
;
;
; Show the number of dial attempts
;
CALL JMP_ILPRT
DB ' - try #',0
MOV BX,Word Ptr DIALCT ;increment the dial count
INC BX
MOV Word Ptr DIALCT,BX
CALL DECOUT ;show number of attempts so far
MOV AL,' ' ;extra space to position cursor
CALL STYPE
MOV AL,Byte Ptr AUTODIAL ;using a Hayes-type modem?
OR AL,AL
JZ DIAL19 ;if not, exit
MOV CH,CR ;tells the modem the number is done
CALL SENDCHR ;just have one character to send
;
DIAL18: CALL JMP_INMODEM ;catch any output from the modem
JNB DIAL18
JMP SMRESULT ;number sent to modem, now get results
;
;
; Dialing is all done, this section is PMMI-only
;
DIAL19: MOV AL,07FH ;turn on PMMI 'DTR'
CALL OUT_MODCTL2 ;timer rate?
MOV CH,1 ;0.1 second per interval
CALL JMP_TIMER ;wait for modem to turn on 'DTR'
MOV AL,5DH ;2 stop bits, no parity, 8 data bits
CALL OUT_MODCTL1
MOV DH,4 ;clear to send mask
MOV CL,WAITCTS ;wait time for CTS
CALL WAIT ;..(30 seconds, can set 'WAITCTS' for
;..up to 51 seconds for European use)
;
; If PMMI connection made, go get options for starting communications
;
JNAE L2A8
JMP CONMADE ;connection made
;
;
; Connection not made, see if a redial is desired
;
L2A8:
; CALL DISCONNT ;hang-up so we can redial if desired
;
DIALAGN:MOV SP,OFFSET STACK ;reset the stack to normal, just in case
MOV AL,Byte Ptr CRFLAG ;continuous redial flag
OR AL,AL
JZ L2A9
JMP DIALAGN2 ;if already set, go dial again
L2A9:
L2A10:
CALL JMP_ILPRT ;see if we should keep trying
DB CR,LF,CR,LF,' Redial? (C/Y/N/Q): ',BELL,0
CALL KBDCHR
PUSH AX
CALL CRLF ;turn up a line
POP AX
CMP AL,'Y' ;redial?
JZ DIALAGN2 ;yes, redial
CMP AL,'C' ;continuous redial?
JZ DIALAGN1 ;if yes, set continuous redial flag
CMP AL,'Q' ;kill the Hayes-type modem speaker?
JZ L2A11
JMP DIALEXIT1 ;none of these, quit
L2A11:
CALL SMQUIET ;strangle speaker
;
DIALAGN1:
MOV AL,1
MOV Byte Ptr CRFLAG,AL ;continuous redial flag
;
DIALAGN2:
MOV AL,Byte Ptr AUTODIAL ;using a Hayes-type modem?
OR AL,AL
JNZ DIALAGN3 ;if yes, exit
MOV CH,RBWAIT ;wait for PMMI reset (or busy)
CALL JMP_TIMER ;or busy tone may be sensed as dialtone
JMPS DIALAGN4
;
DIALAGN3:
MOV CH,SMRWAIT
CALL JMP_TIMER
;
DIALAGN4:
CALL CRLF ;start a new line
JMP DIAL5 ;redial entry point
;.....
;
;
; Connection has been made
;
CONMADE:
MOV AL,BYTE PTR PMMIMODEM
OR AL,AL
JZ CONMADE1
MOV AL,Byte Ptr CURRENT ;get current baud rate
CALL OUT_BAUDRP ;set baudrate
;
CONMADE1:
MOV CH,2
CALL JMP_TIMER
CALL JMP_ILPRT
DB BELL,CR,LF,CR,LF,' CONNECTED',0
MOV AL,BYTE PTR AUTODIR ;going direct to terminal mode?
OR AL,AL
JZ CONMADE1A
JMP RETURN
;
CONMADE1A:
MOV AL,BYTE PTR CRFLAG ;in continuous redial or first time try?
OR AL,AL
JNZ CONMADE1B
JMP RETURN ;go to terminal mode if first time
;
CONMADE1B:
CALL JMP_ILPRT
DB ' - any key for terminal mode ',0
;
CONMADE2:
MOV DL,10
CONMADE3:
CALL STAT ;keypress?
JZ CONMADE4 ;exit if no keys pressed
CALL KEYIN
XOR AL,AL
JMP RETURN ;key pressed, go to terminal mode
;
CONMADE4:
MOV CH,1 ;wait 0.1 second
CALL JMP_TIMER
DEC DL ;one less loop to make
JNZ CONMADE3 ;see if a keyboard character yet
MOV AL,BELL ;sound a bell
CALL STYPE
JMPS CONMADE2
;.....
;
;
; Automatic dialing routine, prints the number being dialed. If we find
; 'R', it either has to be the final character for ringback or toss it.
;
DIALA: CALL STYPE ;print whatever character, dashes, etc.
CMP AL,'R' ;could it be a ringback character?
JNZ DIALA1 ;if not, probably a number so exit
MOV AL,DL ;get the character count. Is this "r"..
CMP AL,1 ;..the last character in the string?
JNZ L2A13
JMP RINGBK ;yes, must be ringback char, do ringback
L2A13:
RET ;if not, ignore the 'r'
;
DIALA1: MOV CH,AL ;store the character for now
CALL DIALAD ;check for alternate dialing like 'MCI'
MOV AL,CH ;get the original character back
DIALA2: CMP AL,'*' ;* is a valid dial digit
JZ DIALA3
CMP AL,'#' ;# is a valid dial digit
JZ DIALA3
CMP AL,',' ;comma indicates a short delay-time
JZ DIALA3
CMP AL,'0' ;digits are (0-9)
JNB L2A14
RET ;exit less than ASCII '0'
L2A14:
CMP AL,'9'+1
JNAE L2A15
RET ;exit if more than ASCII '9'
L2A15:
SUB AL,'0' ;strip ASCII - could also do 'ANI 0FH'
JNZ DIALA3
MOV AL,10 ;convert zero to 10 pulses
;
;
; Sends the digit to the modem. Waits 100 ms. after each digit to in-
; sure it gets to the modem ok.
;
DIALA3: MOV CL,AL
MOV AL,Byte Ptr PMMIMODEM ;using a PMMI?
OR AL,AL
JNZ DIALA4 ;if yes, exit
CALL SENDCHR ;character is already in the 'B' reg.
MOV CH,1 ;slight delay to let modem settle down
JMP JMP_TIMER
;
DIALA4:
MOV AL,Byte Ptr PULSERATE
CALL OUT_BAUDRP
;
DIALA5: CALL IN_BAUDRP
AND AL,TMPUL
JNZ DIALA5
;
DIALA6: CALL IN_BAUDRP
AND AL,TMPUL
JZ DIALA6
;
DIALA7: MOV AL,MAKEM
CALL OUT_MODCTL1
;
DIALA8: CALL IN_BAUDRP
AND AL,TMPUL
JNZ DIALA8
MOV AL,BRKMASK
CALL OUT_MODCTL1
;
DIALA9: CALL IN_BAUDRP
AND AL,TMPUL
JZ DIALA9
DEC CL
JNZ DIALA7
MOV AL,MAKEM
CALL OUT_MODCTL1
MOV CH,2
JMP JMP_TIMER
;.....
;
; Print bad library number message and abort if a null is encountered.
;
DIALBAD:
CALL JMP_ILPRT
DB CR,LF,CR,LF,'++ Bad library number called ++',CR,LF,0
;
DIALEXIT:
CALL CRLF ;turn up a new line
;
DIALEXIT1:
MOV SP,OFFSET STACK ;make sure the stack is normal again
CALL JMP_GOODBYE ;user routine to disable DTR, if any
CALL DISCONNT ;hang up the phone and reset the modem
;
DIALEXIT2:
MOV BYTE PTR CRFLAG,0 ;reset the continuous redial flag
JMP MENU
;.....
;
;
; Disconnect from the line, reconnect and wait for the dialtone.
;
DIALBGN:MOV AL,Byte Ptr AUTODIAL ;Hayes-type modem?
OR AL,AL
JZ DIALBG1
RET ;if yes, finished
;
DIALBG1:MOV AL,MAKEM ;go off-hook
CALL OUT_MODCTL1
MOV DH,DTMSK ;dial tone mask
MOV CL,50 ;waits up to 10 sec. for dial tone
CALL WAIT ;wait for dial tone
;
;
; Wait subroutine will return with carry set if unable to get dialtone.
; If carry is not set, the dialtone was received.
;
JNAE L2A18
RET ;if dial tone within 10 seconds
L2A18:
CALL JMP_ILPRT ;otherwise print error message
DB CR,LF,CR,LF,'++ NO DIAL TONE ++',BELL,0
POP BX ;restore the stack to normal
JMP DIALEXIT ;forget it.
;.....
;
;
; Do any alternate dialing such as 'MCI' or 'SPRINT'
;
DIALAD: MOV AL,Byte Ptr AUTODIAL ;using a Hayes-type modem?
OR AL,AL
JNZ L2A19
RET ;if not, exit
L2A19:
MOV AL,Byte Ptr TOUCHPULSE ;using touch tone dialing?
CMP AL,'T'
JZ L2A20
RET ;if not, ignore
L2A20:
MOV AL,CH ;get the character back
CMP AL,'<' ;alternate dialing system #1 (MCI?)
JNZ DIALAD1 ;if not, exit
PUSH BX ;save the current values
MOV BX,(Offset ALTDIAL1) ;alternate dialing area
JMPS DIALAD2
;
DIALAD1:CMP AL,'>' ;alternate dialing system #2 (Sprint?)
JZ L2A21
RET ;if neither, exit
L2A21:
PUSH BX ;save the current values
MOV BX,(Offset ALTDIAL2)
;
DIALAD2:MOV AL,Byte Ptr [BX]
CMP AL,'$' ;ready to terminate?
JZ DIALAD3 ;if yes, exit
;
;
; Move the semicolons up one line if you do not want to see the SPRINT
; number dialed.
;
CALL STYPE ;display the character
MOV CH,AL ;need the char. in 'CH' to send to modem
CALL DIALA2 ;send proper characters to the modem
INC BX ;next location
CALL STAT ;keypress?
JZ DIALAD2 ;if not, do the next character
CALL KEYIN ;yes, go get it
CMP AL,CANCEL ;ctl-x?
JNZ DIALAD2 ;if not, handle the next character
POP BX ;if yes, reset the stack
JMP DIALEXIT ;if yes, exit
;
DIALAD3:MOV AL,' '
MOV CH,AL ;clears 'CH' from last digit sent
CALL STYPE ;separate from the main number
POP BX ;restore the stack
RET
;.....
;
;
; Disconnect the autodial modem from the phone line. Sends 'I, CR' to
; the Racal-Vadic to return to idle mode.
;
GOODBYE:
DISCONNT:
MOV AL,Byte Ptr AUTODIAL ;using a Hayes-type autodial modem?
OR AL,AL
JNZ DISCONN1 ;if yes, skip PMMI section
XOR AL,AL
CALL OUT_MODCTL1 ;hang up
CALL OUT_MODCTL2 ;clear DAV, ESD, etc.
PUSH CX
MOV CH,10 ;1 second for PMMI to disconnect
CALL JMP_TIMER
POP CX
RET
;...
;
;
; Disconnect the autodial modem from the phone line
;
DISCONN1:
MOV CH,12 ;wait 1.2 seconds pause
CALL JMP_TIMER
MOV BX,(Offset SM_DISC) ;get into command mode
CALL SENDOUT
MOV CH,12 ;another 1.2 seconds pause
CALL JMP_TIMER
MOV AL,' ' ;space character
;
; If printing +++ and ATH, ATD, etc. move the three semicolons up one
; line to include a space on the crt to look better.
;
DB 90H,90H,90H
;;; CALL STYPE ;show on local crt only
MOV BX,(Offset SM_DISC1) ;now disconnect the modem
CALL SENDOUT
;
DISCONN2:
CALL JMP_INMODEM ;wait 0.1 seconds after last char.
JNB DISCONN2
RET
;...
;
;
; Hayes Stuff
;
SMQUIET:
MOV AL,Byte Ptr SPKRFLG ;speaker flag set to quiet?
OR AL,AL
JZ L2A23
RET ;if yes, forget it
L2A23:
MOV AL,YES
MOV BYTE PTR SPKRFLG,AL ;flip the flag to quiet, now
MOV BX,(Offset SM_SPKOFF)
CALL SENDOUT
MOV CH,6
JMP JMP_TIMER ;time for an 'ok' from modem and return
;.....
;
;
SMNOISEY:
MOV AL,Byte Ptr SPKRFLG ;speaker already turned on?
OR AL,AL
JNZ L2A24
RET ;if yes, forget it
L2A24:
MOV AL,NO ;set for noisey, now
MOV BYTE PTR SPKRFLG,AL
MOV BX,(Offset SM_SPKON)
CALL SENDOUT
MOV CH,6
JMP JMP_TIMER
;.....
;
;
; Hayes-like autodial modem control codes
;
SM_DIAL DB 'ATDT $' ;set for touch (or pulse) dialing
SM_DISC DB '+++$' ;puts the modem in local command mode
SM_DISC1 DB 'ATH0',CR,'$' ;disconnects the modem
SM_SPKOFF DB 'ATM0',CR,'$' ;turns the speaker off
SM_SPKON DB 'ATM1',CR,'$' ;turns the speaker on
SPKRFLG DB 0 ;0 = speaker has not been silenced
;.....
;
;
; Set the autodial modem for pulse dialing
;
SMINIT: MOV AL,Byte Ptr TOUCHPULSE ;touch or pulse dialing for autodial?
MOV Byte Ptr SM_DIAL+3,AL ;store
MOV BX,(Offset SM_DIAL)
CALL SENDOUT
;
SMINIT1:CALL JMP_INMODEM ;wait for modem to finish, if needed
JNB SMINIT1
RET
;.....
;
;
; Send the string pointed to by 'BX' to both the CRT and the modem.
;
SENDOUT:CALL SENDNOW ;wait until modem is ready
MOV AL,Byte Ptr [BX] ;get the character
CMP AL,'$'
JNZ L2A29
RET ;if yes, finished
L2A29:
MOV AL,Byte Ptr [BX]
CALL OUT_MODDATP ;send to modem
;
;
; If you want to print the +++ ATD, etc. from Hayes-type units, move the
; three semicolons down one line.
;
;;; CALL STYPE ;show on CRT
DB 90H,90H,90H
INC BX
JMPS SENDOUT
;.....
;
;
; Checks for answer from Hayes-type autodial modem
;
SMRESULT:
CALL RCVREADY ;see if any incoming character yet
JZ SMRESUL1 ;if yes, exit and look at it
CALL STAT ;else see if want to abort ringing
JZ SMRESULT ;if neither, wait for one of them
CALL KEYIN ;get character from keyboard
CMP AL,CANCEL ;CTL-X to terminate dialing?
JNZ SMRESULT ;if not, keep going
MOV CH,CR
CALL SENDCHR ;tells the modem to hang up right away
JMP DIALEXIT ;abort dialing routine
;
SMRESUL1:
CALL IN_MODDATP ;get the character, then
AND AL,7FH ;remove any parity
MOV CH,AL ;store for 'GIVLF' area if needed
CMP AL,'B' ;'BUSY' (for Anchor modems, etc.)
JZ BUSY ;if busy, flush string and retry
CMP AL,'0' ;'OK' single digit result code
JZ SMRESUL1 ;ok, loop for next response
CMP AL,'O' ;'ok' verbose digit result code
JZ SMRESUL1 ;ok loop for next response
CMP AL,'1' ;'CONNECT', single digit result code
JNZ L2A30
JMP ON_LINE ;connected, reset redial flags
L2A30:
CMP AL,'C' ;'CONNECT', verbose result code
JNZ L2A31
JMP ON_LINE ;connected, reset redial flags
L2A31:
CMP AL,'3' ;'NO CARRIER', single digit result code
JZ NO_CARRIER ;no carrier, flush string and retry
CMP AL,'N' ;'NO CARRIER', verbose result code
JZ NO_CARRIER ;no carrier, flush string and retry
CMP AL,'4' ;'ERROR', single digit result code
JNZ L2A32
JMP FAILED ;error, go display
L2A32:
CMP AL,'E' ;'ERROR', verbose result code
JNZ L2A33
JMP FAILED ;error, go display
L2A33:
CMP AL,'5' ;'CONNECT 1200' single digit result code
JNZ SMDM1
JMP ON_1200 ;connected, reset redial flags
;
SMDM1: CMP AL,LF ;<LF> is end-of-line for verbose mode
JZ SMRESULT ;yes, go get the next response
CMP AL,CR ;<CR> may precede digit in digit mode
JZ SMRESULT ;yes, go get the next response
;
CALL STAT ;else, see if want to abort ringing
JZ SMDM1A ;if not, get next character
CALL KEYIN ;else, get character from keyboard
CMP AL,CANCEL ;CTL-X to terminate dialing?
JNZ SMDM1A ;if not, keep going
MOV CH,CR
CALL SENDCHR ;tells the modem to hang up right away
JMP DIALEXIT ;abort dialing routine
;
SMDM1A: CALL JMP_INMODEM ;get next character
JMPS SMDM1 ;loop until end of response encountered
;
;
; The Anchor modem gives a busy result code, although still waits the
; normal time-out period to do it.
;
BUSY: CALL JMP_ILPRT
DB 'busy! ',0
JMP DIALAGN
;.....
;
;
; Failed call is usually caused by continuous ringing with no answer.
; The modem times out (can be set to either 30 seconds or 60 seconds.
;
FAILED: CALL JMP_ILPRT
DB 'abort ',0
JMP DIALAGN
;.....
;
;
NO_CARRIER:
CALL JMP_ILPRT
DB 'no carrier ',0
JMP DIALAGN
;.....
;
;
ON_LINE:
CALL JMP_ILPRT
DB 'on line',0
JMP CONMADE
;.....
;
;
ON_1200:
CALL JMP_ILPRT
DB 'on at 1200',0
JMP CONMADE
;.....
;
; END OF SPECIAL HAYES-LIKE HANDLING
;------------------------------------------------------------------------
;
; Handles the special ringback numbers. Dials, lets it ring only once,
; hangs up and then redials.
;
RINGBK: MOV AL,Byte Ptr AUTODIAL ;using a Hayes-type modem?
OR AL,AL
JNZ RINGBK2 ;if yes, ringback not possible
MOV AL,Byte Ptr CMDBUF+1 ;get the number of chars. in the buffer
DEC AL ;subtract 1 to avoid the ringback char
MOV Byte Ptr CMDBUF+1,AL ;store the new value
MOV DH,DTMSK ;load tone detect mask
MOV CL,RBLMT ;waits up to 7 seconds for a ring
CALL WAIT
JB RINGBK0 ;if no ring detected, pretend we got one
JMP RINGBK1 ;hangup, redial, & listen for carrier
;
RINGBK0:
MOV CH,25 ;got a ring, wait 2.5 sec
CALL TIMER
CALL IN_BAUDRP ;is tone still present?
AND AL,DH
JNZ RINGBK1
JMP DIALAGN ;yes, must be busy, do a normal redial
;.....
;
;
; Hang up, redial and listen for dial tone
;
RINGBK1:CALL HANGUP ;hang up the phone
CALL JMP_ILPRT
DB 'ringback set, first ring ',0
MOV CH,RBWAIT ;wait 5 seconds before redialing..
CALL JMP_TIMER ;..for line to clear, etc.
CALL DIALBGN ;disconnect, reconnect, wait for tone
JNB L2A38
JMP DIALEXIT ;go redial number
L2A38:
MOV AL,BYTE PTR NUMBER ;number of characters in buffer
CMP AL,1+1 ;more than one character?
JNB L2A38A
JMP DIAL12 ;go redial for the table ringback number
;
L2A38A: JMP DIAL14 ;if more than one, hand-entered number
;.....
;
;
RINGBK2:CALL JMP_ILPRT
DB CR,LF,'++ No ringback for autodial modem ++',0
POP BX ;reset the stack
JMP DIALEXIT
;.....
;
;
HANGUP: MOV AL,CLEAR
CALL OUT_MODCTL2
XOR AL,AL
JMP OUT_MODCTL1 ;turn off DTR, originate/answer tones
;.....
;
;
; This is the auto-linking area. Up to 32 numbers may be linked, each
; should have a comma for a separator, such as:
;
; B>>COMMAND: CAL A,F,3,A,G,A,H
;
AUTO: MOV BYTE PTR AUTODIR,AL ;direct to terminal mode on answer
;
AUTO1: MOV BYTE PTR AUTOFL,0FFH ;set the auto-linking flag
MOV BYTE PTR CRFLAG,0FFH ;set the continuous redial flag
MOV CH,64 ;maximum number of characters to move
MOV BX,OFFSET CMDBUF+1 ;start with number in the string
MOV DX,OFFSET CMDBUF+65 ;move to aft part of buffer
JMP MOVE
;.....
;
;
; Linking routine
;
AUTO2: MOV AL,BYTE PTR AUTOFL ;increment the flag for each new try
INC AL
INC AL
MOV BYTE PTR AUTOFL,AL
MOV CL,AL ;hold momentarily
MOV CH,0
MOV AL,BYTE PTR CMDBUF+65 ;see how many characters typed
CMP AL,CL
JNB AUTO3
MOV AL,1 ;reset the flag to start over
MOV CL,AL
MOV BYTE PTR AUTOFL,AL
;
AUTO3: MOV BX,OFFSET CMDBUF+65
ADD BX,CX
JMP DIAL6 ;go to work
;.....
;
;
AUTODIR DB 0 ;direct to terminal mode on answer
AUTOFL DB 0 ;auto-linking flag
NUMBER DB 0 ;number of characters in CMDBUF
;.....
;
;
; Time-out routine. Must be called with mask in 'D' reg. for input at
; relative port 2 and number of seconds (times 10) in 'C' reg.
;
WAIT: MOV CH,2
CALL TIMER ;wait for timer to go high then low
CALL IN_BAUDRP ;PMMIADDR+2 (modem status port)
AND AL,DH ;(CTS or dialtone mask)
JNZ L2A39
RET ;active low, so return on 0
L2A39:
PUSH CX ;save..
PUSH DX ;..active registers
CALL STAT ;keypress?
JZ WAIT1 ;if not, exit
CALL KEYIN ;yes, get char
CMP AL,CANCEL ;CTL-X to intentionally abort?
JZ WAIT2 ;yes, disconnect, jmp to menu
;
WAIT1: POP DX ;restore..
POP CX ;..registers
DEC CL ;count-down
JNZ WAIT
STC ;set carry to indicate mask not set
RET
;.....
;
;
WAIT2: POP DX ;reset..
POP CX ;..stack
JMP DONETCD ;disconnect
;.....
;
; (END OF HAYES/PMMI DIALING ROUTINE)
;=======================================================================
; SPECIAL PMMI MENU
;
SPCLMENU:
MOV AL,Byte Ptr PMMIMODEM
OR AL,AL
JNZ L2A40
RET
L2A40:
CALL JMP_NXTSCRN
CALL ILPRT
DB ' Additional Subcommands for PMMI Modems'
DB CR,LF,LF
DB ' Modem control:',CR,LF
DB ' A - Answer tone for send or receive',CR,LF
DB ' O - Originate tone for send or receive',CR,LF,LF
DB ' Parity option:',CR,LF
DB ' 1 - Set and check for odd parity',CR,LF
DB ' 0 - Set and check for even parity',CR,LF
DB ' Both ends must be capable of these options'
DB CR,LF
DB ' which are available only in R and S modes.'
DB CR,LF
DB ' The parity checking will be part of the'
DB CR,LF
DB ' file transfer protocol.',CR,LF,LF
DB ' Speed Options:',CR,LF
DB ' After entering your primary and secondary '
DB 'options,',CR,LF
DB ' you can set the modem speed by placing a '
DB ' "." after',CR,LF
DB ' the options followed by the speed e.g., '
DB '300, 600.',CR,LF,LF
DB ' EXAMPLE: SBO.600 will set the modem for '
DB '600 baud',CR,LF,0
RET ;all done
;.....
; (END OF PMMI MENU)
;=======================================================================
;
;
; Timer routine. Waits 0.1 seconds for each unit in 'B' reg.
;
TIMER: PUSH BX
;
TIMER1: PUSH CX
;
TIMER2: CALL JMP_INMODEM ;100 ms. delay per loop
JNB TIMER2
POP CX
DEC CH
JNZ TIMER1
POP BX
RET
;.....
;
;
;
;************** END OF SPECIAL HAYES/PMMI ROUTINES *********************
;
;
;=======================================================================
;
ORG ((offset $+255+50)/256*256)-50 ;even page for 'NUMLIB'
;
;
;
CRITE: CALL JMP_ILPRT
DB 'for Menu)',CR,LF,'Copyright (c) '
DB '1984 - Irvin M. Hoff',CR,LF
DB 'Translation to CPM-86 - Alex K. Soya',CR,LF,0
RET
;.....
;
; END OF SPECIAL PATCH AREA
;=======================================================================
;
; Long distance alternate dialing such as MCI, SPRINT, etc. Must end
; with a '$', use as many commas (2 seconds delay, each) as needed to
; let the alternate dialing code return with a new dial tone. Fill in
; any character (periods are fine) after the $ to keep number of columns
; to 24, i.e., '1234567,,,,12345,,$.....' -- the first group is the
; MCI or SPRINT access number, the second group is the user number. A
; small delay is usually required after the billing number also.
;
ALTDIAL1 DB 'xxxxxxx,,,,,,xxxxxxxx,,$' ;accessed by a < character
;
ALTDIAL2 DB 'xxxxxxx,,,,,,xxxxxxxx,,$' ;accessed by a > character
;
;=======================================================================
;
HEXSHOW DB SHOWHEX ;can easily change SHOWHEX via DDT
;
SAVSIZ DB XFRSIZ*8 ;can easily change buffer size for file
;transfers with DDT for "NUMBLIB-1" ad-
;dress. Normally 4k (32 records or 4k).
;
;=======================================================================
;
; Phone number library table for auto-dialing. Each number must be as
; long as"LIBLEN" (EQU at start of program). Some areas require extra
; characters such as: 1-313-846-7127. Room is left for those. Use
; a (<) for alternate dialing system #1, and a (>) for alternate dialing
; System #2. Either would preceed the actual number, for example:
;
; DB 'A=Alan Alda..........<123-456-7890' ;'A'
;
; - - - - - - - - - - - -
;
; NOTE: At least one dot (.) MUST precede the actual phone number
;
; '----5---10---15---20---25---30--34'
NUMBLIB DB 'A=Bob Robesky.......1-209-227-2083' ;'A'
DB 'B=Byron McKay.......1-415-965-4097' ;'B'
DB 'C=Bruce Jorgens.....1-509-255-6324' ;'C'
DB 'D=Phil Cary.........1-505-522-8856' ;'D'
DB 'E=Bill Earnest......1-215-398-3937' ;'E'
DB 'F=Chuck Forsberg....1-503-621-3193' ;'F'
DB 'G=Ron Fowler........1-414-563-9932' ;'G'
DB 'H=Charlie Hoffman...1-813-831-7276' ;'H'
DB 'I=Jack Kinn.........1-817-547-8890' ;'I'
DB 'J=Walt Jung.........1-301-661-2175' ;'J'
DB 'K=Sigi Kluger.......1-915-598-1668' ;'K'
DB 'L=Keith Petersen....1-313-759-6569' ;'L'
DB 'M=Wayne Masters.....1-408-378-7474' ;'M'
DB 'N=Dick Mead.........1-213-799-1632' ;'N'
DB 'O=Al Mehr...........1-408-238-9621' ;'O'
DB 'P=Pasadena RBBS.....1-213-577-9947' ;'P'
DB 'Q=Mark Pulver.......1-312-789-0499' ;'Q'
DB 'R=Bruce Ratoff......1-201-272-1874' ;'R'
DB 'S=Ken Stritzel......1-201-584-9227' ;'S'
DB 'T=TCBBS, Dearborn...1-313-846-6127' ;'T'
DB 'U=AnaHUG RCPM.......1-714-774-7860' ;'U'
DB 'V=Dave Austin.......1-707-257-6502' ;'V'
DB 'W=Paul Bagdonovitch.1-201-747-7301' ;'W'
DB 'X=Kirk De Haan......1-408-296-5078' ;'X'
DB 'Y=Byron Kantor......1-619-273-4354' ;'Y'
DB 'Z=Chuck Metz........1-408-354-5934' ;'Z'
DB '0=Bill Parrott......1-913-682-3328' ;'0'
DB '1=Larry Snyder......1-305-671-2330' ;'1'
DB '2=Alex Soya.........1-305-259-7955' ;'2'
DB '3=Tony Stanley......1-912-929-8728' ;'3'
DB '4=Ed Svoboda........1-408-732-9190' ;'4'
DB '5=Tampa Bay Bandit..1-813-937-3608' ;'5'
DB '6=Thousand Oaks.....1-805-492-5472' ;'6'
DB '7=Bill Wood.........1-619-256-3914' ;'7'
DB '8=Spare.............1-xxx-xxx-xxxx' ;'8'
DB '9=Spare.............1-xxx-xxx-xxxx' ;'9'
DB 0 ;end
; '----5---10---15---20---25---30--34'
;
;-----------------------------------------------------------------------
;
; This is the storage area for the ten function keys. The M7FNK.COM
; program dynamically allocates the storage for the keys. Thus, no
; function key is limited to so-and-so many characters. Rather, the
; total number of bytes in the function key library (including flags)
; is 256.
;
INTCPT DB '^' ;intercept character (prefix)
;
FNCTBL DB 0,'DIR ',CR,0
DB 1,'DIR *.* $U0AD ',CR,0
DB 2,'XMODEM S ',0
DB 3,'XMODEM R ',0
DB 4,'BYE ',CR,0
DB 5,'RBBS ',CR,0
DB 6,'(vacant)',0
DB 7,'(vacant)',0
DB 8,'(vacant)',0
DB 9,'Nice chatting, see you again soon... ',CR,0
RS 256-((Offset $)-(Offset FNCTBL))
;
;
;
;***********************************************************************
;
;
; P - R - O - G - R - A - M S - T - A - R - T - S H - E - R - E
;
;
;***********************************************************************
;
;
START: MOV AX,CS ; stack resides in the Code Segment
MOV SS,AX
MOV SP, Offset STACK ;start local stack
;
;
; The 'FIXCNT' calculations are done here and the values stored so the
; overhead of doing the calculation is not incurred in the RECV routine
; where it is desired to pick up a character from the modem data port as
; quickly as possible.
;
MOV BX,590 ;adjust to get 1 second time intervals
CALL FIXCNT
MOV Word Ptr TIMVAL,BX
MOV BX,36 ;should be 1/16 of above value
CALL FIXCNT
MOV Word Ptr QUIKTIM,BX
;
;
; Now display the program name and version number and we are under way
;
CALL ILPRT
DB CR,LF,'MDM',VERSION/100+'0',VERSION MOD 100/10+'0'
DB VERSION MOD 10+'0',' modem pgm (type M ',0
CALL CRITE
CALL JMP_SYSVER ;give configuration message
CALL CRCGEN ;generate tables for fast 'CRC' check
CALL INITADR ;initialize addresses
CALL INTERCEPT ;establish the function key intercept
CALL PROCOPT ;process any options
MOV AL,Byte Ptr OPTION ;any options on the command line?
CMP AL,' '+1
JNB RESTART
JMP MENU ;if not, show the menu
;
;
; Comes here from menu once the options have been set
;
RESTART:MOV SP, Offset STACK ;make sure we have a clean stack
CALL CKCHAR ;catch any garbage characters left over
MOV AL,Byte Ptr PMMIMODEM
OR AL,AL
JNZ RESTART1 ;if yes, accept 'C' or 'D'
MOV AL,Byte Ptr AUTODIAL ;using a Hayes-type modem?
OR AL,AL
JZ RESTART2 ;exit if neither modem-type
;
RESTART1:
MOV AL,Byte Ptr OPTION ;get the option
CMP AL,'C' ;call (dial) function?
JNZ L3A2
JMP JMP_DIAL ;yes, go to it
L3A2:
MOV AL,Byte Ptr PMMIMODEM
OR AL,AL
JZ RESTART2
CALL SETBAUD ;just the PMMI has to check each time
;
RESTART2:
CALL MOVEFCB
MOV AL,Byte Ptr OPTION ;get main option
CMP AL,'D' ;disconnect?
JNZ L3A4
JMP DONETCD ;yes, disconnect then back to the menu
L3A4:
CMP AL,'M' ;menu asked for?
JNZ L3A5
JMP MENU2 ;go display the menu
L3A5:
CMP AL,'R' ;want to receive a file?
JNZ L3A6
JMP RCVFIL ;exit if yes
L3A6:
CMP AL,'S' ;want to send a file?
JNZ L3A7
JMP SENDFIL ;exit if yes
L3A7:
CMP AL,'T' ;want terminal mode?
JNZ RESTART3 ;if not, exit
XOR AL,AL
MOV Byte Ptr ECHOFLG,AL ;reset echo flag
MOV Byte Ptr LOCFLG,AL ;reset local flag
JMP DSKSAVE ;exit if yes
;
RESTART3:
CMP AL,'E' ;want echo mode?
JNZ NOECHO ;if not, exit
MOV Byte Ptr ECHOFLG,AL ;set the echo flag
XOR AL,AL
MOV Byte Ptr LOCFLG,AL ;reset local flag
JMP DSKSAVE
;
NOECHO: CMP AL,'L' ;want local echo mode?
JNZ NOLOCAL ;if not, exit
MOV Byte Ptr LOCFLG,AL ;set the local flag
XOR AL,AL
MOV Byte Ptr ECHOFLG,AL ;reset echo flag
JMP DSKSAVE
;
NOLOCAL:CALL NTVLDMSG ;say not a valid option
JMP MENU ;then go back to the command mode
;....
;
;
INITADR:CALL GETUSER ;get current user number
MOV Byte Ptr OLDUSER,AL ;save to restore upon exit
CALL GETMAX ;find maximum ram for printer use
JMP JMP_INITMOD ;initialize non-PMMI systems if needed
;.....
;
;
; Get the function key intercept character and put in appropriate places
;
INTERCEPT:
MOV AL,Byte Ptr INTCPT ;get the function key intercept char.
AND AL,07FH ;strip off any parity
MOV Byte Ptr FNCKY,AL ;store
CMP AL,' ' ;printing character?
JNB INTER2 ;if yes, exit
ADD AL,40H ;change to printing character
JMP FIXFNK ;fix-patch area of extra bytes
;
INTER1: MOV AL,'^'
MOV BYTE PTR MENU3,AL ;store the "control-" character
RET
;
INTER2: MOV Byte Ptr MENU3+1,AL
RET
;.....
;
;
; Process any options - put 0 in appropriate place in option table if
; option is selected
;
PROCOPT:MOV DX,Offset FCB+1
MOV SI,DX
MOV AL,[SI]
MOV Byte Ptr OPTION,AL
CMP AL,' ' ;exit if no options
JNZ OPTLP
RET
;
OPTLP: INC DX
MOV SI,DX
MOV AL,[SI]
CMP AL,' '
JZ ENDOPT
MOV BX, Offset OPTBL
MOV CH, (Offset OPTBE)-(Offset OPTBL)
;
OPTCK: CMP AL,Byte Ptr [BX]
JNZ OPTNO
CMP AL,'O' ;want originate tones?
MOV CH,AL ;store momentarily
MOV AL,ORIGMOD
JZ OPTCK1
MOV AL,CH ;get the option back
CMP AL,'A' ;want answer tones?
JNZ OPTCK2 ;if not, exit
MOV AL,ANSWMOD
;
OPTCK1: MOV Byte Ptr UARTCTLB,AL
;
OPTCK2: MOV Byte Ptr [BX],0
JMPS OPTLP
;
OPTNO: INC BX
DEC CH
JNZ OPTCK
CALL NTVLDMSG
POP BX ;preserve stack
JMP MENU
;
ENDOPT: MOV AL,Byte Ptr VSEEFLG
OR AL,AL
JNZ CKOPTN
MOV Byte Ptr QFLG,AL ;quiet mode for watching data items
;
CKOPTN: MOV AL,Byte Ptr OPTION ;check on the primary option
CMP AL,'D' ;going to disconnect?
JNZ L3A9
RET
L3A9:
CMP AL,'E' ;return if echo option
JNZ L3A10
RET
L3A10:
CMP AL,'M' ;return if help option
JNZ L3A11
RET
L3A11:
CMP AL,'L' ;return if local echo option
JNZ L3A12
RET
L3A12:
CMP AL,'T' ;return if terminal mode
JNZ L3A13
RET
L3A13:
MOV CH,AL ;save the primary option for a moment
MOV AL,Byte Ptr PMMIMODEM ;PMMI modem?
OR AL,AL
JNZ CKOPTN0 ;if yes, accept 'C'
MOV AL,Byte Ptr AUTODIAL ;using a Hayes-type modem?
OR AL,AL
JZ CKOPTN1 ;exit if neither
;
CKOPTN0:MOV AL,CH ;get the character back
CMP AL,'C' ;going to call a number now?
JNZ L3A14
RET
L3A14:
;
CKOPTN1:MOV AL,Byte Ptr NFILFLG ;saving memory for disk file?
OR AL,AL
JZ CKOPTN2 ;if not, continue
POP BX ;reset the stack from 'CALL PROCOPT'
JMP MENU0 ;go show the 'FILE OPEN' message
;
CKOPTN2:MOV AL,CH ;get the option back
CMP AL,'S'
JZ CKFILE
CMP AL,'R'
JNZ BDOPT ;none of these, bad option
MOV AL,Byte Ptr BATCHFLG ;see if the batch mode flag is set
OR AL,AL
JNZ CKFILE
RET ;if yes, exit
;
CKFILE: MOV AL,Byte Ptr FCB+17 ;'S' and 'R' need a file name
CMP AL,' '
JZ REENT
RET ;exit if a file name is present
;
REENT: CALL ILPRT
DB '++ Enter primary option plus file name ++'
DB CR,LF,BELL,0
POP BX ;reset stack from 'CALL SETFCB
JMP MENU ;abort to command line
;.....
;
;
BDOPT: CALL ILPRT
DB CR,LF,'++ Bad option ++',CR,LF,LF,0
;.....
;
;
; Check for any garbage characters on line - catch and ignore
;
CKCHAR: CALL RCVREADY ;any characters ready to receive?
JZ L3A17
RET ;if not, return
L3A17:
CALL IN_MODDATP ;otherwise get the character and ignore
JMPS CKCHAR ;check for any additional characters
;.....
;
;
; Revised terminal routine allowing memory save. First checks for bad
; options, to prevent wiping out the disk with accidental memory save.
;
DSKSAVE:MOV AL,Byte Ptr BATCHFLG ;batch flag set?
OR AL,AL
JNZ DSKSAVE1 ;if not set, everything is normal
MOV AL,'B' ;if set, shouldn't be, so reset it
MOV Byte Ptr BATCHFLG,AL
JMP NOTVLD ;if set, error for 'E', 'L' or 'T'
;
DSKSAVE1:
MOV Byte Ptr XFLG,AL ;will use the ASCII capture buffer size
MOV AL,Byte Ptr NFILFLG ;already saving for a file?
OR AL,AL
JZ DSKSAVE2 ;exit if not, and open a file
CALL BUFMSG ;tell if buffer if on or off
JMPS TERM
;
DSKSAVE2:
MOV AL,Byte Ptr .FCB+1 ;first character of filename (if any)
CMP AL,' ' ;file specified?
JNZ GOODNM ;yes, good name
XOR AL,AL
MOV Byte Ptr NFILFLG,AL ;show no file being saved
MOV Byte Ptr SAVEFLG,AL ;reset the flag to zero
JMPS TERM
;...
;
;
GOODNM: CALL ERASFIL
MOV BX, Offset FCB3
CALL INITFCB
MOV BX, Offset FCB ;move the disk name into FCB3 area
MOV DX, Offset FCB3
MOV CH,12
CALL MOVE
MOV DX, Offset FCB3 ;now make a file from that name
MOV CL,MAKE
INT 224
MOV DX, Offset FCB3 ;now open the file from FCB3
MOV CL,OPEN
INT 224
MOV BX, offset BUFFER ;reset pointers to start of buffer
MOV Word Ptr HLSAVE,BX
MOV AL,1
MOV Byte Ptr NFILFLG,AL ;show now saving to memory for disk file
CALL BUFMSG2 ;show buffer is available
;
TERM: MOV AL,Byte Ptr LSTTST ;allowing the printer to be used?
OR AL,AL
JZ L3A18
CALL GOLIST ;if yes, see if anything to print
L3A18:
CALL STAT ;keyboard have a character?
JNZ L3A19
JMP TERML ;if not, see if any incoming
L3A19:
CALL KEYIN ;get character from keyboard
MOV CH,AL ;save for now to protect 'A' reg.
CMP AL,RUB ;test for rub
JNZ NOTRUB ;exit if not
MOV AL,Byte Ptr CONVRUB ;convert rub to backspace?
OR AL,AL
JZ NOTRUB ;exit if no conversion
MOV CH,BKSP ;call it a backspace
JMP NOTOG ;go send a backspace
;
NOTRUB: MOV AL,Byte Ptr FNKFLG ;get function key active flag
OR AL,AL
JZ NOF ;if not set yet, exit
MOV AL,CH ;get character
CMP AL,'0'
JB NOFNK1 ;ignore invalid key codes
CMP AL,'9'+1
JNB NOFNK1
AND AL,0FH ;make 0..9
JMP SENDFK
;
NOF: MOV AL,Byte Ptr INTCPT ;check intercept character
CMP AL,CH
JNZ NOFNK1 ;skip if no function key
MOV Byte Ptr FNKFLG,AL ;set the function flag
JMP TERML ;do not send the intercept character
;
NOFNK1: XOR AL,AL ;reset the flag
MOV Byte Ptr FNKFLG,AL
MOV AL,Byte Ptr EXACFLG
OR AL,AL ;exact?
MOV AL,0 ;(cannot use 'XRA A' here)
MOV Byte Ptr EXACFLG,AL ;clear for next time
JZ NTEXAFLG ;go if EXACFLG not set 'YES'
MOV AL,Byte Ptr LOCNXTCHR
OR AL,AL ;should we send on exacflg?
JNZ L3A20
JMP NOTOG ;jump if LOCONEXTCHR 'NO'
L3A20:
MOV AL,Byte Ptr EXTCHR ;we want to send EXTCHR in any case
CMP AL,CH
JNZ L3A21
JMP NOTOG ;send if EXTCHR
L3A21:
JMPS LOCCHK ;otherwise do local stuff
;...
;
;
NTEXAFLG:
MOV AL,Byte Ptr EXTCHR ;treat next character in special way?
CMP AL,CH ;check against this control character
JNZ NTEXA1 ;yes, set exacflg for next character
MOV AL,1
MOV Byte Ptr EXACFLG,AL ;set the flag
JMP TERM ;do not send, get next character
;
NTEXA1: MOV AL,Byte Ptr LOCNXTCHR
OR AL,AL ;should we send if not EXACFLG?
JZ LOCCHK
JMP NOTOG ;jump if loconextchr 'YES'
;
LOCCHK: CALL EXITTST1 ;want to exit to menu?
MOV AL,Byte Ptr NOCONNCT ;want to disconnect from line?
CMP AL,CH
JNZ L3A23
JMP DONETCD ;if yes go disconnect
L3A23:
MOV AL,Byte Ptr TRANCHR ;output text file to remote?
CMP AL,CH
JNZ L3A24
JMP TRANSFER
L3A24:
MOV AL,Byte Ptr TRANLOGON
OR AL,AL
JZ SKPLOGON
MOV AL,Byte Ptr LOGCHR ;send logon?
CMP AL,CH
JNZ L3A25
JMP SENDLOG
L3A25:
;
SKPLOGON:
MOV AL,Byte Ptr LSTTST ;going to use the external printer?
OR AL,AL
JZ NOLST ;if not, skip this area
MOV AL,Byte Ptr LSTCHR ;get the printer control-character
CMP AL,CH ;did we just ask for printer control?
JNZ NOLST ;if not, exit
MOV AL,Byte Ptr LISTFLG ;otherwise reset the printer toggle
NOT AL
MOV Byte Ptr LISTFLG,AL ;and store
CALL CRLF
CALL CRLF
CALL LSTMSG ;tell if printer is on or off now
CALL CRLF
JMP TERML ;back to the terminal mode again
;.....
;
;
NOLST: MOV AL,Byte Ptr BRKCHR ;PMMI break?
CMP AL,CH
JNZ L3A26
JMP BREAK
L3A26:
MOV AL,Byte Ptr PMMIMODEM ;using a PMMI board?
OR AL,AL
JZ NOLST1 ;if not, skip the next few lines
MOV AL,Byte Ptr CHGBAUD ;PMMI change baud?
CMP AL,CH
LAHF
XCHG AL,AH
PUSH AX
PUSH BX
JNZ L3A27
CALL JMP_NEWBAUD
L3A27:
POP BX
POP AX
XCHG AL,AH
SAHF
JNZ NOLST1
JMP TERML
;...
;
;
NOLST1: MOV AL,Byte Ptr UNSAVECHR ;close input buffer?
CMP AL,CH
JZ NOLST2 ;if yes, disable copy
MOV AL,Byte Ptr SAVECHR ;open input buffer?
CMP AL,CH
JZ L3A29
JMP NOTOG
L3A29:
MOV AL,Byte Ptr NFILFLG ;do not allow save if..
OR AL,AL
JNZ L3A30
JMP TERML ;..this flag is set.
L3A30:
JMPS NOLST3
;
NOLST2: XOR AL,AL ;stop copy into file
;
NOLST3: MOV Byte Ptr SAVEFLG,AL
CALL BUFMSG
JMP TERM ;get next character
;.....
;
;
;***********************************************************************
;
; SEND A CP/M FILE
;
;***********************************************************************
;
;
SENDFIL:XOR AL,AL ;set to checksum initially on send
MOV Byte Ptr CRCFLAG,AL ;..initially on send
CALL CKCHAR ;catch any garbage characters
;
SENDFIL1:
MOV AL,Byte Ptr BATCHFLG ;check if multiple file..
OR AL,AL ;..mode is set.
JNZ SENDC1
CALL ILPRT
DB 'Ready to send in batch mode',CR,LF,0
;
SENDFIL2:
CALL JMP_PARITY
MOV AL,YES ;indicate send for batch mode
MOV Byte Ptr SENDFLG,AL
MOV AL,Byte Ptr FSTFLG ;if first time through..
OR AL,AL ;..scan the command line..
JNZ L3A31
CALL TNMBUF ;..for multiple names.
L3A31:
CALL SENDFN ;sends file name to receive
LAHF
XCHG AL,AH
PUSH AX
CALL CRLF
CALL SHOWFIL
MOV AL,' '
CALL STYPE
POP AX
XCHG AL,AH
SAHF
JNB SENDC2 ;carry set means no more files
MOV AL,'B' ;stop batch
MOV Byte Ptr BATCHFLG,AL ;mode option
MOV AL,EOT ;final transfer end
CALL SEND
JMP DONE
;
SENDC1: MOV AL,Byte Ptr FCB+1
CMP AL,' '
JNZ SENDC2
JMP BLKFILE
;
SENDC2: CALL CNREC ;get number of records
CALL OPENFIL
MOV DL,120 ;wait 2 minutes maximum
CALL WAITNAK
;
SENDLP: CALL CKABORT ;want to terminate while sending file?
CALL RDRECD
JB SENDEOF
CALL INCRRNO
MOV AL,1
MOV Byte Ptr ERRCT,AL
;
SENDRPT:CALL CKABORT ;want to terminate while sending file?
CALL SENDHDR
CALL SENDREC
MOV AL,Byte Ptr CRCFLAG
OR AL,AL
JNZ SNDCRC
CALL SENDCKS
JMPS SNDCONT
;
SNDCRC: CALL SENDCRC
;
SNDCONT:CALL GETACK
JB SENDRPT
JMPS SENDLP
;.....
;
;
SENDEOF:MOV AL,EOT
CALL SEND
CALL GETACK
JB SENDEOF
JMP DONE
;.....
;
;
;***********************************************************************
;
; RECEIVE A CP/M FILE
;
;***********************************************************************
;
;
RCVFIL: MOV AL,Byte Ptr CRCDFLT ;get mode requested by operator
MOV Byte Ptr CRCFLAG,AL ;store it
;
RCVFIL1:CALL JMP_PARITY
MOV AL,Byte Ptr BATCHFLG ;check if multiple file mode
OR AL,AL
JNZ RCVC1 ;if not, exit
MOV AL,NO ;flag where to return..
MOV Byte Ptr SENDFLG,AL ;..for next file transfer
CALL GETFN ;get the file name
JNB RCVC2 ;carry set means no more files
MOV AL,'B' ;stop batch
MOV Byte Ptr BATCHFLG,AL ;mode option
JMP DONE
;
RCVC1: MOV AL,Byte Ptr FCB+1 ;make sure file is named
CMP AL,' '
JNZ L3A35
JMP BLKFILE
L3A35:
JMPS RCVC3
;
RCVC2: CALL SHOWFIL ;show the file name
MOV AL,' '
CALL STYPE
CALL SNDPRG ;get progress and wait for quiet line
CALL CKCPM2
CALL CRLF
CALL CKBAKUP
;
RCVC3: CALL ERASFIL
CALL MAKEFIL
CALL WAITQ1
MOV AL,Byte Ptr BATCHFLG ;do not print message if in batch mode
OR AL,AL
JZ RCVFST
CALL ILPRTQ
DB 'File open, ready to receive',CR,LF,0
;
RCVFST: MOV AL,Byte Ptr CRCFLAG
OR AL,AL
JZ RCVNAKM ;if in 'CRC' mode
CALL ILPRTQ ;then say so
DB 'CRC in effect',CR,LF,0
MOV AL,CRC
JMPS RCVLP0
;
RCVNAKM:CALL ILPRTQ ;else say 'CHECKSUM' mode
DB 'Checksum in effect',CR,LF,0
MOV AL,NAK
;
RCVLP0: LAHF
XCHG AL,AH
PUSH AX
CALL ILPRT
DB 'Waiting.....',0
;
NOPRG: POP AX
XCHG AL,AH
SAHF
CALL SEND
;
RCVLP: CALL RCVRECD
JB RCVEOT
CALL REPORT ;show record received if not in quiet
CALL WRRECD
CALL INCRRNO
CALL SENDACK
JMPS RCVLP
;
RCVEOT:
CALL WRBLOCK
CALL SENDACK
CALL CLOSFIL
JMP DONE
;
SENDACK:MOV AL,ACK
CALL SEND
RET
;
;.....
;
;
;=================== FILE TRANSFER IN T-MODE ===========================
;
;
; File transfer routine - called with CTL-T from terminal mode. Trans-
; fer may be cancelled while sending, by using CTL-X.
;
TRANSFER:
MOV BX, Offset FCB4
CALL INITFCB ;initializes FCBs pointed..
MOV BX, offset FCB+16 ;..to by 'BX' reg.
CALL INITFCB
;
;
; Get name of file to send in "T" (terminal) mode
;
GET: CALL ILPRT
DB CR,LF,'File name to send? (CR to abort): ',0
MOV DX, offset CMDBUF
CALL INBUF
MOV AL,Byte Ptr CMDBUF+2 ;was file entered?
CMP AL,' '
JNZ L3A36
JMP RETURN ;if not probably wanted to quit
L3A36:
MOV DX, Offset CMDBUF
MOV BX, Offset FCB4
CALL CMDLINE
MOV DX, Offset FCB4
MOV CL,OPEN
INT 224
CMP AL,0FFH ;return with 0FFH means 'NO SUCH FILE'
JNZ L3A37
JMP TRANSL
L3A37:
MOV AL,Byte Ptr XONWAIT ;waiting for X-on to send next line?
OR AL,AL
JNZ DLYSAV ;if yes, skip additional delays
;
;
; Choice of normal speed or delays between characters / lines
;
CALL ILPRT
DB 'Want to include time delays? (Y/N): ',0
CALL KBDCHR
CMP AL,'N' ;if 'N' send normal speed
JZ DLYSAV
XOR AL,AL ;otherwise use character/line delays
;
DLYSAV: MOV Byte Ptr DLYFLG,AL ;store the decision
CALL CRLF
MOV DX, Offset CMDBUF+2 ;make sure cmdbuf has been selected
MOV CL,SETDMA
INT 224
;
;
; Get 128-byte record
;
READMR: MOV DX, Offset FCB4
MOV CL,READ
INT 224
OR AL,AL ;check for a good read
JZ READMR1
DEC AL ;check for end of file to send
JZ RETURNS
CALL ERXIT ;neither of those, was a read error
DB '++ DISK READ ERROR ++','$'
;
;
; Successful read, so send the record
;
READMR1:CALL SEND80C ;send one 128-char record
CMP AL,EOFCHAR ;end of file - omit if object..
JZ RETURNS ;..code is to be sent.
CMP AL,CANCEL ;cancellation?
JNZ READMR
;
RETURN: CALL ILPRT
DB CR,LF,LF,'(in Terminal-mode now)',CR,LF,LF,0
CALL SENDNOW ;insures last character is finished
CALL CKCHAR ;catch any echo character on line
JMP TERM ;finished, back to t-mode
;.....
;
;
RETURNS:CALL ILPRT
DB CR,LF,'[Transfer completed]',0
JMPS RETURN
;.....
;
;
TRANSL: CALL ILPRT
DB CR,LF,BELL,'++ FILE NAME ERROR ++ ',CR,LF,0
JMP GET
;.....
;
;
; Send one 128-byes record
;
SEND80C:MOV CH,128 ;will send a maximum of 128 character
MOV BX, Offset CMDBUF+2 ;they are in the cmdbuf area
;
SENDCH1:PUSH DX
CALL SPEED ;0-90 ms. delay between characters
POP DX
MOV AL,Byte Ptr [BX]
CMP AL,EOFCHAR
JNZ L3A38
RET
L3A38:
CALL MODOUT ;send the character to modem
CALL STAT ;test to see if
OR AL,AL ;cancellation requested
JZ SKIP1
CALL KEYIN
CMP AL,CANCEL
JNZ L3A39
RET
L3A39:
;
SKIP1: INC BX
DEC CH
JNZ SENDCH1
RET
;.....
;
;
; Send the character to the output
;
MODOUT: PUSH AX ; save character so we can use AX
CMP AL,LF
JNZ MODOUTL
MOV AL,Byte Ptr ADDLF ;going to send the line feed to modem?
OR AL,AL
JNZ MODOUTL ;if yes, exit
POP AX ;get the char. back (a line feed)
CALL STYPE ;show on CRT, do not send to modem
RET
;
MODOUTL:MOV AL,Byte Ptr XOFFTST ;waiting for X-off, X-on ?
OR AL,AL
JZ L3A40
CALL TXOFF ;if yes, go check
L3A40:
CALL SENDRDY ;wait until modem is ready to send
JNZ MODOUTL
POP AX ;get the character back
CALL STYPE ;send character to CRT
CALL OUT_MODDATP ;send character to modem
CMP AL,CR ;was it an end of line?
JZ MODOUTN
RET ;if yes, see if any delay is needed
;
;
; Delay to allow slow BBS systems (most use BASIC) to enter the line.
; Choice of 0-9 for about 100 ms. each, maximum of 900 ms.
;
MODOUTN:MOV AL,Byte Ptr XONWAIT ;wait for X-on after CR?
OR AL,AL
JZ L3A42
JMP WAITXON ;if yes, handle separately
L3A42:
MOV DH,10
;
MODOUTT:PUSH DX
CALL SPEED1 ;10 ms delay
POP DX
DEC DH
JNZ MODOUTT ;10 loops for 100 ms.
RET
;.....
;
;
; Add from 0 to 90 ms. delay between characters for slow (most use
; BASIC) bulletin board systems. Also used to add 0-900 ms. delay
; between lines.
;
SPEED: MOV AL,Byte Ptr BYTDLY ;get delay between characters (0-9)
JMPS L3A43 ;1=10 ms, 5=50 ms, 9=90 ms, etc.
;
SPEED1: MOV AL,Byte Ptr CRDLY ;get delay after crlf (0-9)
L3A43:
OR AL,AL ;100 ms, 5=500 ms, 9=900 ms, etc.
JNZ L3A44
RET ;if no delay needed, return
L3A44:
MOV CL,AL ;store number requested in c-reg.
MOV AL,Byte Ptr DLYFLG ;want any delays this file?
OR AL,AL
JZ SPEED2
RET ;if not, skip this section
;
SPEED2: CALL SPEED3 ;outer loop
DEC CL
JNZ SPEED2
RET ;done whenever the c-reg. is zero
;...
;
;
SPEED3: PUSH BX ;save current 'BX' value
MOV BX,20
MOV AL,Byte Ptr XOFFTST
OR AL,AL
JZ SPEED4
MOV BX,20 ;adjust for 'X-OFF' testing
MOV AL,Byte Ptr ECHOFLG
OR AL,AL
JZ SPEED4
MOV AL,Byte Ptr LOCFLG
OR AL,AL
JZ SPEED4
MOV BX,25 ;adjust for remote echo
;
SPEED4: CALL FIXCNT ;multiply delay by clock speed
XCHG BX,DX ;transfer delay to 'DE'
POP BX ;restore current 'BX' from"speed3"
;
SPEED5: DEC DX ;inner loop
MOV AL,Byte Ptr XOFFTST
OR AL,AL
JZ L3A46
CALL TXOFF
L3A46:
MOV AL,DL
OR AL,DH
JNZ SPEED5
RET
;...
;
;
TXOFF: CALL RCVREADY
JZ L3A47
RET
L3A47:
CALL IN_MODDATP
AND AL,7FH
CMP AL,XOFF
JNZ L3A48
CALL WAITXON
L3A48:
RET
;.....
;
;
WAITXON:CALL RCVREADY ;have a character? (like x-on)
JNZ WTXON1 ;if no char. see if want to abort
CALL IN_MODDATP
AND AL,7FH ;strip off any parity
CMP AL,XON ;see if char. was x-on
JNZ WTXON1
RET ;if yes, keep going
;
WTXON1: CALL STAT ;test to see if requesting cancellation
JZ WAITXON
CALL KEYIN ;can abort if the x-on never comes
CMP AL,CANCEL ;ctl-x to abort?
JNZ WAITXON ;if not, keep going
RET
;.....
;
;================ END OF FILE TRANSFER IN T-MODE =======================
;
;
;***********************************************************************
;
; SUBROUTINES
;
;***********************************************************************
;
; Returns with the zero flag set if retry requested. If using multi-
; file (batch) modem, then no questions asked, just quit.
;
CKQUIT: MOV AL,Byte Ptr BATCHFLG ;using batch mode now?
OR AL,AL
JNZ CKQUIT1
JMP ABORT ;quit if using batch mode
;
CKQUIT1:MOV AL,1
MOV Byte Ptr ERRCT,AL
CALL ILPRT
DB CR,LF,'Multiple errors encountered.',CR,LF
DB 'Type Q to quit, R to retry: ',BELL,0
CALL KEYIN
LAHF
XCHG AL,AH
PUSH AX
CALL CRLF
POP AX
XCHG AL,AH
CALL UCASE ;instead of 'ANI 5FH'
CMP AL,'R'
JNZ L3A52
JMP RCVRECD ;if 'R' keep trying
L3A52:
CMP AL,'Q'
JNZ CKQUIT1
JMP ABORT
;.....
;
;
; Show the file name as stored in the FCB but in CP/M format
;
SHOWFIL:MOV AL, Byte Ptr QFLG
OR AL,AL
JNZ L4A1
RET
L4A1:
MOV BX, Offset FCB+1
;
SHOWNM: XOR AL,AL
MOV Byte Ptr FTYCNT,AL
MOV CL,11
;
PRNAM: CALL FTYTST
INC BX
DEC CL
JNZ PRNAM
RET
;.....
;
;
; Give report of received records as they occur
;
REPORT: MOV AL,Byte Ptr QFLG
OR AL,AL
JNZ L4A2
RET
L4A2:
MOV BX,Word Ptr RECDNO ;get record number
INC BX
CALL ILPRT
DB CR,'Received # ',0
CALL DECOUT ;print record number in decimal
CALL ILPRT
DB ' ',0
;
MOV AL,Byte Ptr HEXSHOW
OR AL,AL
JNZ L4A3
RET
L4A3:
CALL ILPRT
DB '(',0
CALL DHXOUT ;16 bit hex conversion and output
CALL ILPRT
DB 'H) ',0
RET
;.....
;
;
FTYTST: MOV AL,Byte Ptr FTYCNT
INC AL
MOV Byte Ptr FTYCNT,AL
CMP AL,9 ;are we at the file type?
JZ SPCTST ;go if so
;
ENDSPT: MOV AL,Byte PTr [BX]
CMP AL,' ' ;test for space
JZ L4A4
CALL STYPE ;type if not
L4A4: RET
;.....
;
;
SPCTST: MOV AL,Byte Ptr [BX]
CMP AL,' ' ;test for space in 1st file type byte
JNZ L4A5
RET ;do not output period if space
L4A5: MOV AL,'.'
CALL STYPE
JMPS ENDSPT ;output 1st file type byte
;.....
;
;
; Get sender's progress report if it is present and wait for line to get
; quiet
;
SNDPRG: MOV CH,5 ;wait up to 5 seconds
CALL RECV
CALL STYPE ;show the progress report from sender
JNB SNDPRG
RET
;.....
;
;
SENDFN: CALL ILPRTQ
DB 'Awaiting name NAK',CR,LF,0
CALL GETACK
JNB SENDFN1
CALL SENDACK
SENDFN1:
MOV BX, Offset FILECT
DEC Byte Ptr [BX]
JS NOMRNM
MOV BX,Word Ptr NBSAVE ;get file name..
MOV DX, Offset FCB ;..in FCB
MOV CH,12
CALL MOVE
MOV Word Ptr NBSAVE,BX
CALL SENDNM ;send it
OR AL,AL ;clear carry
RET
;.....
;
;
NOMRNM: MOV AL,EOT
CALL SEND
STC
RET
;.....
;
;
; Wait for line to get quiet and gobble characters
;
WAITQ1: MOV CH,1
CALL RECV
JNB WAITQ1
RET
;.....
;
;
SENDNM: PUSH BX
;
SENDNM1:MOV DH,11 ;count characters in name
MOV CL,0 ;initialize checksum
MOV BX, Offset FCB+1 ;address name
;
NAMLPS: MOV AL,Byte Ptr [BX] ;send name
AND AL,7FH ;strip high order bit so CP/M2..
CALL SEND ;..will not send R/O file designation.
;
ACKLP: PUSH CX ;save checksum
MOV CH,5 ;wait for receiver to acknowledge..
CALL RECV ;..getting the letter.
POP CX
JB SCKSER
CMP AL,ACK
JNZ ACKLP
INC BX ;next character
DEC DH
JNZ NAMLPS
MOV AL,EOFCHAR ;tell receiver the end of name
CALL SEND
MOV DH,CL ;save checksum
;
CKSMLP: MOV CH,5 ;wait up to 5 seconds
CALL RECV ;get checksum
CMP AL,DH
JNZ SCKSER ;exit if bad name
MOV AL,OKNMCH ;good name-tell receiver
CALL SEND
POP BX
RET
;.....
;
;
SCKSER: MOV AL,BDNMCH ;bad name-tell receiver
CALL SEND
CALL ILPRT
DB CR,LF,'++ ERROR sending name ++',CR,LF,0
MOV DL,120 ;do handshaking over (2 minutes maximum)
CALL WAITNLP ;don't print "WAITING READY SIGNAL" msg
CALL SENDACK
JMP SENDNM1
;.....
;
;
; This patch fixes a trivial problem with the display of the function
; key group on the menu. It uses some of the extra bytes available in
; this area from the CKSMLP fix.
;
FIXFNK: MOV BYTE PTR MENU3+1,AL ;store the character in the menu display
CMP AL,'[' ;'ESC' character, printed
JNB FIXFNK1 ;if 'ESC' or more, exit
JMP INTER1 ;otherwise include a '^'
;
FIXFNK1:
JMP INTER2
;
; Patch to close FCB3 instead of FCB when in disk-capture mode.
;
WRERRSP:CALL WRTFIL2 ;close FCB3 file
JMP WRERR1 ;go write 'DISK FULL' message and quit
EXTRA DB '123456789 ' ;10 extras from CKSMLP (there were 27)
;
;
GETFN: MOV BX, FCB
CALL L4A6 ;does not initialize drive
CALL ILPRTQ
DB 'Awaiting file name',CR,LF,0
CALL HSNAK
CALL GETNM ;get the name
CMP AL,EOT ;if EOT, then no more files
JZ NOMRNMG
OR AL,AL ;clear carry
RET
;
NOMRNMG:STC
RET
;
;
GETNM: PUSH BX
;
GETNM1: MOV AL,0FFH
MOV Byte Ptr FLTRFLG,AL
MOV CL,0 ;initialize checksum
MOV BX, FCB+1
;
NAMELPG:MOV CH,5
CALL RECV ;get the character
PUSH CX
LAHF
XCHG AL,AH
PUSH AX
MOV AL,0FFH
MOV Byte Ptr TIMFLG,AL
MOV CH,1
CALL RECV
XOR AL,AL
MOV Byte Ptr TIMFLG,AL
POP AX
XCHG AL,AH
SAHF
POP CX
JNB GETNM3
CALL ILPRTQ
DB 'Time out receiving filename',CR,LF,0
JMP GCKSER
;
GETNM3: CMP AL,EOT ;if EOT, then no more files
JNZ L4A7
JMP GNRET
L4A7:
CMP AL,EOFCHAR ;got end of name
JZ ENDNAME
LAHF
XCHG AL,AH
PUSH AX
PUSH CX
CALL SENDACK
POP CX
POP AX
XCHG AL,AH
MOV Byte Ptr [BX],AL ;put name in FCB
INC BX ;get next character
MOV AL,BL ;don not let noise cause overflow..
CMP AL,7FH ;..into the program area.
JZ GCKSER
JMP NAMELPG
;
ENDNAME:XOR AL,AL
MOV Byte Ptr FLTRFLG,AL
MOV AL,CL ;send checksum
MOV DH,CL
CALL SEND
;
NMLP1: MOV CH,5 ;wait up to 5 second to see if..
CALL RECV ;..the checksum is good
CMP AL,OKNMCH ;yes if 'OKNMCH' sent
JZ GNRET
CMP AL,DH
JZ NMLP1 ;in case it is echo of send
CMP AL,CR
JZ NMLP1
CMP AL,LF
JZ NMLP1
;
GCKSER: MOV BX, FCB ;clear FCB (except drive) since it..
CALL L4A6 ;..might be damaged.
CALL ILPRTQ
DB CR,LF,'** Checksum error **',CR,LF,0
XOR AL,AL
MOV Byte Ptr FLTRFLG,AL
CALL HSNAK ;do handshaking over
JMP GETNM1
;
GNRET: LAHF
XCHG AL,AH
PUSH AX
XCHG AL,AH
XOR AL,AL
MOV Byte Ptr FLTRFLG,AL
POP AX
XCHG AL,AH
SAHF
POP BX
RET
;
HSNAK: MOV DL,180 ;3 minute wait for file name
XOR AL,AL
MOV Byte Ptr FLTRFLG,AL
;
HSNAK1: CALL CKABORT ;want to abort?
MOV AL,NAK ;send 'NAK' until receiving 'ACK'
CALL SEND
MOV CH,1 ;wait up to 1 second for a character
CALL RECV
CMP AL,ACK ;'ACK' is what we were waiting for
JNZ L4A8
RET
L4A8:
DEC DL
JNZ HSNAK1
JMP ABORT ;back to command line
;
;.....
;
;
TNMBUF: MOV AL,1 ;call from 'SENDFIL' only once.
MOV Byte Ptr FSTFLG,AL
XOR AL,AL
MOV Byte Ptr FILECT,AL
CALL SCAN
MOV BX, Offset NAMEBUF
MOV Word Ptr NBSAVE,BX ;save address of 1st name
;
TNLP1: CALL TRTOBUF
MOV BX, Offset FCB
MOV DX, Offset FCBBUF
CALL CMDLINE ;parse name to CP/M format
;
TNLP2: CALL MFNAME ;search for names (wildcard format)
JB NEXTNM
MOV AL,Byte Ptr FCB+10 ;if CP/M 2 $sys file..
AND AL,80H ;..do not send
JNZ TNLP2
MOV BX,Word Ptr NBSAVE ;get name
MOV DX, FCB ;move it to FCB
XCHG BX,DX
MOV CH,12
CALL MOVE
XCHG BX,DX
MOV Word Ptr NBSAVE,BX ;addressof next name
MOV BX, Offset FILECT ;count files found
INC Byte Ptr [BX]
JMPS TNLP2
;.....
;
;
NEXTNM: MOV BX, Offset NAMECT ;count names found
DEC Byte Ptr [BX]
JNZ TNLP1
MOV BX, Offset NAMEBUF ;save start of buffer
MOV Word Ptr NBSAVE,BX
MOV AL,Byte Ptr FILECT
CMP AL,64+1 ;no more than 64 transfers
JNB L4A9
RET
L4A9:
MOV AL,64 ;only transfer first 64
MOV Byte Ptr FILECT,AL
RET
;.....
;
;
; Tells when buffer is opened/closed for memory save to write on disk
;
BUFMSG: CALL ILPRT
DB CR,LF,'** Memory buffer ',0
MOV AL,Byte Ptr SAVEFLG
OR AL,AL
JZ BUFMSG1
CALL ILPRT
DB 'open **',CR,LF,LF,';',0
RET
;
BUFMSG1:CALL ILPRT
DB 'closed **',CR,LF,LF,0
RET
;
BUFMSG2:CALL ILPRT
DB CR,LF,'** Memory buffer available **',CR,LF,0
RET
;.....
;
;
; Clear the screen and return to the menu command
;
EXITMENU:
CALL CRLF
CALL CLREOS ;clear line to clean up any mess
JMP MENU0
;.....
;
;
; Checks to see if the modem has a character ready
;
RCVREADY:
CALL IN_MODCTL1
CALL ANI_MODRCVB
JMP CPI_MODRCVR
;.....
;
;
; Checks to see if the modem is ready to receive a character
;
SENDRDY:CALL IN_MODCTL1
CALL ANI_MODSNDB
JMP CPI_MODSNDR
;.....
;
;
SENDNOW:CALL EXITTEST ;see if want to quit now
CALL SENDRDY ;ready to send a character?
JNZ SENDNOW ;if not ready wait some more
RET ;exit if ready
;.....
;
;
; Send the log-on message when requested
;
SENDLOG:MOV BX,Word Ptr LOGONPTR ;'BX' points to start of logon message
CALL LOGLP
JMP TERML
;...
;
;
LOGLP: CALL SENDNOW ;wait until modem is ready
MOV AL,Byte Ptr [BX] ;get logon byte
OR AL,AL ;last character in string is '0'
JNZ L4A10
RET ;return if finished
L4A10:
CALL OUT_MODDATP ;otherwise send the character
CALL LOGLP1 ;check for echo character and display it
LAHF ;next location in message
INC BX
SAHF
JMPS LOGLP ;get next character
;.....
;
;
LOGLP1: CALL JMP_INMODEM ;get the echo character
JNB L4A11
CALL JMP_INMODEM ;if none, try once more
L4A11:
JNB L4A12
RET ;if no character don't try to print
L4A12:
AND AL,7FH ;strip off any parity
JMP STYPE ;display the character, then return
;.....
;
;
; Check for exit character
;
EXITTEST:
CALL STAT ;anything on keyboard?
JNZ L4A13
RET
L4A13:
CALL KEYIN ;get it, then
MOV CH,AL ;save to protect the 'A' reg.
;
EXITTST1:
MOV AL,EXITCHR ;exit character
CMP AL,CH ;asking to exit to menu?
JZ L4A14
RET ;if not, back to work
L4A14:
POP BX ;clear the stack from 'CALL'
JMPS EXITMENU ;exit to the menu
;.....
;
;
LSTMSG: CALL ILPRT
DB 'Printer buffer is ',0
MOV AL,Byte Ptr LISTFLG ;see if printer should be on or off
OR AL,AL
JZ LSTMSG1
CALL ILPRT
DB 'ON',CR,LF,0
RET
;...
;
;
LSTMSG1:CALL ILPRT
DB 'OFF',CR,LF,0
RET
;.....
;
;
; Special function key handler. This routine is entered with the
; function key number (0..9) in A. The corresponding function key is
; then transmitted.
;
SENDFK: PUSH BX ;save register
MOV BX, Offset FNCTBL ;point to function key codes
;
SFK1: CMP AL,Byte Ptr [BX] ;this the one?
LAHF ;point to next byte
INC BX
SAHF
JNZ SFK1 ;loop until found
CALL LOGLP ;send the char
POP BX
XOR AL,AL ;reset the function flag
MOV Byte Ptr FNKFLG,AL
JMPS TERML
;.....
;
;
; Send keyboard character to modem, also to console if "E" or "L". If
; "E", include a LF after a CR, if either, include a LF if toggle is set.
;
NOTOG: CALL SENDCHR ;send char. in 'B' to modem
MOV AL,Byte Ptr LOCFLG ;using the local mode?
OR AL,AL
JNZ LTYPE ;if yes, show the character
MOV AL,Byte Ptr ECHOFLG ;in echo mode?
OR AL,AL
JZ TERML ;if not, see if it was a 'CR'
;
LTYPE: MOV AL,CH ;get the char. back
CALL STYPE ;show on the local CRT
CALL CHKSAVE ;to store local if buffer open
CALL CHKPRNT ;put on printer if running
;
CHKCR: MOV AL,CR
CMP AL,CH
JNZ TERML ;if not cr, all done
MOV AL,Byte Ptr ECHOFLG ;in echo mode now?
OR AL,AL
JNZ CHKLF ;if yes add a line feed
MOV AL,Byte Ptr ADDLF ;going to add a line feed in 'L' mode?
OR AL,AL
JNZ CHKLF
JMP TERM ;if not, exit
;
CHKLF: MOV CH,LF
JMPS NOTOG ;send locally and to remote
;.....
;
;
TERML: CALL RCVREADY ;character on the receive-ready line?
JZ L4A16
JMP TERM ;if not, exit
L4A16:
CALL IN_MODDATP ;get the character
AND AL,7FH ;strip parity
JNZ L4A17
JMP TERM ;don't bother with nulls
L4A17:
CMP AL,RUB
JNZ L4A18
JMP TERM ;don't bother with rubouts for fill
L4A18:
MOV CH,AL ;store temporarily
MOV AL,Byte Ptr IGNORCTL ;ignoring all but necessary ctl-chars?
OR AL,AL
JZ GIVLF ;if zero, display them all
MOV AL,CH
CMP AL,' '
JNB GIVLF ;display all printing characters
CMP AL,'G'-40H ;^g for bell
JNB L4A19
JMP TERM ;ignore ctl-characters less than ^g
L4A19:
CMP AL,CR+1
JNAE GIVLF
JMP TERM ;ignore ctl-charsacters more than ^m
;
GIVLF: MOV AL,CH ;get the character back
CALL STYPE ;show it on the CRT
CALL CHKSAVE ;saving for disk file?
CALL CHKPRNT ;printer running?
MOV AL,Byte Ptr ECHOFLG ;going to echo the character?
OR AL,AL
JZ NOECH ;if not, do not resend
;
GIVLF1: CALL SENDCHR ;send char. in 'B' to modem
;
NOECH: MOV AL,CR
CMP AL,CH ;was it a 'CR' just now?
JZ L4A21
JMP TERM ;if not, all done so exit
L4A21:
MOV AL,Byte Ptr ECHOFLG ;in the echo mode?
OR AL,AL
JNZ L4A22
JMP TERM
L4A22:
CALL SENDNOW ;modem ready for a character?
MOV CH,LF
JMPS GIVLF ;send lf
;.....
;
;
; See if putting character into memory for a disk file
;
CHKSAVE:MOV AL,Byte Ptr SAVEFLG ;saving to disk?
OR AL,AL
JNZ L4A23
RET ;if not, exit
L4A23:
MOV BX,Word Ptr HLSAVE ;get last address
MOV Byte Ptr [BX],CH ;store this character
INC BX ;increment for next character
MOV Word Ptr HLSAVE,BX ;remember that location
MOV AL,LF
CMP AL,CH ;this character a line feed?
JNZ CHKSAVE1 ;..type ";" after each line feed..
MOV AL,CR ;insure at left column with a lf
CALL STYPE
CALL TYPESCLN ;show a ';' on CRT
;
CHKSAVE1:
MOV AL,BH
MOV BX, Offset BUFTOP ;get the address at top of buffer
CMP AL,BH
JNZ L4A24
CALL D_CTL_S ;if different, buffer is not full
L4A24:
RET
;.....
;
;
; Memory buffer is full, send a X-OFF (CTL-S, DC3), save any extra in-
; coming characters, then dump to disk, reset buffer to include those
; characters.
;
D_CTL_S:CALL SENDNOW ;modem ready for a character?
MOV AL,XOFF ;send a ctl-s to stop remote computer
CALL OUT_MODDATP
CALL CHKPRNT ;insure character gets to the printer
MOV BX, offset BUFFDSK ;address of aux. buffer
CALL GETDSK ;put any extra chars. into aux. buffer
PUSH DX ;save the number of aux. chars.
MOV AL,1 ;show we put something in the buffer..
MOV Byte Ptr WRFLG,AL ;..to protect erasing an empty file
MOV BX,Word Ptr HLSAVE ;find current end of buffer
CALL WRTDSK1 ;write the records
POP DX ;get aux. char. count back
MOV BX, offset BUFFER ;start again at bottom of buffer
XOR AL,AL ;set 'A' to zero
CMP AL,DH ;see if any count in 'D'
JZ D_CTL_Q ;if nothing, exit and continue
MOV CX, offset BUFFDSK ;address of aux. buffer
;
;
; Move the characters from the auxiliary buffer to the main buffer and
; display
;
D_CTL_S1:
MOV SI,CX ;get the character there
MOV AL,[SI]
MOV BYTE PTR [BX],AL ;store in main buffer
CALL STYPE ;show on CRT
PUSH BX
PUSH DX
PUSH CX
LAHF
XCHG AL,AH
PUSH AX
XCHG AL,AH
MOV CH,AL
CALL CHKPRNT
POP AX ;get the character again
XCHG AL,AH
POP CX
POP DX
POP BX
CMP AL,LF
JNZ L4A25
CALL TYPESCLN
L4A25:
LAHF ;next buffer position
INC BX
SAHF
LAHF ;next aux. buffer position
INC CX
SAHF
DEC DH ;one less to go
JNZ D_CTL_S1 ;if not zero, keep going
MOV CH,0 ;falls through to 'CHKPRNT' next
;
D_CTL_Q:MOV Word Ptr HLSAVE,BX ;next position to store in buffer
CALL SENDNOW
MOV AL,XON ;allow remote input to continue
JMP OUT_MODDATP
;.....
;
;
; Gets any incoming characters after sending an XOFF and stores at BX.
; Returns with number of characters stored in D-reg.
;
GETDSK: MOV DH,0 ;character count in buffer
MOV DL,128 ;maximum for buffer length
;
GETDSK1:CALL JMP_INMODEM ;get any character
JNB L4A26
RET ;if none, finished
L4A26:
CMP AL,' '
JNB GETDSK2 ;if greater, handle normally
CMP AL,CR+1 ;ignore ctl-chars. > cr
JNB GETDSK1
;
GETDSK2:MOV Byte Ptr [BX],AL ;store
LAHF ;next buffer location to use
INC BX
SAHF
INC DH ;increment character count
DEC DL ;room for one less
JNZ GETDSK1 ;if room in buffer, keep going
RET ;if buffer is filled, exit
;.....
;
;
; See if printing the character, if yes, put into buffer
;
CHKPRNT:MOV AL,Byte Ptr LISTFLG ;printer in use?
OR AL,AL
JNZ L4A27
RET ;return if not
L4A27:
MOV BX,Word Ptr HLSAVE1 ;get input address
MOV Byte Ptr [BX],CH ;save this character there
INC BX ;increment the buffer location
MOV Word Ptr HLSAVE1,BX ;store for next character
MOV AL,Byte Ptr MAXRAM ;see if at top of buffer yet
CMP AL,BH
JNZ L4A28
CALL P_CTL_S ;if different, buffer is not full
L4A28:
RET
;.....
;
;
; Memory buffer is full, send a X-OFF (CTL-S, DC3), save any extra in-
; coming characters, then dump to disk, reset buffer to include those
; characters.
;
P_CTL_S:CALL SENDNOW ;wait until modem is ready
MOV AL,XOFF ;send a ctl-s to stop remote computer
CALL OUT_MODDATP
MOV BX, Offset BUFFPNT ;address of aux. buffer
CALL GETDSK ;put any extra chars. into aux. buffer
MOV AL,DH ;get the aux. buffer char. count
MOV Byte Ptr DSTORE,AL ;save for later
RET
;.....
;
;
; Output has now caught up to the input and both are at top of buffer
;
P_CTL_S1:
MOV AL,Byte Ptr DSTORE ;get the aux. buffer char. count
MOV DH,AL ;put into 'D' reg.
XOR AL,AL ;set 'A' to zero
CMP AL,DH ;see if any count in 'D'
MOV BX, Offset PBUFF ;address at start of printer buffer
JZ P_CTL_Q ;if nothing, exit and continue
MOV CX, Offset BUFFPNT ;address of aux. buffer
;
;
; Move the characters from the aux. buffer to the main buffer and display
;
P_CTL_S2:
MOV SI,CX ;get the character there
MOV AL,[SI]
MOV Byte Ptr [BX],AL ;store in main buffer
CALL STYPE ;show on CRT
PUSH BX
PUSH DX
PUSH CX
LAHF
XCHG AL,AH
PUSH AX
XCHG AL,AH
MOV CH,AL
CALL CHKSAVE
POP AX
XCHG AL,AH
POP CX
POP DX
POP BX
CMP AL,LF
JNZ L4A29
CALL TYPESCLN
L4A29:
LAHF ;next buffer position
INC BX
SAHF
LAHF ;next aux. buffer position
INC CX
SAHF
DEC DH ;one less to go
JNZ P_CTL_S2 ;if not zero, keep going
;
P_CTL_Q:MOV Word Ptr HLSAVE1,BX ;next position to store in buffer
MOV BX, Offset PBUFF ;start of buffer location
MOV Word Ptr HLSAVE2,BX ;output to start of buffer
CALL SENDNOW ;wait until modem is ready
MOV AL,XON ;send start character..
JMP OUT_MODDATP ;..to remote computer, back to work
;.....
;
;
; Obtain Printer Status using Direct Bios Call
LISTST: PUSH DX
MOV DX, OFFSET REGLIST
MOV Byte Ptr REGLIST,15 ; BIOS function 15
MOV Word Ptr REGLIST+1,0 ; Clear them anyway
MOV Word Ptr REGLIST+3,0 ; As MPM get upset
MOV CX,50 ; Direct Bios Call
INT 224
POP DX
RET
REGLIST DB 0 ; Function Code
DW 0 ; value (CX)
DW 0 ; value (DX)
;
;
;.....
;
;
; List the character on the printer if it is ready, then see if at the
; top of the buffer.
;
GOLIST: CALL LISTST ;get the printer status
OR AL,AL
JNZ L4A30
RET ;return if printer not ready
;
;
; Compare input and output pointers. If at same address, nothing to
; print.
;
L4A30: CALL CMP_I_O ;if the same, nothing to print
JNZ GOLIST1
RET
;
;
; If not the same, print the character
;
GOLIST1:PUSH BX ;save current buffer address
MOV DL,Byte Ptr [BX] ;get the character to display
MOV CL,BLIST ;list routine
INT 224
POP BX ;restore current buffer address
INC BX ;increment pointer for next position
MOV Word Ptr HLSAVE2,BX ;store for next time through here
;
;
; See if the output is at the end of the buffer now. If yes, go put
; the auxiliary characters into the start of the buffer.
;
MOV AL,Byte Ptr MAXRAM ;check for end of buffer area
CMP AL,BH
JNZ L4A32
JMP P_CTL_S1 ;if at end, restore aux. buffer
L4A32:
;
;
; See if the output has caught up with the input - if so, reset the
; pointers to the start of the buffer
;
CALL CMP_I_O
JZ L4A33
RET ;if not, back to work
L4A33:
MOV BX, Offset PBUFF ;if output caught input, reset both..
MOV Word Ptr HLSAVE1,BX ;..to bottom of buffer to start over
MOV Word Ptr HLSAVE2,BX
RET
;.....
;
;
; Compare the input and output pointers to see if the same address
;
CMP_I_O:MOV BX,Word Ptr HLSAVE1 ;get input pointer address
XCHG BX,DX ;put in 'DE'
MOV BX,Word Ptr HLSAVE2 ;get output pointer address
MOV AL,BH
CMP AL,DH
JZ L4A34
RET ;return if different
L4A34:
MOV AL,BL
CMP AL,DL
RET
;.....
;
;
GETMAX: MOV AL,Byte Ptr BDOS+2 ;'MSP' of 'BDOS' address
MOV Byte Ptr MAXRAM,AL ;save
RET
;.....
;
;
; This subroutine will loop until the modem receives a character or 100
; milliseconds. It returns with a character in 'A' reg. but if no char-
; acter was recieved it returns after a timeout with carry set.
;
INMODEM:
PUSH BX
MOV BX,33 ;about 100 milliseconds
CALL FIXCNT
MOV CH,BH ;delay is in 'BX'
MOV CL,BL ;transfer to 'BC'
POP BX ;get original value of 'BX' back
;
INMODEM1:
CALL RCVREADY ;see if there is a character ready
JNZ INMODEM2 ;if no character, exit
CALL IN_MODDATP ;get the character
AND AL,7FH ;strip off any parity
RET ;return with character in 'A' reg.
;
INMODEM2:
DEC CX ;otherwise keep timing
MOV AL,CH
OR AL,CL
JNZ INMODEM1 ;loop until timeout if needed
STC ;shows a timeout occured
RET
;.....
;
;
; Send a space tone to the phone line for a short time.
;
BREAK: MOV AL,Byte Ptr PMMIMODEM ;using the PMMI modem?
OR AL,AL
JZ BREAK1 ;if not, exit
MOV AL,Byte Ptr MODCTLB ;get the last modem control byte
AND AL,BRKMSK ;set the transmit break bit low
CALL OUT_MODCTL2 ;send it to the modem
MOV CH,2
CALL TIMER ;send a space tone for 200 ms.
MOV AL,Byte Ptr MODCTLB ;get the last modem control byte
CALL OUT_MODCTL2 ;restore to normal
JMP TERM ;back to work
;...
;
;
BREAK1: CALL JMP_BREAK ;get the user'S BREAK ROUTINE
JMP TERM ;back to work
;.....
;
;
;=======================================================================
; WRITE BUFFER TO DISK
;
; Make sure this record is included in the count.
;
WRTDSK: MOV BX,Word Ptr HLSAVE
MOV Byte Ptr [BX],EOFCHAR ;ascii file, store end-of-file char.
MOV DX,127
ADD BX,DX
;
WRTDSK1:MOV DX,-( Offset BUFFER) ;subtract the start of the buffer..
ADD BX,DX ;by adding a minus number to buffer end
MOV AL,BL ;divide hl by 128..
OR AL,AL
RCL AL,1 ;..to get the..
MOV BL,BH ;..number of records
MOV BH,0
LAHF
XCHG AL,AH
PUSH AX
SHL BX,1
POP AX
XCHG AL,AH
SAHF
MOV AL,0
ADC AL,BL
MOV BL,AL ;number of records in 'BX'
;
;
; See if buffer is empty. If yes, see if we need to erase an empty
; file or have already written something.
;
MOV DX, Offset BUFFER
MOV SI,DX
MOV AL,[SI]
CMP AL,EOFCHAR ;'EOF' in first address means..
JNZ WRTDSK2 ;..nothing in buffer to write
MOV AL,Byte Ptr WRFLG ;first time by this way?
OR AL,AL
JZ NOWRITE ;if yes, show erasing file
RET ;otherwise go close file
;.....
;
;
; Write to disk. Start from BUFFER (in 'DE'). Number of records to
; write in 'BX'.
;
WRTDSK2:MOV CL,SETDMA
CALL BDOSRT
PUSH DX
MOV CL,WRITE
MOV DX, Offset FCB3 ;location of filename to write to
CALL BDOSRT
POP DX
OR AL,AL
JNZ WRTDSK2A ;error if disk is full ** special patch
XCHG BX,DX ;put the current address in 'BX'..
PUSH DX ;..and number of records left in..
MOV DX,128 ;..for now
ADD BX,DX ;add for next record write, now in 'BX'
POP DX ;restore number of records left
XCHG BX,DX ;records to 'BX' again, address to 'DE'
DEC BX ;one less record left
MOV AL,BH
OR AL,BL ;done writing when 'H' and 'H' both zero
JNZ WRTDSK2 ;otherwise do another disk write
RET
;
WRTDSK2A:
JMP WRERRSP
;.....
;
;
; Error while writing a record, show why it is aborting
;
WRERR: MOV CL,CANCEL ;send cancel char. to sending station
CALL SEND
CALL CLOSFIL ;close the current file
WRERR1: CALL ERXIT ;also will reset stack
DB '++ DISK FULL, SAVING PARTIAL FILE ++','$'
;.....
;
;
; If no data to store on the disk, close the empty file and erase it
;
NOWRITE:CALL WRTFIL2 ;close the empty file
CALL NOASK ;erase the empty file
CALL ILPRT
DB '++ Nothing to save, erasing file ++'
DB CR,LF,BELL,0
JMP DONETCA ;reset any flags, return to menu
;.....
;
;
; Show you are in memory-save for disk write
;
TYPESCLN:
MOV AL,';'
JMP STYPE ;show on CRT, return
;.....
;
;
; Save the registers, call BDOS then restore the registers
;
BDOSRT: PUSH CX
PUSH DX
PUSH BX
INT 224
POP BX
POP DX
POP CX
RET
;.....
;
;
INITFCB:MOV Byte Ptr [BX],0 ;entry at +2 will leave drive # intact
L4A6: INC BX ;will initialize an FCB..
MOV CH,11 ;..pointed to by BX-reg. fills 1st pos.
;
LOOP11: MOV Byte Ptr [BX],' ' ;..with 0, next 11 with..
INC BX ;..blanks, and last..
DEC CH ;..21 with nulls.
JNZ LOOP11
MOV CH,21
;
LOOP21: MOV Byte Ptr [BX],0
INC BX
DEC CH
JNZ LOOP21
RET
;.....
;
;
; Scans CMDBUF coutning names and putting delimiter (space) after last
; name
;
SCAN: PUSH BX
MOV BX, Offset NAMECT
MOV Byte Ptr [BX],0
MOV BX, Offset CMDBUF+1 ;find end of cmd line..
MOV CL,Byte Ptr [BX] ;..and put space there.
MOV CH,0
MOV BX, Offset CMDBUF+2
LAHF
ADD BX,CX
RCR SI,1
SAHF
RCL SI,1
MOV Byte Ptr [BX],' '
MOV BX, Offset CMDBUF+1
MOV CH,Byte Ptr [BX]
INC CH
INC CH
;
SCANLP1:LAHF
INC BX
SAHF
DEC CH
JZ DNSCAN
MOV AL,Byte Ptr [BX]
CMP AL,' '
JNZ SCANLP1
;
SCANLP2:LAHF ;eat extra spaces
INC BX
SAHF
DEC CH
JZ DNSCAN
MOV AL,Byte Ptr [BX]
CMP AL,' '
JZ SCANLP2
MOV Word Ptr BGNMS,BX ;save start of names in cmdbuf
INC CH
LAHF
DEC BX
SAHF
;
SCANLP3:LAHF
INC BX
SAHF
DEC CH
JZ DNSCAN
MOV AL,Byte Ptr [BX]
CMP AL,' '
JNZ SCANLP3
MOV AL,Byte Ptr NAMECT ;counts names
INC AL
MOV Byte Ptr NAMECT,AL
;
SCANLP4:LAHF ;eat spaces
INC BX
SAHF
DEC CH
JZ DNSCAN
MOV AL,Byte Ptr [BX]
CMP AL,' '
JZ SCANLP4
JMPS SCANLP3
;.....
;
;
DNSCAN: MOV Byte Ptr [BX],' ' ;space after last char
POP BX
RET
;.....
;
;
; Places next name in buffer so 'CMDLINE' may parse it
;
TRTOBUF:MOV BX,Word Ptr BGNMS
MOV CH,0
MOV DX, Offset FCBBUF+2
;
TBLP: MOV AL,Byte Ptr [BX]
CMP AL,' '
JZ TRBFEND
MOV SI,DX
MOV [SI],AL
INC BX
INC DX
INC CH ;count chars in name
JMPS TBLP
;.....
;
;
TRBFEND:INC BX
MOV AL,Byte Ptr [BX] ;eat extra spaces
CMP AL,' '
JZ TRBFEND
MOV Word Ptr BGNMS,BX
MOV BX, Offset FCBBUF+1 ;put # chars before name
MOV Byte Ptr [BX],CH
RET
;.....
;
;
CKCPM2: MOV CL,CPMVER ;bdos 12 -- version number -- cp/m 2.2?
INT 224
OR AL,AL
JNZ L5A2
RET
L5A2:
MOV CL,SETDMA
MOV DX, Offset TBUF
INT 224
MOV CL,SRCHF
MOV DX, Offset FCB
INT 224
CMP AL,0FFH
JNZ L5A3
RET
L5A3:
;
CALL GETADD
MOV DX,9
ADD BX,DX ;point to R/O attribute byte
MOV AL,Byte Ptr [BX]
AND AL,80H ;test most significant byte
JNZ MKCHG ;if set, make change
INC BX ;check system attribute byte
MOV AL,Byte Ptr [BX]
AND AL,80H
JNZ L5A4
RET ;not $SYS or $R/O attribute
L5A4:
DEC BX
;
MKCHG: MOV DX,-8
ADD BX,DX ;point BX to filename + 1
MOV DX, Offset FCB+1 ;move directory name to FCB..
MOV CH,11 ;..without changing drive.
CALL MOVE
MOV BX, Offset FCB+9 ;R/O attribute
MOV AL,Byte Ptr [BX]
AND AL,7FH ;strip R/O attribute
MOV Byte Ptr [BX],AL
INC BX ;system attribute
MOV AL,Byte Ptr [BX]
AND AL,7FH
MOV Byte Ptr [BX],AL
MOV DX, FCB
MOV CL,30 ;set new attributes in directory
INT 224
;
; Called by 'CKBAKUP' below, return done here .
;
PLANCHG:MOV BX, FCB ;change name to type "BAK"
MOV DX, FCB2
MOV CH,9 ;move drive and name (not type)
CALL MOVE
MOV BX,75H ;start of type in FCB2
MOV Byte Ptr [BX],'B'
INC BX
MOV Byte Ptr [BX],'A'
INC BX
MOV Byte Ptr [BX],'K'
MOV DX, FCB2
MOV CL,ERASE ;erase any previous backups
INT 224
MOV BX, FCB2 ;FCB2 drive field should..
MOV Byte Ptr [BX],0 ;..0 for rename.
MOV DX, FCB
MOV CL,23 ;rename
INT 224
RET
;.....
;
;
CKBAKUP:MOV AL,Byte Ptr BAKUPBYTE
OR AL,AL
JNZ L5A5
RET
L5A5:
MOV CL,SRCHF
MOV DX, FCB
INT 224
INC AL
JNZ L5A6
RET ;file not found
L5A6:
JMPS PLANCHG ;in 'CKCPM2' - ret done there
;.....
;
;
;***********************************************************************
;
; RECEIVE A RECORD FROM SENDING STATION
;
;***********************************************************************
;
; If CRC is in effect, there is a 10-second timeout to the first SOH.
; It then tries six more times to let the sender know the system is
; capable of receiving a 'CRC' check. At the end of that time a NAK is
; sent which tells the sender to use CHECKSUM checking instead of CRC.
; This allows automatic compatability with systems implementing CRC -
; (Cyclic Redundancy Checking). The search for SOH will cycle through
; one record interval and ignore noise or characters sent by the remote
; for any purpose (such as progress reporting). So extraneous characters
; that are sometimes sent by remote-end protocol will be gobbled up until
; the first SOH. EOT is tested only as the first returned character af-
; ter each sector.
;
SRCHSOH EQU 160 ;number of times to loop search for SOH
;
RCVRECD:MOV AL,1
MOV Byte Ptr ERRCT,AL ;initialize the error count
;
RCVSQ: MOV CH,10 ;10 seconds allowed to receive 1st char.
MOV DX,SRCHSOH ;initialize loof for up to 160 secs.
CALL RECV ;get the 1st character
JNB L5A7
JMP RCVSTOT ;timeout error if not rcvd in 10 seconds
L5A7:
MOV CL,AL ;save the character for now
CMP AL,EOT ;see if end of transmission
STC ;set carry
JNZ L5A8
RET ;return with carry set
L5A8:
;
SOHLUP: MOV AL,0FFH
MOV Byte Ptr CHRFLG,AL
MOV Byte Ptr TIMFLG,AL
MOV AL,DL ;get search count-down value
CMP AL,SRCHSOH ;see if it is the 1st returned character
MOV AL,CL ;get the first character now
JZ NORECV ;skip RECV routine if 1st character
MOV CH,1
CALL RECV
MOV CH,AL
JNB TSTSOH
;
NORECV: MOV CH,AL
XOR AL,AL ;else set the value that forces timeoutw
MOV Byte Ptr CHRFLG,AL
;
TSTSOH: MOV AL,CH ;get the character
CMP AL,SOH ;see if it is SOH
LAHF
XCHG AL,AH
PUSH AX
XCHG AL,AH
XOR AL,AL
MOV Byte Ptr TIMFLG,AL ;restore this flag
POP AX
XCHG AL,AH
SAHF
JNZ L5A9
JMP RCVSOH ;got SOH, get rcd # and its complement
L5A9:
MOV AL,DH
OR AL,DL ;see if counted-down to zero
LAHF
DEC DX
SAHF
JNZ SOHLUP ;go around again if not
MOV AL,Byte Ptr CHRFLG ;see if timeout needs to be forced
OR AL,AL
JNZ L5A10
JMP RCVSTOT ;go do timeout and countthem
L5A10:
MOV AL,Byte Ptr QFLG
OR AL,AL
JZ RCVSERR
;
RCVSEH: CALL CRLF
MOV AL,CH
CALL HEXO
CALL ILPRT
DB 'H received not SOH - ',0
;
RCVPRN: CALL SHOWERR ;display error count
;
RCVSERR:CALL WAITQ1 ;wait for 1 second with no characters
CALL CKABORT ;want to stop receiving now?
MOV AL,Byte Ptr CRCFLAG ;get 'CRC' flag
OR AL,AL ;'CRC' in effect?
MOV AL,NAK ;put 'NAK' in 'A' reg.
JZ RCVSER1 ;no, send the 'NAK'
MOV AL,Byte Ptr FIRSTME ;get first time switch
OR AL,AL ;has first 'SOH' been received?
MOV AL,NAK ;put 'NAK' in 'A' reg.
JNZ RCVSER1 ;yes, then send 'NAK'
MOV AL,CRC ;tell sender 'CRC' is in effect
;
RCVSER1:CALL SEND ;..the 'NAK' or 'CRC' request
MOV AL,Byte Ptr ERRCT ;abort if we have reached error limit
INC AL
MOV Byte Ptr ERRCT,AL ;store for next time
CMP AL,ERRLIM ;see if at limit yet
JNB L5A11
JMP RCVSQ ;if not, keep going
L5A11:
MOV AL,Byte Ptr RETRY ;see if retry after 10 errors is set
OR AL,AL
JNZ L5A12
JMP ABORT ;if 'YES', abort
L5A12:
JMP CKQUIT ;if 'NO' check for continued use
RCVSABT:MOV SP,STACK ;reset the stack just in case
CALL CLOSFIL ;close the partial file
CALL NOASK ;delete partial file
CALL ILPRT
DB CR,LF,LF
DB '++ RECEIVED FILE CANCELLED ++',CR,LF,BELL
DB '++ UNFINISHED FILE DELETED ++',CR,LF,0
JMP DONETCA
RCVSTOT:MOV AL,Byte Ptr QFLG
OR AL,AL
JZ RCVSCRC
;
RCVSPT: CALL ILPRT
DB CR,LF,'++ Timeout ',0
CALL SHOWERR
;
RCVSCRC:CALL RCVSCRC2
JMP RCVSERR
;
;
; Routine will switch from 'CRC' to Checksum if 'ERCNT' reaches 'ERRCRC'
; and 'FIRSTIME' is false
;
RCVSCRC2:
MOV AL,Byte Ptr ERRCT
CMP AL,ERRCRC
JZ L5A13
RET
L5A13:
MOV AL,Byte Ptr FIRSTME
OR AL,AL
JZ L5A14
RET
L5A14:
MOV AL,Byte Ptr CRCFLAG
OR AL,AL
JNZ L5A15
RET
L5A15:
NOT AL
MOV Byte Ptr CRCFLAG,AL
MOV Byte Ptr CRCDFLT,AL
CALL ILPRTQ
DB '** Switching to Checksum mode **',CR,BELL,LF,0
RET
;.....
;
;
; Got SOH - get block #, block # complemented
;
RCVSOH: MOV AL,0FFH
MOV Byte Ptr FIRSTME,AL ;indicate 1st soh was received
MOV CH,5 ;timeout = 5 seconds
CALL RECV ;get record
JB RCVSTOT ;got timeout
MOV DH,AL
MOV CH,5 ;timeout = 5 seconds
CALL RECV
JNB L5A16
JMP RCVSTOT
L5A16:
NOT AL
CMP AL,DH
JZ RCVDATA
MOV AL,Byte Ptr QFLG
OR AL,AL
JNZ RCVBSE
JMP RCVSERR
;
RCVBSE: CALL ILPRT
DB CR,LF,'++ Bad record # in header ',0
JMP RCVPRN
;
RCVDATA:MOV AL,DH
MOV Byte Ptr RCVRNO,AL
MOV AL,1
MOV Byte Ptr DATAFLG,AL
MOV CL,0
MOV BX,0
MOV Word Ptr CRCVAL,BX
MOV BX,80H
;
RCVCHR: MOV CH,5 ;Wait up to 5 seconds for a character
CALL RECV
JNB L5A18
JMP RCVSTOT
L5A18:
MOV Byte Ptr [BX],AL
INC BL
JNZ RCVCHR
XOR AL,AL
MOV Byte Ptr DATAFLG,AL
MOV AL,Byte Ptr CRCFLAG
OR AL,AL
JNZ RCVCRC
MOV DH,CL
MOV CH,5 ;wait up to 5 seconds for an answer
CALL RECV
JNB L5A19
JMP RCVSTOT
L5A19:
CMP AL,DH
JNZ RCVCERR
;
CHKSNUM:MOV AL,Byte Ptr RCVRNO
MOV CH,AL
MOV AL,Byte Ptr RECDNO
CMP AL,CH
JZ RECVACK
INC AL
CMP AL,CH
JZ L5A20
JMP ABORT
L5A20:
RET
;.....
;
;
RCVCRC: MOV DL,2 ;number of 'CRC' bytes
;
RCVCRC2:MOV CH,5 ;wait up to 5 seconds for a character
CALL RECV
JNB L5A21
JMP RCVSTOT
L5A21:
DEC DL
JNZ RCVCRC2
CALL CRCCHK
OR AL,AL
JZ CHKSNUM
MOV AL,Byte Ptr QFLG
OR AL,AL
JNZ L5A22
JMP RCVSERR
L5A22:
;
RCVCRER:CALL ILPRT
DB '++ CRC error ',0
JMP RCVPRN
;
RCVCERR:MOV AL,Byte Ptr QFLG
OR AL,AL
JNZ RCVCPR
JMP RCVSERR
;
RCVCPR: CALL ILPRT
DB '++ CHECKSUM error ',0
JMP RCVPRN
;
RECVACK:CALL SENDACK
JMP RCVRECD
;
;
; Get the error count and display on CRT
;
SHOWERR:PUSH BX
MOV BX,Word Ptr ERRCT
MOV BH,0
CALL DECOUT
POP BX
CALL ILPRT
DB ' ++',CR,LF,0
MOV AL,Byte Ptr ERRCT
CMP AL,ERRLIM
JNAE L5A24
JMP ABORT
L5A24:
RET
;.....
;
;
SENDHDR:MOV AL,Byte Ptr QFLG
OR AL,AL
JZ SENDHNM
CALL ILPRT
DB CR,'Sending # ',0
PUSH BX ;store current address
MOV BX,Word Ptr RECDNO ;get record number
CALL DECOUT ;print it in decimal
CALL ILPRT
DB ' ',0
;
MOV AL,Byte Ptr HEXSHOW
OR AL,AL
JZ L5A25
CALL ILPRT
DB '(',0
CALL DHXOUT ;16 bit hex conversion & output
CALL ILPRT
DB 'H) ',0
L5A25:
;
POP BX ;restore current address
;
SENDHNM:MOV AL,SOH ;send 'SOH' character to the output
CALL SEND
MOV AL,Byte Ptr RECDNO ;send record number to the output
CALL SEND
MOV AL,Byte Ptr RECDNO
NOT AL ;complement the record number
JMP SEND ;send this value to the output
;.....
;
;
SENDREC:MOV AL,1
MOV Byte Ptr DATAFLG,AL
MOV CL,0
MOV BX,0 ;new record, clear 'CHECKSUM' value
MOV Word Ptr CRCVAL,BX ;new record, clear 'CRC' value
MOV BX, Offset TBUF ;store at 0080H
;
SENDC: MOV AL,Byte Ptr [BX]
CALL SEND
INC BL
JNZ SENDC
XOR AL,AL
MOV Byte Ptr DATAFLG,AL
RET
;.....
;
;
SENDCKS:MOV AL,CL
JMP SEND
;.....
;
;
SENDCRC:PUSH BX
MOV BX,Word Ptr CRCVAL
MOV AL,BH
CALL SEND
MOV AL,BL
CALL SEND
POP BX
XOR AL,AL ;reset the carry bit
RET
;.....
;
;
; After a record is sent, a character is returned telling if it was re-
; ceived properly or not. An ACK allows the next record to be sent. A
; NAK causes the current record to be resent. If no character (or any
; character other than ACK or NAK) is received after a short wait (10
; to 12 seconds), a timeout error message is shown and the record will
; be resent. The GETACK routine can gobble up a string of up to 191
; characters while searching for an 'ACK' or a 'NAK'.
;
GETACK: MOV DL,192 ;number of characters to gobble
;
ACKLUP: MOV AL,0FFH
MOV Byte Ptr CHRFLG,AL ;set the character flag
MOV Byte Ptr TIMFLG,AL ;set the time flag
MOV CH,1
CALL RECV
MOV CH,AL ;save the character
JNB ACKTST
XOR AL,AL
MOV Byte Ptr CHRFLG,AL ;reset the character flag, was none
;
ACKTST: XOR AL,AL
MOV Byte Ptr TIMFLG,AL
MOV AL,CH ;get the character back
CMP AL,ACK
JNZ L5A26
RET
L5A26:
CMP AL,NAK
JZ GETACK1
;
NOAKNK: DEC DL ;one less to go
JNZ ACKLUP ;loop around again if not zero
MOV AL,Byte Ptr CHRFLG
OR AL,AL
JNZ GETACK1
JMP GETATOT
;
GETACK1:MOV AL,Byte Ptr BENHERE
XOR AL,CH
JZ ACKER0 ;do not say 'ACK error' if 1st 'NAK'
MOV AL,Byte Ptr QFLG
OR AL,AL
JZ ACKERR
CALL ILPRT
DB '++ ',0
MOV AL,CH
CMP AL,NAK
JZ GETACK3
CALL HEXO
CALL ILPRT
DB 'H',0
JMPS GETACK4
;
GETACK3:CALL ILPRT
DB 'NAK',0
;
GETACK4:CALL ILPRT
DB ' received not ACK - ',0
CALL SHOWERR
;
ACKER0: XOR AL,AL
MOV Byte Ptr BENHERE,AL
;
ACKERR: MOV AL,Byte Ptr ERRCT
INC AL
MOV Byte Ptr ERRCT,AL
CMP AL,ERRLIM+1 ;at error limit yet?
JNB ACKERR1
RET ;if not, return
;
ACKERR1:CALL ERXIT
DB CR,LF,'++ SEND-FILE CANCELLED ++','$'
;.....
;
;
; Reached error limit
;
GETATOT:CALL ILPRT
DB CR,'++ TIMEOUT - no ACK - ',0
CALL SHOWERR ;display error count
JMPS ACKERR
;.....
;
;
CKABORT:MOV AL,Byte Ptr QFLG
OR AL,AL
JNZ L5A29
RET
L5A29:
CALL STAT
JNZ L5A30
RET
L5A30:
CALL KEYIN
CMP AL,CANCEL
JZ ABORT
RET
;
;
; Aborts send or receive routines and returns to command line
;
ABORT: MOV SP, Offset STACK
;
ABORTL: MOV CH,1 ;1-second delay to clear input
CALL RECV
JNB ABORTL
MOV AL,CANCEL ;show you are cancelling
CALL SEND
;
ABORTW: MOV CH,1 ;1-second delay to clear input
CALL RECV
JNB ABORTW
MOV AL,' '
CALL SEND
MOV AL,'B' ;turn multi-file mode..
MOV Byte Ptr BATCHFLG,AL ;..off so routine ends.
MOV Byte Ptr ABORTFLG,AL ;shows an abort was made
XOR AL,AL
MOV Byte Ptr NFILFLG,AL ;stop copy into memory for disk file
MOV AL,Byte Ptr OPTION ;receiving a file now?
CMP AL,'R'
JNZ L5A32
JMP RCVSABT ;if yes, cancel the unfinished file
L5A32:
CALL ILPRT
DB CR,LF,LF,'++ FILE CANCELLED ++',CR,LF,BELL,0
JMP DONETCA
;.....
;
;
; Increment the record count
;
INCRRNO:PUSH BX
MOV BX,Word Ptr RECDNO ;get record number
LAHF ;bump it
INC BX
SAHF
MOV Word Ptr RECDNO,BX ;store it
MOV AL,BL
POP BX
RET
;.....
;
;
; First check for any wild cards and disallow, just to be safe. Do not
; want a group of files being accidently erased.
;
ERASFIL:MOV BX, FCB ;file name is stored here
MOV CH,11 ;maximum of 11 chars for filename.ext
;
ERASFIL1:
INC BX ;next location in file name
MOV AL,Byte Ptr [BX] ;get the char.
CMP AL,'?' ;check for any wild card chars.
JZ ERRORW ;error if one is found
DEC CH ;number of tries left
JNZ ERASFIL1 ;if not zero, keep checking
MOV AL,Byte Ptr BATCHFLG ;don't ask for erase..
OR AL,AL ;..in multi-file mode,..
JZ NOASK ;..just do it.
MOV DX, FCB
MOV CL,SRCHF
INT 224
INC AL
JNZ L5A33
RET ;file erased ok, return
L5A33:
CALL ILPRT ;otherwise make sure it'S OK
DB 'File exists - erase? (Y/N): ',BELL,0
CALL KBDCHR
CMP AL,'Y'
JZ L5A34
JMP MENU ;if not a 'Y' do not erase
L5A34:
CALL CRLF ;otherwise erase the file
;
NOASK: MOV DX, FCB
MOV CL,ERASE
INT 224
RET
;.....
;
;
ERRORW: POP BX ;restore stack from "call ERASFIL"
CALL ILPRT
DB '++ NO WILDCARDS ALLOWED FOR TEXT FILES ++'
DB CR,LF,BELL,0
JMP MENU
;.....
;
;
BLKFILE:CALL ILPRT ;no file named for send or receive
DB '++ NO FILE SPECIFIED ++',CR,LF,BELL,0
JMP MENU
;.....
;
;
MAKEFIL:MOV DX, FCB
MOV CL,MAKE
INT 224
INC AL
JZ L5A35
RET
L5A35:
CALL ERXIT
DB '++ ERROR -- Can''t open file ++',CR,LF
DB '++ Directory is perhaps full ++','$'
;
CNREC: MOV CL,FILSIZ ;compute file size function in cp/m 2.x
MOV DX, FCB ;point to file control block
INT 224
MOV BX,Word Ptr .FCB+33 ;get record count
MOV Word Ptr RCNT,BX ;store it
MOV BX,0 ;zero 'BX'
MOV Word Ptr .FCB+33,BX ;reset random record in FCB
RET
;.....
;
;
OPENFIL:XOR AL,AL
MOV Byte Ptr .FCBEXT,AL
MOV DX, FCB
MOV CL,OPEN
INT 224
INC AL
JZ L5A36
JMP SENDTIME ;send transfer time, # of records, etc.
L5A36:
CALL ERXIT ;file did not open
DB '++ FILE NOT FOUND ++','$'
;.....
;
;
CLOSFIL:MOV DX, FCB ;get the file name
MOV CL,CLOSE
INT 224 ; close the file
INC AL
JZ L5A37
RET
L5A37:
JMP ERXIT1 ;no file to close, exit
;.....
;
;
; Update record read
;
RDRECD: MOV AL,Byte Ptr RECINBF ;decrement 'RECORDS IN BUFFER' count
DEC AL
MOV Byte Ptr RECINBF,AL
JS RDBLOCK
MOV BX,Word Ptr RECPTR ;find where last move stopped
MOV DX,128
CALL MOVE128 ;move 128 characters
MOV Word Ptr RECPTR,BX ;store new address for next move
RET
;.....
;
;
; Buffer empty so read in another block from the disk
;
RDBLOCK:MOV AL,Byte Ptr EOFLG
CMP AL,1
STC
JNZ L5A38
RET
L5A38:
MOV CL,0
MOV DX, Offset BUFFER
;
RDRECLP:PUSH CX
PUSH DX
MOV CL,SETDMA
INT 224
MOV DX, FCB
MOV CL,READ
INT 224
POP DX
POP CX
OR AL,AL
JZ RDRECOK
DEC AL
JZ REOF
CALL ERXIT
DB '++ FILE READ ERROR ++','$'
;
RDRECOK:MOV BX,128
LAHF
ADD BX,DX
RCR SI,1
SAHF
RCL SI,1
XCHG BX,DX
INC CL
CALL DSKSIZ ;establish buffer size
JZ RDBFULL
JMPS RDRECLP
;...
;
;
REOF: MOV AL,1
MOV Byte Ptr EOFLG,AL
MOV AL,CL
;
;
; Buffer full or received "End Of File (EOF)"
;
RDBFULL:MOV Byte Ptr RECINBF,AL
MOV BX, Offset BUFFER
MOV Word Ptr RECPTR,BX
MOV CL,SETDMA
MOV DX, Offset TBUF
INT 224
JMP RDRECD
;.....
;
;
; Write a record
;
WRRECD: MOV BX,Word Ptr RECPTR
XCHG BX,DX
MOV BX,128
CALL MOVE128
XCHG BX,DX
MOV Word Ptr RECPTR,BX ;new record pointer
MOV AL,Byte Ptr RECINBF ;increment 'RECORDS IN BUFFER' count
INC AL
MOV Byte Ptr RECINBF,AL
MOV CL,AL ;store the record count for now
CALL DSKSIZ ;establish buffer size
JZ WRBLOCK
RET ;buffer not full, return
;
;
; Write a block to disk
;
WRBLOCK:MOV AL,Byte Ptr RECINBF ;get the number of records in the buffer
OR AL,AL
JNZ L5A40
RET ;if zero, don't try to move to disk
L5A40:
MOV CL,AL ;otherwise store in 'C' reg.
MOV DX,Offset BUFFER ;start of buffer to move to disk
;
DSKWRT: PUSH CX
PUSH DX
PUSH BX
MOV CL,SETDMA
INT 224
MOV CL,WRITE
MOV DX, FCB
INT 224
POP BX
POP DX
POP CX
OR AL,AL
JZ L5A41
JMP WRERR ;error if disk is full
L5A41:
MOV BX,128 ;add in another page
ADD BX,DX
XCHG BX,DX
DEC CL ;one less record left to move to disk
JNZ DSKWRT
XOR AL,AL
MOV Byte Ptr RECINBF,AL ;zero the 'RECORDS IN BUFFER' count
MOV BX, Offset BUFFER ;reset location to next buffer start
MOV Word Ptr RECPTR,BX
RET
;.....
;
;
; Determine if the buffer size is for file transfer or for ASCII capture
; to disk then compare with current record length
;
DSKSIZ: MOV AL,Byte Ptr XFLG ;see if transferring files now
OR AL,AL
MOV AL,CL ;get the current record count
JZ DSKSIZ1 ;if yes, exit
MOV AL,CL
CMP AL,BUFSIZ*8 ;buffer size for ASCII capture to disk
RET ;return with flag set for the compare
;...
;
;
DSKSIZ1:MOV AL,Byte Ptr SAVSIZ ;get the file transfer buffer size..
CMP AL,CL ;..from special storage area and compare
RET ;return with flag set for the compare
;.....
;
;
; Timeout time is in B, in seconds. Entry via 'RECVDG' deletes garbage
; characters on the line. For example, having just sent a record, cal-
; ling RECVDG will delete any line noise induced characters LONG before
; the ACK/NAK would be received.
;
RECVDG: CALL CKCHAR ;catch any garbage characters
;
RECV: PUSH DX
;
;
; Get back quickly to gobble 2nd character if TIMFLG is set by the GETNM
; routine - or just step through quickly after the first wait for 'SOH'
; in the 'SOHLUP' routine.
;
MSEC: PUSH BX
MOV BX, Offset TIMFLG
MOV DL, Byte Ptr [BX]
INC DL
MOV BX,Word Ptr QUIKTIM
JZ DOQUIK
MOV BX,Word Ptr TIMVAL
;
DOQUIK: XCHG BX,DX
POP BX
;
MWTI: CALL RCVREADY
JZ MCHAR
MOV AL,DH
OR AL,DL
LAHF
DEC DX
SAHF
JNZ MWTI
DEC CH
JNZ MSEC
POP DX
CALL CKABORT
STC
RET
;.....
;
;
; Get the character from the modem, but filter out 'ACK' and '.' chars.
; if recieving a file name. ('FILTRFLG' is set by the 'GETNM' routine.)
;
MCHAR: CALL IN_MODDATP ;get the character that is waiting
POP DX
LAHF ;save the character for later use also
XCHG AL,AH
PUSH AX
XCHG AL,AH
CMP AL,ACK ;see if it is 'ACK'
JZ ISACK
CMP AL,'.' ;see if it is a period
JNZ DOUPD ;neither, so update 'CRC'
;
ISACK: PUSH BX
PUSH DX
MOV BX,Offset FLTRFLG ;see if need to each 'ACK' or period
MOV DL,Byte Ptr [BX]
INC DL
POP DX
POP BX
JZ MWTI ;yes, so do it
;
DOUPD: CALL CRCUPD ;calculate 'CRC'
ADD AL,CL
MOV CL,AL
MOV AL,Byte Ptr RSEEFLG
OR AL,AL
JZ MONIN
MOV AL,Byte Ptr VSEEFLG
OR AL,AL
JNZ NOMONIN
MOV AL,Byte Ptr DATAFLG
OR AL,AL
JZ NOMONIN
;
MONIN: POP AX ;get the character again
XCHG AL,AH
SAHF
LAHF ;resave it for later use also
XCHG AL,AH
PUSH AX
CALL CKABORT ;show the character on the CRT
;
NOMONIN:CALL CKABORT
POP AX ;get the character back once more
XCHG AL,AH
OR AL,AL ;reset the carry flag
RET ;return with the character and flag set
;.....
;
;
; Send a character to the modem
;
SEND: PUSH AX
MOV AL,Byte Ptr SSEEFLG
OR AL,AL
JZ MONOUT
MOV AL,Byte Ptr VSEEFLG
OR AL,AL
JNZ NOMONOT
MOV AL,Byte Ptr DATAFLG
OR AL,AL
JZ NOMONOT
;
MONOUT: POP AX
PUSH AX
CALL SHOW
;
NOMONOT:POP AX
PUSH AX
CALL CRCUPD ;update the 'CRC' calcuation
ADD AL,CL
MOV CL,AL
;
SENDW: CALL SENDRDY
JNZ SENDW
POP AX
JMP OUT_MODDATP ;send character to modem, done
;.....
;
;
; Waits for the first character received while waiting to send a file.
; If a character is not received in one second, it loops again until a
; char. is received or it times out. The count is set for two minutes
; before timeout. This gives the receiving station ample time to name
; a file, etc.
;
WAITNAK:CALL ILPRT
DB 'Waiting ready signal',CR,LF,0
CALL CRLF
;
WAITNLP:CALL CKABORT
MOV CH,1 ;wait up to 1 second for a character
CALL RECV
CMP AL,CANCEL ;want to quit?
JNZ L5A42
JMP ABORT
L5A42:
CMP AL,CRC ;'CRC' request?
JZ WAITCRC ;yes, go set 'CRC' flag
CMP AL,NAK
JZ WAITCHK
DEC DL
JNZ WAITNLP
JMP ABORT
;...
;
;
WAITCRC:CALL ILPRTQ
DB 'CRC request received',CR,LF,0
MOV AL,1
MOV Byte Ptr CRCFLAG,AL ;make sure in 'CRC' mode then
RET
;.....
;
;
WAITCHK:MOV AL,Byte Ptr BATCHFLG ;in batch mode?
OR AL,AL
JNZ L5A43
RET
L5A43:
CALL ILPRTQ
DB 'Got checksum request',CR,LF,0
RET
;.....
;
;
WAITCHK1:
CALL ILPRTQ
DB 'Name NAK received',CR,LF,0
RET
;.....
;
;
; Finished with the file transfer
;
DONE: MOV AL,Byte Ptr BATCHFLG ;in batch mode?
OR AL,AL
JZ L5A44
JMP DONETC ;exit if not
L5A44:
MOV AL,Byte Ptr QFLG
OR AL,AL
JNZ L5A45
JMP NMSTRNS
L5A45:
MOV CH,12 ;zero out FTRNMSG
MOV BX,(Offset FTRNMSG)
MOV AL,0
;
ZEROLP: MOV Byte Ptr [BX],AL
INC BX
DEC CH
JNZ ZEROLP
MOV CH,12 ;put file name in FTRNMSG
MOV BX, FCB+1
MOV DX,(Offset FTRNMSG)
;
LOADMSG:MOV AL,4 ;start of file type?
CMP AL,CH
JZ PERIOD ;put in period if so
MOV AL,Byte Ptr [BX]
CMP AL,' ' ;don't put in space
JZ SKPSP
MOV SI,DX ;store in FTRNMSG
MOV [SI],AL
INC DX
;
SKPSP: INC BX
DEC CH
MOV AL,CH
OR AL,AL ;end of file name?
JZ FTRNMSG0 ;display file name
JMPS LOADMSG ;loop for another character
;.....
;
;
PERIOD: MOV AL,Byte Ptr [BX]
CMP AL,' ' ;is file type empty?
JZ FTRNMSG0 ;go if so
MOV AL,'.' ;else put period in message
MOV SI,DX
MOV [SI],AL
INC DX
DEC CH
JMPS LOADMSG
;.....
;
;
FTRNMSG0:
CALL ILPRT
DB CR,LF
;
FTRNMSG RS 12
DB 0
CALL ILPRT
DB ' Transferred',CR,LF,LF,BELL,0
;
NMSTRNS:MOV AL,Byte Ptr .FCB ;save drive no.
MOV Byte Ptr DISKNO,AL
MOV BX, FCB ;blank out file control blocks
CALL INITFCB
MOV AL,Byte Ptr DISKNO ;put drive number back
MOV Byte Ptr .FCB,AL
MOV BX,Offset RESTSN ;restore record numbers..
MOV DX,Offset RECDNOB ;..for new file transfer.
MOV CH,(Offset RECDNOE)-(Offset RECDNOB) ;routine also done in menu.
CALL MOVE
CALL SENDNOW ;insures last character is finished
CALL CKCHAR ;catch any echo characters on line
MOV AL,Byte Ptr SENDFLG ;goes to either send or..
OR AL,AL ;..receive file, depending..
JZ L6A1
JMP SENDFIL2 ;..upon which routine set..
L6A1:
JMP RCVFIL1 ;..the flag in multi-file mode.
;.....
;
;
DONETC: CALL CKABORT ;slight delay for next message
CALL ILPRT
DB CR,LF,'[Transfer completed]',CR,LF,BELL,0
;
DONETCA:MOV AL,Byte Ptr XITFLG ;special 'X' flag set?
OR AL,AL
JNZ L6A2
JMP BYEBYE ;if yes, disconnect and reboot
L6A2:
MOV AL,Byte Ptr DISCFLG ;normal 'D' flag set?
OR AL,AL
JZ DONETCD ;if yes, disconnect, get next command
;
DONETCB:CALL JMP_NOPARITY ;reset to no parity
XOR AL,AL
MOV Byte Ptr CRCFLAG,AL ;reset back to checksum
MOV Byte Ptr FIRSTME,AL ;reset first-time 'SOH' flag
MOV Byte Ptr FSTFLG,AL ;reset multi-file trans
MOV Byte Ptr NFILFLG,AL ;turn off the memory save for disk file
MOV Byte Ptr SAVEFLG,AL ;stop memory save in term routine.
MOV AL,Byte Ptr VSEEFLG ;view flag set?
OR AL,AL
JNZ DONETCC ;if not, exit
NOT AL
MOV Byte Ptr QFLG,AL ;VSEEFLG also sets the QFLG
MOV Byte Ptr VSEEFLG,AL ;reset the flag
;
DONETCC:MOV BX, Offset QFLG ;in quiet mode?
MOV AL,Byte Ptr [BX]
OR AL,AL
MOV Byte Ptr [BX],'Q' ;reset the flag to normal
JNZ L6A3
JMP MENU ;if yes, go back to command line
L6A3:
MOV AL,Byte Ptr ABORTFLG ;come here from a timeout?
OR AL,AL
JZ L6A4
JMP MENU ;if yes, go to command mode
L6A4:
MOV AL,Byte Ptr JMPCMD ;requesting return to command mode?
OR AL,AL
JNZ L6A5
JMP MENU ;if yes go to command mode
L6A5:
CALL CRLF ;turn up a new line
JMP TERM ;otherwise return to terminal mode
;.....
;
;
DONETCD:CALL ILPRT
DB CR,LF,'<< DISCONNECTED >>',BELL,CR,LF,0
CALL JMP_GOODBYE ;set 'DTR' low for 300 ms.
MOV AL,Byte Ptr PMMIMODEM
OR AL,AL
JZ L6A6
CALL JMP_DISCONNT
L6A6:
MOV AL,Byte Ptr AUTODIAL ;using a Hayes-type modem?
OR AL,AL
JZ L6A7
CALL JMP_DISCONNT ;if yes, disconnect
L6A7:
JMP MENU0 ;back to command line
;.....
;
;
MOVEFCB:MOV BX, FCB+16
MOV DX, FCB
MOV CH,16
CALL MOVE
XOR AL,AL
MOV Byte Ptr .FCBSNO,AL
MOV Byte Ptr .FCBEXT,AL
RET
;.....
;
;
SHOW: CMP AL,LF
JZ CTYPE
CMP AL,CR
JZ CTYPE
CMP AL,9
JZ CTYPE
CMP AL,' '
JB SEEHEX
CMP AL,7FH
JB CTYPE
;
SEEHEX: LAHF
XCHG AL,AH
PUSH AX
MOV AL,'('
CALL CTYPE
POP AX
XCHG AL,AH
SAHF
CALL HEXO
MOV AL,')'
JMPS CTYPE
;.....
;
;
CTYPE: PUSH CX
PUSH DX
PUSH BX
MOV DL,AL
MOV CL,WRCON
INT 224
POP BX
POP DX
POP CX
RET
;.....
;
;
CRLF: LAHF
XCHG AL,AH
PUSH AX
MOV AL,CR
CALL STYPE
MOV AL,LF
CALL STYPE
POP AX
XCHG AL,AH
SAHF
RET
;.....
;
;
STAT: PUSH CX
PUSH DX
PUSH BX
;
VSTAT: MOV DL,0FEH ; Direct Console I/O Status function flag
MOV CL,6
INT 224
POP BX ; vois la
POP DX
POP CX
OR AL,AL
RET
;.....
;
;
KEYIN: PUSH CX
PUSH DX
PUSH BX
;
VKEYIN: MOV DL,0FFH ; KEYIN FLAG FOR direct CONSOLE I?O
MOV CL,6
INT 224
OR AL,AL
JZ VKEYIN
POP BX ;..by 'INITADR' routine
POP DX
POP CX
RET
;.....
;
;
STYPE: LAHF
XCHG AL,AH
PUSH AX
XCHG AL,AH
PUSH CX
PUSH DX
PUSH BX
;
VTYPE: MOV DL,AL ; Direct Conout requirtes Char in DL
MOV CL,6
INT 224
POP BX
POP DX
POP CX
POP AX
XCHG AL,AH
SAHF
RET
;.....
;
;
; Get a character from the keyboard, convert to upper-case if needed,
; and show on CRT
;
KBDCHR: CALL KEYIN ;get a keyboard character
CALL UCASE ;convert to upper case if needed
CALL STYPE ;show on CRT
RET
;.....
;
;
UCASE: CMP AL,61H ;changes lower case character..
JNB L6A8
RET ;..in 'A'reg. to upper case.
L6A8:
CMP AL,7AH+1 ;see if more than small 'Z'
JNAE L6A9
RET
L6A9:
AND AL,5FH
RET
;.....
;
;
DECOUT: LAHF
XCHG AL,AH
PUSH AX
PUSH CX
PUSH DX
PUSH BX
MOV CX,-10
MOV DX,-1
;
DECOU1: ADD BX,CX
INC DX
JB DECOU1
MOV CX,10
ADD BX,CX
XCHG BX,DX
MOV AL,BH
OR AL,BL
JZ L6A10
CALL DECOUT
L6A10:
MOV AL,DL
ADD AL,'0'
CALL CTYPE
POP BX
POP DX
POP CX
POP AX
XCHG AL,AH
SAHF
RET
;.....
;
;
;----> DHXOUT: - double precision hex output routine
;
DHXOUT: PUSH BX
LAHF
XCHG AL,AH
PUSH AX
MOV AL,BH ;get ms byte
CALL HEXO ;output high order byte
MOV AL,BL ;get ls byte
CALL HEXO ;output low order byte
POP AX
XCHG AL,AH
SAHF
POP BX
RET
;.....
;
;
; Prints a hex value in 'A' on the CRT
;
HEXO: LAHF
XCHG AL,AH
PUSH AX
XCHG AL,AH
RCR AL,1
RCR AL,1
RCR AL,1
RCR AL,1
CALL NIBBL
POP AX
XCHG AL,AH
;
NIBBL: AND AL,0FH
CMP AL,10
JB ISNUM
ADD AL,7
;
ISNUM: ADD AL,'0' ;add in ASCII bias
JMP CTYPE
;.....
;
;
; Displays the control-characters shown in the menu
;
SHFTYPE:LAHF
XCHG AL,AH
PUSH AX
CALL ILPRT
DB 'CTL-',0
POP AX
XCHG AL,AH
ADD AL,40H ;convert binary to ASCII chars.
CALL STYPE ;show on the CRT
JMPS ILPRT
;.....
;
;
; Write a string of characters to the CRT
;
ILPRT: POP SI
;
ILPRT1: LODS BYTE PTR [SI] ;get the character
OR AL,AL ;see if a "0" for end of string
JZ ILPRT2 ;if yes, all done
CALL CTYPE ;show on CRT
JMPS ILPRT1
;
ILPRT2: PUSH SI ;restore the address
RET
;.....
;
;
; Write a string of characters unless in the Quiet mode
;
ILPRTQ: POP SI
;
ILPRTQ1:LODS Byte Ptr [SI] ;get the character
OR AL,AL ;see if a "0" for end of string
JZ ILPRTQ2 ;if yes, all done
MOV BL,Byte Ptr QFLG
OR BL,BL
JZ ILPRTQ1
CALL CTYPE ;show on CRT if not in quiet mode
JMPS ILPRTQ1
;
ILPRTQ2:PUSH SI ;restore the address
RET
;.....
;
;
PRTMSG: MOV CL,PRINT ;print the string
INT 224
RET
;.....
;
;
; Displays error statement then resturns to command mode
;
ERXIT: POP DX
CALL PRTMSG
MOV AL,BELL
CALL STYPE
CALL CRLF
;
ERXIT1: MOV AL,1
MOV Byte Ptr ABORTFLG,AL ;shows an unintentional abort
MOV AL,Byte Ptr BATCHFLG ;in batch mode?
OR AL,AL
JZ L6A12
JMP DONETCB ;if not, exit
L6A12:
JMP ABORT ;abort other computer
;.....
;
;
; Exits directly to CP/M
;
EXIT: MOV AL,Byte Ptr OLDUSER ;get original user number back
MOV DL,AL
CALL SETUSER
MOV CL,SETDMA
MOV DX, ofFSET TBUF ;restore original buffer area
INT 224
MOV CX,1A00H ;a little delay timer
;
EXIT1: DEC CX ;one less loop to make
MOV AL,CH
OR AL,CL
JNZ EXIT1 ;loop again till both are zero
CALL CKCON ;catch any extra keyboard characters
MOV AL,Byte Ptr NFILFLG ;saving for a disk file?
OR AL,AL
JZ L6A13
CALL WRTFIL1 ;if yes, close the file
L6A13:
EXIT2: MOV CL,0 ;if not, reboot
MOV DL,0
INT 224
;.....
;
;
; Catch any extra keyboard characters coming through BDOS
;
CKCON: MOV CL,CONST ;see if any characters waiting
INT 224
OR AL,AL
JNZ L6A15
RET ;if not, exit
L6A15:
MOV CL,RDCON ;otherwise get the character
INT 224
XOR AL,AL ;discard the character
JMPS CKCON ;see if any others
;.....
;
;
MOVE128:MOV CH,128
;
MOVE: MOV AL,Byte Ptr [BX]
MOV SI,DX
MOV [SI],AL
LAHF
INC BX
SAHF
LAHF
INC DX
SAHF
DEC CH
JNZ MOVE
RET
;.....
;
;
; Sends the character in 'A' to the modem
;
SENDCHR:CALL SENDNOW ;wait until modem is ready for character
MOV AL,CH ;get the original character back
JMP OUT_MODDATP ;send the character to modem, return
;.....
;
;
; Initializes CP/M file control blocks AT 5CH and 6CH
;
SETFCB: MOV DX, Offset CMDBUF
MOV BX, FCB
JMPS CMDLINE
;.....
;
;
; Adjusts loop counter for the selected clock speed. Returns with delay
; in 'BX'.
;
FIXCNT: MOV AL,Byte Ptr CLOCK ;get the user's clock speed
PUSH DX ;save the current 'DE' value
PUSH BX
POP DX ;get same value into 'DE' as in 'BX'
;
CNTMUL: LAHF ;add 'DE' to 'BX'
ADD BX,DX
RCR SI,1
SAHF
RCL SI,1
DEC AL ;one less to go
JNZ CNTMUL
POP DX ;restore current 'DE', delay in 'BX'
RET
;.....
;
;
;=======================================================================
;
; Loads a command line addressed by 'DE' registers (max # characters in
; line in 'DE', number of characters in line in DE+1, line starts in
; DE+2) into FCB addressed by 'BX' registers. The FCB should be at least
; 33 bytes in length. The command line buffer must have a maximum length
; at least one more than the greatest number of characters that will be
; needed.
CMDLINE:LAHF
XCHG AL,AH
PUSH AX
XCHG AL,AH
PUSH CX
PUSH DX
PUSH BX
CALL INITIAL ;fills FCBs with blanks and nulls
XCHG BX,DX ;get start of command line in hl.
INC BX ;address # bytes in cmd line.
MOV DL,Byte Ptr [BX] ;load de pair with # bytes.
MOV DH,0
INC BX
ADD BX,DX ;point to byte after last char..
MOV Byte Ptr [BX],CR ;..in cmd line and store delimiter.
POP BX ;restore BX and DE.
POP DX
PUSH DX
PUSH BX
INC DX ;address start of command.
INC DX
CALL DRIVE
;
NAME1: MOV CL,8 ;transfer first filename to FCB.
CALL TRANS
CMP AL,CR
JZ DONEL
CMP AL,' ' ;if space, then start of..
JZ NAME2 ;..second filename.
POP BX ;filetype must be after..
PUSH BX ;..eighth byte of name.
MOV CX,9
ADD BX,CX
MOV CL,3 ;transfer type of first file
CALL TRANS
CMP AL,CR
JZ DONEL
;
NAME2: MOV SI,DX ;eat multiple spaces..
MOV AL,[SI]
CMP AL,' ' ;..between names.
JNZ NAME3
INC DX
JMPS NAME2
;
NAME3: POP BX ;second name starts in 16th byte.
PUSH BX ;point BX to this byte.
MOV CX,16
ADD BX,CX
CALL DRIVE
MOV CL,8
CALL TRANS
CMP AL,CR
JZ DONEL
POP BX ;second type starts in 25th byte.
PUSH BX
MOV CX,25
ADD BX,CX
MOV CL,3
CALL TRANS
;
DONEL: POP BX
PUSH BX
INC BX ;point to 1st char of 1st name in FCB
CALL SCANL ;check for * (ambiguous names)
POP BX
PUSH BX
MOV CX,17 ;..to 1st char of second name in FCB
ADD BX,CX
CALL SCANL
POP BX
POP DX
POP CX
POP AX
XCHG AL,AH
SAHF
RET
;.....
;
;
; Subroutines for CMDLINE section
;
INITIAL:PUSH BX ;initializes FCB with 1 null (for first drive)..
PUSH CX ;..11 blanks, 4 nulls, 1 null (for 2nd drive)..
MOV Byte Ptr [BX],0 ;..11 blanks, and 4 nulls.
LAHF
INC BX
SAHF
MOV CH,11
MOV AL,' '
CALL INITFILL
MOV CH,5
XOR AL,AL
CALL INITFILL
MOV CH,11
MOV AL,' '
CALL INITFILL
MOV CH,4
XOR AL,AL
CALL INITFILL
POP CX
POP BX
RET
;.....
;
;
INITFILL:
MOV Byte Ptr [BX],AL
LAHF
INC BX
SAHF
DEC CH
JNZ INITFILL
RET
;.....
;
;
DRIVE: INC DX ;check 2nd byte of filename. if it..
MOV SI,DX ;..is a ":", then drive was specified..
MOV AL,[SI]
DEC DX
CMP AL,':'
JNZ DEFDR ;..else zero for default drive ..
MOV SI,DX ;..('INIT' put zero)
MOV AL,[SI]
AND AL,5FH
SUB AL,40H ;calculate drive (A=1, B=2,...)..
MOV Byte Ptr [BX],AL ;..and place it in FCB.
LAHF ;address first byte of..
INC DX
SAHF
LAHF ;..in command line,..
INC DX
SAHF
;
DEFDR: LAHF ;..and name field in FCB
INC BX
SAHF
RET
;.....
;
;
TRANS: MOV SI,DX ;transfer from command line to FCB..
MOV AL,[SI]
INC DX ;..up to number of chars specified..
CMP AL,CR ;..by 'C' reg. keep scanning field..
JNZ L6A16
RET ;..without transfer until a delimiting..
L6A16:
CMP AL,'.' ;..field char such as '.', blank, or..
JNZ L6A17
RET ;..CR (for end of commmand line).
L6A17:
CMP AL,' '
JNZ L6A18
RET
L6A18:
DEC CL
JS TRANS ;once c-reg is less than zero, keep..
MOV Byte Ptr [BX],AL ;..reading cmd line but do not..
INC BX ;..transfer to FCB.
JMPS TRANS
;...
;
;
SCANL: MOV CH,8 ;scan file name addressed by BX.
;
TSTNAM: MOV AL,Byte Ptr [BX]
CMP AL,'*' ;if '*' found, fill in rest of field..
JZ FILL1 ;..with '?' for ambiguous name.
INC BX
DEC CH
JNZ TSTNAM
JMPS TSTTYP
;...
;
;
FILL1: CALL FILL
;
TSTTYP: MOV CH,3 ;scan and fill type field for name..
;
TSTTYPL:MOV AL,Byte Ptr [BX] ;..specified above.
CMP AL,'*'
JZ FILL2
LAHF
INC BX
SAHF
DEC CH
JNZ TSTTYPL
RET
;.....
;
;
FILL2: CALL FILL
RET
;.....
;
;
FILL: MOV Byte Ptr [BX],'?' ;routine transfers '?'.
LAHF
INC BX
SAHF
DEC CH
JNZ FILL
RET
;=======================================================================
;
; LISTS DIRECTORY AND GIVES FREE SPACE REMAINING ON THE REQUESTED DRIVE.
;
;
; Disk system reset - currently bypassed, if you wish this feature, put
; JMP DIRLIST2 instead of JMP DIRLIST3 in the eighth line. The
; current disk (plus the A: drive) will then reset each DIR re-
; quest. You can also reset the disk with the LOG command when
; when inserting a different one. This saves a reset each time
; DIR might be requested.
;
DIRLIST:CALL GETDISK
ADD AL,'A' ;change to ascii
MOV Byte Ptr DRNAME,AL ;show for drive name
MOV Byte Ptr ACTDRV,AL ;show for space remaining on drive
;
DIRLIST1:
JMPS DIRLIST3
;
DIRLIST2:
MOV CL,RESET ;13 reset disk system (resetdk)
INT 224
;
;
; Directory list routine
;
DIRLIST3:
MOV DX, Offset CMDBUF ;put command line in FCBb..
MOV BX, FCB ;..addressed by BX-reg..
CALL CMDLINE ;..and then...
MOV BX, Offset FCB4
CALL INITFCB
MOV AL,Byte Ptr .FCB2 ;get drive number
MOV Byte Ptr FCB4,AL
MOV AL,Byte Ptr .FCB2+1
CMP AL,' ' ;if a space (blank) get all names
LAHF
XCHG AL,AH
PUSH AX
JNZ L6A19
CALL QSTMARK
L6A19:
POP AX
XCHG AL,AH
SAHF
JZ L6A20
CALL MOVNAME ;else move name into FCB
L6A20:
CALL DRIVEL
MOV CL,SETDMA
MOV DX, TBUF
INT 224
MOV AL,Byte Ptr NOOFCOL ;number of columns into 'A' reg.
MOV Byte Ptr NAMECT,AL ;CRLF after 'NOOFCOL' number of columns
MOV DX, Offset FCB4
MOV CL,SRCHF ;do first search
INT 224
INC AL ;0FFH --> 0 if no file(s) found
JNZ DIRLOOP
CALL ILPRT
DB '++ FILE NOT FOUND ++',0
JMP STORAGE ;still show storage on default drive
;
DIRLOOP:CALL GETADD
LAHF ;point to first letter of filename
INC BX
SAHF
MOV DX,(Offset PRTNAME)
MOV CX,8
CALL MOVER
LAHF
INC DX
SAHF
MOV CX,3
CALL MOVER
CALL ILPRT
;
PRTNAME DB ' ','.',' ',0 ; 8 spaces, period, 3 spaces
;
NEXTSR: MOV DX, oFFSET FCB4
MOV CL,SRCHN ;do next search
INT 224
INC AL ;if 0FFH --> 0 then..
JZ STORAGE ;..directory-read finished.
LAHF
XCHG AL,AH
PUSH AX
PUSH DX
PUSH BX
MOV AL,Byte Ptr NAMECT
DEC AL
MOV Byte Ptr NAMECT,AL ;name count updated
OR AL,AL
JNZ L6A21
CALL CRLF ;terminate line of file names
L6A21:
JNZ FENCE
MOV AL,Byte Ptr NOOFCOL ;restart columns-per-line count
MOV Byte Ptr NAMECT,AL
JMPS NOFENCE ;fence not needed
;
FENCE: CALL ILPRT
DB ' : ',0 ;fence if not at end of line or..
; ;..LAST FILENAME
NOFENCE:POP BX
POP DX
POP AX
XCHG AL,AH
SAHF
JMPS DIRLOOP
;.....
;
;
; Determine storage remaining on default drive
;
STORAGE:
CALL CRLF
MOV CL,DSKPAR ;current disk parameter block
INT 224
ADD BX,2
MOV AL,ES: BYTE PTR [BX] ;Get Block Shift Factor
MOV BSHIFTF,AL
INC BX ;bump to block mask
MOV AL,ES: BYTE PTR [BX] ;get it
MOV BMASK,AL
ADD BX,2
MOV DX,ES: WORD PTR [BX] ;get max block number
MOV Word Ptr BMAX,DX ;put it away
MOV CL,DSKALL ;address of CP/m Allocation vector
INT 224
XCHG BX,DX ;get its length
MOV BX, Word Ptr BMAX
INC BX
MOV CX,0 ;initialize block count to zero
GSPBYT:
PUSH DX ;save allocation address
XCHG BX,DX
MOV AL,ES: BYTE PTR [BX]
XCHG BX,DX
MOV DL,8 ;set to process 8 blocks
GSPLUP:
RCL AL,1 ;test bit
JC NOTFRE
INC CX
NOTFRE:
MOV DH,AL ;save bits
DEC BX
MOV AL,BL
OR AL,BH
JZ ENDALC ;quit if out of blocks
MOV AL,DH ;restore bits
DEC DL ;count down 8 bits
JNZ GSPLUP ;do another bit
POP DX ;bump to next count....
INC DX ;...of allocation vector
JMP GSPBYT ;process it
;
ENDALC:
POP DX ;clear allocation vector pointer from stack
MOV BX,CX ;copy block to bx
MOV AL,Byte Ptr BSHIFTF ;get block shift factor
SUB AL,3 ;convert from record to K
JZ PRTFREE ;skip shifts of 1K blocks
FREKLP:
ADD BX,BX ;multiply blocks by 'K per block'
DEC AL
JNZ FREKLP
;
PRTFREE:CALL DECOUT ;(# of free k bytes now in 'BX')
MOV DX,(Offset FREEMSG)
JMP PRTMSG
;.....
;
;
; Subroutines for 'DIRLIST' section
;
QSTMARK:MOV AL,'?' ;if blank in FCB, put in 11 ?'S.
MOV CH,11
MOV BX, oFFSET FCB4+1
;
QSTLP: MOV Byte Ptr [BX],AL
LAHF
INC BX
SAHF
DEC CH
JNZ QSTLP
RET
;.....
;
;
MOVNAME:MOV BX, FCB2+1
MOV DX, Offset FCB4+1
MOV CX,11
CALL MOVER
RET
;.....
;
;
GETADD: DEC AL ;un-do the inr above
ADD AL,AL ;times 32
ADD AL,AL
ADD AL,AL
ADD AL,AL
ADD AL,AL
ADD AL,TBUF ;add buffer offset
MOV BL,AL
MOV BH,0
RET
;.....
;
;
DRIVEL: MOV AL,Byte Ptr FCB4 ;if no drive, use
OR AL,AL ;default drive in drname.
JZ PRNTHD
LAHF
XCHG AL,AH
PUSH AX
XCHG AL,AH
DEC AL
MOV DL,AL
MOV CL,SELDSK
INT 224
POP AX
XCHG AL,AH
ADD AL,40H ;make 1=a, 2=b, etc., and..
MOV Byte Ptr DRNAME,AL ;..overwrite default stored below.
MOV Byte Ptr ACTDRV,AL
;
PRNTHD: CALL ILPRT
DB 'Drive '
;
DRNAME DB ' :',CR,LF,0
RET
;.....
;
;
; Initialized storage
;
FREEMSG DB 'k bytes free on drive '
ACTDRV DB ' :',CR,LF,'$'
;
;
; Uninitialized storage
;
BMAX Rb 2 ;highest block number on drive
BMASK Rb 1 ;rec/blk - 1
BSHIFTF Rb 1 ;number of shifts to multiply by rec/blk
;.....
;
;
;=======================================================================
;
; Duplicates 'READ BUFFER' routine same as CP/M function 10, but does
; not use CTL-C (reason for the routine). Does allow controls U, R, E
; and H (BACKSPACE). Outputs bell if the input is greater than the
; buffer.
;
INBUF: LAHF
XCHG AL,AH
PUSH AX
XCHG AL,AH
PUSH BX
PUSH CX
PUSH DX ;'DE' registers must be pushed last
;
INBUFA: CALL CLEARBUF ;clear the buffer area
POP DX ;get address of buffer on retries
PUSH DX ;restore stack
XOR AL,AL
LAHF ;address count field
INC DX
SAHF
MOV SI,DX ;initialize with a zero in count byte
MOV [SI],AL
LAHF
INC DX
SAHF
XCHG BX,DX ;address first buffer byte with 'BX'
;
INBUFB: CALL KEYIN ;(waits for char)
CALL UCASE ;convert to upper case if needed
CMP AL,CR ;is it <return> (enter command)?
JNZ L6A24
JMP INBUFR ;if so, then return.
L6A24:
CMP AL,08H ;CTL-H backspaces over deleted character
JZ DELETE
CMP AL,7FH ;is it a delete?
JZ DELETE
CMP AL,'U'-40H ;is it a CTL-U?
JNZ L6A25
JMP INBUFO ;output #, CR, LF, and start over
L6A25:
CMP AL,'R'-40H ;CTL-R retypes line
JNZ L6A26
JMP RETYPE
L6A26:
;
INBUFC: MOV CH,AL ;save inputted character
XCHG BX,DX ;save 'BX' in 'DE'
POP BX ;get address of buffer in 'BX'
PUSH BX ;restore stack
INC BX ;address count byte
INC Byte Ptr [BX] ;increase count byte
DEC BX ;address maximum
MOV AL,Byte Ptr [BX] ;put maximum in 'A'
INC BX ;address count
CMP AL,Byte Ptr [BX] ;compare count to maximum
JNB L6A27
JMP ALERTL ;if maximum, ring bell and wait for cr.
L6A27:
XCHG BX,DX ;restore buffer pointer to 'BX'
MOV Byte Ptr [BX],CH ;put inputted character in buffer
MOV AL,CH ;output it
CMP AL,EXITCHR ;exit character?
JNZ L6A28
JMP INBUFR ;if yes, all done
L6A28:
CMP AL,20H ;printing character?
JNAE L6A29
CALL STYPE ;if yes, print it
L6A29:
LAHF ;bump pointer
INC BX
SAHF
JMPS INBUFB ;get next character
;...
;
;
DELETE: XCHG BX,DX ;save buffer pointer in 'DE'
POP BX ;address beginning of buffer
PUSH BX ;restore stack
INC BX ;address count field
MOV AL,Byte Ptr [BX]
SUB AL,1 ;decrease count
MOV Byte Ptr [BX],AL
JB NODEL ;don't delete past beginning of buffer
XCHG BX,DX ;restore buffer pointer to 'BX'
DEC BX ;point to last byte inputted
MOV AL,Byte Ptr [BX] ;get character being deleted
MOV Byte Ptr [BX],' ' ;restore blank
CMP AL,' ' ;see if non-printing character
JB DELETE1 ;if yes, skip the CRT backup
MOV AL,BKSP
CALL STYPE ;true erase if 08H
MOV AL,' '
CALL STYPE
MOV AL,BKSP
CALL STYPE
DELETE1:
JMP INBUFB
;.....
;
;
MORE DB '12345' ;5 bytes extra from DELETE routine fix
;
NODEL: INC Byte Ptr [BX] ;don't leave count negative
XCHG BX,DX ;restore pointer to 'BX'
MOV AL,BELL ;says can go no further
CALL STYPE
JMP INBUFB
;.....
;
;
INBUFO: MOV AL,'#' ;announces the line has been removed
CALL STYPE
CALL CRLF
JMP INBUFA
;.....
;
;
RETYPE: POP DX
PUSH DX
LAHF ;point to current number..
INC DX
SAHF
MOV SI,DX ;..of characters.
MOV AL,[SI]
MOV CH,AL
MOV AL,'#'
CALL STYPE
CALL CRLF
MOV AL,CH ;test if zero input
OR AL,AL
JNZ CTLRLP
JMP INBUFB
;...
;
;
CTLRLP: LAHF
INC DX
SAHF
MOV SI,DX
MOV AL,[SI]
CALL STYPE
DEC CH
JNZ CTLRLP
JMP INBUFB
;.....
;
;
ALERTL: MOV AL,BELL ;alarm for full buffer
CALL STYPE
DEC Byte Ptr [BX]
XCHG BX,DX
JMP INBUFB
;.....
;
;
PCRLF: CALL CRLF
JMP INBUFB
;.....
;
;
INBUFR: CALL CRLF ;1st new line after a command character
POP DX
POP CX
POP BX
POP AX
XCHG AL,AH
SAHF
RET
;.....
;
;
CLEARBUF:
POP DX ;accounts for call
POP BX ;address buffer in 'BX'
PUSH BX ;restore..
PUSH DX ;..stack
MOV CH,Byte Ptr [BX] ;save maximum in 'B'
LAHF ;point to first..
INC BX
SAHF
LAHF ;..buffer byte.
INC BX
SAHF
MOV AL,' '
;
CLEARL: MOV Byte Ptr [BX],AL
LAHF
INC BX
SAHF
DEC CH
JNZ CLEARL
RET
;.....
;
;
;=======================================================================
;
; In-line compare. Compares string addressed by 'DE' to string after
; call (ends with zero). Return with carry set means strings not the
; same. All registers except 'A'-reg are unaffected.
;
INLNCOMP:
POP BX ;point 'SI' to 1st char.
PUSH DX
;
ILCOMPL:MOV AL,Byte Ptr [BX] ;'BX' points to in-line string.
OR AL,AL ;end of string if zero.
JZ SAME
MOV SI,DX
MOV AL,[SI]
CMP AL,Byte Ptr [BX]
JNZ NOTSAME
INC BX
INC DX
JMPS ILCOMPL
;...
;
;
NOTSAME:XOR AL,AL ;if not same, finish thru..
;
NSLP: INC BX ;..string so return will..
CMP AL,Byte Ptr [BX] ;..go to instruction after..
JNZ NSLP ;..string and not remainder of string.
STC
;
SAME: POP DX
LAHF ;avoids a NOP instruction..
INC BX
SAHF
PUSH BX ;..when returning.
RET
;.....
;
;
;=======================================================================
;
; Multi-file access subroutine. Allows processing of multiple files
; (i.e., *.ASM) from disk. Builds the correct name in the FCB each time
; it is called. The command is used in programs to process single or
; multiple files. The FCB is set up with the next name, ready to do
; normal processing (open, read, etc.) when routine is called. Carry is
; set if no more names are found.
MFNAME: PUSH CX
PUSH DX
PUSH BX
MOV CL,SETDMA
MOV DX, TBUF
INT 224
POP BX
POP DX
POP CX
XOR AL,AL
MOV Byte Ptr .FCBEXT,AL
MOV AL,Byte Ptr MFFLG1
OR AL,AL
JNZ MFNAME1
MOV AL,1
MOV Byte Ptr MFFLG1,AL
MOV BX, FCB
MOV DX, Offset MFNAME5
MOV CX,12
CALL MOVER
MOV AL,Byte Ptr .FCB
MOV Byte Ptr MFNAME6,AL ;save disk in current FCB
MOV BX, Offset MFNAME5
MOV DX, FCB
MOV CX,12
CALL MOVER
PUSH CX
PUSH DX
PUSH BX
MOV CL, SRCHF
MOV DX, FCB
INT 224
POP BX
POP DX
POP CX
JMPS MFNAME2
;...
;
;
MFNAME1:MOV BX, Offset MFNAME6
MOV DX, FCB
MOV CX,12
CALL MOVER
PUSH CX
PUSH DX
PUSH BX
MOV CL,SRCHF
MOV DX, FCB
INT 224
POP BX
POP DX
POP CX
MOV BX,Offset MFNAME5
MOV DX,FCB
MOV CX,12
CALL MOVER
PUSH CX
PUSH DX
PUSH BX
MOV CL,SRCHN
MOV DX, FCB
INT 224
POP BX
POP DX
POP CX
;
MFNAME2:INC AL
STC
JNZ MFNAME3
MOV Byte Ptr MFFLG1,AL
RET
;.....
;
;
MFNAME3:DEC AL
AND AL,3
ADD AL,AL
ADD AL,AL
ADD AL,AL
ADD AL,AL
ADD AL,AL
ADD AL,81H
MOV BL,AL
MOV BH,0
PUSH BX ;save name pointer
MOV DX, Offset MFNAME6+1
MOV CX,11
CALL MOVER
POP BX
MOV DX, FCB+1
MOV CX,11
CALL MOVER
XOR AL,AL
MOV Byte Ptr .FCBEXT,AL
MOV Byte Ptr .FCBRNO,AL
RET
;.....
;
;
MFNAME4:
MOVER: MOV AL,Byte Ptr [BX] ;used if an 8080 CPU is active
MOV SI,DX
MOV [SI],AL
INC BX
INC DX
DEC CX
MOV AL,CH
OR AL,CL
JNZ MFNAME4
RET
;.....
;
; (END OF MULTI-FILE ACCESS ROUTINE)
;=======================================================================
; CALCULATE FILE TRANSFER TIME
;
;
; Shows the time to transfer a file at various baud rates. (110-19200)
;
SENDTIME:
CALL ILPRT ;print following message:
DB 'File open: ',0
MOV BX,Word Ptr RCNT ;get record count.
CALL DECOUT ;print decimal number of records
;
MOV AL,Byte Ptr HEXSHOW
OR AL,AL
JZ SENDTIME1
CALL ILPRT
DB ' (',0
CALL DHXOUT ;now print size in hex.
CALL ILPRT
DB 'H)',0
;
SENDTIME1:
CALL ILPRT
DB ' records'
DB CR,LF,'Send time: ',0
MOV AL,Byte Ptr MSPEED ;get the speed indicator
MOV DH,0
MOV DL,AL ;set up for table access
MOV BX,(Offset BTABLE) ;point to baud factor table
LAHF ;index to proper factor
ADD BX,DX
SAHF
LAHF ;factor in 'DE'
ADD BX,DX
SAHF
MOV DL,Byte Ptr [BX]
LAHF
INC BX
SAHF
MOV DH,Byte Ptr [BX]
MOV BX,Word Ptr RCNT ;get # of records
CALL DVHLDE ;divide BX by value in DE (records/min)
PUSH BX
MOV BX,CX
CALL DECOUT ;print the minutes portion
CALL ILPRT
DB ' mins, ',0
MOV BX,(Offset RECDBL) ;point to divisors for seconds
MOV DX,0 ; calculation
MOV AL,Byte Ptr MSPEED ;get index for baud rate
MOV DL,AL
LAHF ;index into table
ADD BX,DX
RCR SI,1
SAHF
RCL SI,1
MOV AL,Byte Ptr [BX] ;get multiplier
POP BX ;get remainder
CALL MULHLA ;multiply the 'BX' x 'A'
CALL SHFTHL
CALL SHFTHL
CALL SHFTHL
CALL SHFTHL
MOV BH,0
CALL DECOUT ;print the seconds portion
CALL ILPRT
DB ' secs at ',0
CALL PRTBAUD
CALL ILPRTQ
DB 'To cancel: use CTL-X',CR,LF,0
RET
;
BTABLE DW 5,13,20,26,29,48,85,152,280,480,0 ;records/min for..
RECDBL DB 192,74,48,37,33,20,11,6,3,2,0 ;110-19200 baud
;.....
;
;
; Shows baud rates set for 'time to send' file transfer
;
PRTBAUD:MOV BX,(Offset BAUDSPD)
MOV DH,0
MOV AL,Byte Ptr MSPEED ;get baud rate code
MOV DL,AL ;x1
ADD AL,AL ;x2
ADD AL,AL ;x4
ADD AL,DL ;x5
ADD AL,DL
MOV DL,AL
LAHF ;point to correct rate
ADD BX,DX
RCR SI,1
SAHF
RCL SI,1
XCHG BX,DX
MOV CL,PRINT
INT 224
CALL ILPRT
DB ' bps ',CR,LF,0
RET
;.....
;
;
BAUDSPD DB '110$',0,0,'300$',0,0,'450$',0,0,'600$',0,0,'710$',0,0
DB '1200$',0,'2400$',0,'4800$',0,'9600$',0,'19200$'
;.....
;
;
;----> DVHLDE: Divides 'BX' by value in 'DE',
; Upon exit: 'BC'=quotient,'BL'=remainder
;
DVHLDE: PUSH DX ;save divisor
MOV AL,DL
NOT AL ;negate divisor
MOV DL,AL
MOV AL,DH
NOT AL
MOV DH,AL
LAHF ;'DE' is now two's complemented
INC DX
SAHF
MOV CX,0 ;init quotient
;
DIVL1: LAHF ;subtract divisor from dividend
ADD BX,DX
RCR SI,1
SAHF
RCL SI,1
LAHF ;bump quotient
INC CX
SAHF
JB DIVL1 ;loop till sign changes
LAHF ;adjust quotient
DEC CX
SAHF
POP DX ;retrieve divisor
LAHF ;adjust remainder
ADD BX,DX
RCR SI,1
SAHF
RCL SI,1
RET
;.....
;
;
;----> MULHLA: Multiply the value in 'BX' by the value in 'A'
; Return with answer in 'BX'
;
MULHLA: XCHG BX,DX ;multiplicand to 'DE'
MOV BX,0 ;init product
INC AL ;adjust multiplier for zero test
;
MULLP: DEC AL
JNZ L7A5
RET
L7A5:
LAHF
ADD BX,DX
RCR SI,1
SAHF
RCL SI,1
JMPS MULLP
;.....
;
;
; Shift 'BX' register pair one bit to the right
;
SHFTHL: RCR BX,1
RET
;.....
;
;
; (END OF FILE TRANSFER TIME ROUTINE)
;=======================================================================
; CRC SUBROUTINES
;
;
; Check 'CRC' bytes of record just received
;
CRCCHK: PUSH BX
MOV BX,Word Ptr CRCVAL
MOV AL,BH
OR AL,BL
POP BX
JNZ L7A7
RET
L7A7:
MOV AL,0FFH
RET
;.....
;
;
; Generate the CRC tables for fast calculations
;
CRCGEN: MOV BX, OFFSET CRCTBL ;address at start of 'CRC' lookup table
MOV CL,0
;
CRCGEN1:XCHG BX,DX ;store table location into 'DE'
MOV BX,0 ;clear 'BX' pair
MOV AL,CL
PUSH CX
MOV CH,8
XOR AL,BH
MOV BH,AL
;
CRCGEN2:SHL BX,1 ;index into the table
JNB CRCGEN3
MOV AL,16 ;using x^ 16 + x^12 + x^5 + 1 algorithm
XOR AL,BH
MOV BH,AL
MOV AL,32+1
XOR AL,BL
MOV BL,AL
;
CRCGEN3:DEC CH
JNZ CRCGEN2 ;make 8 loops, one for each bit
;
;
; Value now in 'BX', table address still stored in 'DE'. Exchange, and
; store the 'CRC' value in the two tables after splitting.
;
POP CX ;finished borrowing the 'B' reg.
XCHG BX,DX ;address back in 'BX', 'CRC' in 'DE'
MOV Byte Ptr [BX],DH ;store 1st part of 'CRC' value
INC BH ;move up 256 bytes
MOV Byte Ptr [BX],DL ;store 2nd part of 'CRC' value
DEC BH ;move back 256 bytes
LAHF ;increment to next location
INC BX
SAHF
INC CL ;done when 'C' reg. turns zero again
JNZ CRCGEN1 ;now go do the next location
RET
;.....
;
;
; Update the CRC value from a character in the 'A' register
;
CRCUPD: LAHF ;save all registers just in case
XCHG AL,AH
PUSH AX
XCHG AL,AH
PUSH CX
PUSH DX
PUSH BX
MOV BX,Word Ptr CRCVAL ;get current value
XCHG BX,DX ;put in 'DE' for now
MOV CH,0
XOR AL,DH
MOV CL,AL ;now have the character in 'BC' pair
MOV BX, Offset CRCTBL ;start of 'CRC' lookup-table
ADD BX,CX ;index into the 'CRC' table
MOV AL,Byte Ptr [BX] ;get the value from the table
XOR AL,DL
MOV DH,AL
INC BH ;move 256 bytes for 2nd table location
MOV DL,Byte Ptr [BX] ;put value there into 'E' register
XCHG BX,DX ;put 'DE' into 'BX'
MOV Word Ptr CRCVAL,BX ;updated 'CRC' value with this character
POP BX ;restore all registers
POP DX
POP CX
POP AX
XCHG AL,AH
SAHF
RET
;.....
;
;==================== END OF CRC SUBROUTINE ============================
;
;
;=========================START OF MENU ================================
;
;
MENU0: MOV AL,Byte Ptr NFILFLG
OR AL,AL
JZ MENU ;exit if not saving memory for disk file
CALL ILPRT ;else print message
DB CR,LF,'** File still open, use DEL, DIR, WRT, E, L '
DB 'or T ** ',CR,LF,BELL,0
JMPS MENU1
;
MENU: XOR AL,AL
MOV Byte Ptr ABORTFLG,AL ;null the flag
;
MENU1: MOV BX, OFFSET RESTSN ;restore record numbers..
MOV DX, OFFSET RECDNOB ;..for new file transfer.
MOV CH, (OFFSET RECDNOE)-(OFFSET RECDNOB)
CALL MOVE
MOV BX,OFFSET RESTROPT ;restore option table
MOV DX,OFFSET OPTBL
MOV CH, (OFFSET OPTBE)-(OFFSET OPTBL)
CALL MOVE
XOR AL,AL
MOV Byte Ptr FSTFLG,AL
MOV Byte Ptr TIMFLG,AL
MOV Byte Ptr FLTRFLG,AL ;reset multi-file trans
MOV Byte Ptr MFFLG1,AL ;reset mfaccess routine..
JMP XPRT
;.....
;
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
; MENU OF COMMANDS
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
MENU2: CALL CLRTST
CALL ILPRT
DB ' Single Letter Commands',CR,LF,LF
DB ' ? - Display current settings',CR,LF
MENU3 DB ' ^ - Function key intercept character, '
DB 'then (0-9)',CR,LF
DB ' M - Display the menu',CR,LF
DB ' E - Terminal mode with echo',CR,LF
DB ' L - Terminal mode with local echo',CR,LF
DB ' T - Terminal mode',CR,LF
DB ' For copying text to disk use T (E or L) '
DB 'FILENAME.TYP',CR,LF
DB ' Start or Stop toggles described on subsequent'
DB ' screen.',CR,LF
DB ' R - Receive CP/M file using Christensen Protocol'
DB CR,LF
DB ' S - Send CP/M file using Christensen Protocol',CR,LF
DB ' COMMAND: R (or S) FILENAME.TYP',CR,LF
DB ' R and S can use the following subcommands:'
DB CR,LF
DB ' B - Bulk transfer using wildcards '
DB '(e.g., *.*)',CR,LF
DB ' D - Disconnect when done'
DB CR,LF
DB ' Q - Quiet mode (no messages to console)'
DB CR,LF
DB ' V - View <R> or <S> bytes on console'
DB CR,LF
DB ' X - When done, disconnect, go to CP/M'
DB CR,LF,LF
DB ' The single letter commands may also be used on '
DB 'the',CR,LF
DB ' command line when the program is initially '
DB 'executed.',CR,LF,LF,0
;
THREELTR:
CALL JMP_NXTSCRN
CALL ILPRT
DB ' Three Letter Commands',CR,LF,LF
DB 'CPM - Exit from this program to CP/M',CR,LF
DB 'DIR - List directory and space free (may specify '
DB 'drive)',CR,LF
DB 'ERA - Erase file (may specify drive)',CR,LF
DB 'LOG - Change default drive/user no. (specify '
DB 'drive/user)',CR,LF
DB ' and reset disks. e.g. LOG A0: or LOG B: '
DB '(user # unchanged)',CR,LF
DB 'SPD - Set file output speed in terminal mode'
DB CR,LF,0
;
CALL SORPTST
JNZ NOTIME
CALL ILPRT
DB 'TIM - Select Baud rate for "time-to-send" msg.',CR,LF,0
;
NOTIME: MOV AL,Byte Ptr TOGGLECRC
OR AL,AL
JZ NOTOCRC
CALL ILPRT
DB 'TCC - Toggle CRC/Checksum mode on receive',CR,LF,0
;
NOTOCRC:MOV AL,Byte Ptr TOGGLELOC
OR AL,AL
JZ NOTOGLOC
CALL ILPRT
DB 'TLC - Toggle local command immediate or after ',0
MOV AL,Byte Ptr EXTCHR
CALL SHFTYPE
DB CR,LF,0
;
NOTOGLOC:
MOV AL,Byte Ptr TOGGLELF
OR AL,AL
JZ NOTOGRUB
CALL ILPRT
DB 'TLF - Toggle LF after CR in "L" or "T" mode for '
DB 'a disk file',CR,LF,0
;
NOTOGRUB:
MOV AL,Byte Ptr TOGGLERUB
OR AL,AL
JZ NOTOGLF
CALL ILPRT
DB 'TRB - Toggle rubout to backspace conversion',CR,LF,0
;
NOTOGLF:MOV AL,Byte Ptr TOGXOFF
OR AL,AL
JZ NOTOGXOF
CALL ILPRT
DB 'TXO - Toggle XOFF testing in terminal mode '
DB 'file output',CR,LF,0
;
NOTOGXOF:
MOV AL,Byte Ptr PMMIMODEM ;using a PMMI modem?
OR AL,AL
JNZ NONUM
MOV AL,Byte Ptr AUTODIAL ;using a Hayes-type modem?
OR AL,AL
JNZ NOTOGX2
;
NOTOGX1:CALL ILPRT
DB 'NUM - List remote systems',CR,LF,0
;
NOTOGX2:MOV AL,Byte Ptr SETUPTST
OR AL,AL
JZ NONUM
CALL ILPRT
DB 'SET - Set modem baud rate',CR,LF,0
;
NONUM: CALL ILPRT
DB 'BYE - Disconnect, then return to CP/M'
DB CR,LF,0
MOV AL,Byte Ptr PMMIMODEM ;using a PMMI modem?
OR AL,AL
JNZ NONUM0 ;if yes, display 'CAL'
MOV AL,Byte Ptr AUTODIAL ;usina a Hayes-type modem?
OR AL,AL
JZ NOPMMI ;exit if neither
;
NONUM0: CALL ILPRT
DB 'CAL - Dial number',CR,LF,0
;
NOPMMI: CALL ILPRT
DB 'DSC - Disconnect from the phone line',CR,LF,LF
DB ' The following are terminal text '
DB 'buffer commands:',CR,LF,LF,0
;
SKIPLF: CALL ILPRT
DB 'DEL - Delete memory buffer and file',CR,LF
DB 'WRT - Write memory buffer to disk file',CR,LF,LF,0
CALL NXTSCRN
CALL ILPRT
DB ' Local Commands while in Terminal Mode'
DB CR,LF,LF,0
MOV AL,Byte Ptr BRKCHR
CALL SHFTYPE
DB ' - Send a break tone for 300 ms.',CR,LF,0
MOV AL,Byte Ptr PMMIMODEM
OR AL,AL
JZ SKIPLF1
MOV AL,Byte Ptr CHGBAUD
CALL SHFTYPE
DB ' - Change baud rate',CR,LF,0
;
SKIPLF1:MOV AL,EXITCHR
CALL SHFTYPE
DB ' - Exit to command mode',CR,LF,0
MOV AL,Byte Ptr TRANLOGON
OR AL,AL
JZ NOTRNLOG
MOV AL,Byte Ptr LOGCHR
CALL SHFTYPE
DB ' - Send log-on message',CR,LF,0
;
NOTRNLOG:
MOV AL,Byte Ptr NOCONNCT
CALL SHFTYPE
DB ' - Disconnect from the phone line',CR,LF,0
MOV AL,Byte Ptr LSTTST
OR AL,AL
JZ NOTLIST
MOV AL,Byte Ptr LSTCHR
CALL SHFTYPE
DB ' - Toggle printer',CR,LF,0
;
NOTLIST:MOV AL,LF
CALL STYPE
MOV AL,Byte Ptr SAVECHR
CALL SHFTYPE
DB ' - Start copy into buffer',CR,LF,0
MOV AL,Byte Ptr UNSAVECHR
CALL SHFTYPE
DB ' - Stop copy into buffer',CR,LF,LF
DB ' Start & Stop may be toggled as often as '
DB 'desired.',CR,LF
DB ' A ";" at start of line indicates buffer '
DB 'is copying.',CR,LF
DB ' XOFF automatically used to stop input '
DB 'when writing',CR,LF
DB ' full buffer to disk, XON sent to '
DB 'resume.',CR,LF,LF,0
MOV AL,Byte Ptr TRANCHR
CALL SHFTYPE
DB ' - Transfer ASCII file to remote',CR,LF,LF,0
MOV AL,Byte Ptr LOCNXTCHR
OR AL,AL
MOV AL,Byte Ptr EXTCHR
JNZ REMDFLT
CALL SHFTYPE
DB ' - Send local control character to remote'
DB CR,LF,LF,0
JMPS CKSPCL
;
REMDFLT:CALL SHFTYPE
DB ' - Next character will be used for local control'
DB CR,LF,0
;
CKSPCL: CALL JMP_SPCLMENU ;may have a special menu in the overlay
; ;FALLS ON THROUGH TO 'XPRT'
;
;
; (END OF COMMAND MENU)
;=======================================================================
; START OF COMMAND LINE HANDLING
;
;
; Check first to see if a file was opened for copying incoming to disk
;
XPRT: CALL CRLF ;turn up a blank line to look nice
L7A8:
MOV AL,Byte Ptr NFILFLG ;have a file open for text mode copy?
OR AL,AL
JZ XPRT1 ;if not, exit
;
CALL GETSPC ;otherwise show remaining space
CALL ILPRT
DB ' Bytes of buffer free',CR,LF,LF,0
;
;
; Show disk drive and user number, then command line
;
XPRT1: MOV CL,CURDSK ;current disk function
INT 224
ADD AL,'A' ;make ASCII
CALL STYPE
CALL GETUSER ;get current user number
OR AL,AL
JZ XPRT2 ;skip if user 0
MOV BH,0
MOV BL,AL
CALL DECOUT ;show current user area
;
XPRT2: MOV AL,'>'
CALL STYPE
MOV AL,'>'
CALL STYPE
CALL ILPRT
DB 'COMMAND: ',0
XOR AL,AL
MOV Byte Ptr XFLG,AL ;null the buffer-length flag
;
;
; Get the command line parameters
;
GETCMD: MOV DX,OFFSET CMDBUF ;enter command
CALL INBUF
MOV AL,Byte Ptr CMDBUF+2
CMP AL,EXITCHR ;exit character
JZ XPRT1
;
GETCMD1:CMP AL, Byte Ptr Fncky ;function key intercept character
JNZ L7A9
JMP FUNCT ; (supplied from 'INTCPT' table)
L7A9:
CMP AL,'?'
JNZ L7A10
JMP CURPAR
L7A10:
CMP AL,' '
JNZ L7A11
JMP L7A8 ;skip the extra line feed
L7A11:
MOV AL,Byte Ptr CMDBUF+3
CMP AL,':' ;see if request for new drive/user
JNZ L7A12
JMP SETDRV
L7A12:
MOV DX,OFFSET CMDBUF+2 ;point to command
CALL INLNCOMP
DB 'CPM',0
JNAE L7A13
JMP EXIT
L7A13:
CALL CRLF ;(1st CR/LF at 'INBUFR')
CALL INLNCOMP
DB 'LOG',0
JNAE L7A14
JMP LOGNEW
L7A14:
CALL INLNCOMP
DB 'DIR',0
JNAE L7A15
JMP DIR
L7A15:
CALL INLNCOMP
DB 'ERA',0
JNAE L7A_16
JMP ERASEF
L7A16:
CALL INLNCOMP
DB 'SPD',0
JNAE L7A17
JMP SETSPD
L7A17:
CALL INLNCOMP
DB 'TIM',0
JNAE L7A18
JMP SETTIM
L7A18:
CALL INLNCOMP
DB 'TCC',0
JNAE L7A19
JMP TOGCRC
L7A19:
CALL INLNCOMP
DB 'TRB',0
JNAE L7A20
JMP TOGRUB
L7A20:
CALL INLNCOMP
DB 'TLC',0
JNAE L7A21
JMP TOGLOC
L7A21:
CALL INLNCOMP
DB 'TLF',0
JNAE L7A22
JMP TOGLF
L7A22:
CALL INLNCOMP
DB 'TXO',0
JNAE L7A23
JMP TOGTXOFF
L7A23:
MOV AL,Byte Ptr PMMIMODEM ;using a PMMI modem?
OR AL,AL
JNZ NONUM1 ;if yes, exit
MOV AL,Byte Ptr AUTODIAL ;using a Hayes-type modem?
OR AL,AL
JNZ NONUM1 ;if yes, exit
CALL INLNCOMP
DB 'NUM',0
JNAE L7A24
JMP NUMPRN
L7A24:
;
NONUM1: MOV AL,Byte Ptr SETUPTST
OR AL,AL
JZ NXTOPT1
CALL INLNCOMP
DB 'SET',0
JNAE L7A25
JMP SETUPENT
L7A25:
;
NXTOPT1:CALL INLNCOMP
DB 'WRT',0
JNAE L7A26
JMP WRTFIL
L7A26:
CALL INLNCOMP
DB 'DEL',0
JNAE L7A27
JMP NEWFILE
L7A27:
CALL INLNCOMP
DB 'BYE',0
JNAE L7A28
JMP BYEBYE
L7A28:
CALL INLNCOMP
DB 'DSC',0
JNAE L7A29
JMP DONETCD
L7A29:
MOV AL,Byte Ptr PMMIMODEM ;using a PMMI modem?
OR AL,AL
JNZ NXTOPT0 ;if yes, exit
MOV AL,Byte Ptr AUTODIAl ;using a Hayes-type modem?
OR AL,AL
JZ NXOPT2 ;exit if neither modem-type
;
NXTOPT0:CALL INLNCOMP ;'DE' set from 1st 'INLNCOMP' call
DB 'CAL',0
JB NXOPT2
MOV AL,' ' ;fool the system
MOV Byte Ptr CMDBUF+3,AL ;..'TBUF' so that it..
JMPS DOOPT ;..looks at option for dial
;
NXOPT2: MOV AL,Byte Ptr CMDBUF+2
MOV BX, Offset COMPLIST
CALL COMPARE ;compares list pointed to by BX..
JB NOTVLD ;carry set = no match
;
DOOPT: CALL SETFCB ;loads command buffer into FCB
CALL PROCOPT ;check out the options
JMP RESTART ;go to work
;.....
;
;
NOTVLD: CALL NTVLDMSG
JMP XPRT
;.....
;
;
NTVLDMSG:
CALL ILPRT
DB '++ Invalid command ++',CR,LF,BELL,0
RET
;.....
;
;
FUNCT: MOV AL,Byte Ptr INTCPT ;get the function key intercept char.
AND AL,07FH ;strip off any parity
LAHF ;save the character for now
XCHG AL,AH
PUSH AX
CALL CLRTST
CALL ILPRT
DB ' SPECIAL FUNCTION KEY TABLE'
DB CR,LF,LF,0
POP AX ;get the character back
XCHG AL,AH
CMP AL,' ' ;see if a printing character
JNB FUNCT1 ;if a printing character, show it
LAHF
XCHG AL,AH
PUSH AX
CALL ILPRT
DB 'CTL-',0
POP AX
XCHG AL,AH
ADD AL,40H ;convert binary to ASCII character
;
FUNCT1: CALL STYPE ;show on the CRT
CALL ILPRT
DB ' current function key intercept character',CR,LF,LF,0
;
;
; Shows the functions of the (0-9) keys
;
MOV BX, Offset FNCTBL-1 ;index into the function key table
MOV CH,10 ;has ten entries
;
FUNCT2: INC BX ;next table location
MOV AL,Byte Ptr [BX] ;get the binary function number
ADD AL,'0' ;convert binary to ASCII digits
CALL STYPE
MOV AL,' '
CALL STYPE
;
FUNCT3: INC BX ;next table location
MOV AL,Byte Ptr [BX]
OR AL,AL ;see if a binary zero
JZ FUNCT5
CMP AL,CR
JNZ FUNCT4
CALL ILPRT
DB '<CR>',0
JMPS FUNCT3
;
FUNCT4: CALL STYPE
JMPS FUNCT3
;
FUNCT5: CALL CRLF
DEC CH
JNZ FUNCT2
CALL CRLF
JMP XPRT
;.....
;
;
BYEBYE: MOV AL,Byte Ptr PMMIMODEM ;using a PMMI modem?
OR AL,AL
JZ L7A30
CALL JMP_GOODBYE ;if yes, disconnect
L7A30:
MOV AL,Byte Ptr AUTODIAL ;using a Hayes-type modem?
OR AL,AL
JZ L7A31
CALL SMRESET ;if yes, disconnect
L7A31:
CALL JMP_GOODBYE ;user's custom-area goodbye routine
CALL ILPRT
DB CR,LF,'<< Exit to CP/M >>',CR,LF,0
JMP EXIT ;return to CP/M
;
SMRESET:MOV CH,20
CALL TIMER
MOV BX, Offset SM_DISC
CALL SENDOUT
MOV CH,20
CALL TIMER
MOV AL,' '
;
; If showing the +++ and ATH and ATD, etc. move the three semicolons up
; one line.
;
DB 90H,90H,90H
;;; CALL STYPE
MOV BX,(Offset SM_ATZ)
CALL SENDOUT
;
SMRESET1:
MOV CH,2
CALL RECV
JNB SMRESET1
RET
;.....
;
;
SM_ATZ DB 'ATZ',CR,'$'
;.....
;
;
DIR: MOV CL,CURDSK
INT 224
MOV Byte Ptr DISKSAV,AL
CALL DIRLIST
MOV AL,Byte Ptr DISKSAV
MOV DL,AL
MOV CL,SELDSK
INT 224
JMP XPRT
;.....
;
;
ERASEF: MOV DX, OFFSET CMDBUF ;put cmd line into FCB at 'BX'
MOV BX, FCB
CALL CMDLINE
CALL MOVEFCB ;move FCB+16 to FCB
MOV AL,Byte Ptr .FCB+1
CMP AL,' '
JNZ L7A34
JMP NOTVLD ;go if no file specified
L7A34:
MOV DX, FCB
MOV CL,SRCHF
INT 224
INC AL ;0 if file not found
JNZ ERAFILE ;ok, go erase
CALL ILPRT
DB '++ File not found ++',CR,LF,BELL,0
JMP XPRT
;.....
;
;
ERAFILE:MOV DX, FCB
MOV CL,ERASE
INT 224
CALL ILPRT
DB 'File erased',CR,LF,0
JMP XPRT
;.....
;
;
LOGNEW: MOV AL,Byte Ptr NFILFLG ;file open for memory save to disk?
OR AL,AL
JZ L7A35
JMP NORESET ;if yes, do not reset disk drive now
L7A35:
MOV AL,Byte Ptr CMDBUF+6 ;any disk drive specified?
CMP AL,' '
JNZ LOGNEW1 ;if not a blank, exit
CALL GETDISK ;if not, use current drive
ADD AL,'A' ;to compensate for next line
;
LOGNEW1:SUB AL,'A'
CMP AL,15+1 ;for drives 0-15
JNAE L7A36
JMP NOTVLD ;if more than 15, display error message
L7A36:
MOV Byte Ptr DISKSAV,AL ;store requested drive
CALL GETUSER ;pick up current user number
MOV CH,AL ;save it
MOV AL,Byte Ptr CMDBUF+7 ;get new user number
CALL CHRCHK ;check the char.
CALL FINDUSER
MOV AL,Byte Ptr CMDBUF+8 ;get 2nd digit
CALL CHRCHK ;check the char.
CALL L7A37
;
LOGNEW2:CALL SAVEUSER
MOV CL,RESET
INT 224
MOV AL,Byte Ptr DISKSAV
MOV DL,AL
MOV CL,SELDSK
INT 224
MOV AL,Byte Ptr SAVUSR
MOV DL,AL
CALL SETUSER
JMP XPRT
;.....
;
;
CHRCHK: CMP AL,' '
JZ CHRCHK1
CMP AL,':' ;in case of A: or A1: or A11: (etc.)
JZ CHRCHK1
RET
;
CHRCHK1:POP AX ;reset the 'CALL' on the stack
JMPS LOGNEW2
;.....
;
;
FINDUSER:
MOV CH,0 ;zero the 'B' reg. for 1st time through
L7A37:
CALL NUMCHK ;if neither, see if a valid number
MOV CL,AL ;save
MOV AL,CH ;get save first digit
ADD AL,AL ;x2
ADD AL,AL ;x4
ADD AL,AL ;x8
ADD AL,CH ;x9
ADD AL,CH ;x10
ADD AL,CL
MOV CH,AL ;save
RET
;.....
;
;
SAVEUSER:
MOV AL,CH
CMP AL,15+1 ;user numbers are 0-15
JNAE L7A39
JMP NOTVLD
L7A39:
MOV Byte Ptr SAVUSR,AL
RET
;.....
;
;
NUMGET: MOV DX, Offset CMDBUF
CALL INBUF
MOV AL,Byte Ptr CMDBUF+2 ;get number
CMP AL,' '
JNZ L7A40
RET
L7A40:
;
NUMCHK: SUB AL,'0' ;remove ascii bias
CMP AL,9+1
JNB L7A41
RET ;ok if 9 or less
L7A41:
POP BX ;remove 1st call from the stack
POP BX ;remove 2nd call from the stack
JMP NOTVLD
;
GETUSER:MOV DL,0FFH ;get current user
;
SETUSER:MOV CL,USER ;set up bdos call
INT 224
RET
;.....
;
;
GETDISK:MOV CL,CURDSK ;get current drive
INT 224
RET
;.....
;
;
NORESET:CALL ILPRT
DB '++ Terminal mode file open ++',CR,LF
DB '++ Use WRT or DEL before LOG command ++',CR,LF
DB CR,LF,BELL,0
XOR AL,AL
JMP XPRT
;.....
;
;
SETSPD: CALL ILPRT
DB 'Delay between chars. (0-9): ',0
;
NOKEYS: CALL STAT
JZ NOKEYS
CALL KEYIN
CALL STYPE
CALL SAVEA
SUB AL,'0'
CMP AL,10
JNAE L7A42
JMP NOTVLD
L7A42:
MOV Byte Ptr BYTDLY,AL
;
CALL ILPRT
DB 'Delay at end of line (0-9): ',0
;
NOKEYS1:CALL STAT
JNZ L8A1
JMP NOKEYS1
L8A1:
CALL KEYIN
CALL STYPE
CALL SAVEA
SUB AL,'0'
CMP AL,10
JNAE L8A2
JMP NOTVLD
L8A2:
MOV Byte Ptr CRDLY,AL
;
SPDMSG: CALL ILPRT
DB CR,LF,'Char. delay (terminal file mode) is: ',0
MOV AL,Byte Ptr BYTDLY
MOV CH,AL
MOV AL,CH
PUSH BX
MOV BL,AL
MOV BH,0
CALL DECOUT
POP BX
CALL ILPRT
DB '0 ms. per character',CR,LF
DB 'Line delay (terminal file mode) is: ',0
MOV AL,Byte Ptr CRDLY
MOV CH,AL
PUSH BX
MOV BL,AL
MOV BH,0
CALL DECOUT
POP BX
CALL ILPRT
DB '00 ms. per character',CR,LF,0
JMP XPRT
;......
;
;
SAVEA: LAHF
XCHG AL,AH
PUSH AX
CALL ILPRT
DB CR,LF,0
POP AX
XCHG AL,AH
SAHF
RET
;.....
;
;
SETDRV: MOV AL,Byte Ptr CMDBUF+2 ;get the disk drive
SUB AL,'A' ;convert to binary value
CMP AL,15+1 ;for drives 0-15
JNAE L8A3
JMP NOTVLD
L8A3:
MOV DL,AL
MOV CL,SELDSK ;select requested drive
INT 224
MOV AL,Byte Ptr CMDBUF+5 ;get user number, if any
CMP AL,' ' ;keep current user area?
JNZ L8A4
JMP XPRT
L8A4:
SUB AL,'0' ;convert to binary value
CMP AL,1 ;if a '1', could be units or tens
JNZ SETDRV1 ;if not, numbers stop at 15 so exit
MOV AL,Byte Ptr CMDBUF+6 ;check for a 2nd digit
CMP AL,'0'
JB SETDRV2 ;if less, not a valid number, ignore
SUB AL,'0'-10 ;leave the '10' in as two digits used
;
SETDRV1:CMP AL,15+1 ;user areas are 0-15
JNAE L8A5
JMP NOTVLD
L8A5:
MOV DL,AL
CALL SETUSER
JMP XPRT ;back to work
;
SETDRV2:MOV AL,1
JMPS SETDRV1
;.....
;
;
SETTIM: CALL SORPTST
JZ L8A6
CALL ILPRT
L8A6:
CALL ILPRT
DB 'Use 0-8 to give baud rate for ''S'' mode '
DB 'time-to-send message,',CR,LF
DB 'where 0=110, 1=300, 2=450, 3=600, 4=710, 5=1200, '
DB '6=2400, ',CR,LF,'7=4800 8=9600 and 9=19200 Baud.'
DB CR,LF,LF,'Enter value: ',0
CALL NUMGET
CMP AL,9+1 ;only looking for 0-9 answers
JNAE L8A7
JMP NOTVLD
L8A7:
MOV Byte Ptr MSPEED,AL
CALL SETTIM1
JMP XPRT
;.....
;
;
SETTIM1:CALL SORPTST
JNZ SETTIM2
CALL ILPRT
DB 'Rate for the S mode time-to-send message is set to ',0
JMPS SETTIM3
;...
;
;
SETTIM2:CALL ILPRT
DB 'Modem speed is ',0
;
SETTIM3:JMP PRTBAUD
;.....
;
;
SORPTST:MOV AL,Byte Ptr SETUPTST ;if setup is 'YES' or PMMIMODEM is..
MOV CH,AL ;..'YES' or autodial modem is 'YES'..
MOV AL,Byte Ptr PMMIMODEM ;..return with zero bit not set.
OR AL,CH
JZ L8A8
RET
L8A8:
MOV AL,Byte Ptr AUTODIAL
OR AL,CH
RET
;.....
;
;
TOGCRC: MOV AL,Byte Ptr TOGGLECRC ;allowing CRC/CHECKSUM toggle?
OR AL,AL
JNZ L8A9
JMP NOTVLD ;if not, exit
L8A9:
MOV AL,Byte Ptr CRCDFLT ;get present value and switch it
NOT AL
MOV Byte Ptr CRCDFLT,AL
CALL TOGCRC1 ;show on CRT it has been changed
JMP XPRT
;.....
;
;
TOGCRC1:CALL ILPRT
DB 'Mode: ',0
MOV AL,Byte Ptr CRCDFLT ;see if set for 'CRC' or 'CHECKSUM'
OR AL,AL
JZ CHEKMSG
CALL ILPRT
DB 'CRC',CR,LF,0
RET
;.....
;
;
CHEKMSG:CALL ILPRT
DB 'CHECKSUM',CR,LF,0
RET
;.....
;
;
TOGRUB: MOV AL,Byte Ptr TOGGLERUB
OR AL,AL
JNZ L8A10
JMP NOTVLD
L8A10:
MOV AL,Byte Ptr CONVRUB
NOT AL
MOV Byte Ptr CONVRUB,AL
CALL TOGRUB1
JMP XPRT
;.....
;
;
TOGRUB1:MOV AL,Byte Ptr CONVRUB
OR AL,AL
JZ NORUBMSG
CALL ILPRT
DB 'Rub is backspace',CR,LF,0
RET
;.....
;
;
NORUBMSG:
CALL ILPRT
DB 'Rub is rub',CR,LF,0
RET
;.....
;
;
TOGLOC: MOV AL,Byte Ptr TOGGLELOC
OR AL,AL
JNZ L8A11
JMP NOTVLD
L8A11:
MOV AL,Byte Ptr LOCNXTCHR
NOT AL
MOV Byte Ptr LOCNXTCHR,AL
CALL TOGLOC1
JMP XPRT
;.....
;
;
TOGLOC1:CALL ILPRT
DB 'Use ',0
MOV AL,Byte Ptr LOCNXTCHR
OR AL,AL
MOV AL,Byte Ptr EXTCHR
JZ LOCMSG
CALL SHFTYPE
DB ' before local command',CR,LF,0
RET
;...
;
;
LOCMSG: CALL SHFTYPE
DB ' to send local command to remote',CR,LF,0
RET
;.....
;
;
TOGLF: MOV AL,Byte Ptr TOGGLELF
OR AL,AL
JNZ L8A12
JMP NOTVLD
L8A12:
MOV AL,Byte Ptr ADDLF
NOT AL
MOV Byte Ptr ADDLF,AL
CALL TOGLF1
JMP XPRT
;.....
;
;
TOGLF1: CALL ILPRT
DB 'LF ',0
MOV AL,Byte Ptr ADDLF ;adding lf after cr?
OR AL,AL
JNZ LFMSG ;if yes, exit
CALL ILPRT
DB 'NOT ',0
;
LFMSG: CALL ILPRT
DB 'sent after CR in "L" or "T" for a disk file',CR,LF,0
RET
;.....
;
;
TOGTXOFF:
MOV AL,Byte Ptr TOGXOFF
OR AL,AL
JNZ L8A13
JMP NOTVLD
L8A13:
CALL ILPRT
DB 'Use XOFF testing? (Y/N): ',0
CALL GETANS
JB NOCHG3
MOV Byte Ptr XOFFTST,AL
;
NOCHG3: CALL XOFFMSG
CALL ILPRT
DB CR,LF,'Use XON waiting after <CR> (Y/N): ',0
CALL GETANS
JB NOCHG4
MOV Byte Ptr XONWAIT,AL
;
NOCHG4: CALL XONMSG
MOV AL,Byte Ptr XONWAIT
OR AL,AL
JNZ L8A14
JMP XPRT
L8A14:
NOT AL
MOV Byte Ptr XOFFTST,AL ;do not allow both
CALL ILPRT
DB 'Therefore ',0
CALL XOFFMSG
JMP XPRT
;.....
;
;
GETANS: MOV DX,(Offset CMDBUF)
CALL INBUF
MOV AL,Byte Ptr CMDBUF+2 ;get answer
CMP AL,' '
CMC ;set the carry flag
JNZ L8A15
RET
L8A15:
MOV CH,AL
CMP AL,'N'
MOV AL,0
JNZ L8A16
RET
L8A16:
MOV AL,CH
CMP AL,'Y'
MOV AL,1
JNZ L8A17
RET
L8A17:
POP AX ;preserve stack
JMP NOTVLD
;.....
;
;
XOFFMSG:CALL ILPRT
DB 'XOFF testing ',0
MOV AL,Byte Ptr XOFFTST
OR AL,AL
JNZ XOTSTON
CALL ILPRT
DB 'NOT ',0
;
XOTSTON:CALL ILPRT
DB 'used',0
;
XONMSG1:CALL ILPRT
DB ' in terminal mode file output',CR,LF,0
RET
;.....
;
;
XONMSG: CALL ILPRT
DB 'XON ',0
MOV AL,Byte Ptr XONWAIT
OR AL,AL
JNZ XONMSG2
CALL ILPRT
DB 'NOT ',0
;
XONMSG2:CALL ILPRT
DB 'automatically tested after CR',0
JMPS XONMSG1
;...
;
;
SETUPENT:
MOV AL,Byte Ptr SETUPTST
OR AL,AL
JNZ L8A18
JMP NOTVLD
L8A18:
MOV DX,(Offset CMDBUF)+1
CALL JMP_SETUPR
MOV AL,Byte Ptr AUTODIAL ;using a Hayes-type modem?
OR AL,AL
JNZ L8A19
JMP XPRT ;if not, exit, otherwise..
L8A19:
MOV CH,'A' ;..send 'AT',CR to autodial modem..
CALL SENDCHR ;..to insure its baud rate..
MOV CH,'T' ;..matches that just selected.
CALL SENDCHR
MOV CH,CR
CALL SENDCHR
JMP XPRT
;.....
;
;
NEWFILE:MOV AL,Byte Ptr NFILFLG ;file open for disk save?
OR AL,AL
JZ NOFILOPN ;if not, show "no file open" message
MOV AL,Byte Ptr FCB3+1 ;check that file was requested
CMP AL,' '
JZ NOFILOPN ;if no file, do not erase
MOV DX,(Offset FCB3) ;otherwise erase the old file
MOV CL,ERASE
INT 224
XOR AL,AL
MOV Byte Ptr NFILFLG,AL ;no file mentioned, reset flags
MOV Byte Ptr SAVEFLG,AL
MOV BX,(Offset FCB3)
CALL INITFCB
MOV BX,(Offset BUFFER) ;reset flags to bottom of ram just..
MOV Word Ptr HLSAVE,BX ;..to insure they are there
JMP XPRT
;.....
;
;
WRTFIL: MOV AL,Byte Ptr NFILFLG ;saving memory for a disk file?
OR AL,AL
JZ NOFILOPN ;not saving a file, don't bother writing
CALL WRTFIL1 ;close the file
MOV Byte Ptr SAVEFLG,AL
MOV Byte Ptr WRFLG,AL
MOV BX,(Offset FCB3)
CALL INITFCB ;blank out 'FCB' to written file
MOV BX,(Offset BUFFER) ;can't be erased
MOV Word Ptr HLSAVE,BX ;reset to buffer start for next time
JMP XPRT
;...
;
;
WRTFIL1:MOV AL,Byte Ptr FCB3+1 ;check that file was requested
CMP AL,' '
JNZ L8A20
RET
L8A20:
CALL WRTDSK ;write buffer to disk if not empty
WRTFIL2:
MOV DX,(Offset FCB3) ;close the file
MOV CL,CLOSE
INT 224
XOR AL,AL
MOV Byte Ptr NFILFLG,AL ;file written, reset flags
RET
;.....
;
;
NOFILOPN:
CALL ILPRT
DB '++ No File Open ++',CR,LF,BELL,0
JMP XPRT
;.....
;
;
; THIS ROUTINE DISPLAYS THE PHONE NUMBERS IN THE LIBRARY
;
NUMPRN: PUSH BX
CALL CLRTST
CALL ILPRT
DB ' Library of Phone Numbers of Remote Systems'
DB 0
MOV CL,18 ;number of lines to move
MOV BX, (OFFSET NUMBLIB) ;address of source memory
MOV DX,(Offset BUFFER) ;address of target memory
CALL NEWLINE ;start with CRLF
MOV SI,DX ;+LF
MOV [SI],AL
LAHF ;and bump it
INC DX
SAHF
;
NUMPRN1:LAHF ;skip PMMI dialing letter
INC BX
SAHF
LAHF ;and equal sign
INC BX
SAHF
MOV CH,LIBLEN-2 ;number of bytes to move
CALL MOVE ;move to buffer
CALL SPACES ;2 entries + 3 spaces = 63 characters
PUSH BX ;save source address
PUSH DX ;save destination address
LAHF ;skip next two characters
INC BX
SAHF
LAHF
INC BX
SAHF
MOV DX,(17*LIBLEN) ;get offset of 17 times entry length
LAHF ;add it to the source address
ADD BX,DX
RCR SI,1
SAHF
RCL SI,1
POP DX ;restor destination address
MOV CH,LIBLEN-2 ;get length of library entry
CALL MOVE ;move another entry
POP BX ;restore source address
CALL NEWLINE ;start next line
DEC CL ;one less line to print
JNZ NUMPRN1 ;if not finished, do another
MOV AL,'$'
MOV SI,DX
MOV [SI],AL
MOV CL,PRINT
MOV DX,(Offset BUFFER) ;point to table of numbers to print
INT 224
CALL CRLF
CALL CRLF
POP BX
JMP XPRT ;finished, back to prompt
;.....
;
;
NEWLINE:MOV AL,CR ;puts CRLF at memory pointed by 'DE'
MOV SI,DX ;store it
MOV [SI],AL
MOV AL,LF ;line feed
LAHF ;bump pointer
INC DX
SAHF
MOV SI,DX ;store lf
MOV [SI],AL
LAHF ;bump pointer
INC DX
SAHF
RET
;.....
;
;
SPACES: MOV AL,' ' ;space
MOV SI,DX
MOV [SI],AL
LAHF ;1
INC DX
SAHF
MOV SI,DX
MOV [SI],AL
LAHF ;2
INC DX
SAHF
MOV SI,DX
MOV [SI],AL
LAHF ;3
INC DX
SAHF
RET
;.....
;
;
;
;
COMPARE:MOV CH,Byte Ptr [BX] ;compares 'A' reg. with list..
;
COMPLP: INC BX ;..addressed by BX. first element..
CMP AL,Byte Ptr [BX] ;..of list must be number of elements..
JZ VALID ;..being compared. returns with..
DEC CH ;..carry set if 'A' reg. does not..
JNZ COMPLP ;.. contain an element in list.
STC
;
VALID: RET
;.....
;
;
NXTSCRN:CALL ILPRT
DB 'HIT any KEY to CONTINUE',0
;
NOKEY1: CALL STAT ;get keyboard status
JZ NOKEY1 ;keep looping until keypress
CALL KEYIN ;gobble up keypress
CMP AL,'C'-40H ;control-c to abort?
JNZ CLRTST
POP BX ;clear stack of return address
CALL CRLF ;turn up a blank line
JMP XPRT
;.....
;
;
CLRTST: MOV AL,Byte Ptr SCRNTEST
OR AL,AL
JZ LOTSALF
JMP CLRSCRN
;.....
;
;
LOTSALF:MOV AL,CR
CALL STYPE
MOV CH,12
MOV AL,LF
;
LFLOOP: CALL STYPE
DEC CH
JNZ LFLOOP
RET
;.....
;
;
CURPAR: CALL CLRTST
CALL ILPRT
DB ' Current Settings',CR,LF,LF,0
CALL TOGCRC1
CALL TOGRUB1
MOV AL,Byte Ptr LSTTST
OR AL,AL
JZ NOLIST1
CALL LSTMSG
;
NOLIST1:CALL SETTIM1
CALL ILPRT
DB 'Terminal mode file buffer is ',0
MOV AL,Byte Ptr NFILFLG ;saving memory for a disk file?
OR AL,AL
JNZ ACTIVE ;if yes, go say "active"
CALL ILPRT
DB 'in',0 ;if not, say "inactive"
;
ACTIVE: CALL ILPRT
DB 'active',CR,LF,'Unused portion of buffer is ',0
CALL GETSPC
CALL ILPRT
DB ' bytes',CR,LF,0
CALL TOGLOC1
CALL TOGLF1
CALL XOFFMSG
CALL XONMSG
CALL SPDMSG
CALL CRLF
CALL CRLF
CALL CRLF
JMP XPRT
;.....
;
;
GETSPC: MOV BX,(Offset BUFTOP) ;top of memory buffer
MOV DX,Word Ptr HLSAVE ;current buffer location
SUB BX,DX
CALL DECOUT ;print the space remaining
RET
;.....
;
;
;***********************************************************************
;
; D - A - T - A A - R - E - A
;
;***********************************************************************
;
;
COMPLIST DB 6,'S','R','T','E','L','M'
;.....
;
;
; OPTION TABLE
;
OPTBL EQU (Offset $)
ANSWFLG DB 'A'
BATCHFLG DB 'B'
DISCFLG DB 'D'
JMPCMD DB 'J'
LOCCHFLG DB 'L'
ORIGFLG DB 'O'
QFLG DB 'Q'
RSEEFLG DB 'R'
SSEEFLG DB 'S'
VSEEFLG DB 'V'
XITFLG DB 'X'
EPARITY DB '0' ;even parity sub-option (only in S or R mode)
OPARITY DB '1' ;odd parity sub-option (only in S or R mode)
OPTBE EQU (Offset $) ;..transfer when program initially called.
;
;
; The following must be in the same order as the table above:
;
RESTROPT DB 'A','B','D','J','L','O','Q','R','S','V','X','0','1'
;
;
; The next 14 bytes equal the number of bytes between RECDNOB and
; RECDNOE.
;
RESTSN DB 0,0,0,0,0,0
DW (Offset BUFFER)
DB 0,0,0,0,0,NAK
;
RECDNOB EQU (Offset $) ;start of table marker
RCVRNO DB 0 ;\
RECDNO DB 0,0 ; \
ERRCT DB 0 ; \
ERRCDE DB 0 ; \
EOFLG DB 0 ; \ 14 bytes between table markers
RECPTR DW (Offset BUFFER) ; /
RECINBF DB 0 ; /
MAXEXT DB 0 ; /
RCNT DB 0,0 ; /
DATAFLG DB 0 ;/
BENHERE DB NAK ;
RECDNOE EQU (Offset $) ;end of table marker
;
;
; Additional 16-bit initialized storage
;
CRCVAL DW 0
DIALCT DW 0
HLSAVE DW (Offset BUFFER)
HLSAVE1 DW (Offset PBUFF)
HLSAVE2 DW (Offset PBUFF)
;
;
; Additional general purpose initialized storage
;
ABORTFLG DB 0
ACKFLG DB 0
CRCFLAG DB 0
CRFLAG DB 0
CURRENT DB 52 ;PMMI 300 baud speed value (defaults to 300)
DLYFLG DB 0
ECHOFLG DB 0
EXACFLG DB 0
FIRSTME DB 0
FNCKY DB '^' ; Function Key Intercept character
FNKFLG DB 0 ;function key activity flag
FSTFLG DB 0
LISTFLG DB 0
LOCFLG DB 0
MFFLG1 DB 0
MODCTLB DB 07FH
NFILFLG DB 0
ONERR DB 0
OPTION DB 0
ORIGSAV DB 0
RINGBKFL DB 0
SAVEFLG DB 0
UARTCTLB DB ORIGMOD ;for originate mode
WRFLG DB 0
XFLG DB 0
CMDBUF DB 80H,0 ;command buffer control area
;
;
; General purpose unitialized storage area
;
RS 128 ;storage area for 'CMDBUF'
BGNMS RS 2
TIMFLG RS 1
FLTRFLG RS 1
CHRFLG RS 1
TIMVAL RS 2
QUIKTIM RS 2
DISKNO RS 1
DISKSAV RS 1
DSTORE RS 1
FILECT RS 1
FTYCNT RS 1
MAXRAM RS 1
NAMECT RS 1
NBSAVE RS 2
OLDUSER RS 1
SENDFLG RS 1
SAVUSR RS 1
;
FCB3 RS 33
FCB4 RS 33
FCBBUF RS 15
MFNAME5 RS 12 ;requested name
MFNAME6 RS 12 ;current name
RS 100 ;stack depth
;
;
EVENPAGE EQU ((Offset $)+255)/256*256 ;sets buffers on even page
;
;
ORG EVENPAGE
;
;
STACK EQU (Offset EVENPAGE)-2 ;store original stack pointer
CRCTBL RS 512 ;two tables of 128 bytes each
BUFFDSK RS 128 ;buffer for disk save
BUFFPNT RS 128 ;buffer for printer
BUFFER RS 1024*BUFSIZ ;send/receive file buffer
BUFTOP RS 0 ;filled in when length is found
PBUFF EQU (Offset $) ;printer buffer starts here
NAMEBUF EQU (Offset $) ;batch-mode filenames buffer
;.....
;
; ; BDOS EQUATES
;
RDCON EQU 1
WRCON EQU 2
BLIST EQU 5
PRINT EQU 9
RDBUF EQU 10
CONST EQU 11
CPMVER EQU 12
RESET EQU 13
SELDSK EQU 14
OPEN EQU 15
CLOSE EQU 16
SRCHF EQU 17
SRCHN EQU 18
ERASE EQU 19
READ EQU 20
WRITE EQU 21
MAKE EQU 22
REN EQU 23
CURDSK EQU 25
SETDMA EQU 26
DSKALL EQU 27
DSKPAR EQU 31
USER EQU 32
FILSIZ EQU 35
REIPL EQU 0
BDOS EQU 5
FCB EQU 5CH
FCBEXT EQU FCB+12
FCBSNO EQU FCB+32
FCBRNO EQU FCB+32
FCB2 EQU 6CH
TBUF EQU 80H
;.....
;
;
END