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" 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 ; is end-of-line for verbose mode JZ SMRESULT ;yes, go get the next response CMP AL,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 (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 or 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 '',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 (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