IMD 1.16: 31/05/2007 20:21:33 FOGCPM.131 --FOGCPM131MDM740 ASM MDM740 ASM !"MDM740 ASM#$%&'()*+,-./012MDM740 ASM3456789:;<=>?@ABMDM740 ASMCDEFGHIJKLMNOPQRMDM740 ASMSTUVWXYZ[\]^_`abMDM740 ASMcdefghijklmnopqrMDM740 ASMstuvwxyz{|}~MDM740 ASMMDM740 ASM MDM740 ASM -08-00 86 -CPM131 DOC This is the disk name.  VERSION EQU 740 ;MDM740 (05/07/84) -- CP/M MODEM PROGRAM * ; ; ; NOTE: This program is written in Zilog Z80 code. ; When assembled, it will run on 8080, 8085 ; or Z80 computers. ; ; 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, THE PROMETHEUS PROMODEM, THE HAYES 300 AND 1200, U.S. ROBOTICS ; MODEMS AND THE PMMI S-100 PLUG IN MODEM. IT SUPPORTS UP TO TWO AL- ; TERNATE DIALING SYSTEMS SUCH AS 'MCI', 'SPRINT', ETC. ; ; 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. ; ; NOTE: Current version is 73 sectors long. Use this figure when using ; DDT, etc. to merge the appropriate overlay, regardless of what ; the overlay may call for (such as 66 sectors for overlays made ; when the program was not as lengthy.) ; ;*********************************************************************** ; ; THIS PROGRAM IS COPYRIGHTED. NO CHANGES MAY BE MADE ; WITHOUT PERMISSION UNLESS FOR PERSONAL USE ONLY. IT ; MAY BE DISTRIBUTED IN ITS ORIGINAL FORM WITH NO PRE- ; VIOUS WRITTEN PERMISSION WITH THE UNDERSTANDING THAT ; NO FINANCIAL GAIN WILL RESULT FROM SUCH TRANSACTION. ; ; - Irvin M. Hoff ; ;*********************************************************************** ; ; 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. ; ; M7NM-6.ASM can be used to change the telephone overlay numbers ; and/or set the alternate dialing system code (also used to ; change HEXSHO and SAVSIZ, mentioned below.) ; ; M7LIB.COM can be used to very easily and very quickly change ; any of the telephone overlay numbers. ; ; M7FNK.COM 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. ; ; Significant address changes now used: ; ; 0DFEH - HEXSHO 00 = do not show hex record count ; FF = show both hex and decimal count ; 0DFFH - SAVSIZ 20 = 4k file transfer buffer size ; 40 = 8k file transfer buffer size ; 80 = 16k file transfer buffer size ; 0E00H - NUMLIB (start of telephone number library) ; ;*********************************************************************** ; ; In past years many people have contributed ideas for modem pro- ; grams that I have adapted for use in the MDM7 series. The list ; below includes as many of those as I can recall -- Frank Gaude' ; deserving special mention: ; ; Ward Christensen, Jim Mills, Mark Zeigler, Keith Petersen, ; Paul Kelly, Bruce Ratoff, John Mahr, Rich Berg, Bob Clyne, ; Bill Earnest, Paul Hansknecht, Ron Fowler, Fred Viles, Bob ; Plouffe, Ben Bronson, Sigi Kluger, Frank Gaude' and likely ; others. ; - Irv Hoff W6FFC ; ;*********************************************************************** ; ; 05/07/84 Numerous small bugs fixed that have apparently been present ; MDM740 since MODEM7 days. Copyright notice added when the program ; is brought up, to be legal. Auto-linking added which gives ; the ability to automatically redial a sequential list up to ; 32 numbers. Two options: ; ; B>>COMMAND: A,F,4,G,Z ; or ; B>>COMMAND: A/F/4/G/Z ; ; The '/' beeps just once when connected and then jumps auto- ; matically to the terminal mode to catch any signon messages ; from IBM or Unix systems, etc. The first option beeps con- ; tinuously until the operator hits any key. This places the ; program in the terminal mode. These two options combine to ; make MDM740 one of the most useful modem programs currently ; available for dialing busy numbers. ; - Irv Hoff ; ; 01/01/83 First version. Can be assembled with ASM.COM. (Previously ; MDM700 it was necessary to have the MODEM7.LIB file and use MAC.COM ; to assemble the program.) Selected MDM700 as a new program ; to allow me to make changes that I felt might be beneficial. ; This would not hinder others from updating existing programs ; to their own satisfaction. The name was also selected so it ; would fit on databanks limiting file names to 6 characters. ; - Irv Hoff ; ;*********************************************************************** ; ; PORT EQU 0C0H ;your base port (data or status) ; MDCTL1 EQU PORT ;modem control port MDDATP EQU PORT+1 ;modem data port MDRCVB EQU 02H ;modem receive bit (DAV) MDRCVR EQU 02H ;modem receive ready MDSNDB EQU 01H ;modem send bit MDSNDR EQU 01H ;modem send ready bit ; ; ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; special equates for PMMI ; MDCTL2 EQU PORT+3 ;modem status port ; BAUDRP EQU PORT+2 ;modem baud rate port BRKMASK EQU 0FBH ;mask to set break EVPAMSK EQU 20H ;mask to set even parity NOPAMSK EQU 10H ;mask to reset to no parity ODPAMSK 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 seconds ;any number 0-255 acceptable  ; ; (end of special PMMI eauates) ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; 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 ; ; JP 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. ; PMMIMD: DEFB YES ;yes=PMMI modem AUTDIAL: DEFB NO ;yes=Hayes-type autodial modem TCHPUL: DEFB 'T' ;T=touch, P=pulse (autodial-only) ; CLOCK: DEFB 40 ;clock speed in MHz x 10, 25.5 MHz max. ;2 MHz=20, 3.68 MH=37, 4 MHz=40, etc. MSPEED: DEFB 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: DEFB 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: DEFB 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 NOFCOL: DEFB 5 ;number of directory columns STUPTST: DEFB NO ;yes=non-PMMI setup routine SCRNTST: DEFB NO ;yes=if home cursor and clear screen ;routine at CLRSCR RETRY: DEFB YES ;yes=reset the error limit to try again ;no=abort after 10 consecutive errors ;(ARPANET users should select yes) BACKUP: DEFB NO ;yes=make .BAK file CRCDFLT: DEFB YES ;yes=default to CRC checking ;no=default to Checksum checking TGLECRC: DEFB YES ;yes=allow toggling of Checksum to CRC CONVRUB: DEFB YES ;yes=convert rub to backspace TGLERUB: DEFB YES ;yes=allow toggling of rub to backspace ADDLFD: DEFB NO ;no=no LF after CR to send file in ;terminal mode (added by remote echo) TGLELF: DEFB YES ;yes=allow toggling of LF after CR TRANLOG: DEFB NO ;yes=allow transmission of logon ;write logon sequence at location LOGON SAVCCP: DEFB YES ;yes=do not overwrite CCP LOCNXT: DEFB NO ;yes=local cmd if EXTCHR precedes ;no=not local cmd if EXTCHR precedes TGLELOC: DEFB YES ;yes=allow toggling of LOCNXT LSTTST: DEFB YES ;yes=allow toggling of printer on/off ;in terminal mode. Set to no if using ;the printer port for the modem XOFFTST: DEFB NO ;yes=allow testing of XOFF from remote ;while sending a file in terminal mode XONWAIT: DEFB NO ;yes=wait for XON after sending CR while ;transmitting a file in terminal mode TGXOFF: DEFB YES ;yes=allow toggling of XOFF testing IGNRCTL: DEFB YES ;yes=do not send control characters ;above CTL-M to CRT in terminal mode ;no=send any incoming CTL-char to CRT EXTRA1: DEFB 0 ;for future expansion EXTRA2: DEFB 0 ;for future expansion BRKCHR: DEFB '@'-40H ;^@ = Send a 300 ms. break tone NOCONCT: DEFB 'N'-40H ;^N = Disconnect from phone line LOGCHR: DEFB 'L'-40H ;^L = Send logon LSTCHR: DEFB 'P'-40H ;^P = Toggle printer UNSAVCH: DEFB 'R'-40H ;^R = Close input text buffer TRANCHR: DEFB 'T'-40H ;^T = Transmit file to remote SAVECHR: DEFB 'Y'-40H ;^Y = Open input text buffer EXTCHR: DEFB '^'-40H ;^^ = Send next character ; ; ; Equates used only by PMMI routines grouped together here ; PULRATE: DEFB 250 ;125=20pps dialing, 250=10pps CHGBAUD: DEFB 'B'-40H ;^B = Used with PMMIMD in terminal ;mode to change baud rate on fly ; ; ; Handles in/out ports for data and status ; I$MDCTL1: IN A,(MDCTL1) ;in modem control port RET DEFB 0,0,0,0,0,0,0 ;spares if needed for non-PMMI ; O$MDDATP: OUT (MDDATP),A ;out modem data port RET DEFB 0,0,0,0,0,0,0 ;spares if needed for non=PMMI ; I$MDDATP: IN A,(MDDATP) ;in modem data port RET DEFB 0,0,0,0,0,0,0 ;spares if needed for non-PMMI ; A$MDRCVB: AND MDRCVB ;bit to test for receive ready RET C$MDRCVR: CP MDRCVR ;value of receive bit when ready RET A$MDSNDB: AND MDSNDB ;bit to test for send ready  RET C$MDSNDR: CP MDSNDR ;value of send bit when ready RET ; ; ;====================== SPECIAL PMMI PORTS ============================= ; I$BAUDRP: IN A,(BAUDRP) ;in baudrate port RET O$BAUDRP: OUT (BAUDRP),A ;out baudrate port RET O$MDCTL1: OUT (MDCTL1),A ;out modem control port #1 RET O$MDCTL2: OUT (MDCTL2),A ;out modem control port #2 RET ; ;================== END OF SPECIAL PMMI PORTS ========================== ; ; LOGONPTR: DEFW LOGON J$DIAL: JP DIAL J$DSCONT: JP DSCONT J$GOODBY: JP GOODBY J$INITMD: JP INITMD J$NWBAU: JP NWBAU J$NPARIT: JP NPARIT J$PRITY: JP PRITY J$STUPR: JP STUPR J$SPMEN: JP SPMEN J$SYSVR: JP SYSVR J$BREAK: JP SNDBRK ; ; ; Next six lines should not be changed by user overlay as these go to ; specific locations in the main program, not in the overlay. ; J$ILPRT: JP ILPRT J$INBUF: JP INBUF J$INLNCP: JP INLNCP J$INMDM: JP INMDM J$NXTSCR: JP NXTSCR J$TIMER: JP TIMER ; ; ; 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 DEFB ESC,79H,0,0,0 RET ;..... ; ; CLRSCR: CALL ILPRT DEFB ESC,3AH,0,0,0 RET ;..... ; ; ;======================= SIGN-ON MESSAGE ============================== ; ; Send version number and date ; SYSVR: LD A,(PMMIMD) ;using the PMMI S-100 modem? OR A JP Z,SYSVR1 ;go if not CALL ILPRT DEFB 'Version for PMMI S-100 modem starting at port: ',0 LD A,(I$MDCTL1+1) CALL HEXO ;put in PMMI control port number CALL ILPRT DEFB 'H',CR,LF,0 RET ;..... ; ; SYSVR1: CALL ILPRT ;if not using the PMMI S-100 board DEFB '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: DEFS 59 ;up to 59 characters allowed DEFB 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.) ; ; INITMD: 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 INITMD, above). End your routine with ; a RET. ; STUPR: RET ; ; ; Not needed if using the PMMI board, as it has its own break routine ; SNDBRK: RET ; ; ;**************** START OF SPECIAL PMMI ROUTINES ********************** ; ; ;======================================================================= ; ; SETS THE BAUD RATE ; ;======================================================================= ; ; STBAUD: LD A,(ANSWFLG) ;if 'O' or 'A' not requested and OR A ; baudrate not specified, returns JP Z,FXBAUD ; with current mode and rate LD A,(ORIGFLG) ;if option requested, a blank returns OR A ; with current mode and rate RET NZ ;no change if neither 'O' or 'A' shown ; FXBAUD: CALL GTBAUD ;calculate PMMI baud rate divisor CALL STMSPD ;set the file time transfer value CALL O$BAUDRP ;set the PMMI board to that baudrate CP 52 LD A,5FH ;DTR (filter for over 300 baud) JP C,GT300 ;yes, greater than LD A,7FH ;DTR (filter for 300 and less baud) ; GT300: CALL O$MDCTL2 LD (MDCTLB),A ;save modem control byte ; OFHOOK: LD HL,7500 ;throw in some delay ; OFFDLY: DEC L JP NZ,OFFDLY DEC H JP NZ,OFFDLY LD A,(UARTCT) ;UART control byte for 'A' or 'O' CALL O$MDCTL1 ;now set to answer or originate LD A,C LD (MSPEED),A ;set the file transfer time value XOR A ;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). ; GTBAUD: LD A,(FCB+9) ;get 1st digit of requested baudrate CP ' ' ;if a space, return with current speed LD A,(CURRENT) RET Z LD A,(FCB+9) OR A ;if a null, return with current speed LD A,(CURRENT) RET Z ; LD DE,FCB+9 ;get the requested speed LD HL,0 ; DECLP: LD A,(DE) ;get the ASCII digit INC DE CP ' ' JP Z,DECLP CP '0' ;numerals are 0-9 JP C,BADRTE CP '9'+1 JP NC,BADRTE SUB '0' LD B,H LD C,L ADD HL,HL ADD HL,HL ADD HL,BC ADD HL,HL ADD A,L LD L,A JP NZ,DIGNC INC H ; DIGNC: LD A,E CP FCB+12 JP NZ,DECLP LD A,H CPL LD D,A LD A,L CPL LD E,A INC DE LD HL,15625 ;250000/16 LD BC,-1 ; DIVLP: INC BC ADD HL,DE JP C,DIVLP LD A,B OR A LD A,C LD (CURRENT),A ;can use this the next time by default RET Z ; BADRTE: CALL ERXIT DEFB '++ INVALID BAUDRATE ++$' ;..... ; ; ;======================================================================= ; SETS 'MSPEED' TO BAUD RATE ; ; STMSPD: LD C,0 ;changes PMMI mspeed for 110-710 bps CP 100 ;<300 bps RET NC INC C ;C=1 for 300 bps CP 40 ;<450 bps RET NC INC C ;C=2 for 450 bps CP 30 ;<600 bps RET NC INC C ;C=3 for 600 bps CP 24 ;<710 bps RET NC INC C ;C=4 for 710 bps RET ;..... ; ; ; Change baudrate on-the-fly with CTL-B (while in terminal mode) ; NWBAU: LD A,(PMMIMD) OR A RET Z CALL ILPRT DEFB CR,LF,'Enter new Baudrate: ',0 LD HL,FCB+9 LD (HL),' ' ;keep current baud if none included ; NWBAU1: CALL KEYIN  ;get the baud rate CP CR ;carriage ret finishes baud rate entry CALL Z,CRLF ;if a 'CR', baud rate has been entered JP Z,FXBAUD ;go change the baud rate ;..... ; ; NWBAU2: CP '0' ;numerals are 0-9 JP C,NWBAU1 CP '9'+1 JP NC,NWBAU1 ;if not a numeral, ignore, ask again LD (HL),A ;store answer starting at FCB+9 CALL TYPE ;show the numeral on the CRT INC HL ;next storage location in FCB JP NWBAU1 ;get the next numeral ;..... ; ; ;======================= PRITY ROUTINES =============================== ; ;--->PRITY: Routine to setup PMMI for odd/even parity. ; PRITY: LD A,(PMMIMD) ;is modem a PMMI? OR A ;set flags RET Z ;no, return LD A,(OPRITY) ;get odd parity request byte OR A ;set flags JP NZ,EVNPAR ;if not odd see if it is even LD A,(UARTCT) ;get uart/modem control byte AND ODPAMSK JP PRITY1 ;... ; ; EVNPAR: LD A,(EPRITY) ;get even parity request byte OR A ;set flags RET NZ ;if even parity not specified return LD A,(UARTCT) ;get uart/modem control byte AND ODPAMSK ;set for parity OR EVPAMSK ;now set for even parity ; PRITY1: LD (UARTCT),A JP O$MDCTL1 ;send to PMMI ;..... ; ; NPARIT: LD A,(PMMIMD) OR A RET Z LD A,(UARTCT) OR NOPAMSK ;reset parity bit on PMMI JP O$MDCTL1 ;..... ; ; ;==================== END OF PRITY ROUTINES =========================== ; ; ;======================================================================= ; ; HAYES/PMMI DIALING ROUTINES ; ;======================================================================= ; ; DEFS 128 ;for expansion ; ; Modem control command words ; BRKMSK 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 SMWAIT 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: LD A,(PMMIMD) ;using a PMMI modem? OR A JP NZ,DIAL1 LD A,(AUTDIAL) OR A RET Z ;return if neither modem CALL SMNSY ;make sure autodial modem speaker is on ; DIAL1: XOR A LD (AUTDIR),A ;zero the direct to terminal mode flag LD (AUTOFL),A ;zero the auto-linking flag LD (CRFLAG),A ;zero the continuous dial flag LD HL,0 LD (DIALCT),HL ;zero the dial count LD HL,CMDBUF+1 ;point to the number of characters in LD A,(HL) ; the buffer, then get the number CP 3+1 ;anything typed after 'CAL'? JP C,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. ; LD C,A ;put into the 'C' reg. LD B,0 ;will move original number down 4 SUB 4 ;eliminate the 'CAL' portion LD (HL),A ;store new count at cmdbuf+1 INC HL ;CMDBUF+2 (first character of string) EX DE,HL ;'DE' now has CMDBUF+2 LD HL,CMDBUF+6 ;point to number (or letter) to dial CALL MOVER ;move the group down 4 places JP 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: LD C,18 ;number of lines to move LD HL,NUMLIB ;start of phone number library LD DE,BUFFER ;buffer add. to store them temporarily CALL NEWLINE ;start with CR/LF LD (DE),A ;+LF INC DE ;and bump it ; DIAL3: LD B,LIBLEN ;number of bytes to move CALL MOVE ;move to buffer CALL SPACES ;2 entries + 3 spaces = 71 characters PUSH HL ;save source address PUSH DE ;save destination address LD DE,17*LIBLEN ;get offset of 17 times entry length ADD HL,DE ;add it to source address POP DE ;restore destination address LD B,LIBLEN ;get length of library entry CALL MOVE ;move another entry POP HL ;restore source address CALL NEWLINE DEC C ;one less line to print JP NZ,DIAL3 ;if not zero, print another LD A,'$' ;BDOS print routine terminate character LD (DE),A ;store in buffer CALL CLRTST LD C,PRINT LD DE,BUFFER ;print the library on the CRT CALL BDOS CALL J$ILPRT ;ask which one is wanted DEFB CR,LF,'Enter library code or phone number,',CR,LF DEFB 'Hit RET to abort this function now or',CR,LF DEFB 'CTL-X quits while dialing or ringing: ',0 LD DE,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: LD HL,CMDBUF+1 ;number of characters in buffer LD A,(HL) OR A ;null means CR was typed JP Z,DLXIT2 ;abort dialing, return to menu LD (NUMBER),A LD A,(CMDBUF+3) ;see if at least two characters entered CP '/' ;slash for linking, direct to terminal CALL Z,AUTO ; mode on answer CP ',' ;comma used for linking CALL Z,AUTO1 ;if yes, set it up for auto-linking ; ; ; Check to see how many characters were typed. If more than one, then ; it was a hand-entered phone number, so exit. ; DIAL5: CALL DIALBG ;disconnect, reconnect LD A,(AUTOFL) ;auto-link flag set? OR A JP NZ,AUTO2 ;if yes exit LD A,(NUMBER) ;number of characters in buffer LD (CMDBUF+1),A ;reset the character count, if needed CP 1+1 ;more than one character? JP NC,DIAL14 ;if more than one, hand-entered number LD HL,CMDBUF+2 ;first character in phone number line ; ; ; ; If just one character entered, see if a (A-Z) letter ; DIAL6: LD A,(HL) LD B,'A' ;first letter of alphabet LD E,0  ;counts number of letters to match LD C,26 ;number of letters in alphabet ; DIAL7: CP B ;letter from table? JP Z,DIAL9 ;if yes, get phone number, else INC B ;make next letter (A-Z) INC E ;count up DEC C ;count down JP NZ,DIAL7 ;try next one in (A-Z) table ; ; ; If not (A-Z) then should be (0-9) ; LD B,'0' ;first digit to check LD E,26 ;point past alpha codes LD C,10 ;number of digits in table ; DIAL8: CP B ;number from table? JP Z,DIAL9 ;if yes, go dial, else INC B ;make next digit to compare INC E ;make next table line number DEC C ;count down - loop counter JP NZ,DIAL8 ;loop JP DIALBD ;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: LD HL,NUMLIB ;phone number library LD BC,LIBLEN ;length of library entry LD A,E ;number of times to library length to HL OR A ;set flags JP Z,DIAL11 ; DIAL10: LD A,(HL) ;get first char of selected lib entry OR A ;set flags JP Z,DIALBD ;send bad library msg and abort ADD HL,BC ;increment 'HL' by library length DEC E ;countdown JP NZ,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: LD B,LIBLEN ;number of characters to get from table LD DE,CMDBUF+1 ;point to buffer EX DE,HL ;'HL' points to CMDBUF+1 LD (HL),B ;length of each table entry EX DE,HL ;restore the registers INC DE ;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: LD A,(AUTDIAL) ;using a Hayes-type modem? OR A CALL NZ,SMINIT ;if yes, initialize LD HL,CMDBUF+1 LD E,(HL) ;number of chars in buffer INC HL ;point to 1st character in buffer ; DIAL13: LD A,(HL) ;get next character CALL TYPE ;show it INC HL ;bump pointer DEC E ;decrement count JP Z,DLXIT ;exit if no '.' (bad library entry) CP '.' ;dot? JP Z,DIAL15 ;yes, go dial the phone JP DIAL13 ;no, loop for next character ;..... ; ; ; There is a user entered phone number in 'CMDBUF' area ; DIAL14: LD A,(AUTDIAL) ;using a Hayes-type modem? OR A CALL NZ,SMINIT ;if yes, initialize LD HL,CMDBUF+1 ;get the number of characters in buffer LD A,(HL) LD E,(HL) INC HL ;point to 1st character to dial ;..... ; ; ; Loop to dial the phone number pointed to by 'HL', character count in ; the 'E' register. ; DIAL15: LD A,(HL) ;get first number from the buffer OR A ;set flags JP Z,DIALBD ;bad number if a null ; ; ; Dial a digit, check keyboard for abort ; CALL DL ;dial a digit, show on CRT CALL STAT ;keypress? JP Z,DIAL17 ;if not, exit CALL KEYIN ;yes, go get it CP CANCEL ;CTL-X? JP NZ,DIAL17 ;if not, exit LD A,(AUTDIAL) ;using a Hayes-type modem? OR A JP Z,DLXIT ;if not, exit now, otherise clear line ; ; ; If using an autodial modem, backspace 30 tims to make sure the entire ; number plus 'DT' part of 'ATDT' is erased. ; LD C,30 ; DIAL16: LD B,BKSP CALL SNDCHR ;send to the modem to cancel call DEC C JP NZ,DIAL16 ;if not zero, do another LD B,CR CALL SNDCHR LD A,' ' CALL TYPE ;show on CRT JP DLXIT ;now go abort ; DIAL17: INC HL ;bump pointer DEC E ;one less character to go JP NZ,DIAL15 ;if not done, send the next digit ; ; ; Show the number of dial attempts ; CALL J$ILPRT DEFB ' - try #',0 LD HL,(DIALCT) ;increment the dial count INC HL LD (DIALCT),HL CALL DECOUT ;show number of attempts so far LD A,' ' ;extra space to position cursor CALL TYPE LD A,(AUTDIAL) ;using a Hayes-type modem? OR A JP Z,DIAL19 ;if not, exit LD B,CR ;tells the modem the nu mber is done CALL SNDCHR ;just have one character to send ; DIAL18: CALL J$INMDM ;catch any output from the modem JP NC,DIAL18 JP SMRSLT ;number sent to modem, now get results ; ; ; Dialing is all done, this section is PMMI-only ; DIAL19: LD A,07FH ;turn on PMMI 'DTR' CALL O$MDCTL2 ;timer rate? LD B,1 ;0.1 second per interval CALL J$TIMER LD A,5DH ;2 stop bits, nor parity, 8 data bits CALL O$MDCTL1 LD D,4 ;clear to send mask LD C,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 ; JP NC,CONMD ;connection made ; ; Connection not made, see if a redial is desired ; ; CALL DSCONT ;hang-up so we can redial ; DLGN: LD SP,STACK ;reset the stack to normal, just in case LD A,(CRFLAG) ;continuous redial flag OR A JP NZ,DLGN2 ;if already set, go dial again CALL J$ILPRT ;see if we should keep trying DEFB CR,LF,CR,LF,' Redial? (C/Y/N/Q): ',BELL,0 CALL KBDCHR CALL CRLF ;turn up a line CP 'Y' ;redial? JP Z,DLGN2 ;yes, redial CP 'C' ;continuous redial? JP Z,DLGN1 ;if yes, set continuous redial flag CP 'Q' JP NZ,DLXIT1 ;none of these, quit CALL SMQT ;turn off the loud speaker for 'Quiet' ; DLGN1: LD A,1 LD (CRFLAG),A ;continuous redial flag ; DLGN2: LD A,(AUTDIAL) ;using a Hayes-type modem? OR A JP NZ,DLGN3 ;if yes, exit LD B,RBWAIT ;wait for PMMI reset (or busy) CALL J$TIMER ;or busy tone may be sensed as dialtone JP DLGN4 ; DLGN3: LD B,SMWAIT CALL J$TIMER ; DLGN4: CALL CRLF ;start a new line JP DIAL5 ;redial entry point ;..... ; ; ; Connection has been made ; CONMD: LD A,(PMMIMD) OR A JP Z,CONMD1 LD A,(CURRENT) ;get curret baud rate CALL O$BAUDRP ;set baudrate ; CONMD1: LD B,2 CALL J$TIMER CALL J$ILPRT DEFB BELL,CR,LF,CR,LF,' CONNECTED',0 LD A,(AUTDIR) ;going direct to terminal mode? OR A JP NZ,RETRN LD A,(CRFLAG) ;in continuous redial or first time try? OR A JP Z,RETRN ;go to terminal mode if first time CALL J$ILPRT DEFB ' - any key for terminal mode ',0 ; CONMD2: LD E,10 ; CONMD3: CALL STAT ;keypress? JP Z,CONMD4 ;exit if no keys pressed CALL KEYIN XOR A JP RETRN ;key pressed, go to terminal mode ; CONMD4: LD B,1 ;wait 0.1 second CALL J$TIMER DEC E ;one less loop to make JP NZ,CONMD3 ;see if a keyboard character yet LD A,BELL ;sound a bell CALL TYPE JP CONMD2 ;reset the counter ;..... ; ; ; 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. ; DL: CALL TYPE ;print whatever character, dashes, etc. CP 'R' ;could it be a ringback character? JP NZ,DL1 ;if not, probably a number so exit LD A,E ;get the character count. Is this "R" CP 1 ; the last character in the string? JP Z,RNGBK ;if yes, set up ringback RET ;if not, ignore the 'R' ; DL1: LD B,A ;store the character for now CALL DLD ;check for alternate dialing like 'MCI' LD A,B ;get the original character back ; DL2: CP '*' ;* is a valid dial digit JP Z,DL3 CP '#' ;# is a valid dial digit JP Z,DL3 CP ',' ;comma indicates a short delay-time JP Z,DL3 CP '0' ;digits are (0-9) RET C ;exit less than ASCII '0' CP '9'+1 RET NC ;exit if more than ASCII '9' SUB '0' ;strip ASCII - could also do 'ANI 0FH' JP NZ,DL3 LD A,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. ; DL3: LD C,A LD A,(PMMIMD) ;using a PMMI? OR A JP NZ,DL4 ;if yes, exit CALL SNDCHR ;character is already in the 'B' reg. LD B,1 ;slight delay to let modem settle down JP J$TIMER ;... ; ; DL4: LD A,(PULRATE) CALL O$BAUDRP ; DL5: CALL I$BAUDRP AND TMPUL JP NZ,DL5 ; DL6: CALL I$BAUDRP AND TMPUL JP Z,DL6 ; DL7: LD A,MAKEM CALL O$MDCTL1 ; DL8: CALL I$BAUDRP AND TMPUL JP NZ,DL8 LD A,BRKMSK CALL O$MDCTL1 ; DL9: CALL I$BAUDRP AND TMPUL JP Z,DL9 DEC C JP NZ,DL7 LD A,MAKEM CALL O$MDCTL1 LD B,2 JP J$TIMER ;..... ; ; ; Print bad library number message and abort if a null is encountered. ; DIALBD: CALL J$ILPRT DEFB CR,LF,CR,LF,'++ Bad library number called ++',CR,LF,0 ; DLXIT: CALL CRLF ;turn up a new line ; DLXIT1: LD SP,STACK ;make sure the stack is normal again ;;; CALL J$GOODBY ;user routine to disable DTR, if any DEFB 0,0,0 ;(PREVENT DOUBLE TIME FOR DISCONNECT) CALL J$DSCONT ;hang up the phone and reset the modem ; DLXIT2: XOR A LD (CRFLAG),A ;reset the continuous redial flag JP MENU ;..... ; ; ; Disconnect from the line, reconnect and wait for the dialtone. ; DIALBG: LD A,(AUTDIAL) ;Hayes-type autodial modem? OR A RET NZ ;if yes, finished LD A,MAKEM ;go off-hook CALL O$MDCTL1 LD D,DTMSK ;dial tone mask LD C,50 ;waits up to 10 seconds 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. ; RET NC ;if dial tone within 10 seconds CALL J$ILPRT ;otherwise print error message DEFB CR,LF,CR,LF,'++ NO DIAL TONE ++ ',BELL,0 POP HL ;restore the stack to normal JP DLXIT ;forget it. ;..... ; ; ; Do any alternate dialing such as 'MCI' or 'SPRINT' ; DLD: LD A,(AUTDIAL) ;using a Hayes-type modem? OR A RET Z ;if not, exit LD A,(TCHPUL) ;using touch tone dialing? CP 'T' RET NZ ;if not, ignore LD A,B ;get the character back CP '<' ;alternate dialing system #1 (MCI?) JP NZ,DLD1 ;if not, exit PUSH HL ;save the current values LD HL,ALTDL1 ;alternate dialing area JP DLD2 ; DLD1: CP '>' ;alternate dialing system #2 (Sprint?) RET NZ ;if neither, exit PUSH HL ;save the current values LD HL,ALTDL2 ; DLD2: LD A,(HL) CP '$' ;ready to terminate? JP Z,DLD3 ;if yes, exit ; ; ; Move the semicolons up one line if you do not want to see the Sprint ; number dialed. ; CALL TYPE ;display the character ;;; DB 0,0,0 ;(keeps the total bytes similar) LD B,A ;need the char. in 'B' to send to modem CALL DL2 ;send proper characters to the modem INC HL ;next location CALL STAT ;keypress? JP Z,DLD2 ;if not, do the next character CALL KEYIN ;yes, go get it CP CANCEL ;CTL-X? JP NZ,DLD2 ;if not, handle the next character POP HL ;if yes, reset the stack JP DLXIT ;if yes, exit ; DLD3: LD A,' ' LD B,A ;clears 'B' from last digit sent CALL TYPE POP HL ;restore the stack RET ;..... ; ; ; Disconnect the autodial modem from the phone line. Sends 'I, CR' to ; the Racal-Vadic to return to IDLE mode ; GOODBY: DSCONT: LD A,(AUTDIAL) ;using a Hayes-type autodial modem? OR A JP NZ,DSCON1 ;if yes, skip PMMI section XOR A CALL O$MDCTL1 ;hang up CALL O$MDCTL2 ;clear DAV, ESD, etc. PUSH BC LD B,10 ;1 second for PMMI to disconnect CALL J$TIMER POP BC RET ;... ; ; ; Disconnect the autodial modem from the phone line ; DSCON1: LD B,12 ;1.2 seconds pause CALL J$TIMER LD HL,SM$DISC ;get into command mode CALL SNDOUT LD B,12 ;another 1.2 seconds pause CALL J$TIMER LD A,' ' ;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. ; DEFB 0,0,0 ;;; CALL TYPE ;show on local CRT only LD HL,SM$DISC1 ;now disconnect the modem CALL SNDOUT ; DSCON2: CALL J$INMDM ;wait 0.1 seconds after last character JP NC,DSCON2 RET ;..... ; ; ;----------------------------------------------------------------------- ; Hayes Stuff ; SMQT: LD A,(SPKRFLG) ;speaker flag set to quiet? OR A RET NZ ;if yes, forget it LD A,YES LD (SPKRFLG),A ;flip the flag to quiet, now LD HL,SM$SOFF CALL SNDOUT LD B,6 JP J$TIMER ;time for an 'OK' from modem and return ;..... ; ; SMNSY: LD A,(SPKRFLG) ;speaker already turned on? OR A RET Z ;if yes, forget it LD A,NO ;set for noisey, now LD (SPKRFLG),A LD HL,SM$SON CALL SNDOUT LD B,6 JP J$TIMER ;..... ; ; ; Hayes-like autodial modem control codes ; SM$DIAL: DEFB 'ATDT $' ;set for touch (or pulse) dialing SM$DISC: DEFB '+++$' ;puts the modem in local command mode SM$DISC1: DEFB 'ATH',CR,'$' ;disconnects the modem SM$SOFF: DEFB 'ATM0',CR,'$' ;turns the speaker off SM$SON: DEFB 'ATM1',CR,'$' ;turns the speaker on SPKRFLG: DEFB 0 ;0 = speaker has not been silenced ;..... ; ; ; Set the autodial modem for pulse dialing ; SMINIT: LD A,(TCHPUL) ;touch or pulse dialing for autodial? LD (SM$DIAL+3),A ;store LD HL,SM$DIAL CALL SNDOUT ; SMINT1: CALL J$INMDM ;wait for modem to finish, if needed JP NC,SMINT1 RET ;..... ; ; ; Send the string pointed to by 'HL' to both the CRT and the modem ; SNDOUT: CALL SNDNOW ;wait until modem is ready LD A,(HL) ;get the character CP '$' RET Z ;if yes, finished LD A,(HL) CALL O$MDDATP ;send to modem ; ; ; If you want to print the +++ ATD, etc. from Hayes-type units, move the ; three semi-colons down one line. ; ;;; CALL TYPE ;show on CRT DEFB 0,0,0 ;(PREVENT SHOWING THE +++ ATD) INC HL JP SNDOUT ;..... ; ; ; Checks for answer from Hayes-type autodial modem ; ; SMRSLT: CALL RCVRDY ;see if any incoming character yet JP Z,SMRSL1 ;if yes, exit and look at it CALL STAT ;else see if want to abort ringing JP Z,SMRSLT ;if neither, wait for one of them CALL KEYIN ;get character from keyboard CP CANCEL ;CTL-X to terminate dialing? JP NZ,SMRSLT ;if not, keep going LD B,CR CALL SNDCHR ;tells the modem to hang up right away JP DLXIT ;abort dialing routine ; SMRSL1: CALL I$MDDATP ;get the character, then AND 7FH ;remove any parity LD B,A ;store for 'GIVLF' area if needed CP 'B' ;'BUSY' (for Anchor modems, etc.) JP Z,BUSY ;if busy, flush string and retry CP '0' ;'OK' single digit result code JP Z,SMRSL1 ;ok, loop for next response CP 'O' ;'OK' verbose digit result coe JP Z,SMRSL1 ;ok, loop for next response CP '1' ;'CONNECT', single digit result code JP Z,ON$LIN ;connected,  reset redial flags CP 'C' ;'CONNECT', verbose result code JP Z,ON$LIN ;connected, reset redial flags CP '3' ;'NO CARRIER', single digit result code JP Z,NO$CAR ;no carrier, flush string and retry CP 'N' ;'NO CARRIER', verbose result code JP Z,NO$CAR ;no carrier, flush string and retry CP '4' ;'ERROR', single digit result code JP Z,FAILED ;error, go display CP 'E' ;'ERROR', verbose result code JP Z,FAILED ;error, go display CP '5' ;'CONNECT 1200' single digit result code JP Z,ON$120 ;connected, reset redial flags ; SMDM1: CP LF ; is end-of-line for verbose mode JP Z,SMRSLT ;yes, go get the next response CP CR ; may precede digit in digit mode JP Z,SMRSLT ;yes, go get the next response ; CALL STAT ;else, see if want to abort ringing JP Z,SMDM1A ;if not, get next character CALL KEYIN ;else, get character from keyboard CP CANCEL ;CTL-X to terminate dialing? JP NZ,SMDM1A ;if not, keep going LD B,CR CALL SNDCHR ;tells the modem to hang up right away JP DLXIT ;abort dialing routine ; SMDM1A: CALL J$INMDM ;get next character JP SMDM1 ;loop until end of response encountered ; ; ; The Ancho modem gives a busy result code, although still waits the ; normal time-out period to do it. ; BUSY: CALL J$ILPRT DEFB 'busy! ',0 JP DLGN ;..... ; ; ; 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 J$ILPRT DEFB 'abort ',0 JP DLGN ;..... ; ; NO$CAR: CALL J$ILPRT DEFB 'no carrier ',0 JP DLGN ;..... ; ; ON$LIN: CALL J$ILPRT DEFB 'on line',0 JP CONMD ;..... ; ; ON$120: CALL J$ILPRT DEFB 'on at 1200',0 JP CONMD ;..... ; ; end of special Hayes-like handling ;----------------------------------------------------------------------- ; ; Handles the special ringback numbers. Dials, lets it ring only once, ; hangs up and then redials. ; RNGBK: LD A,(AUTDIAL) ;using a Hayes-type modem? OR A JP NZ,RNGBK2 ;if yes, ringback not possible LD A,(CMDBUF+1) ;get the number of chars. in the buffer DEC A ;subtract 1 to avoid the ringback char LD (CMDBUF+1),A ;store the new value LD D,DTMSK ;load tone detect mask LD C,RBLMT ;waits up to 7 seconds for a ring CALL WAIT JP NC,RNGBK0 ;if no ring detected, pretend we got one JP RNGBK1 ;hangup, redial, & listen for carrier ; RNGBK0: LD B,25 ;got a ring, wait 2.5 seconds CALL TIMER CALL I$BAUDRP ;is tone still present? AND D JP Z,DLGN ;yes, must be busy, do a normal redial ; ; ; Hang up, redial and listen for dial tone ; RNGBK1: CALL HANGUP ;hang up the phone CALL J$ILPRT DEFB 'ringback set, first ring ',0 LD B,RBWAIT ;wait 5 seconds before redialing CALL J$TIMER ; for line to clear, etc. CALL DIALBG ;disconnect, reconnect, wait for tone JP C,DLXIT LD A,(NUMBER) ;number of characters in buffer CP 1+1 ;more than one character? JP NC,DIAL14 ;if more than one, hand-entered number JP DIAL12 ;go redial for the table ringback number ;..... ; ; RNGBK2: CALL J$ILPRT DEFB CR,LF,'++ No ringback for autodial modem ++',0 POP HL ;reset the stack JP DLXIT ;..... ; ; HANGUP: LD A,CLEAR CALL O$MDCTL2 XOR A JP O$MDCTL1 ;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: LD (AUTDIR),A ;direct to terminal mode on answer ; AUTO1: LD A,0FFH ;set the flags to -1 LD (AUTOFL),A ;set the auto-linking flag LD (CRFLAG),A ;set the continuous redial flag LD B,64 ;maximum number of characters to move LD HL,CMDBUF+1 ;start with number in the string LD DE,CMDBUF+65 ;move to aft part of buffer JP MOVE ;when finished return to caller ;..... ; ; ; Linking routine ; AUTO2: LD A,(AUTOFL) ;increment the flag for each new try INC A INC A LD (AUTOFL),A LD C,A ;hold momentarily LD B,0 LD A,(CMDBUF+65) ;see how many characters typed CP C JP NC,AUTO3 LD A,1 ;reset the flag to start over LD C,A LD (AUTOFL),A ; AUTO3: LD HL,CMDBUF+65 ADD HL,BC JP DIAL6 ;go to work ;..... ; ; AUTDIR: DEFB 0 ;direct to terminal mode on answer AUTOFL: DEFB 0 ;auto-linking flag NUMBER: DEFB 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: LD B,2 CALL TIMER ;wait for timer to go high then low CALL I$BAUDRP ;PMMIADDR+2 (modem status port) AND D ;(CTS or dialtone mask) RET Z ;active low, so return on 0 PUSH BC ;save the registers PUSH DE CALL STAT ;keypress? JP Z,WAIT1 ;if not, exit CALL KEYIN ;yes, get char CP CANCEL ;CTL-X to intentionally abort? JP Z,WAIT2 ;yes, disconnect, jmp to menu ; WAIT1: POP DE ;restore the registers POP BC DEC C ;count-down JP NZ,WAIT SCF ;set carry to indicate mask not set RET ;..... ; ; WAIT2: POP DE ;restore the registers POP  BC JP DONETD ;disconnect ;..... ; ; (END OF HAYES/PMMI DIALING ROUTINE) ;======================================================================= ; SPECIAL PMMI MENU ; SPMEN: LD A,(PMMIMD) OR A RET Z CALL J$NXTSCR CALL ILPRT DEFB ' Additional Subcommands for PMMI Modems' DEFB CR,LF,LF DEFB ' Modem control:',CR,LF DEFB ' A - Answer tone for send or receive',CR,LF DEFB ' O - Originate tone for send or receive',CR,LF,LF DEFB ' Parity option:',CR,LF DEFB ' 1 - Set and check for odd parity',CR,LF DEFB ' 0 - Set and check for even parity',CR,LF DEFB ' Both ends must be capable of these options' DEFB CR,LF DEFB ' which are available only in R and S modes.' DEFB CR,LF DEFB ' The parity checking will be part of the' DEFB CR,LF DEFB ' file transfer protocol.',CR,LF,LF DEFB ' Speed Options:',CR,LF DEFB ' After entering your primary and secondary ' DEFB 'options,',CR,LF DEFB ' you can set the modem speed by placing a ' DEFB ' "." after',CR,LF DEFB ' the options followed by the speed e.g., ' DEFB '300, 600.',CR,LF,LF DEFB ' EXAMPLE: SBO.600 will set the modem for ' DEFB '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 HL ; TIMER1: PUSH BC ; TIMER2: CALL J$INMDM ;100 ms. delay per loop JP NC,TIMER2 POP BC DEC B JP NZ,TIMER1 POP HL RET ;..... ; ; ; ;************** END OF SPECIAL HAYES/PMMI ROUTINES ********************* ; ; ;======================================================================= ; ; CALCULATES DISK SPACE REMAINING IF CP/M+ ; CKCPM3: CALL CRLF LD C,CPMVER ;check version # CALL BDOS LD A,L CP 30H ;version 3.0? RET C ;use normal method if not CP/M 3.0 POP HL ;remove 'CALL CKCPM3' from stack LD C,CURDSK CALL BDOS LD E,A LD C,46 ;CP/M 3.0 compute free space call CALL BDOS LD C,3 ;answer is 3 bytes long (24 bits) ; FREE30: LD HL,TBUF+2 ;answer is located here LD B,3 ;convert to 'K' length OR A ; FREE31: LD A,(HL) RRA LD (HL),A DEC HL DEC B JP NZ,FREE31 ;loop for 3 bytes DEC C JP NZ,FREE30 ;shift 3 times LD HL,(TBUF) ;get result in 'K' JP PRTFREE ;display result ;..... ; ; ;======================================================================= ; ; ORG (($+255+50)/256*256)-102 ;even page for 'NUMLIB' ; ; ; PATCH AREA ; ; Patch to put copyright notice in program ; CRITE: CALL J$ILPRT DEFB 'for Menu)',CR,LF,'Copyright (c) ' DEFB '1984 - Irvin M. Hoff',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. ; ALTDL1: DEFB 'xxxxxxx,,,,,,xxxxxxxx,,$' ;accessed by a < character ; ALTDL2: DEFB 'xxxxxxx,,,,,,xxxxxxxx,,$' ;accessed by a > character ; ;======================================================================= ; HEXSHO: DEFB SHOWHEX ;can easily change SHOWHEX via DDT ; SAVSIZ: DEFB XFRSIZ*8 ;can easily change buffer size for file ;transfers with DDT for "NUMLIB-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' NUMLIB: DEFB 'A=Bob Robesky.......1-209-227-2083' ;'A' DEFB 'B=Byron McKay.......1-415-965-4097' ;'B' DEFB 'C=Chuck Metz........1-408-354-5934' ;'C' DEFB 'D=Bruce Jorgens.....1-509-255-6324' ;'D' DEFB 'E=Bill Earnest......1-215-398-3937' ;'E' DEFB 'F=Chuck Forsberg....1-503-621-3193' ;'F' DEFB 'G=Ron Fowler........1-414-563-9932' ;'G' DEFB 'H=Kirk De Haan......1-408-296-5078' ;'H' DEFB 'I=Jack Kinn.........1-817-547-8890' ;'I' DEFB 'J=Walt Jung.........1-301-661-2175' ;'J' DEFB 'K=Keith Petersen....1-313-759-6569' ;'K' DEFB 'L=Larry Snyder......1-305-671-2330' ;'L' DEFB 'M=Wayne Masters.....1-408-378-7474' ;'M' D EFB 'N=Dick Mead.........1-213-799-1632' ;'N' DEFB 'O=Al Mehr...........1-408-238-9621' ;'O' DEFB 'P=Pasadena RBBS.....1-213-577-9947' ;'P' DEFB 'Q=Mark Pulver.......1-312-789-0499' ;'Q' DEFB 'R=Bruce Ratoff......1-201-272-1874' ;'R' DEFB 'S=Ken Stritzel......1-201-584-9227' ;'S' DEFB 'T=TCBBS, Dearborn...1-313-846-6127' ;'T' DEFB 'U=AnaHUG RCPM.......1-714-774-7860' ;'U' DEFB 'V=Dave Austin.......1-707-257-6502' ;'V' DEFB 'W=Bill Wood.........1-619-256-3914' ;'W' DEFB 'X=Charlie Hoffman...1-813-831-7276' ;'X' DEFB 'Y=Byron Kantor......1-619-273-4354' ;'Y' DEFB 'Z=Spare.............1-xxx-xxx-xxxx' ;'Z' DEFB '0=Paul Bagdonovich..1-201-747-7301' ;'0' DEFB '1=Bill Parrott......1-913-682-3328' ;'1' DEFB '2=Alex Soya.........1-305-676-3573' ;'2' DEFB '3=Tony Stanley......1-912-929-8728' ;'3' DEFB '4=Tampa Bay Bandit..1-813-937-3608' ;'4' DEFB '5=Thousand Oaks.....1-805-492-5472' ;'5' DEFB '6=Spare.............1-xxx-xxx-xxxx' ;'6' DEFB '7=Spare.............1-xxx-xxx-xxxx' ;'7' DEFB '8=Spare.............1-xxx-xxx-xxxx' ;'8' DEFB '9=Spare.............1-xxx-xxx-xxxx' ;'9' DEFB 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: DEFB '^' ;intercept character (prefix) ; FNCTBL: DEFB 0,'DIR ',CR,0 DEFB 1,'DIR *.* $U0AD ',CR,0 DEFB 2,'XMODEM S ',0 DEFB 3,'XMODEM R ',0 DEFB 4,'BYE ',CR,0 DEFB 5,'RBBS ',CR,0 DEFB 6,'(vacant)',0 DEFB 7,'(vacant)',0 DEFB 8,'(vacant)',0 DEFB 9,'Nice chatting, see you again soon... ',CR,0 DEFS 256-($-FNCTBL) ; ; ; ;*********************************************************************** ; ; ; P - R - O - G - R - A - M S - T - A - R - T - S H - E - R - E ; ; ;*********************************************************************** ; ; START: LD HL,0 ADD HL,SP ;add the current stack pointer to 'HL' LD (STACK),HL LD SP,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. ; LD HL,624 ;adjust to get 1 second time intervals CALL FIXCNT LD (TIMVAL),HL LD HL,39 ;should be 1/16 of above value CALL FIXCNT LD (QUIKTIM),HL ; ; ; Now display the program name and version number and we are under way ; CALL ILPRT DEFB CR,LF,'MDM',VERSION/100+'0',VERSION MOD 100/10+'0' DEFB VERSION MOD 10+'0',' modem pgm (type M ',0 CALL CRITE CALL J$SYSVR ;give configuration message CALL CRCGN ;generate tables for fast 'CRC' check CALL INITAD ;initialize addresses CALL INTRCPT ;establish the function key intercept CALL PROCOPT ;process any options LD A,(OPTION) ;any options on the command line? CP ' '+1 JP C,MENU ;if not, show the menu ; ; ; Comes here from menu once the options have been set ; RSTRT: LD SP,STACK ;make sure we have a clean stack CALL CKCHAR ;catch any garbage characters left over LD A,(PMMIMD) OR A JP NZ,RSTRT1 ;if yes, accept 'C' or 'D' LD A,(AUTDIAL) ;using a Hayes-type modem? OR A JP Z,RSTRT2 ;exit if neither modem-type ; RSTRT1: LD A,(OPTION) ;get the option CP 'C' ;call (dial) function? JP Z,J$DIAL ;yes, go to it LD A,(PMMIMD) OR A CALL NZ,STBAUD ;just the PMMI has to check each time ; RSTRT2: CALL MOVEFCB LD A,(OPTION) ;get main option CP 'D' ;disconnect? JP Z,DONETD ;yes, disconnect then back to the menu CP 'M' ;menu asked for? JP Z,MENU2 ;go display the menu CP 'R' ;want to receive a file? JP Z,RCVFL ;exit if yes CP 'S' ;want to send a file? JP Z,SNDFL ;exit if yes CP 'T' ;want terminal mode? JP NZ,RSTRT3 ;if not, exit XOR A LD (ECHOFLG),A ;reset echo flag LD (LOCFLG),A ;reset local flag JP DSKSV ;exit if yes ; RSTRT3: CP 'E' ;want echo mode? JP NZ,NOECHO ;if not, exit LD (ECHOFLG),A ;set the echo flag XOR A LD (LOCFLG),A ;reset local flag JP DSKSV ; NOECHO: CP 'L' ;want local echo mode? JP NZ,NOLOCL ;if not, exit LD (LOCFLG),A ;set the local flag XOR A LD (ECHOFLG),A ;reset echo flag JP DSKSV ; NOLOCL: CALL NVLDMS ;say not a valid option JP MENU ;then go back to the command mode ;..... ; ; INITAD: LD HL,(0000H+1) ;BIOS warm reboot jump vector LD DE,3 ADD HL,DE LD (VSTAT+1),HL ;BIOS console status jump vector ADD HL,DE LD (VKEYIN+1),HL ;BIOS console keyboard jump vector ADD HL,DE LD (VTYPE+1),HL ;BIOS console CRT jump vector LD DE,33 ADD HL,DE LD (GOLIST+1),HL ;BIOS list device status jump vector CALL GETUSER ;get current user number LD (OLDUSER),A ;save to restore upon exit CALL GTMAX ;find maximum ram for printer use JP J$INITMD ;initialize non-PMMI systems if needed ;..... ; ; ; Get the function key intercept character and put in appropriate places ; INTRCPT:LD A,(INTCPT) ;get the function key intercept char. AND 07FH ;strip off any parity LD (GTCMD1+1),A ;store in the menu area CP ' ' ;printing character? JP NC,INTER2 ;if yes, exit ADD A,40H ;change to printing character JP FIXFNK ;fix-patch area of extra bytes ; INTER1: LD A,'^' LD (MENU3),A ;store the "control-" character RET ; INTER2: LD (MENU3+1),A RET ;..... ; ; ; Process any options - put 0 in appropriate place in option table if ; option is selected ; PROCOPT:LD DE,FCB+1 LD A,(DE) LD (OPTION),A CP ' ' ;exit if no options RET Z ; OPTLP: INC DE LD A,(DE) CP ' ' JP Z,ENDOPT LD HL,OPTBL LD B,OPTBE-OPTBL ; OPTCK: CP (HL) JP NZ,OPTNO CP 'O' ;want originate tones? LD B,A ;store momentarily LD A,ORIGMOD JP Z,OPTCK1 LD A,B ;get the option back CP 'A' ;want answer tones? JP NZ,OPTCK2 ;if not, exit LD A,ANSWMOD ; OPTCK1: LD (UARTCT),A ; OPTCK2: LD (HL),0 JP OPTLP ; OPTNO: INC HL DEC B JP NZ,OPTCK CALL NVLDMS POP HL ;preserve stack JP MENU ; ENDOPT: LD A,(VSEEFLG) OR A JP NZ,CKOPT LD (QFLG),A ;quiet mode for watching data items ; CKOPT: LD A,(OPTION) ;check on the primary option CP 'D' ;going to disconnect? RET Z CP 'E' ;return if echo option RET Z CP 'M' ;return if help option RET Z CP 'L' ;return if local echo option RET Z CP 'T' ;return if terminal mode RET Z LD B,A ;save the primary option for a moment LD A,(PMMIMD) ;PMMI modem? OR A JP NZ,CKOPT0 ;if yes, accept 'C' LD A,(AUTDIAL) ;using a Hayes-type modem? OR A JP Z,CKOPT1 ;exit if neither ; CKOPT0: LD A,B ;get the character back CP 'C' ;going to call a number now? RET Z ; CKOPT1: LD A,(NFILFLG) ;saving memory for disk file? OR A JP Z,CKOPT2 ;if not, continue POP HL ;reset the stack from 'CALL PROCOPT' JP MENU0 ;go show the 'FILE OPEN' message ; CKOPT2: LD A,B ;get the option back CP 'S' JP Z,CKFILE CP 'R' JP NZ,BDOPT ;none of these, bad option LD A,(BCHFLG) ;see if the batch mode flag is set OR A RET Z ;if yes, exit ; CKFILE: LD A,(FCB+17) ;'S' and 'R' need a file name CP ' ' RET NZ ;exit if a file name is present ; REENT: CALL ILPRT DEFB '++ Enter primary option plus file name ++' DEFB CR,LF,BELL,0 POP HL ;reset stack from 'CALL STFCB JP MENU ;abort to command line ;..... ; ; BDOPT: CALL ILPRT DEFB CR,LF,'++ Bad option ++',CR,LF,LF,0 ;..... ; ; ; Check for any garbage characters on line - catch and ignore ; CKCHAR: CALL RCVRDY ;any characters ready to receive? RET NZ ;if not, return CALL I$MDDATP ;otherwise get the character and ignore JP 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. ; DSKSV: LD A,(BCHFLG) ;batch flag set? OR A JP NZ,DSKSV1 ;if not set, everything is normal LD A,'B' ;if set, shouldn't be, so reset it LD (BCHFLG),A JP NOTVLD ;if set, error for 'E', 'L' or 'T' ; DSKSV1: LD (XFLG),A ;will use the ASCII capture buffer size LD A,(NFILFLG) ;already saving for a file? OR A JP Z,DSKSV2 ;exit if not, and open a file CALL BUFMS ;tell if buffer if on or off JP TERM ; DSKSV2: LD A,(FCB+1) ;first character of filename (if any) CP ' ' ;file specified? JP NZ,GOODNM ;yes, good name XOR A LD (NFILFLG),A ;show no file being saved LD (SAVEFLG),A ;reset the flag to zero JP TERM ;... ; ; GOODNM: CALL ERASF LD HL,FCB3 CALL INITFCB LD HL,FCB ;move the disk name into FCB3 area LD DE,FCB3 LD B,12 CALL MOVE LD DE,FCB3 ;now make a file from that name LD C,MAKE CALL BDOS LD DE,FCB3 ;now open the file from FCB3 LD C,OPEN CALL BDOS LD HL,BUFFER ;reset pointers to start of buffer LD (HLSAV),HL LD A,1 LD (NFILFLG),A ;show now saving to memory for disk file CALL BUFMS2 ;show buffer is available ; TERM: LD A,(LSTTST) ;allowing the printer to be used? OR A CALL NZ,GOLIST ;if yes, see if anything to print CALL STAT ;keyboard have a character? JP Z,TERML ;if not, see if any incoming CALL KEYIN ;get character from keyboard LD B,A ;save for now to protect 'A' reg. CP RUB ;test for rub JP NZ,NOTRUB ;exit if not LD A,(CONVRUB) ;convert rub to backspace? OR A JP Z,NOTRUB ;exit if no conversion LD B,BKSP ;call it a backspace JP NTOG ;go send a backspace ; NOTRUB: LD A,(FNKFLG) ;get function key active flag OR A JP Z,NOF ;if not set yet, exit LD A,B ;get character CP '0' JP C,NOFNK1 ;ignore invalid key codes CP '9'+1 JP NC,NOFNK1 AND 0FH ;make 0..9 JP SNDFK ; NOF: LD A,(INTCPT) ;check intercept character CP B JP NZ,NOFNK1 ;skip if no function key LD (FNKFLG),A ;set the function flag JP TERML ;do not send the intercept character ; NOFNK1: XOR A ;reset the flag LD (FNKFLG),A LD A,(EXACFLG) OR A ;exact? LD A,0 ;(cannot use 'XRA A' here) LD (EXACFLG),A ;clear for next time JP Z,NTEXAF ;go if EXACFLG not set 'YES' LD A,(LOCNXT) OR A ;should we send on exacflg? JP Z,NTOG ;jump if LOCONEXTCHR 'NO' LD A,(EXTCHR) ;we want to send EXTCHR in any case CP B JP Z,NTOG ;send if EXTCHR JP LOCCHK ;otherwise do local stuff ;... ; ; NTEXAF: LD A,(EXTCHR) ;treat next character in special way? CP B ;check against this control character JP NZ,NTEXA1 ;yes, set exacflg for next character LD A,1 LD (EXACFLG),A ;set the flag JP TERM ;do not send, get next character ; NTEXA1: LD A,(LOCNXT) OR A ;should we send if not EXACFLG? JP NZ,NTOG ;jump if loconextchr 'YES' ; LOCCHK: CALL XITST1 ;want to exit to menu? LD A,(NOCONCT) ;want to disconnect from line? CP B JP Z,DONETD ;if yes go disconnect LD A,(TRANCHR) ;output text file to remote? CP B JP Z,TRNSFR LD A,(TRANLOG) OR A JP Z,SKPLOG LD A,(LOGCHR) ;send logon? CP B JP Z,SNDLOG ; SKPLOG: LD A,(LSTTST) ;going to use the external printer? OR A JP Z,NOLST ;if not, skip this area LD A,(LSTCHR) ;get the printer control-character CP B ;did we just ask for printer control? JP NZ,NOLST ;if not, exit LD A,(LISTFLG) ;otherwise reset the printer toggle CPL LD (LISTFLG),A ;and store CALL CRLF CALL CRLF CALL LSTMS ;tell if printer is on or off now CALL CRLF JP TERML ;back to the terminal mode again ;..... ; ; NOLST: LD A,(BRKCHR) ;PMMI break? CP B JP Z,BREAK LD A,(PMMIMD) ;using a PMMI board? OR A JP Z,NOLST1 ;if not, skip the next few lines LD A,(CHGBAUD) ;PMMI change baud? CP B PUSH AF PUSH HL CALL Z,J$NWBAU POP HL POP AF JP Z,TERML ;... ; ; NOLST1: LD A,(UNSAVCH) ;close input buffer? CP B JP Z,NOLST2 ;if yes, disable copy LD A,(SAVECHR) ;open input buffer? CP B JP NZ,NTOG LD A,(NFILFLG) ;do not allow save if flag is set OR A JP Z,TERML JP NOLST3 ; NOLST2: XOR A ;stop copy into file ; NOLST3: LD (SAVEFLG),A CALL BUFMS JP TERM ;get next character ;..... ; ; ;*********************************************************************** ; ; SND A CP/M FILE ; ;*********************************************************************** ; ; SNDFL: XOR A ;set to checksum initially on send LD (CRCFLAG),A ; initially on send CALL CKCHAR ;catch any garbage characters ; SNDFL1: LD A,(BCHFLG) ;check if multiple file OR A ; mode is set. JP NZ,SNDC1 CALL ILPRT DEFB 'Ready to send in batch mode',CR,LF,0 ; SNDFL2: CALL J$PRITY LD A,YES ;indicate send for batch mode LD (SNDFLG),A LD A,(FSTFLG) ;if first time through OR A ; scan the command line CALL Z,TNMBUF ; for multiple names CALL SNDFN ;sends file name to receive PUSH AF CALL CRLF CALL SHOFIL LD A,' ' CALL TYPE POP AF JP NC,SNDC2 ;carry set means no more files LD A,'B' ;stop batch LD (BCHFLG),A ;mode option LD A,EOT ;final transfer end CALL SND JP DONE ; SNDC1: LD A,(FCB+1) CP ' ' JP Z,BLKFILE ; SNDC2: CALL CNREC ;get number of records CALL OPENFIL LD E,120 ;wait 2 minutes maximum CALL WAITNAK ; SNDLP: CALL CKABORT ;want to terminate while sending file? CALL RDRECD JP C,SNDEOF CALL INCRRNO LD A,1 LD (ERRCT),A ; SNDRPT: CALL CKABORT ;want to terminate while sending file? CALL SNDHDR CALL SNDREC LD A,(CRCFLAG) OR A CALL Z,SNDCKS CALL NZ,SNDCRC CALL GTACK JP C,SNDRPT JP SNDLP ;..... ; ; SNDEOF: LD A,EOT CALL SND CALL GTACK JP C,SNDEOF JP DONE ;..... ; ; ;*********************************************************************** ; ; RECEIVE A CP/M FILE ; ;*********************************************************************** ; ; RCVFL: LD A,(CRCDFLT) ;get mode requested by operator LD (CRCFLAG),A ;store it ; RCVFL1: CALL J$PRITY LD A,(BCHFLG) ;check if multiple file mode OR A JP NZ,RCVC1 ;if not, exit LD A,NO ;flag where to return LD (SNDFLG),A ; for next file transfer CALL GETFN ;get the file name JP NC,RCVC2 ;carry set means no more files LD A,'B' ;stop batch LD (BCHFLG),A ;mode option JP DONE ; RCVC1: LD A,(FCB+1) ;make sure file is named CP ' ' JP Z,BLKFILE JP RCVC3 ; RCVC2: CALL SHOFIL ;show the file name LD A,' ' CALL TYPE CALL SNDPRG ;get progress and wait for quiet line CALL CKCPM2 CALL CRLF CALL CKBAKUP ; RCVC3: CALL ERASF CALL MAKEFIL CALL WAITQ1 LD A,(BCHFLG) ;do not print message if in batch mode OR A JP Z,RCVFST CALL ILPRTQ DEFB 'File open, ready to receive',CR,LF,0 ; RCVFST: LD A,(CRCFLAG) OR A JP Z,RCVNKM ;if in 'CRC' mode CALL ILPRTQ ;then say so DEFB 'CRC in effect',CR,LF,0 LD A,CRC JP RCVLP0 ; RCVNKM: CALL ILPRTQ ;else say 'CHECKSUM' mode DEFB 'Checksum in effect',CR,LF,0 LD A,NAK ; RCVLP0: PUSH AF CALL ILPRT DEFB 'Waiting.....',0 ; NOPRG: POP AF CALL SND ; RCVLP: CALL RCVRECD JP C,RCVEOT CALL REPORT ;show record received if not in quiet CALL WRRECD CALL INCRRNO CALL SNDACK JP RCVLP ; RCVEOT: CALL WRBLOCK CALL SNDACK CALL CLOSFIL JP DONE ; SNDACK: LD A,ACK CALL SND RET ; ;..... ; ; ;=================== FILE TRNSFR IN T-MODE =========================== ; ; ; File transfer routine - called with CTL-T from terminal mode. Trans- ; fer may be cancelled while sending, by using CTL-X. ; TRNSFR: LD HL,FCB4 CALL INITFCB ;initializes FCBs pointed LD HL,FCB+16 ; to by 'HL' register CALL INITFCB ; ; ; Get name of file to send in "T" (terminal) mode ; GET: CALL ILPRT DEFB CR,LF,'File name to send? (CR to abort): ',0 LD DE,CMDBUF CALL INBUF LD A,(CMDBUF+2) ;was file entered? CP ' ' JP Z,RETRN ;if not probably wanted to quit LD DE,CMDBUF LD HL,FCB4 CALL CMDLINE LD DE,FCB4 LD C,OPEN CALL BDOS CP 0FFH ;return with 0FFH means 'NO SUCH FILE' JP Z,TRANSL LD A,(XONWAIT) ;waiting for X-on to send next line? OR A JP NZ,DLYSAV ;if yes, skip additional delays ; ; ; Choice of normal speed or delays between characters / lines ; CALL ILPRT DEFB 'Want to include time delays? (Y/N): ',0 CALL KBDCHR CP 'N' ;if 'N' send normal speed JP Z,DLYSAV XOR A ;otherwise use character/line delays ; DLYSAV: LD (DLYFLG),A ;store the decision CALL CRLF LD DE,CMDBUF+2 ;make sure cmdbuf has been selected LD C,STDMA CALL BDOS ; ; ; Get 128-byte record ; READM: LD DE,FCB4 LD C,READ CALL BDOS OR A ;check for a good read JP Z,READM1 DEC A ;check for end of file to send JP Z,RETRNS CALL ERXIT ;neither of those, was a read error DEFB '++ DISK READ ERROR ++','$' ; ; ; Successful read, so send the record ; READM1: CALL SND80C ;send one 128-char record CP EOFCHAR ;end of file - omit if object JP Z,RETRNS ; code is to be sent. CP CANCEL ;cancellation? JP NZ,READM ; RETRN: CALL ILPRT DEFB CR,LF,LF,'(in Terminal-mode now)',CR,LF,LF,0 CALL SNDNOW ;insures last character is finished CALL CKCHAR ;catch any echo character on line JP TERM ;finished, back to t-mode ;..... ; ; RETRNS: CALL ILPRT DEFB CR,LF,'[Transfer completed]',0 JP RETRN ;..... ; ; TRANSL: CALL ILPRT DEFB CR,LF,BELL,'++ FILE NAME ERROR ++ ',CR,LF,0 JP GET ;..... ; ; ; Send one 128-byes record ; SND80C: LD B,128 ;will send a maximum of 128 character LD HL,CMDBUF+2 ;they are in the cmdbuf area ; SNDCH1: PUSH DE CALL SPEED ;0-90 ms. delay between characters POP DE LD A,(HL) CP EOFCHAR RET Z CALL MDOUT ;send the character to modem CALL STAT ;test to see if OR A ;cancellation requested JP Z,SKIP1 CALL KEYIN CP CANCEL RET Z ; SKIP1: INC HL DEC B JP NZ,SNDCH1 RET ;..... ; ; ; Send the character to the output ; MDOUT: PUSH AF ;save the character so can use 'A' reg. CP LF JP NZ,MDOUTL LD A,(ADDLFD) ;going to send the line feed to modem? OR A JP NZ,MDOUTL ;if yes, exit POP AF ;get the char. back (a line feed) CALL TYPE ;show on CRT, do not send to modem RET ; MDOUTL: LD A,(XOFFTST) ;waiting for X-off, X-on ? OR A CALL NZ,TXOFF ;if yes, go check CALL SNDRDY ;wait until modem is ready to send JP NZ,MDOUTL POP AF ;get the character back CALL TYPE ;send character to CRT CALL O$MDDATP ;send character to modem CP CR ;was it an end of line? RET NZ ;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. ; MDOUTN: LD A,(XONWAIT) ;wait for X-on after CR? OR A JP NZ,WATXON ;if yes, handle separately LD D,10 ; MDOUTT: PUSH DE CALL SPEED1 ;10 ms delay POP DE DEC D JP NZ,MDOUTT ;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: LD A,(BYTDLY) ;get delay between characters (0-9) JP SPEED1+3 ;1=10 ms, 5=50 ms, 9=90 ms, etc. ; SPEED1: LD A,(CRDLY) ;get delay after crlf (0-9) OR A ;100 ms, 5=500 ms, 9=900 ms, etc. RET Z ;if no delay needed, return LD C,A ;store number requested in c-reg. LD A,(DLYFLG) ;want any delays this file? OR A RET NZ ;if not, skip this section ; SPEED2: CALL SPEED3 ;outer loop DEC C JP NZ,SPEED2 RET ;done whenever the c-reg. is zero ;... ; ; SPEED3: PUSH HL ;save current 'HL' value LD HL,20 LD A,(XOFFTST) OR A JP Z,SPEED4 LD HL,20 ;adjust for 'X-OFF' testing LD A,(ECHOFLG) OR A JP Z,SPEED4 LD A,(LOCFLG) OR A JP Z,SPEED4 LD HL,25 ;adjust for remote echo ; SPEED4: CALL FIXCNT ;multiply delay by clock speed EX DE,HL ;transfer delay to 'DE' POP HL ;restore current 'HL' from"speed3" ; SPEED5: DEC DE ;inner loop LD A,(XOFFTST) OR A CALL NZ,TXOFF LD A,E OR D JP NZ,SPEED5 RET ;... ; ; TXOFF: CALL RCVRDY RET NZ CALL I$MDDATP AND 7FH CP XOFF CALL Z,WATXON RET ;..... ; ; WATXON: CALL RCVRDY ;have a character? (like x-on) JP NZ,WATXN1 ;if no character see if want to abort CALL I$MDDATP AND 7FH ;strip off any parity CP XON ;see if character was X-on RET Z ;if yes, keep going ; WATXN1: CALL STAT ;test to see if requesting cancellation JP Z,WATXON CALL KEYIN ;can abort if the x-on never comes CP CANCEL ;CTL-X to abort? JP NZ,WATXON ;if not, keep going RET Z ;..... ; ;================ END OF FILE TRNSFR 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. ; CKQIT: LD A,(BCHFLG) ;using batch mode now? OR A JP Z,ABORT ;quit if using batch mode ; CKQIT1: LD A,1 LD (ERRCT),A CALL ILPRT DEFB CR,LF,'Multiple errors encountered.',CR,LF DEFB 'Type Q to quit, R to retry: ',BELL,0 CALL KEYIN PUSH AF CALL CRLF POP AF CALL UCASE ;instead of 'ANI 5FH' CP 'R' JP Z,RCVRECD ;if 'R' keep trying CP 'Q' JP NZ,CKQIT1 JP ABORT ;..... ; ; ; Show the file name as stored in the FCB but in CP/M format ; SHOFIL: LD A,(QFLG) ;can type it if no 'QFLG' OR A RET Z LD HL,FCB+1 ; SHONM: XOR A LD (FTYCNT),A LD C,11 ; PRNAM: CALL FTYTST INC HL DEC C JP NZ,PRNAM RET ;..... ; ; ; Give report of received records as they occur ; REPORT: LD A,(QFLG) OR A RET Z LD HL,(RECNO) ;get record number INC HL CALL ILPRT DEFB CR,'Received # ',0 CALL DECOUT ;print record number in decimal CALL ILPRT DEFB ' ',0 ; LD A,(HEXSHO) OR A RET Z CALL ILPRT DEFB '(', 0 CALL DHXOUT ;16 bit hex conversion and output CALL ILPRT DEFB 'H) ',0 RET ;..... ; ; FTYTST: LD A,(FTYCNT) INC A LD (FTYCNT),A CP 9 ;are we at the file type? JP Z,SPCTST ;go if so ; ENDSPT: LD A,(HL) CP ' ' ;test for space CALL NZ,TYPE ;type if not RET ;..... ; ; SPCTST: LD A,(HL) CP ' ' ;test for space in 1st file type byte RET Z ;do not output period if space LD A,'.' CALL TYPE JP ENDSPT ;output 1st file type byte ;..... ; ; ; Get sender's progress report if it is present and wait for line to get ; quiet ; SNDPRG: LD B,5 ;wait up to 5 seconds CALL RECV CALL TYPE ;show the progress report from sender JP NC,SNDPRG RET ;..... ; ; SNDFN: CALL ILPRTQ DEFB 'Awaiting name NAK ',CR,LF,0 CALL GTACK CALL C,SNDACK LD HL,FILECT DEC (HL) JP M,NOMRN LD HL,(NBSAVE) ;get file name in FCB LD DE,FCB LD B,12 CALL MOVE LD (NBSAVE),HL CALL SNDNM ;send it OR A ;clear carry RET ;..... ; ; NOMRN: LD A,EOT CALL SND SCF RET ;..... ; ; ; Wait for line to get quiet and gobble characters ; WAITQ1: LD B,1 CALL RECV JP NC,WAITQ1 RET ;..... ; ; SNDNM: PUSH HL ; SNDNM1: LD D,11 ;count characters in name LD C,0 ;initialize checksum LD HL,FCB+1 ;address name ; NAMLPS: LD A,(HL) ;send name AND 7FH ;strip high order bit so CP/M 2.x CALL SND ; will not send R/O file designation ; ACKLP: PUSH BC ;save checksum LD B,5 ;wait for receiver to acknowledge CALL RECV ; getting the letter POP BC JP C,SCKSER CP ACK JP NZ,ACKLP INC HL ;next character DEC D JP NZ,NAMLPS LD A,EOFCHAR ;tell receiver the end of name CALL SND LD D,C ;save checksum ; CKSMLP: LD B,5 ;wait up to 5 seconds CALL RECV ;get checksum CP D JP NZ,SCKSER ;exit if bad name LD A,OKNMCH ;good name-tell receiver CALL SND POP HL RET ;..... ; ; SCKSER: LD A,BDNMCH ;bad name-tell receiver CALL SND CALL ILPRT DEFB CR,LF,'++ ERROR sending name ++',CR,LF,0 LD E,120 ;do handshaking over (2 minutes maximum) CALL WAITNLP ;don't print "WAITING READY SIGNAL" msg. CALL SNDACK JP SNDNM1 ;..... ; ; ; This patch fixes a trivial problem with the display of the function ; key group on the menu. It uses some of the extra bytes availble in ; this area from the CKSMLP fix. ; FIXFNK: LD (MENU3+1),A ;store the character in the menu display CP '[' ;'ESC' character, printed JP NC,INTER2 ;if 'ESC' or more, exit JP INTER1 ;otherwise include a '^' ;..... ; ; ; ; Patch to close FCB3 instead of FCB when in disk-capture mode. ; WRERRSP:CALL WRFIL2 ;close FCB3 file JP WRERR1 ;go write 'DISK FULL' message and quit ;..... ; ; EXTRA: DEFB '123456789 ' ;10 extras from CKSMLP (there were 27) ; ; GETFN: LD HL,FCB CALL INITFCB+2 ;does not initialize drive CALL ILPRTQ DEFB 'Awaiting file name',CR,LF,0 CALL HSNAK CALL GETNM ;get the name CP EOT ;if EOT, then no more files JP Z,NOMRNG OR A ;clear carry RET ; NOMRNG: SCF RET ;... ; ; GETNM: PUSH HL ; GETNM1: LD A,0FFH LD (FLTRFLG),A LD C,0 ;initialize checksum LD HL,FCB+1 ; NAMELPG:LD B,5 CALL RECV ;get the character PUSH BC PUSH AF LD A,0FFH LD (TIMFLG),A LD B,1 CALL RECV XOR A LD (TIMFLG),A POP AF POP BC JP NC,GETNM3 CALL ILPRTQ DEFB 'Time out receiving filename',CR,LF,0 JP GCKSER ; GETNM3: CP EOT ;if EOT, then no more files JP Z,GNRET CP EOFCHAR ;got end of name JP Z,ENDNAM PUSH AF PUSH BC CALL SNDACK POP BC POP AF LD (HL),A ;put name in FCB INC HL ;get next character LD A,L ;do not let noise cause overflow CP 7FH ; into the program area JP Z,GCKSER JP NAMELPG ; ENDNAM: XOR A LD (FLTRFLG),A LD A,C ;send checksum LD D,C CALL SND ; NMLP1: LD B,5 ;wait up to 5 second to see if CALL RECV ; the checksum is good CP OKNMCH ;yes if 'OKNMCH' sent JP Z,GNRET CP D JP Z,NMLP1 ;in case it is echo of send CP CR JP Z,NMLP1 CP LF JP Z,NMLP1 ; GCKSER: LD HL,FCB ;clear FCB (except drive) since it CALL INITFCB+2 ; might be damaged CALL ILPRTQ DEFB CR,LF,'** Checksum error **',CR,LF,0 XOR A LD (FLTRFLG),A CALL HSNAK ;do handshaking over JP GETNM1 ; GNRET: PUSH AF XOR A LD (FLTRFLG),A POP AF POP HL RET ; HSNAK: LD E,180 ;3 minute wait for file name XOR A LD (FLTRFLG),A ; HSNAK1: CALL CKABORT ;want to abort? LD A,NAK ;send 'NAK' until receiving 'ACK' CALL SND LD B,1 ;wait up to 1 second for a character CALL RECV CP ACK ;'ACK' is what we were waiting for RET Z DEC E JP NZ,HSNAK1 JP ABORT ;back to command line ;..... ; ; TNMBUF: LD A,1 ;call from 'SNDFL' only once LD (FSTFLG),A XOR A LD (FILECT),A CALL SCAN LD HL,NAMEBUF LD (NBSAVE),HL ;save address of 1st name ; TNLP1: CALL TRTOBUF LD HL,FCB LD DE,FCBBUF CALL CMDLINE ;parse name to CP/M format ; TNLP2: CALL MFNAM ;search for names (wildcard format) JP C,NEXTNM LD A,(FCB+10) ;if CP/M 2.x $SYSs file AND 80H ; do not send JP NZ,TNLP2 LD HL,(NBSAVE) ;get name LD DE,FCB ;move it to FCB EX DE,HL LD B,12 CALL MOVE EX DE,HL LD (NBSAVE),HL ;address of next name LD HL,FILECT ;count files found INC (HL) JP TNLP2 ;..... ; ; NEXTNM: LD HL,NAMECT ;count names found DEC (HL) JP NZ,TNLP1 LD HL,NAMEBUF ;save start of buffer LD (NBSAVE),HL LD A,(FILECT) CP 64+1 ;no more than 64 transfers RET C LD A,64 ;only transfer first 64 LD (FILECT),A RET ;..... ; ; ; Tells when buffer is opened/closed for memory save to write on disk ; BUFMS: CALL ILPRT DEFB CR,LF,'** Memory buffer ',0 LD A,(SAVEFLG)  OR A JP Z,BUFMS1 CALL ILPRT DEFB 'open **',CR,LF,LF,';',0 RET ;... ; ; BUFMS1: CALL ILPRT DEFB 'closed **',CR,LF,LF,0 RET ;... ; ; BUFMS2: CALL ILPRT DEFB CR,LF,'** Memory buffer available **',CR,LF,0 RET ;..... ; ; ; Clear the screen and return to the menu command ; XITMNU: CALL CRLF CALL CLREOS ;clear line to clean up any mess JP MENU0 ;..... ; ; ; Checks to see if the modem has a character ready ; RCVRDY: CALL I$MDCTL1 CALL A$MDRCVB JP C$MDRCVR ;..... ; ; ; Checks to see if the modem is ready to receive a character ; SNDRDY: CALL I$MDCTL1 CALL A$MDSNDB JP C$MDSNDR ;..... ; ; SNDNOW: CALL XITST ;see if want to quit now CALL SNDRDY ;ready to send a character? JP NZ,SNDNOW ;if not ready wait some more RET ;exit if ready ;..... ; ; ; Send the log-on message when requested ; SNDLOG: LD HL,(LOGONPTR) ;'HL' points to start of logon message CALL LOGLP JP TERML ;... ; ; LOGLP: CALL SNDNOW ;wait until modem is ready LD A,(HL) ;get logon byte OR A ;last character in string is '0' RET Z ;return if finished CALL O$MDDATP ;otherwise send the character CALL LOGLP1 ;check for echo character and display it INC HL ;next location in message JP LOGLP ;get next character ;..... ; ; LOGLP1: CALL J$INMDM ;get the echo character CALL C,J$INMDM ;if none, try once more RET C ;if no character do not try to print AND 7FH ;strip off any parity JP TYPE ;display the character, then return ;..... ; ; ; Check for exit character ; XITST: CALL STAT ;anything on keyboard? RET Z CALL KEYIN ;get it, then LD B,A ;save to protect the 'A' register ; XITST1: LD A,EXITCHR ;exit character CP B ;asking to exit to menu? RET NZ ;if not, back to work POP HL ;clear the stack from 'CALL' JP XITMNU ;exit to the menu ;..... ; ; LSTMS: CALL ILPRT DEFB 'Printer buffer is ',0 LD A,(LISTFLG) ;see if printer should be on or off OR A JP Z,LSTMS1 CALL ILPRT DEFB 'ON',CR,LF,0 RET ;... ; ; LSTMS1: CALL ILPRT DEFB '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. ; SNDFK: PUSH HL ;save register LD HL,FNCTBL ;point to function key codes ; SFK1: CP (HL) ;this the one? INC HL ;point to next byte JP NZ,SFK1 ;loop until found CALL LOGLP ;send the char POP HL XOR A ;reset the function flag LD (FNKFLG),A JP 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. ; NTOG: CALL SNDCHR ;send char. in 'B' to modem LD A,(LOCFLG) ;using the local mode? OR A JP NZ,LTYPE ;if yes, show the character LD A,(ECHOFLG) ;in echo mode? OR A JP Z,TERML ;if not, see if it was a 'CR' ; LTYPE: LD A,B ;get the character back CALL TYPE ;show on the local CRT CALL CKSAV ;to store local if buffer open CALL CHKPRNT ;put on printer if running ; CHKCR: LD A,CR CP B JP NZ,TERML ;if not CR, all done LD A,(ECHOFLG) ;in echo mode now? OR A JP NZ,CHKLF ;if yes add a line feed LD A,(ADDLFD) ;going to add a line feed in 'L' mode? OR A JP Z,TERM ;if not, exit ; CHKLF: LD B,LF JP NTOG ;send locally and to remote ;..... ; ; TERML: CALL RCVRDY ;character on the receive-ready line? JP NZ,TERM ;if not, exit CALL I$MDDATP ;get the character AND 7FH ;strip parity JP Z,TERM ;do not bother with nulls CP RUB JP Z,TERM ;do not bother with rubouts for fill LD B,A ;store temporarily LD A,(IGNRCTL) ;ignoring all but necessary CTL-chars? OR A JP Z,GIVLF ;if zero, display them all LD A,B CP ' ' JP NC,GIVLF ;display all printing characters CP 'G'-40H ;^G for bell JP C,TERM ;ignore CTL-characters less than ^G CP CR+1 JP NC,TERM ;ignore CTL-charsacters more than ^M ; GIVLF: LD A,B ;get the character back CALL TYPE ;show it on the CRT CALL CKSAV ;saving for disk file? CALL CHKPRNT ;printer running? LD A,(ECHOFLG) ;going to echo the character? OR A JP Z,NOECH ;if not, do not resend ; GIVLF1: CALL SNDCHR ;send character in 'B' to modem ; NOECH: LD A,CR CP B ;was it a 'CR' just now? JP NZ,TERM ;if not, all done so exit LD A,(ECHOFLG) ;in the echo mode? OR A JP Z,TERM CALL SNDNOW ;modem ready for a character? LD B,LF JP GIVLF ;send LF ;..... ; ; ; See if putting character into memory for a disk file ; CKSAV: LD A,(SAVEFLG) ;saving to disk? OR A RET Z ;if not, exit LD HL,(HLSAV) ;get last address LD (HL),B ;store this character INC HL ;increment for next character LD (HLSAV),HL ;remember that location LD A,LF CP B ;this character a line feed? JP NZ,CKSAV1 ; type ";" after each line feed LD A,CR ;insure at left column with a LF CALL TYPE CALL TYPSEM ;show a ';' on CRT ; CKSAV1: LD A,H LD HL,BUFTOP ;get the address at top of buffer CP H CALL Z,DCTLS ;if different, buffer is not full 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. ; DCTLS: CALL SNDNOW ;modem ready for a character? LD A,XOFF ;send a CTL-S to stop remote computer CALL O$MDDATP CALL CHKPRNT ;insure character gets to the printer LD HL,BUFFDSK ;address of auxiliary buffer CALL GTDSK ;put any extra chars. into aux. buffer PUSH DE ;save the number of aux. chars. LD A,1 ;show we put something in the buffer LD (WRFLG),A ; to protect erasing an empty file LD HL,(HLSAV) ;find current end of buffer CALL WRDSK1 ;write the records POP DE ;get auxiliary character count back LD HL,BUFFER ;start again at bottom of buffer XOR A ;set 'A' to zero CP D ;see if any count in 'D' JP Z,DCTLQ ;if nothing, exit and continue LD BC,BUFFDSK ;address of auxiliary buffer ; ; ; Move the characters from the auxiliary buffer to the main buffer and ; display ; DCTLS1: LD A,(BC) ;get the character there LD (HL),A ;store in main buffer CALL TYPE ;show on CRT PUSH HL PUSH DE PUSH BC PUSH AF LD B,A CALL CHKPRNT POP AF ;get the character again POP BC POP DE POP HL CP LF CALL Z,TYPSEM INC HL ;next buffer position INC BC ;next auxiliary buffer position DEC D ;one less to go JP NZ,DCTLS1 ;if not zero, keep going LD B,0 ;falls through to 'CHKPRNT' next ; DCTLQ: LD (HLSAV),HL ;next position to store in buffer CALL SNDNOW LD A,XON ;allow remote input to continue JP O$MDDATP ;..... ; ; ; Gets any incoming characters after sending an XOFF and stores at HL. ; Returns with number of characters stored in D-reg. ; GTDSK: LD D,0 ;character count in buffer LD E,128 ;maximum for buffer length ; GTDSK1: CALL J$INMDM ;get any character RET C ;if none, finished CP ' ' JP NC,GTDSK2 ;if greater, handle normally CP CR+1 ;ignore CTL-characters > CR JP NC,GTDSK1 ; GTDSK2: LD (HL),A ;store INC HL ;next buffer location to use INC D ;increment character count  DEC E ;room for one less JP NZ,GTDSK1 ;if room in buffer, keep going RET ;if buffer is filled, exit ;..... ; ; ; See if printing the character, if yes, put into buffer ; CHKPRNT:LD A,(LISTFLG) ;printer in use? OR A RET Z ;return if not LD HL,(HLSAV1) ;get input address LD (HL),B ;save this character there INC HL ;increment the buffer location LD (HLSAV1),HL ;store for next character LD A,(MAXRAM) ;see if at top of buffer yet CP H CALL Z,PCTLS ;if different, buffer is not full 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. ; PCTLS: CALL SNDNOW ;wait until modem is ready LD A,XOFF ;send a CTL-S to stop remote computer CALL O$MDDATP LD HL,BUFFPNT ;address of auxiliary buffer CALL GTDSK ;put any extra chars. into aux. buffer LD A,D ;get the aux. buffer character count LD (DSTORE),A ;save for later RET ;..... ; ; ; Output has now caught up to the input and both are at top of buffer ; PCTLS1: LD A,(DSTORE) ;get the aux. buffer character count LD D,A ;put into 'D' register XOR A ;set 'A' to zero CP D ;see if any count in 'D' LD HL,PBUFF ;address at start of printer buffer JP Z,PCTLQ ;if nothing, exit and continue LD BC,BUFFPNT ;address of auxiliary buffer ; ; ; Move the characters from the aux. buffer to the main buffer and display ; PCTLS2: LD A,(BC) ;get the character there LD (HL),A ;store in main buffer CALL TYPE ;show on CRT PUSH HL PUSH DE PUSH BC PUSH AF LD B,A CALL CKSAV POP AF POP BC POP DE POP HL CP LF CALL Z,TYPSEM INC HL ;next buffer position INC BC ;next auxiliary buffer position DEC D ;one less to go JP NZ,PCTLS2 ;if not zero, keep going ; PCTLQ: LD (HLSAV1),HL ;next position to store in buffer LD HL,PBUFF ;start of buffer location LD (HLSAV2),HL ;output to start of buffer CALL SNDNOW ;wait until modem is ready LD A,XON ;send start character  JP O$MDDATP ; to remote computer, back to work ;..... ; ; ; List the character on the printer if it is ready, then see if at the ; top of the buffer. ; GOLIST: CALL $-$ ;get the printer status - filled in OR A ;by 'INITAD' routine RET Z ;return if printer not ready ; ; ; Compare input and output pointers. If at same address, nothing to ; print. ; CALL CMP$I$O ;if the same, nothing to print RET Z ; ; ; If not the same, print the character ; GOLIST1:PUSH HL ;save current buffer address LD E,(HL) ;get the character to display LD C,LIST ;list rutine CALL BDOS POP HL ;restore current buffer address INC HL ;increment pointer for next position LD (HLSAV2),HL ;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. ; LD A,(MAXRAM) ;check for end of buffer area CP H JP Z,PCTLS1 ;if at end, restore auxiliary buffer ; ; ; 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 RET NZ ;if not, back to work LD HL,PBUFF ;if output caught input, reset both LD (HLSAV1),HL ; to bottom of buffer to start over LD (HLSAV2),HL RET ;..... ; ; ; Compare the input and output pointers to see if the same address ; CMP$I$O:LD HL,(HLSAV1) ;get input pointer address EX DE,HL ;put in 'DE' LD HL,(HLSAV2) ;get output pointer address LD A,H CP D RET NZ ;return if different LD A,L CP E RET ;..... ; ; GTMAX: LD A,(SAVCCP) ;going to save 'CCP'? OR A LD A,(BDOS+2) ;'MSP' of 'BDOS' address JP Z,GTMAX1 SBC A,8 ;'CCP' is 2k or 8 pages ; GTMAX1: LD (MAXRAM),A ;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. ; INMDM: PUSH HL LD HL,63 ;about 100 milliseconds CALL FIXCNT LD B,H ;delay is in 'HL' LD C,L ;transfer to 'BC' POP HL ;get original value of 'HL' back ; INMDM1: CALL RCVRDY ;see if there is a character ready JP NZ,INMDM2 ;if no character, exit CALL I$MDDATP ;get the character AND 7FH ;strip off any parity RET ;return with character in 'A' reg. ;... ; ; INMDM2: DEC BC ;otherwise keep timing LD A,B OR C JP NZ,INMDM1 ;loop until timeout if needed SCF ;shows a timeout occured RET ;..... ; ; ; Send a space tone to the phone line for a short time. ; BREAK: LD A,(PMMIMD) ;using the PMMI modem? OR A JP Z,BREAK1 ;if not, exit LD A,(MDCTLB) ;get the last modem control byte AND BRKMASK ;set the transmit break bit low CALL O$MDCTL2 ;send it to the modem LD B,2 CALL TIMER ;send a space tone for 200 ms. LD A,(MDCTLB) ;get the last modem control byte CALL O$MDCTL2 ;restore to normal JP TERM ;back to work ;... ; ; BREAK1: CALL J$BREAK ;get the user'S BREAK ROUTINE JP TERM ;back to work ;..... ; ; ;======================================================================= ; WRITE BUFFER TO DISK ; ; Make sure this record is included in the count. ; WRDSK: LD HL,(HLSAV) LD (HL),EOFCHAR ;ASCII file, store end-of-file char. LD DE,127 ADD HL,DE ; WRDSK1: LD DE,-(BUFFER) ;subtract the start of the buffer ADD HL,DE ;by adding a minus number to buffer end LD A,L ;divide hl by 128 OR A RLA ; to get the LD L,H ; number of records LD H,0 PUSH AF ADD HL,HL POP AF LD A,0 ADC A,L LD L,A ;number of records in 'HL' ; ; ; See if buffer is empty. If yes, see if we need to erase an empty ; file or have already written something. ; LD DE,BUFFER LD A,(DE) CP EOFCHAR ;'EOF' in first address means JP NZ,WRDSK2 ; nothing in buffer to write LD A,(WRFLG) ;first time by this way? OR A JP Z,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 'HL'. ; WRDSK2: LD C,STDMA CALL BDOSRT PUSH DE LD C,WRITE LD DE,FCB3 ;location of filename to write to CALL BDOSRT POP DE OR A JP NZ,WRERRSP ;error if disk is full ** special patch EX DE,HL ;put the current address in 'HL' PUSH DE ; and number of records left in LD DE,128 ; for now ADD HL,DE ;add for next record write, now in 'HL' POP DE ;restore number of records left EX DE,HL ;records to 'HL' again, address to 'DE' DEC HL ;one less record left LD A,H OR L ;done writing when 'H' and 'H' both zero JP NZ,WRDSK2 ;otherwise do another disk write RET ;..... ; ; ; Error while writing a record, show why it is aborting ; WRERR: LD C,CANCEL ;send cancel char. to sending station CALL SND CALL CLOSFIL ;close the current file ; WRERR1: CALL ERXIT ;also will reset stack DEFB '++ DISK FULL, SAVING PARTIAL FILE ++','$' ;..... ; ; ; If no data to store on the disk, close the empty file and erase it ; NOWRITE:CALL WRFIL2 ;close the empty file CALL NOASK ;erase the empty file  CALL ILPRT DEFB '++ Nothing to save, erasing file ++' DEFB CR,LF,BELL,0 JP DONETA ;reset any flags, return to menu ;..... ; ; ; Show you are in memory-save for disk write ; TYPSEM: LD A,';' JP TYPE ;show on CRT, return ;..... ; ; ; Save the registers, call BDOS then restore the registers ; BDOSRT: PUSH BC PUSH DE PUSH HL CALL BDOS POP HL POP DE POP BC RET ;..... ; ; INITFCB:LD (HL),0 ;entry at +2 will leave drive # intact INC HL ;will initialize an FCB LD B,11 ;pointed to by HL-reg. fills 1st pos. ; LOOP11: LD (HL),' ' ; with 0, next 11 with INC HL ; with blanks, and last DEC B ; 21 with nulls JP NZ,LOOP11 LD B,21 ; LOOP21: LD (HL),0 INC HL DEC B JP NZ,LOOP21 RET ;..... ; ; ; Scans CMDBUF counting names and putting delimiter (space) after last ; name. ; SCAN: PUSH HL LD HL,NAMECT LD (HL),0 LD HL,CMDBUF+1 ;find end of command line, add space LD C,(HL) LD B,0 LD HL,CMDBUF+2 ADD HL,BC LD (HL),' ' LD HL,CMDBUF+1 LD B,(HL) INC B INC B ; SCANL1: INC HL DEC B JP Z,DNSCAN LD A,(HL) CP ' ' JP NZ,SCANL1 ; SCANL2: INC HL ;eat extra spaces DEC B JP Z,DNSCAN LD A,(HL) CP ' ' JP Z,SCANL2 LD (BGNMS),HL ;save start of names in CMDBUF INC B DEC HL ; SCANL3: INC HL DEC B JP Z,DNSCAN LD A,(HL) CP ' ' JP NZ,SCANL3 LD A,(NAMECT) ;counts names INC A LD (NAMECT),A ; SCANL4: INC HL ;eat spaces DEC B JP Z,DNSCAN LD A,(HL) CP ' ' JP Z,SCANL4 JP SCANL3 ;..... ; ; DNSCAN: LD (HL),' ' ;space after last character POP HL RET ;..... ; ; ; Places next name in buffer so 'CMDLINE' may parse it ; TRTOBUF:LD HL,(BGNMS) LD B,0 LD DE,FCBBUF+2 ; TBLP: LD A,(HL) CP ' ' JP Z,TRBFEND LD (DE),A INC HL INC DE INC B ;count characterss in name JP TBLP ;..... ; ; TRBFEND:INC HL LD A,(HL) ;eat extra spaces CP ' ' JP Z,TRBFEND LD (BGNMS),HL LD HL,FCBBUF+1 ;put # chars before name LD (HL),B RET ;..... ; ; CKCPM2: LD C,CPMVER ;BDOS 12 -- version number -- cp/m 2.x? CALL BDOS OR A RET Z LD C,STDMA LD DE,TBUF CALL BDOS LD C,SRCHF LD DE,FCB CALL BDOS CP 0FFH RET Z ; CALL GETADD LD DE,9 ADD HL,DE ;point to R/O attribute byte LD A,(HL) AND 80H ;test most significant byte JP NZ,MKCHG ;if set, make change INC HL ;check system attribute byte LD A,(HL) AND 80H RET Z ;not $SYS or $R/O attribute DEC HL ; MKCHG: LD DE,-8 ADD HL,DE ;point HL to filename + 1 LD DE,FCB+1 ;move directory name to FCB LD B,11 ; without changing drive CALL MOVE LD HL,FCB+9 ;R/O attribute LD A,(HL) AND 7FH ;strip R/O attribute LD (HL),A INC HL ;system attribute LD A,(HL) AND 7FH LD (HL),A LD DE,FCB LD C,30 ;set new attributes in directory CALL BDOS ; ; ; Called by 'CKBAKUP' below, return done here through 'BDOS' jump ; PLANCHG:LD HL,FCB ;change name to type "BAK" LD DE,FCB2 LD B,9 ;move drive and name (not type) CALL MOVE LD HL,75H ;start of type in FCB2 LD (HL),'B' INC HL LD (HL),'A' INC HL LD (HL),'K' LD DE,FCB2 LD C,ERASE ;erase any previous backups CALL BDOS LD HL,FCB2 ;FCB2 drive field should have LD (HL),0 LD DE,FCB LD C,23 ;rename JP BDOS ;..... ; ; CKBAKUP:LD A,(BACKUP) OR A RET Z LD C,SRCHF LD DE,FCB CALL BDOS INC A RET Z ;file not found JP PLANCHG ;in 'CKCPM2' - return done there ;..... ; ; ;*********************************************************************** ; ; RECEIVE A RECORD FROM SNDING 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:LD A,1 LD (ERRCT),A ;initialize the error count ; RCVSQ: LD B,10 ;10 seconds allowed to receive 1st char. LD DE,SRCHSOH ;initialize loof for up to 160 seconds CALL RECV ;get the 1st character JP C,RCVSTOT ;timeout error if not rcvd in 10 seconds LD C,A ;save the character for now CP EOT ;see if end of transmission SCF ;set carry RET Z ;return with carry set ; SOHLUP: LD A,0FFH LD (CHRFLG),A LD (TIMFLG),A LD A,E ;get search count-down value CP SRCHSOH ;see if it is the 1st returned character LD A,C ;get the first character now JP Z,NORECV ;skip RECV routine if 1st character LD B,1 CALL RECV LD B,A JP NC,TSTSOH ; NORECV: LD B,A XOR A ;else set the value that forces timeout LD (CHRFLG),A ; TSTSOH: LD A,B ;get the character CP SOH ;see if it is SOH PUSH AF XOR A LD (TIMFLG),A ;restore this flag POP AF JP Z,RCVSOH ;got SOH, get rcd # and its complement LD A,D OR E ;see if counted-down to zero DEC DE JP NZ,SOHLUP ;go around again if not LD A,(CHRFLG) ;see if timeout needs to be forced OR A JP Z,RCVSTOT ;go do timeout and countthem LD A,(QFLG) OR A JP Z,RCVSRR ; RCVSH: CALL CRLF LD A,B CALL HEXO CALL ILPRT DEFB 'H received not SOH - ',0 ; RCVPRN: CALL SHOERR ;display error count ; RCVSRR: CALL WAITQ1 ;wait for 1 second with no characters CALL CKABORT ;want to stop receiving now? LD A,(CRCFLAG) ;get 'CRC' flag OR A ;'CRC' in effect? LD A,NAK ;put 'NAK' in 'A' register JP Z,RCVSR1 ;no, send the 'NAK' LD A,(FIRSTME) ;get first time switch OR A ;has first 'SOH' been received? LD A,NAK ;put 'NAK' in 'A' register JP NZ,RCVSR1 ;yes, then send 'NAK' LD A,CRC ;tell sender 'CRC' is in effect ; RCVSR1: CALL SND ; the 'NAK' or 'CRC' request LD A,(ERRCT) ;abort if we have reached error limit INC A LD (ERRCT),A ;store for next time CP ERRLIM ;see if at limit yet JP C,RCVSQ ;if not, keep going LD A,(RETRY) ;see if retry after 10 errors is set OR A JP Z,ABORT ;if 'YES', abort JP CKQIT ;if 'NO' check for continued use ; RCVSABT:LD SP,STACK ;reset the stack just in case CALL CLOSFIL ;close the partial file CALL NOASK ;delete partial file CALL ILPRT DEFB CR,LF,LF DEFB '++ RECEIVED FILE CANCELLED ++',CR,LF,BELL DEFB '++ UNFINISHED FILE DELETED ++',CR,LF,0 JP DONETA ; RCVSTOT:LD A,(QFLG) OR A JP Z,RCVSCC ; RCVSPT: CALL ILPRT DEFB CR,LF,'++ Timeout ',0 CALL SHOERR ; RCVSCC: CALL RCVSCC2 JP RCVSRR ; ; ; Routine will switch from 'CRC' to Checksum if 'ERCNT' reaches 'ERRCRC' ; and 'FIRSTIME' is false. ; RCVSCC2:LD A,(ERRCT) CP ERRCRC RET NZ LD A,(FIRSTME) OR A RET NZ LD A,(CRCFLAG) OR A RET Z CPL LD (CRCFLAG),A LD (CRCDFLT),A CALL ILPRTQ DEFB '** Switching to Checksum mode **',CR,BELL,LF,0 RET ;..... ; ; ; Got SOH - get block #, block # complemented ; RCVSOH: LD A,0FFH LD (FIRSTME),A ;indicate 1st soh was received LD B,5 ;timeout = 5 seconds CALL RECV ;get record JP C,RCVSTOT ;got timeout LD D,A LD B,5 ;timeout = 5 seconds CALL RECV JP C,RCVSTOT CPL CP D JP Z,RCVDATA LD A,(QFLG) OR A JP Z,RCVSRR ; RCVBSE: CALL ILPRT DEFB CR,LF,'++ Bad record # in header ',0 JP RCVPRN ; RCVDATA:LD A,D LD (RCVRNO),A LD A,1 LD (DATAFLG),A LD C,0 LD HL,0 LD (CRCVAL),HL LD HL,80H ; RCVCHR: LD B,5 ;wait up to 5 seconds for a character CALL RECV JP C,RCVSTOT LD (HL),A INC L JP NZ,RCVCHR XOR A LD (DATAFLG),A LD A,(CRCFLAG) OR A JP NZ,RCVCR LD D,C LD B,5 ;wait up to 5 seconds for an answer CALL RECV JP C,RCVSTOT CP D JP NZ,RCVCERR ; CHKSNUM:LD A,(RCVRNO) LD B,A LD A,(RECNO) CP B JP Z,RCVACK INC A CP B JP NZ,ABORT RET ;..... ; ; RCVCR: LD E,2 ;number of 'CRC' bytes ; RCVCR2: LD B,5 ;wait up to 5 seconds for a character CALL RECV JP C,RCVSTOT DEC E JP NZ,RCVCR2 CALL CRCCHK OR A JP Z,CHKSNUM LD A,(QFLG) OR A JP Z,RCVSRR ; RCVCRER:CALL ILPRT DEFB '++ CRC error ',0 JP RCVPRN ; RCVCERR:LD A,(QFLG) OR A JP Z,RCVSRR ; RCVCPR: CALL ILPRT DEFB '++ CHECKSUM error ',0 JP RCVPRN ; RCVACK: CALL SNDACK JP RCVRECD ; ; ; Get the error count and display on CRT ; SHOERR: PUSH HL LD HL,(ERRCT) LD H,0 CALL DECOUT POP HL CALL ILPRT DEFB ' ++',CR,LF,0 LD A,(ERRCT) CP ERRLIM JP NC,ABORT RET ;..... ; ; SNDHDR: LD A,(QFLG) OR A JP Z,SNDHNM CALL ILPRT DEFB CR,'Sending # ',0 PUSH HL ;store current address LD HL,(RECNO) ;get record number CALL DECOUT ;print it in decimal CALL ILPRT DEFB ' ',0 ; LD A,(HEXSHO) OR A JP Z,SNDHNM-1 CALL ILPRT DEFB '(',0 CALL DHXOUT ;16 bit hex conversion & output CALL ILPRT DEFB 'H) ',0 ; POP HL ;restore current address ; SNDHNM: LD A,SOH ;send 'SOH' character to the output CALL SND LD A,(RECNO) ;send record number to the output CALL SND LD A,(RECNO) CPL ;complement the record number JP SND ;send this value to the output ;..... ; ; SNDREC: LD A,1 LD (DATAFLG),A LD C,0 LD HL,0 ;new record, clear 'CHECKSUM' value LD (CRCVAL),HL ;new record, clear 'CRC' value LD HL,TBUF ;store at 0080H ; SNDC: LD A,(HL) CALL SND INC L JP NZ,SNDC XOR A LD (DATAFLG),A RET ;..... ; ; SNDCKS: LD A,C JP SND ;..... ; ; SNDCRC: PUSH HL LD HL,(CRCVAL) LD A,H CALL SND LD A,L CALL SND POP HL XOR A ;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 GTACK routine can gobble up a string of up to 191 ; characters while searching for an 'ACK' or a 'NAK'. ; GTACK: LD E,192 ;number of characters to gobble ; ACKLUP: LD A,0FFH LD (CHRFLG),A ;set the character flag LD (TIMFLG),A ;set the time flag LD B,1 CALL RECV LD B,A ;save the character JP NC,ACKTST XOR A LD (CHRFLG),A ;reset the character flag, was none ; ACKTST: XOR A LD (TIMFLG),A LD A,B ;get the character back CP ACK RET Z CP NAK JP Z,GTACK1 ; NOAKNK: DEC E ;one less to go JP NZ,ACKLUP ;loop around again if not zero LD A,(CHRFLG) OR A JP Z,GETATOT ; GTACK1: LD A,(BENHERE) XOR B JP Z,ACKER0 ;do not say 'ACK error' if 1st 'NAK' LD A,(QFLG) OR A JP Z,ACKER CALL ILPRT DEFB '++ ',0 LD A,B CP NAK JP Z,GTACK3 CALL HEXO CALL ILPRT DEFB 'H',0 JP GTACK4 ; GTACK3: CALL ILPRT DEFB 'NAK',0 ; GTACK4: CALL ILPRT DEFB ' received not ACK - ',0  CALL SHOERR ; ACKER0: XOR A LD (BENHERE),A ; ACKER: LD A,(ERRCT) INC A LD (ERRCT),A CP ERRLIM+1 ;at error limit yet? RET C ;if not, return ; ACKER1: CALL ERXIT DEFB CR,LF,'++ SEND-FILE CANCELLED ++','$' ;..... ; ; ; Reached error limit ; GETATOT:CALL ILPRT DEFB CR,'++ TIMEOUT - no ACK - ',0 CALL SHOERR ;display error count JP ACKER ;..... ; ; CKABORT:LD A,(QFLG) OR A RET Z CALL STAT RET Z CALL KEYIN CP CANCEL RET NZ ; ; ; Aborts send or receive routines and returns to command line ; ABORT: LD SP,STACK ; ABORTL: LD B,1 ;1-second delay to clear input CALL RECV JP NC,ABORTL LD A,CANCEL ;show you are cancelling CALL SND ; ABORTW: LD B,1 ;1-second delay to clear input CALL RECV JP NC,ABORTW LD A,' ' CALL SND LD A,'B' ;turn multi-file mode LD (BCHFLG),A ; off so routine ends LD (ABTFLG),A ;shows an abort was made XOR A LD (NFILFLG),A ;stop copy into memory for disk file LD A,(OPTION) ;receiving a file now? CP 'R' JP Z,RCVSABT ;if yes, cancel the unfinished file CALL ILPRT DEFB CR,LF,LF,'++ FILE CANCELLED ++',CR,LF,BELL,0 JP DONETA ;..... ; ; ; Increment the record count ; INCRRNO:PUSH HL LD HL,(RECNO) ;get record number INC HL ;bump it LD (RECNO),HL ;store it LD A,L POP HL RET ;..... ; ; ; First check for any wild cards and disallow, just to be safe. Do not ; want a group of files being accidently erased. ; ERASF: LD HL,FCB ;file name is stored here LD B,11 ;maximum of 11 chars for filename.ext ; ERASF1: INC HL ;next location in file name LD A,(HL) ;get the char. CP '?' ;check for any wild card characters JP Z,ERRORW ;error if one is found DEC B ;number of tries left JP NZ,ERASF1 ;if not zero, keep checking LD A,(BCHFLG) ;do not ask for erase OR A ; in multi-file mode, JP Z,NOASK ; just do it LD DE,FCB LD C,SRCHF CALL BDOS INC A RET Z ;file erased ok, return CALL ILPRT ;otherwise make sure it is ok DEFB 'File exists - erase? (Y/N): ',BELL,0 CALL KBDCHR CP 'Y' JP NZ,MENU ;if not a 'Y' do not erase CALL CRLF ;otherwise erase the file ; NOASK: LD DE,FCB LD C,ERASE JP BDOS ;..... ; ; ERRORW: POP HL ;restore stack from "call ERASF" CALL ILPRT DEFB '++ NO WILDCARDS ALLOWED FOR TEXT FILES ++' DEFB CR,LF,BELL,0 JP MENU ;..... ; ; BLKFILE:CALL ILPRT ;no file named for send or receive DEFB '++ NO FILE SPECIFIED ++',CR,LF,BELL,0 JP MENU ;..... ; ; MAKEFIL:LD DE,FCB LD C,MAKE CALL BDOS INC A RET NZ CALL ERXIT DEFB '++ ERROR -- Can''t open file ++',CR,LF DEFB '++ Directory is perhaps full ++','$' ; CNREC: LD C,FILSIZ ;compute file size function in CP/M 2.x LD DE,FCB ;point to file control block CALL BDOS LD HL,(FCB+33) ;get record count LD (RCNT),HL ;store it LD HL,0 ;zero 'HL' LD (FCB+33),HL ;reset random record in FCB RET ;..... ; ; OPENFIL:XOR A LD (FCBEXT),A LD DE,FCB LD C,OPEN CALL BDOS INC A JP NZ,SNDTM ;send transfer time, # of records, etc. CALL ERXIT ;file did not open DEFB '++ FILE NOT FOUND ++','$' ;..... ; ; CLOSFIL:LD DE,FCB ;get the file name LD C,CLOSE CALL BDOS ;close the file INC A RET NZ JP ERXIT1 ;no file to close, exit ;..... ; ; ; Update record read ; RDRECD: LD A,(RECINBF) ;decrement 'RECORDS IN BUFFER' count DEC A LD (RECINBF),A JP M,RDBLOCK LD HL,(RECPTR) ;find where last move stopped LD DE,128 CALL MOVE128 ;move 128 characters LD (RECPTR),HL ;store new address for next move RET ;..... ; ; ; Buffer empty so read in another block from the disk ; RDBLOCK:LD A,(EOFLG) CP 1 SCF RET Z LD C,0 LD DE,BUFFER ; RDRECLP:PUSH BC PUSH DE LD C,STDMA CALL BDOS LD DE,FCB LD C,READ CALL BDOS POP DE POP BC OR A JP Z,RDRECOK DEC A JP Z,REOF CALL ERXIT DEFB '++ FILE READ ERROR ++','$' ; RDRECOK:LD HL,128 ADD HL,DE EX DE,HL INC C CALL DSKSIZ ;establish buffer size JP Z,RDBFULL JP RDRECLP ;... ; ; REOF: LD A,1 LD (EOFLG),A LD A,C ; ; ; Buffer full or received "End Of File (EOF)" ; RDBFULL:LD (RECINBF),A LD HL,BUFFER LD (RECPTR),HL LD C,STDMA LD DE,TBUF CALL BDOS JP RDRECD ;..... ; ; ; Write a record ; WRRECD: LD HL,(RECPTR) EX DE,HL LD HL,128 CALL MOVE128 EX DE,HL LD (RECPTR),HL ;new record pointer LD A,(RECINBF) ;increment 'RECORDS IN BUFFER' count INC A LD (RECINBF),A LD C,A ;store the record count for now CALL DSKSIZ ;establish buffer size RET NZ ;buffer not full, return ; ; ; Write a block to disk ; WRBLOCK:LD A,(RECINBF) ;get the number of records in the buffer OR A RET Z ;if zero, don't try to move to disk LD C,A ;otherwise store in 'C' register LD DE,BUFFER ;start of buffer to move to disk ; DSKWRT: PUSH BC PUSH DE PUSH HL LD C,STDMA CALL BDOS LD C,WRITE LD DE,FCB CALL BDOS POP HL POP DE POP BC OR A JP NZ,WRERR ;error if disk is full LD HL,128 ;add in another page ADD HL,DE EX DE,HL DEC C ;one less record left to move to disk JP NZ,DSKWRT XOR A LD (RECINBF),A ;zero the 'RECORDS IN BUFFER' count LD HL,BUFFER ;reset location to next buffer start LD (RECPTR),HL RET ;..... ; ; ; Determine if the buffer size is for file transfer or for ASCII capture ; to disk then compare with current record length ; DSKSIZ: LD A,(XFLG) ;see if transferring files now OR A LD A,C ;get the current record count JP Z,DSKSIZ1 ;if yes, exit LD A,C CP BUFSIZ*8 ;buffer size for ASCII capture to disk RET ;return with flag set for the compare ;... ; ; DSKSIZ1:LD A,(SAVSIZ) ;get the file transfer buffer size.. CP C ; 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 DE ; ; ; 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 HL LD HL,TIMFLG LD E,(HL) INC E LD HL,(QUIKTIM) JP Z,DOQUIK LD HL,(TIMVAL) ; DOQUIK: EX DE,HL POP HL ; MWTI: CALL RCVRDY JP Z,MCHAR LD A,D OR E DEC DE JP NZ,MWTI DEC B JP NZ,MSEC POP DE CALL CKABORT SCF 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 I$MDDATP ;get the character that is waiting POP DE PUSH AF ;save the character for later use also CP ACK ;see if it is 'ACK' JP Z,ISACK CP '.' ;see if it is a period JP NZ,DOUPD ;neither, so update 'CRC' ; ISACK: PUSH HL PUSH DE LD HL,FLTRFLG ;see if need to each 'ACK' or period LD E,(HL) INC E POP DE POP HL JP Z,MWTI ;yes, so do it ; DOUPD: CALL CRCUPD ;calculate 'CRC' ADD A,C LD C,A LD A,(RSEEFLG) OR A JP Z,MONIN LD A,(VSEEFLG) OR A JP NZ,NOMONIN LD A,(DATAFLG) OR A JP Z,NOMONIN ; MONIN: POP AF ;get the character again PUSH AF ;resave it for later use also CALL SHOW ;show the character on the CRT ; NOMONIN:CALL CKABORT POP AF ;get the character back once more OR A ;reset the carry flag RET ;return with the character and flag set ;..... ; ; ; Send a character to the modem ; SND: PUSH AF LD A,(SSEEFLG) OR A JP Z,MONOUT LD A,(VSEEFLG) OR A JP NZ,NOMONOT LD A,(DATAFLG) OR A JP Z,NOMONOT ; MONOUT: POP AF PUSH AF CALL SHOW ; NOMONOT:POP AF PUSH AF CALL CRCUPD ;update the 'CRC' calcuation ADD A,C LD C,A ; SNDW: CALL SNDRDY JP NZ,SNDW POP AF JP O$MDDATP ;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 DEFB 'Waiting ready signal',CR,LF,0 CALL CRLF ; WAITNLP:CALL CKABORT LD B,1 ;wait up to 1 second for a character CALL RECV CP CANCEL ;want to quit? JP Z,ABORT CP CRC ;'CRC' request? JP Z,WAITCRC ;yes, go set 'CRC' flag CP NAK JP Z,WAICK DEC E JP NZ,WAITNLP JP ABORT ;... ; ; WAITCRC:CALL ILPRTQ DEFB 'CRC request received',CR,LF,0 LD A,1 LD (CRCFLAG),A ;make sure in 'CRC' mode then RET ;..... ; ; WAICK: LD A,(BCHFLG) ;in batch mode? OR A RET Z CALL ILPRTQ DEFB 'Got checksum request',CR,LF,0 RET ;..... ; ; WAICK1: CALL ILPRTQ DEFB 'Name NAK received',CR,LF,0 RET ;..... ; ; ; Finished with the file transfer ; DONE: LD A,(BCHFLG) ;in batch mode? OR A JP NZ,DONET ;exit if not LD A,(QFLG) OR A JP Z,NMSTRNS LD B,12 ;zero out FTRNM LD HL,FTRNM LD A,0 ; ZEROLP: LD (HL),A INC HL DEC B JP NZ,ZEROLP LD B,12 ;put file name in FTRNM LD HL,FCB+1 LD DE,FTRNM ; LOADMSG:LD A,4 ;start of file type? CP B JP Z,PERIOD ;put in period if so LD A,(HL) CP ' ' JP Z,SKPSP LD (DE),A ;store in FTRNM INC DE ; SKPSP: INC HL DEC B LD A,B OR A ;end of file name? JP Z,FTRNM0 ;display file name JP LOADMSG ;loop for another character ;..... ; ; PERIOD: LD A,(HL) CP ' ' ;is file type empty? JP Z,FTRNM0 ;go if so LD A,'.' ;else put period in message LD (DE),A INC DE DEC B JP LOADMSG ;..... ; ; FTRNM0: CALL ILPRT DEFB CR,LF ; FTRNM: DEFS 12 DEFB 0 CALL ILPRT DEFB ' Transferred',CR,LF,LF,BELL,0 ; NMSTRNS:LD A,(FCB) ;save drive number LD (DISKNO),A LD HL,FCB ;blank out file control blocks CALL INITFCB LD A,(DISKNO) ;put drive number back LD (FCB),A LD HL,RESTSN ;restore record numbers LD DE,RECNOB ; for new file transfer LD B,RECNOE-RECNOB ;routine also done in menu CALL MOVE CALL SNDNOW ;insures last character is finished CALL CKCHAR ;catch any echo characters on line LD A,(SNDFLG) ;goes to either send or OR A ; receive file, depending JP NZ,SNDFL2 ; upon which routine set JP RCVFL1 ; the flag in multi-file mode ;..... ; ; DONET: CALL CKABORT ;slight delay for next message CALL ILPRT DEFB CR,LF,'[Transfer completed]',CR,LF,BELL,0 ; DONETA: LD A,(XITFLG) ;special 'X' flag set? OR A JP Z,BYEBYE ;if yes, disconnect and reboot LD A,(DISCFLG) ;normal 'D' flag set? OR A JP Z,DONETD ;if yes, disconnect, get next command ; DONETB: CALL J$NPARIT ;reset to no parity XOR A LD (CRCFLAG),A ;reset back to checksum LD (FIRSTME),A ;reset first-time 'SOH' flag LD (FSTFLG),A ;reset multi-file trans LD (NFILFLG),A ;turn off the memory save for disk file LD (SAVEFLG),A ;stop memory save in term routine. LD A,(VSEEFLG) ;view flag set? OR A JP NZ,DONETC ;if not, exit CPL LD (QFLG),A ;VSEEFLG also sets the QFLG LD (VSEEFLG),A ;reset the flag ; DONETC: LD HL,QFLG ;in quiet mode? LD A,(HL) OR A LD (HL),'Q' ;reset the flag to normal JP Z,MENU ;if yes, go back to command line LD A,(ABTFLG) ;come here from a timeout? OR A JP NZ,MENU ;if yes, go to command mode LD A,(JMPCMD) ;requesting return to command mode? OR A JP Z,MENU ;if yes go to command mode CALL CRLF ;turn up a new line JP TERM ;otherwise return to terminal mode ;..... ; ; DONETD: CALL ILPRT DEFB CR,LF,'<< DISCONNECTED >>',BELL,CR,LF,0 CALL J$GOODBY ;set 'DTR' low for 300 ms. LD A,(PMMIMD) OR A ;;; CALL NZ,J$GOODBY DEFB 0,0,0 ;(PREVENT DOUBLE DISCONNECT) LD A,(AUTDIAL) ;using a Hayes-type modem? OR A ;;; CALL NZ,J$GOODBY ;if yes, disconnect DEFB 0,0,0 ;(PREVENT DOUBLE DISCONNECT) JP MENU0 ;back to command line ;..... ; ; MOVEFCB:LD HL,FCB+16 LD DE,FCB LD B,16 CALL MOVE XOR A LD (FCBSNO),A LD (FCBEXT),A RET ;..... ; ; SHOW: CP LF JP Z,CTYPE CP CR JP Z,CTYPE CP 9 JP Z,CTYPE CP ' ' JP C,SEEHEX CP 7FH JP C,CTYPE ; SEEHEX: PUSH AF LD A,'(' CALL CTYPE POP AF CALL HEXO  LD A,')' JP CTYPE ;..... ; ; CTYPE: PUSH BC PUSH DE PUSH HL LD E,A LD C,WRCON CALL BDOS POP HL POP DE POP BC RET ;..... ; ; CRLF: PUSH AF LD A,CR CALL TYPE LD A,LF CALL TYPE POP AF RET ;..... ; ; STAT: PUSH BC PUSH DE PUSH HL ; VSTAT: CALL $-$ ;BIOS constat address, filled in POP HL ; by 'INITAD' routine POP DE POP BC OR A RET ;..... ; ; KEYIN: PUSH BC PUSH DE PUSH HL ; VKEYIN: CALL $-$ ;BIOS 'CONIN' address, filled in POP HL ; by 'INITAD' routine POP DE POP BC RET ;..... ; ; TYPE: PUSH AF PUSH BC PUSH DE PUSH HL LD C,A ; VTYPE: CALL $-$ ;BIOS 'CONOUT' address, filled in POP HL ; by 'INITAD' routine POP DE POP BC POP AF 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 TYPE ;show on CRT RET ;..... ; ; UCASE: CP 61H ;changes lower case character RET C ; in 'A'reg. to upper case CP 7AH+1 ;see if more than small 'Z' RET NC AND 5FH RET ;..... ; ; DECOUT: PUSH AF PUSH BC PUSH DE PUSH HL LD BC,-10 LD DE,-1 ; DECOU1: ADD HL,BC INC DE JP C,DECOU1 LD BC,10 ADD HL,BC EX DE,HL LD A,H OR L CALL NZ,DECOUT LD A,E ADD A,'0' CALL CTYPE POP HL POP DE POP BC POP AF RET ;..... ; ; ;----> DHXOUT: - double precision hex output routine ; DHXOUT: PUSH HL PUSH AF LD A,H ;get MS byte CALL HEXO ;output high order byte LD A,L ;get LS byte CALL HEXO ;output low order byte POP AF POP HL RET ;..... ; ; ; Prints a hex value in 'A' on the CRT ; HEXO: PUSH AF RRA RRA RRA RRA CALL NIBBL POP AF ; NIBBL: AND 0FH CP 10 JP C,ISNUM ADD A,7 ; ISNUM: ADD A,'0' ;add in ASCII bias JP CTYPE ;..... ; ; ; Displays the control-characters shown in the menu ; SHFTYPE:PUSH AF CALL ILPRT DEFB 'CTL-',0 POP AF ADD A,40H ;convert binary to ASCII chars. CALL TYPE ;show on the CRT JP ILPRT ;..... ; ; ; Write a string of characters to the CRT ; ILPRT: EX (SP),HL ; ILPRT1: LD A,(HL) ;get the character OR A ;see if a "0" for end of string JP Z,ILPRT2 ;if yes, all done CALL CTYPE ;show on CRT INC HL ;get the next location in the string JP ILPRT1 ; ILPRT2: EX (SP),HL ;restore the address RET ;..... ; ; ; Write a string of characters unless in the Quiet mode ILPRTQ: EX (SP),HL ; ILPRTQ1:LD A,(HL) ;get the character OR A ;see if a "0" for end of string JP Z,ILPRTQ2 ;if yes, all done LD A,(QFLG) OR A LD A,(HL) CALL NZ,CTYPE ;show on CRT if not in quiet mode INC HL ;get the next location in the string JP ILPRTQ1 ; ILPRTQ2:EX (SP),HL ;restore the address RET ;..... ; ; PRTMSG: LD C,PRINT ;print the string JP BDOS ;..... ; ; ; Displays error statement then resturns to command mode ; ERXIT: POP DE CALL PRTMSG LD A,BELL CALL TYPE CALL CRLF ; ERXIT1: LD A,1 LD (ABTFLG),A ;shows an unintentional abort LD A,(BCHFLG) ;in batch mode? OR A JP NZ,DONETB ;if not, exit JP ABORT ;abort other computer ;..... ; ; ; Exits directly to CP/M, with no reboot unless you have selected pos- ; sible overwriting of 'CCP' ; EXIT: LD A,(OLDUSER) ;get original user number back LD E,A CALL STUSER LD C,STDMA LD DE,TBUF ;restore original buffer area CALL BDOS LD BC,1A00H ;a little delay timer ; EXIT1: DEC BC ;one less loop to make LD A,B OR C JP NZ,EXIT1 ;loop again till both are zero CALL CKCON ;catch any extra keyboard characters LD A,(NFILFLG) ;saving for a disk file? OR A CALL NZ,WRFIL1 ;if yes, close the file LD A,(SAVCCP) ;was 'CCP' left intact? OR A JP Z,0000H ;if not, warm reboot just in case ; EXIT2: XOR A ;clear the 'A' reg. and all flags LD HL,(STACK) ;get the original stack pointer back LD SP,HL ;set the stack pointer to that address RET ;..... ; ; ; Catch any extra keyboard characters coming through BDOS ; CKCON: LD C,CONST ;see if any characters waiting CALL BDOS OR A RET Z ;if not, exit LD C,RDCON ;otherwise get the character CALL BDOS XOR A ;discard the character JP CKCON ;see if any others ;..... ; ; MOVE128:LD B,128 ; MOVE: LD A,(HL) LD (DE),A INC HL INC DE DEC B JP NZ,MOVE RET ;..... ; ; ; Sends the character in 'A' to the modem ; SNDCHR: CALL SNDNOW ;wait until modem is ready for character LD A,B ;get the original character back JP O$MDDATP ;send the character to modem, return ;..... ; ; ; Initializes CP/M file control blocks AT 5CH and 6CH ; STFCB: LD DE,CMDBUF LD HL,FCB JP CMDLINE ;..... ; ; ; Adjusts loop counter for the selected clock speed. Returns with delay ; in 'HL'. ; FIXCNT: LD A,(CLOCK) ;get the user's clock speed PUSH DE ;save the current 'DE' value PUSH HL POP DE ;get same value into 'DE' as in 'HL' ; CNTMUL: ADD HL,DE ;add 'DE' to 'HL' DEC A ;one less to go JP NZ,CNTMUL POP DE ;restore current 'DE', delay in 'HL' 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 'HL' 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:PUSH AF PUSH BC PUSH DE PUSH HL CALL INITIAL ;fills FCBs with blanks and nulls EX DE,HL ;get start of command line in HL INC HL ;address # bytes in cmd line LD E,(HL) ;load de pair with # bytes LD D,0 INC HL ADD HL,DE ;point to byte after last character LD (HL),CR ; in cmd line and store delimiter POP HL ;restore HL and DE POP DE PUSH DE PUSH HL INC DE ;address start of command INC DE CALL DRIVE ; NAME1: LD C,8 ;transfer first filename to FCB CALL TRANS CP CR JP Z,DONEL CP ' ' ;if space, then start of  JP Z,NAME2 ; second filename POP HL ;filetype must be after PUSH HL ; eighth byte of name LD BC,9 ADD HL,BC LD C,3 ;transfer type of first file CALL TRANS CP CR JP Z,DONEL ; NAME2: LD A,(DE) ;eat multiple spaces CP ' ' ; between names JP NZ,NAME3 INC DE JP NAME2 ; NAME3: POP HL ;second name starts in 16th byte PUSH HL ;point HL to this byte LD BC,16 ADD HL,BC CALL DRIVE LD C,8 CALL TRANS CP CR JP Z,DONEL POP HL ;second type starts in 25th byte PUSH HL LD BC,25 ADD HL,BC LD C,3 CALL TRANS ; DONEL: POP HL PUSH HL INC HL ;point to 1st char of 1st name in FCB CALL SCANL ;check for * (ambiguous names) POP HL PUSH HL LD BC,17 ; to 1st char of second name in FCB ADD HL,BC CALL SCANL POP HL POP DE POP BC POP AF RET ;..... ; ; ; Subroutines for CMDLINE section ; INITIAL:PUSH HL PUSH BC LD (HL),0 INC HL LD B,11 LD A,' ' CALL INITFIL LD B,5 XOR A CALL INITFIL LD B,11 LD A,' ' CALL INITFIL LD B,4 XOR A CALL INITFIL POP BC POP HL RET ;..... ; ; INITFIL:LD (HL),A INC HL DEC B JP NZ,INITFIL RET ;..... ; ; DRIVE: INC DE ;check 2nd byte of filename - if it LD A,(DE) ; is a ":", then drive was specified DEC DE CP ':' JP NZ,DEFDR ;else zero for default drive LD A,(DE) ;('INIT' put zero) AND 5FH SUB 40H ;calculate drive (A=1, B=2,...) LD (HL),A ;place it in FCB. INC DE ;address first byte INC DE ; DEFDR: INC HL ;name field in FCB RET ;..... ; ; TRANS: LD A,(DE) ;transfer from command line to FCB INC DE ;up to number of characters specified CP CR ;in 'C' reg. keep scanning field RET Z ; without transfer until a delimiting CP '.' ; field char such as '.', blank, or RET Z ; CR (for end of commmand line) CP ' ' RET Z DEC C JP M,TRANS ;once C-reg is less than zero, keep LD (HL),A ; reading command line but do not INC HL ; transfer to FCB JP TRANS ;... ; ; SCANL: LD B,8 ;scan file name addressed by HL ;  TSTNAM: LD A,(HL) CP '*' ;if '*' found, fill in rest of field JP Z,FILL1 ; with '?' for ambiguous name INC HL DEC B JP NZ,TSTNAM JP TSTTYP ;... ; ; FILL1: CALL FILL ; TSTTYP: LD B,3 ;scan and fill type field for name ; TSTTYPL:LD A,(HL) ; specified above CP '*' JP Z,FILL2 INC HL DEC B JP NZ,TSTTYPL RET ;..... ; ; FILL2: CALL FILL RET ;..... ; ; FILL: LD (HL),'?' ;routine transfers '?' INC HL DEC B JP NZ,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 DRLST2 instead of JMP DRLST3 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. ; DRLST: CALL GETDISK ADD A,'A' ;change to ASCII LD (DRNAME),A ;show for drive name LD (ACTDRV),A ;show for space remaining on drive ; DRLST1: JP DRLST3 ; DRLST2: LD C,RESET ;13 reset disk system (RESETDK) CALL BDOS ; ; ; Directory list routine ; DRLST3: LD DE,CMDBUF ;put command line in FCB LD HL,FCB ; addressed by HL-reg CALL CMDLINE ; and then LD HL,FCB4 CALL INITFCB LD A,(FCB2) ;get drive number LD (FCB4),A LD A,(FCB2+1) CP ' ' ;if a space (blank) get all names PUSH AF CALL Z,QSTMARK POP AF CALL NZ,MOVNAME ;else move name into FCB CALL DRIVEL LD C,STDMA LD DE,TBUF CALL BDOS LD A,(NOFCOL) ;number of columns into 'A' reg. LD (NAMECT),A ;CRLF after 'NOFCOL' number of columns LD DE,FCB4 LD C,SRCHF ;do first search CALL BDOS INC A ;0FFH --> 0 if no file(s) found JP NZ,DIRLOOP CALL ILPRT DEFB '++ FILE NOT FOUND ++',0 JP STORAGE ;still show storage on default drive ; DIRLOOP:CALL GETADD INC HL ;point to first letter of filename LD DE,PRTNAME LD BC,8 CALL MOVER INC DE LD BC,3 CALL MOVER CALL ILPRT ; PRTNAME:DEFB ' ','.',' ',0 ; 8 spaces, period, 3 spaces ; NEXTSR: LD DE,FCB4 LD C,SRCHN ;do next search CALL BDOS INC A ;if 0FFH --> 0 then JP Z,STORAGE ; directory-read finished PUSH AF PUSH DE PUSH HL LD A,(NAMECT) DEC A LD (NAMECT),A ;name count updated OR A CALL Z,CRLF ;terminate line of file names JP NZ,FENCE LD A,(NOFCOL) ;restart columns-per-line count LD (NAMECT),A JP NOFENCE ;fence not needed ; FENCE: CALL ILPRT DEFB ' : ',0 ;fence if not at end of line or ; ; LAST FILENAME NOFENCE:POP HL POP DE POP AF JP DIRLOOP ;..... ; ; ; Determine storage remaining on default drive ; STORAGE:CALL CKCPM3 LD C,DSKPAR ;current disk parameter block CALL BDOS INC HL INC HL LD A,(HL) ;get block shift factor LD (BSHIFTF),A INC HL ;bump to block mask LD A,(HL) ;get it LD (BMASK),A INC HL INC HL LD E,(HL) ;get max block number INC HL LD D,(HL) EX DE,HL LD (BMAX),HL ;put it away LD C,DSKALL ;address of cp/m allocation vector CALL BDOS EX DE,HL ;get its length LD HL,(BMAX) INC HL LD BC,0 ;initialize block count to zero ; GSPBYT: PUSH DE ;save allocation address LD A,(DE) LD E,8 ;set to process 8 blocks ; GSPLUP: RLA ;test bit JP C,NOTFRE INC BC ; NOTFRE: LD D,A ;save bits DEC HL LD A,L OR H JP Z,ENDALC ;quit if out of blocks LD A,D ;restore bits DEC E ;count down 8 bits JP NZ,GSPLUP ;do another bit POP DE ;bump to next count INC DE ; of allocation vector JP GSPBYT ;process it ; ENDALC: POP DE ;clear alloc vector pointer from stack LD L,C ;copy block to HL LD H,B LD A,(BSHIFTF) ;get block shift factor SUB 3 ;convert from records to thousands (k) JP Z,PRTFREE ;skip shifts if 1k blocks ; FREKLP: ADD HL,HL ;multiply blocks by k per block DEC A JP NZ,FREKLP ; PRTFREE:CALL DECOUT ;(# of free k bytes now in 'HL') LD DE,FREEMSG JP PRTMSG ;..... ; ; ; Subroutines for 'DRLST' section ; QSTMARK:LD A,'?' ;if blank in FCB, put in 11 '?' chars. LD B,11 LD HL,FCB4+1 ; QSTLP: LD (HL),A INC HL DEC B JP NZ,QSTLP RET ;..... ; ; MOVNAME:LD HL,FCB2+1 LD DE,FCB4+1 LD BC,11 CALL MOVER RET ;..... ; ; GETADD: DEC A ;un-do the INR above ADD A,A ;times 32 ADD A,A ADD A,A ADD A,A ADD A,A ADD A,TBUF ;add buffer offset LD L,A LD H,0 RET ;..... ; ; DRIVEL: LD A,(FCB4) ;if no drive, use OR A ; default drive in DRNAME JP Z,PRNTHD PUSH AF DEC A LD E,A LD C,SELDSK CALL BDOS POP AF ADD A,40H ;make 1=A, 2=B, etc., and LD (DRNAME),A ; overwrite default stored below LD (ACTDRV),A ; PRNTHD: CALL ILPRT DEFB 'Drive ' ; DRNAME: DEFB ' :',CR,LF,0 RET ;..... ; ; ; Initialized storage ; FREEMSG:DEFB 'k bytes free on drive ' ACTDRV: DEFB ' :',CR,LF,'$' ; ; ; Uninitialized storage ; BMAX: DEFS 2 ;highest block number on drive BMASK: DEFS 1 ;rec/blk - 1 BSHIFTF:DEFS 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: PUSH AF PUSH HL PUSH BC PUSH DE ;'DE' registers must be pushed last ; INBUFA: CALL CLRBUF ;clear the buffer area POP DE ;get address of buffer on retries PUSH DE ;restore stack XOR A INC DE ;address count field LD (DE),A ;initialize with a zero in count byte INC DE EX DE,HL ;address first buffer byte with 'HL' ; INBUFB: CALL KEYIN ;(waits for char) CALL UCASE ;convert to upper case if needed CP CR ;is it (enter command)? JP Z,INBUFR ;if so, then return. CP 08H ;CTL-H backspaces over deleted character JP Z,DELETE CP 7FH ;is it a delete? JP Z,DELETE CP 'U'-40H ;is it a CTL-U? JP Z,INBUFO ;output #, CR, LF, and start over CP 'R'-40H ;CTL-R retypes line JP Z,RETYPE ; INBUFC: LD B,A ;save inputted character EX DE,HL ;save 'HL' in 'DE' POP HL ;get address of buffer in 'HL' PUSH HL ;restore stack INC HL ;address count byte INC (HL) ;increase count byte DEC HL ;address maximum LD A,(HL) ;put maximum in 'A' INC HL ;address count CP (HL) ;compare count to maximum JP C,ALERTL ;if maximum, ring bell and wait for cr. EX DE,HL ;restore buffer pointer to 'HL' LD (HL),B ;put inputted character in buffer LD A,B ;output it CP EXITCHR ;exit character? JP Z,INBUFR ;if yes, all done CP 20H ;printing character? CALL NC,TYPE ;if yes, print it INC HL ;bump pointer JP INBUFB ;get next character ;... ; ; DELETE: EX DE,HL ;save buffer pointer in 'DE' POP HL ;address beginning of buffer PUSH HL ;restore stack INC HL ;address count field LD A,(HL) SUB 1 ;decrease count LD (HL),A JP C,NODEL ;don't delete past beginning of buffer EX DE,HL ;restore buffer pointer to 'HL' DEC HL ;point to last byte inputted LD A,(HL) ;get the character being deleted LD (HL),' ' ;restore blank CP ' ' ;see if a non-printing character JP C,INBUFB ;if yes, skip the CRT backup LD A,BKSP CALL TYPE ;true erase if 08H LD A,' ' CALL TYPE LD A,BKSP CALL TYPE JP INBUFB ;..... ; ; MORE: DEFB '12345' ;5 bytes extra from DELETE routine fix ; ; NODEL: INC (HL) ;do not leave count negative EX DE,HL ;restore pointer to 'HL' LD A,BELL ;says can go no further CALL TYPE JP INBUFB ;..... ; ; INBUFO: LD A,'#' ;announces the line has been removed CALL TYPE CALL CRLF JP INBUFA ;..... ; ; RETYPE: POP DE PUSH DE INC DE ;point to current number of characters LD A,(DE) LD B,A LD A,'#' CALL TYPE CALL CRLF LD A,B ;test if zero input OR A JP Z,INBUFB ;... ; ; CTLRLP: INC DE LD A,(DE) CALL TYPE DEC B JP NZ,CTLRLP JP INBUFB ;..... ; ; ALERTL: LD A,BELL ;alarm for full buffer CALL TYPE DEC (HL) EX DE,HL JP INBUFB ;..... ; ; PCRLF: CALL CRLF JP INBUFB ;..... ; ; INBUFR: CALL CRLF ;1st new line after a command character POP DE POP BC POP HL POP AF RET ;..... ; ; CLRBUF: POP DE ;accounts for call POP HL ;restore the registers PUSH HL PUSH DE LD B,(HL) ;save maximum in 'B' INC HL ;point to first buffer byte INC HL LD A,' ' ; CLEARL: LD (HL),A INC HL DEC B JP NZ,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. ; INLNCP: EX (SP),HL ;point 'HL' to 1st character PUSH DE ; ILCOMPL:LD A,(HL) ;'HL' points to in-line string OR A ;end of string if zero JP Z,SAME LD A,(DE) CP (HL) JP NZ,NOTSAME INC HL INC DE JP ILCOMPL ;... ; ; NOTSAME:XOR A ;if not same, finish through ; NSLP: INC HL ; string so return will CP (HL) ; go to instruction after JP NZ,NSLP ; string and not remainder of string SCF ; SAME: POP DE INC HL ;avoids a NOP instruction EX (SP),HL ; when returning RET ;..... ; ; ;======================================================================= ; MULTI-FILE ACCESS ROUTINE ; ; 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. ; MFNAM: PUSH BC PUSH DE PUSH HL LD C,STDMA LD DE,TBUF CALL BDOS POP HL POP DE POP BC XOR A LD (FCBEXT),A LD A,(MFFLG1) OR A JP NZ,MFNAM1 LD A,1 LD (MFFLG1),A LD HL,FCB LD DE,MFNAM5 LD BC,12 CALL MOVER LD A,(FCB) LD (MFNAM6),A ;save disk in current FCB LD HL,MFNAM5 LD DE,FCB LD BC,12 CALL MOVER PUSH BC PUSH DE PUSH HL LD C,SRCHF LD DE,FCB CALL BDOS POP HL POP DE POP BC JP MFNAM2 ;... ; ; MFNAM1: LD HL,MFNAM6 LD DE,FCB LD BC,12 CALL MOVER PUSH BC PUSH DE PUSH HL LD C,SRCHF LD DE,FCB CALL BDOS POP HL POP DE POP BC LD HL,MFNAM5 LD DE,FCB LD BC,12 CALL MOVER PUSH BC PUSH DE PUSH HL LD C,SRCHN LD DE,FCB CALL BDOS POP HL POP DE POP BC ; MFNAM2: INC A SCF JP NZ,MFNAM3 LD (MFFLG1),A RET ;..... ; ; MFNAM3: DEC A AND 3 ADD A,A ADD A,A ADD A,A ADD A,A ADD A,A ADD A,81H LD L,A LD H,0 PUSH HL ;save name pointer LD DE,MFNAM6+1 LD BC,11 CALL MOVER POP HL LD DE,FCB+1 LD BC,11 CALL MOVER XOR A LD (FCBEXT),A LD (FCBRNO),A RET ;..... ; ; MOVER: LD A,2 INC A JP PE,MFNAM4 DEFB 0EDH,0B0H ;Z-80 'LDIR' instruction RET ;..... ; ; MFNAM4: LD A,(HL) ;used if an 8080 CPU is active LD (DE),A INC HL INC DE DEC BC LD A,B OR C JP NZ,MFNAM4 RET ;..... ; ; (END OF MULTI-FILE ACCESS ROUTINE) ;======================================================================= ; CALCULATE FILE TRNSFR TIME ; ; ; Shows the time to transfer a file at various baud rates. (110-19200) ; SNDTM: CALL ILPRT DEFB 'File open: ',0 LD HL,(RCNT) ;get record count CALL DECOUT ;print decimal number of records ; LD A,(HEXSHO) OR A JP Z,SNDTM1 CALL ILPRT DEFB ' (',0 CALL DHXOUT ;now print size in hex CALL ILPRT DEFB 'H)',0 ; SNDTM1: CALL ILPRT DEFB ' records' DEFB CR,LF,'Send time: ',0 LD A,(MSPEED) ;get the speed indicator LD D,0 LD E,A ;set up for table access LD HL,BTABLE ;point to baud factor table ADD HL,DE ;index to proper factor ADD HL,DE ;factor in 'DE' LD E,(HL) INC HL LD D,(HL) LD HL,(RCNT) ;get # of records CALL DVHLDE ;divide HL by value in DE (records/min) PUSH HL LD L,C LD H,B CALL DECOUT ;print the minutes portion CALL ILPRT DEFB ' mins, ',0 LD HL,RECDBL ;point to divisors for seconds LD DE,0 ; calculation LD A,(MSPEED) ;get index for baud rate LD E,A ADD HL,DE ;index into table LD A,(HL) ;get multiplier POP HL ;get remainder CALL MULHLA ;multiply the 'HL' x 'A' CALL SHFTHL CALL SHFTHL CALL SHFTHL CALL SHFTHL LD H,0 CALL DECOUT ;print the seconds portion CALL ILPRT DEFB ' secs at ',0 CALL PRTBAUD CALL ILPRTQ DEFB 'To cancel: use CTL-X',CR,LF,0 RET ; BTABLE: DEFW 5,13,20,26,29,48,85,152,280,480,0 ;records/min for.. RECDBL: DEFB 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:LD HL,BAUDSPD LD D,0 LD A,(MSPEED) ;get baud rate code LD E,A ;x1 ADD A,A ;x2 ADD A,A ;x4 ADD A,E ;x5 ADD A,E LD E,A ADD HL,DE ;point to correct rate EX DE,HL LD C,PRINT CALL BDOS CALL ILPRT DEFB ' bps ',CR,LF,0 RET ;..... ; ; BAUDSPD:DEFB '110$',0,0,'300$',0,0,'450$',0,0,'600$',0,0,'710$',0,0 DEFB '1200$',0,'2400$',0,'4800$',0,'9600$',0,'19200$' ;..... ; ; ;----> DVHLDE: Divides 'HL' by value in 'DE', ; Upon exit: 'BC'=quotient,'L'=remainder ; DVHLDE: PUSH DE ;save divisor LD A,E CPL ;negate divisor LD E,A LD A,D CPL LD D,A INC DE ;'DE' is now two's complemented LD BC,0 ;init quotient ; DIVL1: ADD HL,DE ;subtract divisor from dividend INC BC ;bump quotient JP C,DIVL1 ;loop till sign changes DEC BC ;adjust quotient POP DE ;retrieve divisor ADD HL,DE ;adjust remainder RET ;..... ; ; ;----> MULHLA: Multiply the value in 'HL' by the value in 'A' ; Return with answer in 'HL' ; MULHLA: EX DE,HL ;multiplicand to 'DE' LD HL,0 ;init product INC A ;adjust multiplier for zero test ; MULLP: DEC A RET Z ADD HL,DE JP MULLP ;..... ; ; ; Shift 'HL' register pair one bit to the right ; SHFTHL: LD A,L RRA LD L,A OR A ;clear the carry LD A,H RRA LD H,A RET NC LD A,128 OR L LD L,A RET ;..... ; ; ; (END OF FILE TRNSFR TIME ROUTINE) ;======================================================================= ; CRC SUBROUTINES ; ; ; Check 'CRC' bytes of record just received ; CRCCHK: PUSH HL LD HL,(CRCVAL) LD A,H OR L POP HL RET Z LD A,0FFH RET ;..... ; ; ; Generate the CRC tables for fast calculations ; CRCGN: LD HL,CRCTBL ;address at start of 'CRC' lookup table LD C,0 ; CRCGN1: EX DE,HL ;store table location into 'DE' LD HL,0 ;clear 'HL' pair LD A,C PUSH BC LD B,8 XOR H LD H,A ; CRCGN2: ADD HL,HL ;index into the table JP NC,CRCGN3 LD A,16 ;using x^ 16 + x^12 + x^5 + 1 algorithm XOR H ;(called 'SDLC' networking algorithm) LD H,A LD A,32+1 XOR L LD L,A ; CRCGN3: DEC B JP NZ,CRCGN2 ;make 8 loops, one for each bit ; ; ; Value now in 'HL', table address still stored in 'DE'. Exchange, and ; store the 'CRC' value in the two tables after splitting. ; POP BC ;finished borrowing the 'B' register EX DE,HL ;address back in 'HL', 'CRC' in 'DE' LD (HL),D ;store 1st part of 'CRC' value INC H ;move up 256 bytes LD (HL),E ;store 2nd part of 'CRC' value DEC H ;move back 256 bytes INC HL ;increment to next location INC C ;done when 'C' reg. turns zero again JP NZ,CRCGN1 ;now go do the next location RET ;..... ; ; ; Update the CRC value from a character in the 'A' register ; CRCUPD: PUSH AF ;save all registers just in case PUSH BC PUSH DE PUSH HL LD HL,(CRCVAL) ;get current value EX DE,HL ;put in 'DE' for now LD B,0 XOR D LD C,A ;now have the character in 'BC' pair LD HL,CRCTBL ;start of 'CRC' lookup-table ADD HL,BC ;index into the 'CRC' table LD A,(HL) ;get the value from the table XOR E LD D,A INC H ;move 256 bytes for 2nd table location LD E,(HL) ;put value there into 'E' register EX DE,HL ;put 'DE' into 'HL' LD (CRCVAL),HL ;updated 'CRC' value with this character POP HL ;restore all registers POP DE POP BC POP AF RET ;..... ; ;==================== END OF CRC SUBROUTINE ============================ ; ; ;=========================START OF MENU ================================ ; ; MENU0: LD A,(NFILFLG) OR A JP Z,MENU ;exit if not saving memory for disk file CALL ILPRT ;else print message DEFB CR,LF,'** File still open, use DEL, DIR, WRT, E, L ' DEFB 'or T ** ',CR,LF,BELL,0 JP MENU1 ; MENU: XOR A LD (ABTFLG),A ;null the flag ; MENU1: LD HL,RESTSN ;restore record numbers for new file LD DE,RECNOB ; transfer LD B,RECNOE-RECNOB CALL MOVE LD HL,RSTOPT ;restore option table LD DE,OPTBL LD B,OPTBE-OPTBL CALL MOVE XOR A LD (FSTFLG),A LD (TIMFLG),A LD (FLTRFLG),A ;reset multi-file trans LD (MFFLG1),A JP XPRT ;..... ; ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; ; MENU OF COMMANDS ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; MENU2: CALL CLRTST CALL ILPRT DEFB ' Single Letter Commands',CR,LF,LF DEFB ' ? - Display current settings',CR,LF MENU3: DEFB ' ^ - Function key intercept character, ' DEFB 'then (0-9)',CR,LF DEFB ' M - Display the menu',CR,LF DEFB ' E - Terminal mode with echo',CR,LF DEFB ' L - Terminal mode with local echo',CR,LF DEFB ' T - Terminal mode',CR,LF DEFB ' For copying text to disk use T (E or L) ' DEFB 'FILENAME.TYP',CR,LF DEFB ' Start or Stop toggles described on subsequent' DEFB ' screen.',CR,LF DEFB ' R - Receive CP/M file using Christensen Protocol' DEFB CR,LF DEFB ' S - Send CP/M file using Christensen Protocol',CR,LF DEFB ' COMMAND: R (or S) FILENAME.TYP',CR,LF DEFB ' R and S can use the following subcommands:' DEFB CR,LF DEFB ' B - Bulk transfer using wildcards ' DEFB '(e.g., *.*)',CR,LF DEFB ' D - Disconnect when done' DEFB CR,LF DEFB ' Q - Quiet mode (no messages to console)' DEFB CR,LF DEFB ' V - View or bytes on console' DEFB CR,LF DEFB ' X - When done, disconnect, go to CP/M' DEFB CR,LF,LF DEFB ' The single letter commands may also be used on ' DEFB 'the',CR,LF DEFB ' command line when the program is initially ' DEFB 'executed.',CR,LF,LF,0 ; THRLTR: CALL J$NXTSCR CALL ILPRT DEFB ' Three Letter Commands',CR,LF,LF DEFB 'CPM - Exit from this program to CP/M',CR,LF DEFB 'DIR - List directory and space free (may specify ' DEFB 'drive)',CR,LF DEFB 'ERA - Erase file (may specify drive)',CR,LF DEFB 'LOG - Change default drive/user no. (specify ' DEFB 'drive/user)',CR,LF DEFB ' and reset disks. e.g. LOG A0: or LOG B: ' DEFB '(user # unchanged)',CR,LF DEFB 'SPD - Set file output speed in terminal mode' DEFB CR,LF,0 ; CALL SORPTST JP NZ,NOTIME CALL ILPRT DEFB 'TIM - Select Baud rate for "time-to-send" msg.',CR,LF,0 ; NOTIME: LD A,(TGLECRC) OR A JP Z,NOTOCRC CALL ILPRT DEFB 'TCC - Toggle CRC/Checksum mode on receive',CR,LF,0 ; NOTOCRC:LD A,(TGLELOC) OR A JP Z,NTOGOC CALL ILPRT DEFB 'TLC - Toggle local command immediate or after ',0 LD A,(EXTCHR)  CALL SHFTYPE DEFB CR,LF,0 ; NTOGOC: LD A,(TGLELF) OR A JP Z,NTOGUB CALL ILPRT DEFB 'TLF - Toggle LF after CR in "L" or "T" mode for ' DEFB 'a disk file',CR,LF,0 ; NTOGUB: LD A,(TGLERUB) OR A JP Z,NTOGF CALL ILPRT DEFB 'TRB - Toggle rubout to backspace conversion',CR,LF,0 ; NTOGF: LD A,(TGXOFF) OR A JP Z,NTOGOF CALL ILPRT DEFB 'TXO - Toggle XOFF testing in terminal mode ' DEFB 'file output',CR,LF,0 ; NTOGOF: LD A,(PMMIMD) ;using a PMMI modem? OR A JP NZ,NONUM LD A,(AUTDIAL) ;using a Hayes-type modem? OR A JP NZ,NTOG2 ; NTOG1: CALL ILPRT DEFB 'NUM - List remote systems',CR,LF,0 ; NTOG2: LD A,(STUPTST) OR A JP Z,NONUM CALL ILPRT DEFB 'SET - Set modem baud rate',CR,LF,0 ; NONUM: CALL ILPRT DEFB 'BYE - Disconnect, then return to CP/M' DEFB CR,LF,0 LD A,(PMMIMD) ;using a PMMI modem? OR A JP NZ,NONUM0 ;if yes, display 'CAL' LD A,(AUTDIAL) ;usina a Hayes-type modem? OR A JP Z,NOPMMI ;exit if neither ; NONUM0: CALL ILPRT DEFB 'CAL - Dial number',CR,LF,0 ; NOPMMI: CALL ILPRT DEFB 'DSC - Disconnect from the phone line',CR,LF,LF DEFB ' The following are terminal text ' DEFB 'buffer commands:',CR,LF,LF,0 ; SKPLF: CALL ILPRT DEFB 'DEL - Delete memory buffer and file',CR,LF DEFB 'WRT - Write memory buffer to disk file',CR,LF,LF,0 CALL NXTSCR CALL ILPRT DEFB ' Local Commands while in Terminal Mode' DEFB CR,LF,LF,0 LD A,(BRKCHR) CALL SHFTYPE DEFB ' - Send a break tone for 300 ms.',CR,LF,0 LD A,(PMMIMD) OR A JP Z,SKPLF1 LD A,(CHGBAUD) CALL SHFTYPE DEFB ' - Change baud rate',CR,LF,0 ; SKPLF1: LD A,EXITCHR CALL SHFTYPE DEFB ' - Exit to command mode',CR,LF,0 LD A,(TRANLOG) OR A JP Z,NOTLOG LD A,(LOGCHR) CALL SHFTYPE DEFB ' - Send log-on message',CR,LF,0 ; NOTLOG: LD A,(NOCONCT) CALL SHFTYPE DEFB ' - Disconnect from the phone line',CR,LF,0 LD A,(LSTTST) OR A JP Z,NOLIS LD A,(LSTCHR) CALL SHFTYPE DEFB ' - Toggle printer',CR,LF,0 ; NOLIS: LD A,LF CALL TYPE LD A,(SAVECHR) CALL SHFTYPE DEFB ' - Start copy into buffer',CR,LF,0 LD A,(UNSAVCH) CALL SHFTYPE DEFB ' - Stop copy into buffer',CR,LF,LF DEFB ' Start & Stop may be toggled as often as ' DEFB 'desired.',CR,LF DEFB ' A ";" at start of line indicates buffer ' DEFB 'is copying.',CR,LF DEFB ' XOFF automatically used to stop input ' DEFB 'when writing',CR,LF DEFB ' full buffer to disk, XON sent to ' DEFB 'resume.',CR,LF,LF,0 LD A,(TRANCHR) CALL SHFTYPE DEFB ' - Transfer ASCII file to remote',CR,LF,LF,0 LD A,(LOCNXT) OR A LD A,(EXTCHR) JP NZ,REMDFLT CALL SHFTYPE DEFB ' - Send local control character to remote' DEFB CR,LF,LF,0 JP CKSPCL ; REMDFLT:CALL SHFTYPE DEFB ' - Next character will be used for local control' DEFB CR,LF,0 ; CKSPCL: CALL J$SPMEN ;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 LD A,(NFILFLG) ;have a file open for text mode copy? OR A JP Z,XPRT1 ;if not, exit ; CALL GETSPC ;otherwise show remaining space CALL ILPRT DEFB ' Bytes of buffer free',CR,LF,LF,0 ; ; ; Show disk drive and user number, then command line ; XPRT1: LD C,CURDSK ;current disk function CALL BDOS ADD A,'A' ;make ASCII CALL TYPE CALL GETUSER ;get current user number OR A JP Z,XPRT2 ;skip if user 0 LD H,0 LD L,A CALL DECOUT ;show current user area ; XPRT2: LD A,'>' CALL TYPE LD A,'>' CALL TYPE CALL ILPRT DEFB 'COMMAND: ',0 XOR A LD (XFLG),A ;null the buffer-length flag ; ; ; Get the command line parameters ; GTCMD: LD DE,CMDBUF ;enter command CALL INBUF LD A,(CMDBUF+2) CP EXITCHR ;exit character JP Z,XPRT1 ; GTCMD1: CP '^' ;function key intercep t character JP Z,FUNCT ; (supplied from 'INTCPT' table) CP '?' JP Z,CURPAR CP ' ' JP Z,XPRT+3 ;skip the extra line feed LD A,(CMDBUF+3) CP ':' ;see if request for new drive/user JP Z,STDRV LD DE,CMDBUF+2 ;point to command CALL INLNCP DEFB 'CPM',0 JP NC,EXIT CALL CRLF ;(1st CR/LF at 'INBUFR') CALL INLNCP DEFB 'LOG',0 JP NC,LOGNW CALL INLNCP DEFB 'DIR',0 JP NC,DIR CALL INLNCP DEFB 'ERA',0 JP NC,ERASEF CALL INLNCP DEFB 'SPD',0 JP NC,STSPD CALL INLNCP DEFB 'TIM',0 JP NC,STTIM CALL INLNCP DEFB 'TCC',0 JP NC,TGCRC CALL INLNCP DEFB 'TRB',0 JP NC,TGRUB CALL INLNCP DEFB 'TLC',0 JP NC,TGLOC CALL INLNCP DEFB 'TLF',0 JP NC,TGLF CALL INLNCP DEFB 'TXO',0 JP NC,TGTXOFF LD A,(PMMIMD) ;using a PMMI modem? OR A JP NZ,NONUM1 ;if yes, exit LD A,(AUTDIAL) ;using a Hayes-type modem? OR A JP NZ,NONUM1 ;if yes, exit CALL INLNCP DEFB 'NUM',0 JP NC,NUMPR ; NONUM1: LD A,(STUPTST) OR A JP Z,NXOPT1 CALL INLNCP DEFB 'SET',0 JP NC,STUPENT ; NXOPT1: CALL INLNCP DEFB 'WRT',0 JP NC,WRFIL CALL INLNCP DEFB 'DEL',0 JP NC,NEWFILE CALL INLNCP DEFB 'BYE',0 JP NC,BYEBYE CALL INLNCP DEFB 'DSC',0 JP NC,DONETD LD A,(PMMIMD) ;using a PMMI modem? OR A JP NZ,NXOPT0 ;if yes, exit LD A,(AUTDIAL) ;using a Hayes-type modem? OR A JP Z,NXOPT2 ;exit if neither modem-type ; NXOPT0: CALL INLNCP ;'DE' set from 1st 'INLNCP' call DEFB 'CAL',0 JP C,NXOPT2 LD A,' ' ;fool the system LD (CMDBUF+3),A ; 'TBUF' so that it JP DOOPT ; looks at option for dial ; NXOPT2: LD A,(CMDBUF+2) LD HL,COMLST CALL COMPARE ;compares list pointed to by HL JP C,NOTVLD ;carry set = no match ; DOOPT: CALL STFCB ;loads command buffer into FCB CALL PROCOPT ;check out the options JP RSTRT ;go to work ;..... ; ; NOTVLD: CALL NVLDMS JP XPRT ;..... ; ; NVLDMS: CALL ILPRT DEFB '++ Invalid command ++',CR,LF,BELL,0 RET ;..... ; ; FUNCT: LD A,(INTCPT) ;get the function key intercept char. AND 07FH ;strip off any parity PUSH AF ;save the character for now CALL CLRTST CALL ILPRT DEFB ' SPECIAL FUNCTION KEY TABLE' DEFB CR,LF,LF,0 POP AF ;get the character back CP ' ' ;see if a printing character JP NC,FUNCT1 ;if a printing character, show it PUSH AF CALL ILPRT DEFB 'CTL-',0 POP AF ADD A,40H ;convert binary to ASCII character ; FUNCT1: CALL TYPE ;show on the CRT CALL ILPRT DEFB ' current function key intercept character',CR,LF,LF,0 ; ; ; Shows the functions of the (0-9) keys ; LD HL,FNCTBL-1 ;index into the function key table LD B,10 ;has ten entries ; FUNCT2: INC HL ;next table location LD A,(HL) ;get the binary function number ADD A,'0' ;convert binary to ASCII digits CALL TYPE LD A,' ' CALL TYPE ; FUNCT3: INC HL ;next table location LD A,(HL) OR A ;see if a binary zero JP Z,FUNCT5 CP CR JP NZ,FUNCT4 CALL ILPRT DEFB '',0 JP FUNCT3 ; FUNCT4: CALL TYPE JP FUNCT3 ; FUNCT5: CALL CRLF DEC B JP NZ,FUNCT2 CALL CRLF JP XPRT ;..... ; ; BYEBYE: LD A,(PMMIMD) ;using a PMMI modem? OR A ;;; CALL NZ,J$GOODBY ;if yes, disconnect DB 0,0,0 ;(PREVENT DOUBLE DISCONNECT) LD A,(AUTDIAL) ;using a Hayes-type modem? OR A CALL NZ,SMRST ;if yes, disconnect CALL J$GOODBY ;user's custom-area goodbye routine CALL ILPRT DEFB CR,LF,'<< Exit to CP/M >>',CR,LF,0 JP EXIT ;return to CP/M ; SMRST: LD B,20 CALL TIMER LD HL,SM$DISC CALL SNDOUT LD B,20 CALL TIMER LD A,' ' ; ; ; If showing the +++ and ATH and ATD, etc. move the three semicolons up ; one line. ; DEFB 0,0,0 ;;; CALL TYPE LD HL,SM$ATZ CALL SNDOUT ; SMRST1: LD B,2 CALL RECV JP NC,SMRST1 RET ;..... ; ; SM$ATZ: DEFB 'ATZ',CR,'$' ;..... ; ; DIR: LD C,CURDSK CALL BDOS LD (DISKSAV),A CALL DRLST LD A,(DISKSAV) LD E,A LD C,SELDSK CALL BDOS JP XPRT ;..... ; ; ERASEF: LD DE,CMDBUF ;put command line into FCB at 'HL' LD HL,FCB CALL CMDLINE CALL MOVEFCB ;move FCB+16 to FCB LD A,(FCB+1) CP ' '  JP Z,NOTVLD ;go if no file specified LD DE,FCB LD C,SRCHF CALL BDOS INC A ;0 if file not found JP NZ,ERAFILE ;ok, go erase CALL ILPRT DEFB '++ File not found ++',CR,LF,BELL,0 JP XPRT ;..... ; ; ERAFILE:LD DE,FCB LD C,ERASE CALL BDOS CALL ILPRT DEFB 'File erased',CR,LF,0 JP XPRT ;..... ; ; LOGNW: LD A,(NFILFLG) ;file open for memory save to disk? OR A JP NZ,NORESET ;if yes, do not reset disk drive now LD A,(CMDBUF+6) ;any disk drive specified? CP ' ' JP NZ,LOGNW1 ;if not a blank, exit CALL GETDISK ;if not, use current drive ADD A,'A' ;to compensate for next line ; LOGNW1: SUB 'A' CP 15+1 ;for drives 0-15 JP NC,NOTVLD ;if more than 15, display error message LD (DISKSAV),A ;store requested drive CALL GETUSER ;pick up current user number LD B,A ;save it LD A,(CMDBUF+7) ;get new user number CALL CHRCK ;check the character CALL FNDUSR LD A,(CMDBUF+8) ;get 2nd digit CALL CHRCK ;check the character CALL FNDUSR+2 ; LOGNW2: CALL SVUSER ! LD C,RESET CALL BDOS LD A,(DISKSAV) LD E,A LD C,SELDSK CALL BDOS LD A,(SAVUSR) LD E,A CALL STUSER JP XPRT ;..... ; ; CHRCK: CP ' ' JP Z,CHRCK1 CP ':' ;in case of A: or A1: or A11: (etc.) RET NZ ; CHRCK1: POP AF ;reset the 'CALL' on the stack JP LOGNW2 ;..... ; ; FNDUSR: LD B,0 ;zero the 'B' reg. for 1st time through CALL NUMCHK ;if neither, see if a valid number LD C,A ;save LD A,B ;get save first digit ADD A,A ;x2 ADD A,A ;x4 ADD A,A ;x8 ADD A,B ;x9 ADD A,B ;x10 ADD A,C LD B,A ;save RET ;..... ; ; SVUSER: LD A,B CP 15+1 ;user numbers are 0-15 JP NC,NOTVLD LD (SAVUSR),A RET ;..... ; ; NUMGET: LD DE,CMDBUF CALL INBUF LD A,(CMDBUF+2) ;get number CP ' ' RET Z ; NUMCHK: SUB '0' ;remove ascii bias CP 9+1 RET C ;ok if 9 or less POP HL ;remove 1st call from the stack POP HL ;remove 2nd call from the stack JP NOTVLD ; GETUSER:LD E,0FFH ;get current user ; STUSER: LD C,USER ;set up BDOS call JP BDOS ;..... ; ; GETDISK:LD C,CURDSK ;get current drive JP BDOS ;..... ; ; NORESET:CALL ILPRT DEFB '++ Terminal mode file open ++',CR,LF DEFB '++ Use WRT or DEL before LOG command ++',CR,LF DEFB CR,LF,BELL,0 XOR A JP XPRT ;..... ; ; STSPD: CALL ILPRT DEFB 'Delay between chars. (0-9): ',0 ; NOKYS: CALL STAT JP Z,NOKYS CALL KEYIN CALL TYPE CALL SAVEA SUB '0' CP 10 JP NC,NOTVLD LD (BYTDLY),A ; CALL ILPRT DEFB 'Delay at end of line (0-9): ',0 ; NOKYS1: CALL STAT JP Z,NOKYS1 CALL KEYIN CALL TYPE CALL SAVEA SUB '0' CP 10 JP NC,NOTVLD LD (CRDLY),A ; SPDMSG: CALL ILPRT DEFB CR,LF,'Char. delay (terminal file mode) is: ',0 LD A,(BYTDLY) LD B,A LD A,B PUSH HL LD L,A LD H,0 CALL DECOUT POP HL CALL ILPRT DEFB '0 ms. per character',CR,LF DEFB 'Line delay (terminal file mode) is: ',0 LD A,(CRDLY) LD B,A PUSH HL LD L,A LD H,0 CALL DECOUT POP HL CALL ILPRT DEFB '00 ms. per character',CR,LF,0 JP XPRT ;...... ; ; SAVEA: PUSH AF CALL ILPRT DEFB CR,LF,0 POP AF RET ;..... ; ; STDRV: LD A,(CMDBUF+2) ;get the disk drive SUB 'A' ;convert to binary value CP 15+1 ;for drives 0-15 JP NC,NOTVLD LD E,A LD C,SELDSK ;select requested drive CALL BDOS LD A,(CMDBUF+5) ;get user number, if any CP ' ' ;keep current user area? JP Z,XPRT SUB '0' ;convert to binary value CP 1 ;if a '1', could be units or tens JP NZ,STDRV1 ;if not, numbers stop at 15 so exit LD A,(CMDBUF+6) ;check for a 2nd digit CP '0' JP C,STDRV2 ;if less, not a valid number, ignore SUB '0'-10 ;leave the '10' in as two digits used ; STDRV1: CP 15+1 ;user areas are 0-15 JP NC,NOTVLD LD E,A CALL STUSER JP XPRT ;back to work ; STDRV2: LD A,1 JP STDRV1 ;..... ; ; STTIM: CALL SORPTST JP NZ,NOTVLD CALL ILPRT DEFB 'Use 0-8 to give baud rate for ''S'' mode ' DEFB 'time-to-send message,',CR,LF DEFB 'where 0=110, 1=300, 2=450, 3=600, 4=710, 5=1200, ' DEFB '6=2400, ',CR,LF,'7=4800 8=9600 and 9=19200 Baud.' DEFB CR,LF,LF,'Enter value: ',0 CALL NUMGET CP 9+1 ;only looking for 0-9 answers JP NC,NOTVLD LD (MSPEED),A CALL STTIM1 JP XPRT ;..... ; ; STTIM1: CALL SORPTST JP NZ,STTIM2 CALL ILPRT DEFB 'Rate for the S mode time-to-send message is set to ',0 JP STTIM3 ;... ; ; STTIM2: CALL ILPRT DEFB 'Modem speed is ',0 ; STTIM3: JP PRTBAUD ;..... ; ; SORPTST:LD A,(STUPTST) ;if setup is 'YES' or PMMIMD is LD B,A ; 'YES' or autodial modem is 'YES' LD A,(PMMIMD) ; return with zero bit not set OR B RET NZ LD A,(AUTDIAL) OR B RET ;..... ; ; TGCRC: LD A,(TGLECRC) ;allowing CRC/CHECKSUM toggle? OR A JP Z,NOTVLD ;if not, exit LD A,(CRCDFLT) ;get present value and switch it CPL LD (CRCDFLT),A CALL TGCRC1 ;show on CRT it has been changed JP XPRT ;..... ; ; TGCRC1: CALL ILPRT DEFB 'Mode: ',0 LD A,(CRCDFLT) ;see if set for 'CRC' or 'CHECKSUM' OR A JP Z,CHEKMSG CALL ILPRT DEFB 'CRC',CR,LF,0 RET ;..... ; ; CHEKMSG:CALL ILPRT  DEFB 'CHECKSUM',CR,LF,0 RET ;..... ; ; TGRUB: LD A,(TGLERUB) OR A JP Z,NOTVLD LD A,(CONVRUB) CPL LD (CONVRUB),A CALL TGRUB1 JP XPRT ;..... ; ; TGRUB1: LD A,(CONVRUB) OR A JP Z,NORUBMS CALL ILPRT DEFB 'Rub is backspace',CR,LF,0 RET ;..... ; ; NORUBMS:CALL ILPRT DEFB 'Rub is rub',CR,LF,0 RET ;..... ; ; TGLOC: LD A,(TGLELOC) OR A JP Z,NOTVLD LD A,(LOCNXT) CPL LD (LOCNXT),A CALL TGLOC1 JP XPRT ;..... ; ; TGLOC1: CALL ILPRT DEFB 'Use ',0 LD A,(LOCNXT) OR A LD A,(EXTCHR) JP Z,LOCMSG CALL SHFTYPE DEFB ' before local command',CR,LF,0 RET ;... ; ; LOCMSG: CALL SHFTYPE DEFB ' to send local command to remote',CR,LF,0 RET ;..... ; ; TGLF: LD A,(TGLELF) OR A JP Z,NOTVLD LD A,(ADDLFD) CPL LD (ADDLFD),A CALL TGLF1 JP XPRT ;..... ; ; TGLF1: CALL ILPRT DEFB 'LF ',0 LD A,(ADDLFD) ;adding LF after CR? OR A JP NZ,LFMSG ;if yes, exit CALL ILPRT DEFB 'NOT ',0 ; LFMSG: CALL ILPRT DEFB 'sent after CR in "L"" or "T" for a disk file',CR,LF,0 RET ;..... ; ; TGTXOFF:LD A,(TGXOFF) OR A JP Z,NOTVLD CALL ILPRT DEFB 'Use XOFF testing? (Y/N): ',0 CALL GETANS JP C,NOCHG3 LD (XOFFTST),A ; NOCHG3: CALL XOFFMSG CALL ILPRT DEFB CR,LF,'Use XON waiting after (Y/N): ',0 CALL GETANS JP C,NOCHG4 LD (XONWAIT),A ; NOCHG4: CALL XONMS LD A,(XONWAIT) OR A JP Z,XPRT CPL LD (XOFFTST),A ;do not allow both CALL ILPRT DEFB 'Therefore ',0 CALL XOFFMSG JP XPRT ;..... ; ; GETANS: LD DE,CMDBUF CALL INBUF LD A,(CMDBUF+2) ;get answer CP ' ' CCF ;set the carry flag RET Z LD B,A CP 'N' LD A,0 RET Z LD A,B CP 'Y' LD A,1 RET Z POP AF ;preserve stack JP NOTVLD ;..... ; ; XOFFMSG:CALL ILPRT DEFB 'XOFF testing ',0 LD A,(XOFFTST) OR A JP NZ,XOTSTON CALL ILPRT DEFB 'NOT ',0 ; XOTSTON:CALL ILPRT DEFB 'used',0 ; XONMS1: CALL ILPRT DEFB ' in terminal mode file output',CR,LF,0 RET ;..... ; ; XONMS: CALL ILPRT DEFB 'XON ',0 LD A,(XONWAIT) OR A JP NZ,XONMS2 CALL ILPRT DEFB 'NOT ',0 ; XONMS2: CALL ILPRT DEFB 'automatically tested after CR',0 JP XONMS1 ;... ; ; STUPENT:LD A,(STUPTST) OR A JP Z,NOTVLD LD DE,CMDBUF+1 CALL J$STUPR LD A,(AUTDIAL) ;using a Hayes-type modem? OR A JP Z,XPRT ;if not, exit, otherwise LD B,'A' ; send 'AT',CR to autodial modem CALL SNDCHR ; to insure its baud rate LD B,'T' ; matches that just selected CALL SNDCHR LD B,CR CALL SNDCHR JP XPRT ;..... ; ; NEWFILE:LD A,(NFILFLG) ;file open for disk save? OR A JP Z,NFILOP ;if not, show "no file open" message LD A,(FCB3+1) ;check that file was requested CP ' ' JP Z,NFILOP ;if no file, do not erase LD DE,FCB3 ;otherwise erase the old file LD C,ERASE CALL BDOS XOR A LD (NFILFLG),A ;no file mentioned, reset flags LD (SAVEFLG),A LD HL,FCB3 CALL INITFCB LD HL,BUFFER ;reset flags to bottom of ram just LD (HLSAV),HL ; to insure they are there JP XPRT ;..... ; ; WRFIL: LD A,(NFILFLG) ;saving memory for a disk file? OR A JP Z,NFILOP ;not saving a file, don't bother writing CALL WRFIL1 ;close the file LD (SAVEFLG),A LD (WRFLG),A LD HL,FCB3 CALL INITFCB ;blank out 'FCB' to written file LD HL,BUFFER ;can not be erased LD (HLSAV),HL ;reset to buffer start for next time JP XPRT ;... ; ; WRFIL1: LD A,(FCB3+1) ;check that file was requested CP ' ' RET Z CALL WRDSK ;write buffer to disk if not empty ; WRFIL2: LD DE,FCB3 ;close the file LD C,CLOSE CALL BDOS XOR A LD (NFILFLG),A ;file written, reset flags RET ;..... ; ; NFILOP: CALL ILPRT DEFB '++ No File Open ++',CR,LF,BELL,0 JP XPRT ;..... ; ; ; THIS ROUTINE DISPLAYS THE PHONE NUMBERS IN THE LIBRARY ; NUMPR: PUSH HL CALL CLRTST CALL ILPRT DEFB ' Library of Phone Numbers of Remote Systems' DEFB 0 LD C,18 ;number of lines to move LD HL,NUMLIB ;address of source memory LD DE,BUFFER ;address of target memory CALL NEWLINE ;start with CRLF LD (DE),A ;+LF INC DE ;and bump it ; NUMPR1: INC HL ;skip PMMI dialing letter INC HL ;and equal sign LD B,LIBLEN-2 ;number of bytes to move CALL MOVE ;move to buffer CALL SPACES ;2 entries + 3 spaces = 63 characters PUSH HL ;save source address PUSH DE ;save destination address INC HL ;skip next two characters INC HL LD DE,17*LIBLEN ;get offset of 17 times entry length ADD HL,DE ;add it to the source address POP DE ;restore destination address LD B,LIBLEN-2 ;get length of library entry CALL MOVE ;move another entry POP HL ;restore source address CALL NEWLINE ;start next line DEC C ;one less line to print JP NZ,NUMPR1 ;if not finished, do another LD A,'$' LD (DE),A LD C,PRINT LD DE,BUFFER ;point to table of numbers to print CALL BDOS CALL CRLF CALL CRLF POP HL JP XPRT ;finished, back to prompt ;..... ; ; NEWLINE:LD A,CR ;puts CRLF at memory pointed by 'DE' LD (DE),A ;store it LD A,LF ;line feed INC DE ;bump pointer LD (DE),A ;store lf INC DE ;bump pointer RET ;..... ; ; SPACES: LD A,' ' ;space LD (DE),A INC DE ;1 LD (DE),A INC DE ;2 LD (DE),A INC DE ;3 RET ;..... ; ; COMPARE:LD B,(HL) ;compares 'A' register with list ; COMPLP: INC HL ;addressed by HL - first element CP (HL) ;of list must be number of elements JP Z,VALID ;being compared. returns with DEC B ;carry set if 'A' reg. does not JP NZ,COMPLP ;contain an element in list SCF ; VALID: RET ;..... ; ; NXTSCR: CALL ILPRT DEFB 'HIT any KEY to CONTINUE',0 ; NOKEY1: CALL STAT ;get keyboard status JP Z,NOKEY1 ;keep looping until keypress CALL KEYIN ;gobble up keypress CP 'C'-40H ;control-c to abort? JP NZ,CLRTST POP HL ;clear stack of return address CALL CRLF ;turn up a blank line JP XPRT ;..... ; ; CLRTST: LD A,(SCRNTST) OR A JP NZ,CLRSCR ;..... ; ; LOTSALF:LD A,CR CALL TYPE LD B,12 LD A,LF ; LFLOOP: CALL TYPE DEC B JP NZ,LFLOOP RET ;..... ; ; CURPAR: CALL CLRTST CALL ILPRT DEFB ' Curr#ent Settings',CR,LF,LF,0 CALL TGCRC1 CALL TGRUB1 LD A,(LSTTST) OR A JP Z,NOLIS1 CALL LSTMS ; NOLIS1: CALL STTIM1 CALL ILPRT DEFB 'Terminal mode file buffer is ',0 LD A,(NFILFLG) ;saving memory for a disk file? OR A JP NZ,ACTIVE ;if yes, go say "active" CALL ILPRT DEFB 'in',0 ;if not, say "inactive" ; ACTIVE: CALL ILPRT DEFB 'active',CR,LF,'Unused portion of buffer is ',0 CALL GETSPC CALL ILPRT DEFB ' bytes',CR,LF,0 CALL TGLOC1 CALL TGLF1 CALL XOFFMSG CALL XONMS CALL SPDMSG CALL CRLF CALL CRLF CALL CRLF JP XPRT ;..... ; ; GETSPC: LD DE,BUFTOP ;top of memory buffer LD HL,(HLSAV) ;current buffer location EX DE,HL XOR A ;clear the carry bit, if set SUB E LD L,A LD A,H SBC A,D LD H,A CALL DECOUT ;print the space remaining RET ;..... ; ; ;*********************************************************************** ; ; D - A - T - A A - R - E - A ; ;*********************************************************************** ; ; COMLST: DEFB 6,'S','R','T','E','L','M' ;..... ; ; ; OPTION TABLE ; OPTBL EQU $ ANSWFLG: DEFB 'A' BCHFLG: DEFB 'B' DISCFLG: DEFB 'D' JMPCMD: DEFB 'J' LOCLFG: DEFB 'L' ORIGFLG: DEFB 'O' QFLG: DEFB 'Q' RSEEFLG: DEFB 'R' SSEEFLG: DEFB 'S' VSEEFLG: DEFB 'V' XITFLG: DEFB 'X' EPRITY: DEFB '0' ;even parity sub-option (only in S or R mode) OPRITY: DEFB '1' ;odd parity sub-option (only in S or R mode) OPTBE EQU $ ;transfer when program initially called. ; ; ; The following must be in the same order as the table above ; RSTOPT: DEFB 'A','B','D','J','L','O','Q','R','S','V','X','0','1' ; ; ; The next 14 bytes equal the number of bytes between RECNOB and ; RECNOE. ; RESTSN: DEFB 0,0,0,0,0,0 DEFW BUFFER DEFB 0,0,0,0,0,NAK ; RECNOB EQU $ ;start of table marker RCVRNO: DEFB 0 ;\ RECNO: DEFB 0,0 ; \ ERRCT: DEFB 0 ; \ ERRCDE: DEFB 0 ; \ EOFLG: DEFB 0 ; \ 14 bytes between table markers RECPTR: DEFW BUFFER ; / RECINBF: DEFB 0 ; / MAXEXT: DEFB 0 ; / RCNT: DEFB 0,0 ; / DATAFLG: DEFB 0 ;/ BENHERE: DEFB NAK ; RECNOE EQU $ ;end of table marker ; ; ; Additional 16-bit initialized storage ; CRCVAL: DEFW 0 DIALCT: DEFW 0 HLSAV: DEFW BUFFER HLSAV1: DEFW PBUFF HLSAV2: DEFW PBUFF ; ; ; Additional general purpose initialized storage ; ABTFLG: DEFB 0 ACKFLG: DEFB 0 CRCFLAG: DEFB 0 CRFLAG: DEFB 0 CURRENT: DEFB 52 ;PMMI 300 baud speed value DLYFLG: DEFB 0 ; (defafaults to 300) ECHOFLG: DEFB 0 EXACFLG: DEFB 0 FIRSTME: DEFB 0 FNKFLG: DEFB 0 ;function key activity flag FSTFLG: DEFB 0 LISTFLG: DEFB 0 LOCFLG: DEFB 0 MFFLG1: DEFB 0 MDCTLB: DEFB 07FH NFILFLG: DEFB 0 ONERR: DEFB 0 OPTION: DEFB 0 ORIGSAV: DEFB 0 RNGBKFL: DEFB 0 SAVEFLG: DEFB 0 UARTCT: DEFB ORIGMOD ;for originate mode WRFLG: DEFB 0 XFLG: DEFB 0 CMDBUF: DEFB 80H,0 ;command buffer control area ; ; ; General purpose unitialized storage area ; DEFS 128 ;storage area for 'CMDBUF' BGNMS: DEFS 2 TIMFLG: DEFS 1 FLTRFLG: DEFS 1 CHRFLG: DEFS 1 TIMVAL: DEFS 2 QUIKTIM: DEFS 2 DISKNO: DEFS 1 DISKSAV: DEFS 1 DSTORE: DEFS 1 FILECT: DEFS 1 FTYCNT: DEFS 1 MAXRAM: DEFS 1 NAMECT: DEFS 1 NBSAVE: DEFS 2 OLDUSER: DEFS 1 SNDFLG: DEFS 1 SAVUSR: DEFS 1 ; FCB3: DEFS 33 FCB4: DEFS 33 FCBBUF: DEFS 15 MFNAM5: DEFS 12 MFNAM6: DEFS 12 ;current name DEFS 100 ;minimum stack depth ; ; EVNPAGE EQU ($+255)/256*256 ;sets buffers on even page ; ; ORG EVNPAGE ; ; STACK EQU EVNPAGE-2 ;store original stack pointer CRCTBL: DEFS 512 ;two tables of 128 bytes each BUFFDSK: DEFS 128 ;buffer for disk save BUFFPNT: DEFS 128 ;buffer for printer BUFFER: DEFS 1024*BUFSIZ ;send/receive file buffer BUFTOP: DEFS 0 ;filled in when length is found PBUFF EQU $ ;printer buffer starts here NAMEBUF EQU $ ;batch-mode filenames buffer ;..... ; ; ; BDOS EQUATES ; RDCON EQU 1 WRCON EQU 2 LIST 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 STDMA EQU 26 DSKALL EQU 27 DSKPAR EQU 31 USER EQU 32 FILSIZ EQU 35 BDOS EQU 0005H REIPL EQU 0 FCB EQU 5CH FCBEXT EQU FCB+12 FCBSNO EQU FCB+32 FCBRNO EQU FCB+32 FCB2 EQU 6CH TBUF EQU 80H ;..... ; ; END NPAGE EQU ($+255)/256*256 ;sets buffers on even page ; ; ORG EVNPAGE ; ; STACK EQU EVNPAGE-2 ;store original stack pointer CRCTBL: DEFS 512 ;two tables of 128 bytes each BUFFDSK: DEFS 128 ;buffer for disk save BUFFPNT: DEFS 128 ;buffer for printer BUFFER: DEFS 1024*BUFSIZ ;send/receive file buffer BUFTOP: DEFS 0 ;filled in when length is found PBUFF EQU $ ;printer buffer starts here NAMEBUF EQU $ ;batch-mode filenames buffer ;..... ; ; ; BDOS EQUATES ; RDCON EQU 1 WRCON EQU 2 LIST 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 $ This is the release date of the disk.  Fog Library Disk FOG-CPM.131 Copyright (1986) by Fog International Computer Users Group to the extent not copyrighted by the original author for the exclusive use and enjoyment of its members. Any reproduction or distribution for profit or personal gain is strictly forbidden. For information, contact FOG, P. O. Box 3474, Daly City, CA. 94015-0474. as part of the description of a file indicates that the program is distributed on a "try first, pay if you like it" basis. If you find the program(s) meet your need, please refer to the author's documentation for information on becoming a registered user. Only by registering and paying for the programs you like and use will the authors of such programs continue development. Often, more complete documentation, additional modules, and new releases are available only to registered users. Disk 6 of 6. MDM740 telecommunications software. Filename Description -08-00 .86 This is the release date of the disk. -CPM131 .DOC This is the description of the disk contents. MDM740 .ASM AF79 162K ver. 740 [Modem7 87 of 87] g a registered user. Only by registering and paying for the programs you like and use will the authors of such programs continue development. Often, more complete documentation, additional modules, and new releases are available only to registered users. Disk 6 of 6. MDM740 telecommunications software. Filename Description -08-00 .86 This is the release date %&'