;======================================================================= ; Multi-User MBYE33 allows simultaneous useage of a Kaypro '84 series ; machine by two modems - a Hayes 1200 on Data Port and the Internal ; (TI) modem. Further changes include a Wordwrap Chat mode accesible ; from ANY point in your program, Kaypro internal clock support (easily ; changed to ZCLOCK or any other 58167 clock card), all RTCBUF features ; moved into Page Zero for sampling by BBS programs -- ZCPR3 Users should ; check all page zero locations below, they WILL conflict! -- an onscreen ; clock during wait periods that shows Minutes Silent, Auto Exit after ; this call, instant return to any named program (GOFCB) by hitting ^C ; if the zero jump is changed to a call, ^P logoff at any point in the ; system, and a couple of dozen other features. All changes above MBYE33 ; are copyright 1986, Charles McHan, 904-725-7461. Documentation is poor, ; and so (no doubt) is construction, but it WORKS! ;========================================================================== ; System equates ; NO: EQU 0 ;for conditional assembly YES: EQU NOT NO ;(= 0FFFFH usually, not 0FFH) ; OFF: EQU 0 ;for single byte flags ON: EQU 0FFH ; CR: EQU 0DH ;ASCII carriage return LF: EQU 0AH ;ASCII line feed BS: EQU 08H ;ASCII backspace ESC: EQU 1BH ;ASCII escape ; IOBYTE: EQU 0003H ;location of CP/M iobyte FCB: EQU 005CH FCBRNO: EQU FCB+32 TPA: EQU 0100H ;location of CP/M Transient Pgm Area ; ; ; BDOS equates ; BDOS: EQU 0005H SELDSK: EQU 14 OPEN: EQU 15 READ: EQU 20 STDMA: EQU 26 SETUSR: EQU 32 ; ; ;*********************************************************************** ; ; OPTION CONFIGURATION SECTION ; ;*********************************************************************** ; ;-------------------------- general options ---------------------------- ; BYELOW: EQU YES ;yes, running BYE3 below CCP; no for above BIOS ; IF NOT BYELOW ; BIOSEND: EQU 0E243H ;END of BIOS/XBIOS, BIOSEND+1 = first avail RAM RAMTOP: EQU 0F4C0H ;last available RAM if BYELOW is 'NO' ; ENDIF ; SMODEM: EQU NO ;yes if Smartmodem 300 SM1200: EQU YES ;yes if Smartmodem 1200 ANCHOR: EQU NO ;yes if Anchor Signalman Mk XII USR: EQU NO ;yes if US Robotics 212A or Password ; ;------------------------------------------------------------------------- ; IOVAL: EQU 0 ;initial value for IOBYTE (only if MINICK 'YES') MINICK: EQU NO ;yes, running MINICBBS MBBS: EQU NO ;yes, running MBBS message/mail system (tm) OXGATE: EQU NO ;yes, running OXGATE RCPM-BBS system RBBSCK: EQU YES ;yes, running RBBS - sets/resets 'WRTLOC' flag ; ;----------------------------------------------------------------------- ; ; Set only ONE of the below to equ YES, (usually NODEV) (or all NO). ; If you set all to NO, the LST:, RDR: and PUN: devices will not be ; patched during remote operation. ; ; Note that patching the LST: device ; does not interfere with the HARDLOG option. ; ALLDEV: EQU NO ;yes, patch PUN:, RDR: & LST: devices to modem NODEV: EQU NO ;yes, make PUN:, RDR: & LST: dummy calls PRINTER: EQU NO ;yes, patch LST: to modem, retain RDR: & LST: ; ; Miscellaneous options: ; CLK: EQU YES ;yes, print clock onscreen during silent CALLBAK: EQU NO ;yes, allow callback feature (if NORING EQU NO) CHKDSK: EQU NO ;yes, check for valid disk drive CHKUSR: EQU NO ;yes, check for valid user number COMFILE: EQU YES ;yes, chain a .COM file upon carrier reception DECIMAL: EQU YES ;yes, decimal value for userlog DUAL$IO: EQU YES ;yes, console/modem linked together EXFILE: EQU YES ;yes, chain a .COM file upon loss of carrier FKEYS: EQU YES ;yes, local console has special function keys HARDLOG: EQU NO ;yes, echo remote input to printer LGONMSG: EQU NO ;yes, print message before "how many nulls" msg MULTI: EQU NO ;yes, Multi-User PRNTGB: EQU NO ;yes, print "Goodbye..." message PRNTWB: EQU NO ;yes, print a string each time system warm boots PWRQD: EQU NO ;yes, password needed to login REENTR: EQU NO ;yes, .COM file code re-entrant (avoids reloads) RKEYS: EQU NO ;yes, remote console has special function keys TIMEOUT: EQU YES ;yes, auto logout for sleepy callers (NO RTC NEEDED) TIMEUP: EQU YES ;yes, RTC and time limit desired (MAXTIMH/MAXTIML) TOMINS: EQU 1 ;minutes to auto logout: 1 = 2.5 mins!! TRAPCC: EQU YES ;yes, trap ctrl-C's if location 0 <> C3H for GOFCB TRAPCP: EQU YES ;yes, trap ctrl-P's for auto-logoff TRAPLC: EQU NO ;yes, ask if lower case ok/make upper case if not USRLOG: EQU YES ;yes, count number of users WBRTN: EQU NO ;yes, do function each time system warm boots ; ;---------- local console special function keys ---------------- ; TIMEKEY: EQU 'A'-40H ;key to politely send callers away BLNKKEY: EQU 'B'-40H ;key to "blank out" remote terminal SYSDKEY: EQU 'D'-40H ;key to print "System going down soon..." BELKEY: EQU 'G'-40H ;key to toggle console bell on/off TWITKEY: EQU 'N'-40H ;key to hangup modem immediately (Nurdkey) TWT2KEY: EQU 'V'-40H ;Line #2 twit MSGKEY: EQU 'O'-40H ;key to enter "Message from SYSOP: " routine CALKEY: EQU 'W'-40H ;key to clear RTC time up to max time again CLRKEY: EQU 'Z'-40H ;key to clear screen (waiting for call mode only) CHATKEY: EQU 'E'-40H ;KEY TO ENTER CHAT MODE CHXKEY: EQU 'X'-40H ;EXIT CHAT BLLLKEY: EQU 'Q'-40H ;BELL EXKEY: EQU 'U'-40H ;EXIT AFTER CALL KEY ZKEY: EQU 'R'-40H ;RESET COUNTERS ; ;---------- system and hardware dependent options -------------- ; BLKOUT: EQU YES ;turn off remote send CLOSS: EQU 05 ;if carrier dies, wait 1 sec. before hanging up COMUSR: EQU 00 ;user # of .COM file to be called after answer CPM2: EQU YES ;yes, using CP/M 2.2 CTRLC: EQU '@'-40H ;map ^C to this if 0000H<>C3H CWAIT: EQU 10 ;wait up to 20 seconds for carrier at first EXUSR: EQU 00 ;user # of .COM file to be called upon exit IMSAI: EQU NO ;yes, if using IMSAI computer with front panel INULLS: EQU 0 ;initial number of nulls LOSER: EQU NO ;yes, warm boot overwrites part of the BIOS LXID: EQU 11H ;define byte of LXI D,nnnn to fake loader LXIH: EQU 21H ;define byte of LXI H,nnnn to fake loader MAXTIMH: EQU 00H ;max. time on sys (if RTC/TIMEUP) (high byte) MAXTIML: EQU 45H ;max. time on sys (low byte) + 1 minute INCFLG: EQU 10H ;INCREASE TIME LEFT BY THIS AMT PER CTRL W MCMDBA: EQU 0EDD1H ;multi-cmd buffer base address if ZMCMDB true MCMDBS: EQU 200 ;multi-cmd buffer size in bytes if ZMCMDB true MHZ: EQU 40 ;processor speed MHz * 10 (2.5MHz=25, 5MHz=50, etc.) NORING: EQU YES ;yes, UART ring indicator NOT available NULSPRT: EQU NO ;yes, nulls print on console, filter out (Kaypro2) NZCPR: EQU NO ;yes, if running NEWZCPR under secure mode RTC: EQU YES ;yes, if RTC (include CLOCK routine, see RTCBUF:) SELPASS: EQU NO ;require a password SENSE: EQU 0FFH ;sense switch port number SMAXDRV: EQU 5 ;number of drives available to SYSOP SMAXUSR: EQU 16 ;number of user areas available to SYSOP SPDBYTE: EQU YES ;yes, set speed value in MSPEED location TMINS: EQU ((TOMINS*MHZ)+5)/10 ;(don't change this one...) WELFILE: EQU YES ;yes, to send a WELCOME file WELUSR: EQU 00 ;user # of WELCOME file ZCPR2: EQU NO ;yes, if running ZCPR2 - WHEEL SET IN EITHER CASE!!! ZILOG: EQU YES ;yes, using a Z-80 or Z-800 ZMCMDB: EQU NO ;yes, if ZCPR2 multiple command line buffer ; ; ; SINGLE: EQU NO ;yes if only one of the below supported & allowed S110: EQU NO ;yes, if supporting 110 baud & allowed S300: EQU YES ;yes, " " 300 " S450: EQU NO ;yes, " " 450 " S600: EQU NO ;yes, " " 600 " S710: EQU NO ;yes, " " 710 " (PMMI only) S1200: EQU YES ;NO, " " 1200 " ; ; ; If USEZCPR is YES, it automatically sets MAXDRIV and USERMAX from the ; NZCPR locations. Otherwise it uses the vaules you insert for MAXDRV ; and MAXUSR. (USEZCPR valid for NZCPR only, I do believe...) ; USEZCPR: EQU NO ;yes, if using NZCPR to set max drive and user # MAXDRV: EQU 5 ;highest drive supported (2=B:) MAXUSR: EQU 14 ;highest user area (set to 0 for CP.M 1.4) ; ; ; Page zero locations used by MBYE3: ; KILBEL: EQU 003BH ;console bell disable flag (if FKEYS true) MSPEED: EQU 003CH ;baud rate pointer (if SPDBYTE true) MAXDRIV: EQU 003DH ;ZCPR location of MAXDRIV byte (if USEZCPR true) MDMFLG: EQU 003EH ;CTRL-B FLAG LOCATION (now in Page Zero for RBBS use) WHEEL: EQU 003FH ;WHEEL FLAG IF ZCPR (non-standard location) ;rbbs EQU 0040H ; ;rbbs EQU 0041H ; GAMFLG: EQU 0042H ;Increment TOS*2 in games - this is a message system! BELFLG: EQU 0043H ;RBBS RMT BELL TOGGLE NOLFLG: EQU 0044H ;FLAG FOR NO RTC TIMEOUT ON CERTAIN USERS MXTFLG: EQU 0045H ;TL FLAG poked to 45H by MBYE, may be changed by RBBS RTCBUF: EQU 0046H ;RTC BUFFER HR MN SC MT DM (CM CM) (IM IM) LCM TF1: EQU 0051H ;CARRIER PRESENT #2 if high TF2: EQU 0052H ;I/O #2 IF ON ; EQU 0053H ;SPARE ; EQU 0054H ; " " TF5: EQU 0055H ;RBBS poke to allow #2 to be used (polled for ring, ; ;Carrier loss, etc if HIGH ; Note: Increment Location 28 DEC by one for each additonal Line 2 caller ; logged on by this line 1 caller, and these locations will contain the ; TOS of each caller on #2 in ASCII TF6: EQU 0056H ;1ST Line 2 Caller TIMEON ASCII minutes TF7: EQU 0057H ;2ND L2 TIMEON TF8: EQU 0058H ;3RD L2 " TF9: EQU 0059H ;4TH L2 " TF0: EQU 005AH ;5TH L2 " ; ;----------------------------------------------------------------------- ; BP110: EQU 0 ;110 bps - baud rate pointers for MSPEED BP300: EQU 1 ;300 bps BP450: EQU 2 ;450 bps BP600: EQU 3 ;600 bps BP710: EQU 4 ;710 bps BP1200: EQU 5 ;1200 bps BP9600: EQU 8 ;9600 bps BP19200: EQU 9 ;19200 bps ; ;----------------------------------------------------------------------- ; ; There are some cases where warm boot overwrites the initial bios jump ; table. This problem was solved for the Superbrain 3.0 bios by find- ; ing a warmboot call to HIGH in the BIOS. This call is then patched by ; BYE. The form of the call is: WBCALL CALL WMSTRT ; IF LOSER WBCALL: EQU 0DE48H ;check this in your BIOS ; ; ; The following location is called ; WMSTRT: EQU EE48H ;check this in your BIOS ENDIF ;LOSER ; ; ;*********************************************************************** ; ; END OF OPTION CONFIGURATION SECTION FOR BYE3 ; ;*********************************************************************** ; ; ORG TPA ; ; ;----------------------- Special Loader Routine ------------------------ ; START: LXI SP,STACK ;set stack for initialization routine ; IF BYELOW LHLD BDOS+1 ;if bye running, BDOS+1 = BEGOBJ ENDIF ; IF NOT BYELOW LXI H,RAMTOP-(OBJEND-BEGOBJ)+1 ; = BEGOBJ relocated ENDIF ; PUSH H ;Save BEGOBJ address (should be) LXI D,YESITS-BEGOBJ ;(should = 'BYE') DAD D MOV A,M ;Check to see if MBYE3 already relocated CPI 'B' JNZ MOVBYE INX H MOV A,M CPI 'Y' JNZ MOVBYE INX H MOV A,M CPI 'E' JNZ MOVBYE POP H ;if relocated, get start address PUSH H ;save it LXI D,OPTION-BEGOBJ DAD D XRA A MOV M,A ;Clear OPTION POP H ; INX H INX H INX H ;skip initial JMP (JMP BDOS if BYELOW) PCHL ;execute already relocated code ; MOVBYE: ; POP H ;restore HL (BYELOW BDOS location) ; IF BYELOW ;BDOS-(2k CCP+6 byte s/n+(BYE scratch)) LXI D,-(2048+6+(OBJEND-PEND)) DAD D ;make room for CCP, serial#, bye scratch ENDIF ;BYELOW ; IF NOT BYELOW ;RAMTOP-(BYE scratch) LXI H,RAMTOP-(OBJEND-PEND) ENDIF ; ; ; HL now contains the destination address of BYE3 (end of BYE) ; LXI D,PEND-1 ;set up the source pointer LXI B,PEND-BEGOBJ ;set up byte counter ; ; The following is for the Zilog Z-80 or Z-800. ; IF ZILOG XCHG ;reverse source and destination for lddr DB 0EDH,0B8H ;these are the codes for lddr ENDIF ;ZILOG ; UPDATE: ; CALL NEGHL ;prepare value for subtraction DAD D ;form the program offset SHLD OFFSET ;save the program offset XCHG ;set up the offset register LXI H,ENDOBJ ;get the ending addr of the prgm code DAD D ;form new ending addr (new location) SHLD ENDRNG ;save the ending addr of the prgm code LXI H,BEGOBJ ;get the start addr of the program code DAD D ;form new beginning addr (new location) ; ; ; The following code determines whether or not an address is within the ; BYE prgm and sets it to the new address if it is - otherwise it will ; not disturb the code... ; DCX H ;set up the sourc pointer for the modi- ;..fication routine entry MODIFY: INX H ;point to the next (hopefully) instr. DB LXID ;get the address of the end of BYE3 ; ENDRNG: DW 0 MOV A,E SUB L MOV A,D SBB H ;have we finished moving this block? JC BEGIN ;yes, we can begin now. ; ; ; Here is where we test for the 3-byte opcodes ; MVI B,INST3E-INST3 ;get the number of elements in the table LXI D,INST3 ;set up the 3-byte opcodes table pointer ; THRBYT: LDAX D ;get opcode byte from table CMP M ;is this byte a 3-byte opcode? JZ CHANGE ;change the 2nd and 3rd bytes if needed INX D ;no, advance table pointer DCR B ;end of 3-byte table? JNZ THRBYT ;no, keep looking ; ; ; Skip all the 2-byte opcodes - this keeps the transfer program from ; trying to figure out what the second byte is. ; MVI B,INST2E-INST2 ;get the number of elements in the table LXI D,INST2 ;set up the 2-byte-opcodes-table pointer ; TWOBYT: LDAX D ;get opcode byte from table CMP M ;is this byte a 2-byte opcode? JZ SKIP ;yes, skip it and continue DCR B ;no, end of 2-byte table? INX D ;advance table pointer JNZ TWOBYT ;no, keep looking JMP MODIFY ;yes, it's a one-byte opcode, keep going ; SKIP: INX H ;advance object code pointera JMP MODIFY ;continue search ; CHANGE: LXI D,OBJEND ;set up end of range pointer LXI B,BEGOBJ ;set up beginning of range pointer ; ; ; See if the address is above the range ; INX H ;advance pointer to the LSB of the addr MOV A,E SUB M INX H ;advance pointer to the MSB of the addr MOV A,D SBB M JC MODIFY ; ; ; See if the address is below the range ; DCX H ;set back pointer to the LSB of the addr MOV A,M SUB C INX H ;advance pointer to the MSB of the addr MOV A,M SBB B JC MODIFY ; ; ; Update the value of this address by adding the offset to it ; DCX H ;set back pointer to the LSB of the addr DB LXID ;load DE with the offset value ; OFFSET: DW 0 MOV A,M ;get base address ADD E ;change LSB to new address MOV M,A ;update memory INX H ;advance pointer to the MSB of the addr MOV A,M ;get the MSB of the base addr ADC D ;change LSB to new address MOV M,A ;update memory JMP MODIFY ;take care of the next instruction ; ; ; Small subroutine to negate the contents of HL ; NEGHL: MOV A,H CMA MOV H,A ;get the complement of the MSB MOV A,L CMA MOV L,A ;get the complement of the LSB INX H ;make 'HL' totally negative RET ; ; ; Prepare to branch to the bye program ; BEGIN: ; ; Initialize internal copy of BIOS jump table. (Previously done ; every time PATCH run, when only needs to be done once.) ; LXI D,VCOLDBT ;BIOS save table LHLD OFFSET ;+OFFSET DAD D XCHG ;result in DE CALL TBLADDR ;get BIOS table addr in HL MVI B,24 ;save all vectors CALL MOVE ; IF COMFILE LXI D,COMFLG ;clear COMFLG LHLD OFFSET ;to force intial load DAD D XRA A MOV M,A ENDIF ; LXI D,OPTION LHLD OFFSET DAD D LDA FCB+2 ;GET /A/C/Z MOV M,A ;save in OPTION ; LHLD 1 ;JMP WARMBOOT addr. LXI D,10 ;+10 = CONOUT addr. DAD D ;patch TPA copy of jmp table MVI A,0C3H STA VCONOUT ;with JMP CONOUT MOV A,M STA VCONOUT+1 ;so that LCLPRT routine will work INX H MOV A,M STA VCONOUT+2 ; CALL CLRSCRN ;clear screen LXI H,VMSG ;signon message CALL LCLPRT ; IF FKEYS MVI A,ON STA 0FE80H STA MDMFLG MVI A,067H STA 0FFE6H XRA A STA EXFLG STA KILBEL CALL CLRFLG CALL TOGBEL MVI A,MAXTIML STA MXTFLG ENDIF ; LXI H,INITMSG ;tell user what's up... CALL LCLPRT CALL MDINIT ;initialize modem ; IF SMODEM OR SM1200 OR ANCHOR OR USR CALL MDANSW ;raise DTR/RTS now.. ENDIF ; IF SM1200 OR ANCHOR OR USR CALL SET1200 ;set 1200 baud if 1200 ENDIF ; IF SMODEM CALL SET300 ;set 300 baud if 300 ENDIF ; IF SMODEM OR SM1200 OR ANCHOR OR USR MVI B,5 CALL SMDLP1 ;wait a bit for modem to settle LXI H,SM1MSG ;make sure modem at right baud rate CALL MDMPRT CALL SMDLAY LXI H,SMHMSG CALL MDMPRT CALL SMDLAY ;wait a sec... LXI H,SMIMSG ;initialize smartmodem CALL MDMPRT ENDIF ; IF BYELOW LHLD BDOS+1 PUSH H LXI D,BEGOBJ LHLD OFFSET ;get prgram offset DAD D ;form address of new BDOS address SHLD BDOS+1 ;update BDOS vector INX H POP D MOV M,E INX H MOV M,D INX H ENDIF ;BYELOW ; IF NOT BYELOW LXI D,BEGOBJ2 ;start of BYE3 code LHLD OFFSET DAD D ;'HL' >start of relocated code ENDIF ;NOT BYELOW ; PCHL ;jump to relocated BYE3 program ; ; ; The following table defines the 3-byte load instructions used in the ; 8080 instruction set. ; INST3: DB 01H DB 11H DB 21H DB 22H DB 2AH DB 31H DB 32H DB 3AH DB 0C2H DB 0C3H DB 0C4H DB 0CAH DB 0CCH DB 0CDH DB 0D2H DB 0D4H DB 0DAH DB 0DCH DB 0E2H DB 0E4H DB 0EAH DB 0ECH DB 0F2H DB 0F4H DB 0FAH DB 0FCH ; INST3E: ;end of 3 byte op codes ; ; The following table is the listing of the 2-byte opcodes used in the ; 8080 instruction code set. ; INST2: DB 06H DB 0EH DB 16H DB 1EH DB 26H DB 2EH DB 36H DB 3EH DB 0C6H DB 0CEH DB 0D3H DB 0D6H DB 0DBH DB 0DEH DB 0E6H DB 0EEH DB 0F6H DB 0FEH ; INST2E: ;end of 2 byte op codes ; INITMSG: DB CR,LF,'[Initializing modems]',CR,LF,0 ; IF SMODEM OR SM1200 OR ANCHOR OR USR SM1MSG: DB 'AT',CR,80H ; SMIMSG: DB 'ATE0' ENDIF IF SMODEM OR SM1200 DB 'Q0V0' ENDIF IF ANCHOR OR USR DB 'Q1' ENDIF IF SMODEM OR SM1200 OR USR DB 'M0' ENDIF IF SM1200 DB 'X1' ENDIF IF SMODEM OR SM1200 DB ' S0=0' ENDIF IF ANCHOR OR USR DB ' S0=2' ENDIF IF SMODEM OR SM1200 OR ANCHOR OR USR DB ' S2=3' ENDIF IF SMODEM OR SM1200 DB ' S4=255 S5=255 S7=13' ENDIF IF SMODEM OR SM1200 OR ANCHOR OR USR DB CR,80H ENDIF ; ; ;----------------------------------------------------------------------- ; ; THE FOLLOWING CODE GETS MOVED BEGOBJ: JMP 0 ;filled by begin if BYELOW BEGOBJ2:JMP START0 ;hop over fixed vectors ; MCBOOT: JMP MBOOT ;off to warm boot JMP PRNLOG ;go print out items of interest ; ; Variables follow in a predefined order that can be manipulated by a ; passworded or other program to give special users different capabili- ; ties. ; ;*********************************************************************** ; ; Here is a quickie handy reference table to use so we do not get mixed ; up. Please update it in any future changes. ; ; MXUSR - 1 byte ; MXDRV - 1 byte ; TOVAL - 1 byte ; NULLS - 1 byte ; ULCSW - 1 byte ; LFEEDS - 1 byte ; WRTLOC - 1 byte ; HARDON - 1 byte ; LOSTFLG - 1 byte ; COVECT - 2 bytes ; 'BYE' - 3 bytes (check here to confirm MBYE is running) ; COMFLG - 1 byte ; JMP - 1 byte (here so MBYE will relocate CURUSR addr) ; CURUSR - 2 bytes ; JMP - 1 byte (here so MBYE will relocate RTCBUF addr) ; RTCBUF - 2 bytes ; ;*********************************************************************** ; ; The flags below are initialized in the ANSWER routine, they should ; be left as '0' in the source to avoid possible problems with the ; relocation routine. (0FFH is also ok, so some flags can be ON.) ; ; Runtime maximum user area (unused under CP/M 1.4) ; MXUSR: DB 0 ; ; ; Runtime maximum drive available ; MXDRV: DB 0 ; ; ; Number of minutes to wait before timeout ; TOVAL: DB 0 ; ; ; Number of nulls to put after a carriage return ; NULLS: DB 0 ; ; ; Upper-case only switch, 32 for uppercase, 0 for upper/lowercase ; ULCSW: DB 0 ; ; ; Line-feed masking bit (non-zero= mask line feeds) ; LFEEDS: DB NO ; ; ; Location RBBS pokes so modem does not hang-up during disk writes ; WRTLOC: DB NO ; ; Switch to let SYSOP turn on/off the hard log (so his work remotely ; will not show up on the hardlog and waste all that paper) if HARDLOG ; is set 'NO', this is ignored, but takes up space so that smart pro- ; grams will not screw stuff up when they change these locations. ; ; HARDON: DB ON ; ; ; LOSTFLAG has been moved up here, so that we can make BYE hang-up the ; the phone without the "good-bye" message (like if we kill a twit). ; LOSTFLG:DB NO ; ; ; Console output vector which points to the "local console" output rou- ; tine. This address is used by external XMODEM programs to set their ; CONOUT address automatically if their USECON equate is set to YES. ; (Initialized by START0, leave as 0 in source code.) ; COVECT: DW 0 ;used by XMODEM programs to find CONOUT ; ; ; Check these three bytes to insure that BYE is running before using ; any functions dependent on BYE. (No problem to relocator, leave as ; upper case only.) ; YESITS: DB 'BYE' ;tells XMODEM that BYE3 is being used ; ; ; COMFLG is 0 if .COM file is not loaded in TPA, 0FFH if .COM file is ; loaded. This flag is used to avoid unecessary reloading of the .COM ; file (as, for instance, when a user hangs up during the "HOW MANY ; NULLS?" question). ; COMFLG: DB NO ; 0 = .COM file not loaded ; ; ; CURUSR is relocated, (hence the reason for the JMP instruction), and ; is used by MBBS to determine where the current user buffer is located. ; USRMSL: JMP CURUSR ;(address of data, not code) ; ; ; RTCBUF is relocated, (hence the need for JMP), and is used by MBBS to ; determine the location in memory of the real-time clock buffer. ; (9 BCD bytes representing HHMMSS (time), YYYYMMDD (date) and ; MMMM (total mins on system).) If you don't have a real-time clock ; available, set time to all nines (999999H). If an RTC is available, ; CLOCK is called during all modem I/O. During this routine, get RTC ; data and format (if necessary) and copy to RTCBUF, increment # of ; mins on system every 60 secs., check # of mins. on vs. max. allowed, ; and if max. reached or exceeded, JMP to DROPCAR (after time up msg). ; if WRTLOC is set, wait till it clears before JMP DROPCAR... ; RTCBFL: JMP RTCBUF ;(address of 9 byte BCD buffer) ; ; ;*********************************************************************** ; ; THIS IS THE OFFICIAL START OF THE BYE PROGRAM ; ;*********************************************************************** ; ; ; If the carrier is lost - hang up, await ring. Otherwise, say goodbye, ; and hang-up. ; START0: ;start of the BYE program ; LXI SP,STACK ;reset stack pointer ; IF BYELOW LHLD BDOS+1 ;get beginning address of BYE3 program SHLD BDADDR ;save address of BYE3 start ENDIF ;BYELOW ; XRA A ;a=0 STA LOSTFLG ;show no carrier lost STA CHTFLG ; LHLD VCONOUT+1 ;get console output vector SHLD COVECT ;save it for XMODEM ; IF MINICK MVI A,IOVAL ;get proper initial value STA IOBYTE ;set it in IOBYTE ENDIF ;MINICK ; IF USRLOG LDA USRFLG ;check to see if USRLOG flags CPI 0AAH ;have been initialized CNZ RSTULC ;if not, DO it LDA USRFLG+1 CPI 055H CNZ RSTULC ENDIF ; ; If carrier present, assume we have a remote user... ; CALL MDCARCK ;remote user? JNZ GOODBY ;if so, bye bye... ; ; Check for /A/C/Z option on command line ; LDA OPTION ;check for /A/C/Z option... CPI 'A' ;answer immediately? JZ ANSWER0 ;skip to answer routine ; IF COMFILE CPI 'C' ;answer and do comfile? JZ ANSWER0 ;skip to answer routine ENDIF ;COMFILE ; IF USRLOG ;check for reset of counters CPI 'Z' CZ RSTULC ENDIF ;USRLOG ; JMP HANGUP2 ;invalid option, just hang up... ; BYEBYE: ;Say goodbye (if PRNTGB yes) ; IF PRNTGB LXI H,GBMSG ;good-bye message CALL CONPRT ;print this message ENDIF ;PRNTGB ; RET ; GOODBY: ;Issue good-bye and undo Bios patches ; WEGONE: ; CALL MDCARCK ;Check if they're still there JZ HANGUP ;nope, forget it CALL BYEBYE ;else, say bye... ; ; ; Nobody there, or we are done, so hang up ; HANGUP: ; CALL MDMHANG ;hang up modem ; HANGUP0: ; LXI SP,STACK ;set up local stack ; HANGUP1: ; CALL MDCARCK ;anybody still there? CNZ BYEBYE ;if so, say goodbye ; HANGUP2: ; LXI SP,STACK ;set up local stack ; CALL UNPATCH ;unpatch BIOS ; XRA A ;force next warmboot to user 0 STA 0004H ;and drive a: ; IF MBBS OR RBBSCK STA WRTLOC ;clear WRTLOC in case set ENDIF ; CALL MDMHANG ;hang up the phone ; IF COMFILE LDA EXFLG CPI 02 JZ XCPM CALL LODCOM ;load the .COM file ENDIF ;COMFILE ; MVI A,0C3H ;clear any traps left from .COM file STA 0 XRA A STA TIMEIT CALL CLRFLG MVI A,ON STA MDMFLG MVI A,MAXTIML STA MXTFLG ; IF ZMCMDB LXI H,MCMDBA+4 ;if ZCPR2 multi-cmd buffer, clear it SHLD MCMDBA XRA A STA MCMDBA+4 ENDIF ; START1: ;if 'Resume' from ^C interrupt ; LXI SP,STACK ; IF NORING AND NOT (SMODEM OR SM1200 OR ANCHOR OR USR) CALL MDANSW ;raise DTR/RTS for auto answer ENDIF ; IF SMODEM OR SM1200 CALL MDINP CALL MDINP ;clear any previous rings... ENDIF ; ; CALL CLRSCRN ;clear the local console screen ; START2: CALL CLRSCRN XRA A ;clear OPTION flag STA OPTION IF MULTI STA LDFLG ENDIF PUSH H LXI H,CSFMSG CALL LCLPRT IF CLK LXI H,CFMSG CALL LCLPRT ENDIF POP H ; ; Await ringing - check local keyboard for CTL-C exit request, ; CTL-G bell toggle or CTL-Z screen clear. ; RINGWT: ; CALL VCONSTAT ;check if console key ready ORA A JZ RNGWT1 ;nope, check for ring/carrier CALL VCONIN ;yep, get console key ANI 7FH ;strip parity bit ; IF FKEYS CPI BELKEY ;bell key? CZ TOGBEL ;if so, toggle console bell on/off CPI CLRKEY ;clear screen char? CZ CLRSCRN ;if so clear the screen CPI ZKEY CZ RESIT CPI 27 JZ USRCHK ENDIF ; C40: CPI 'C'-40H ;CTL-C? JZ USRCHK ;check for exit ; RNGWT1: ; IF NORING AND NOT (SMODEM OR SM1200) CALL MDCARCK ;check for carrier JNZ ANSWER ;we have carrier, let's say hello. JMP RINGWT ;nope, loop ENDIF ;NORING AND NOT (SMODEM OR SM1200) ; IF SMODEM OR SM1200 CALL MDINST ;check for data available JZ CLKPT CALL MDINP ;yep, get data CPI CR ;if CR, JZ RINGWT ;ignore it CPI '2' ;'RING?' JZ ANSWSM ;yes, answer the phone CPI '3' ;'NO CARRIER?' JZ START2 ;yes, clear OPTION flag, cont. PUSH PSW ;no, save result code CPI '1' ;'300 CONNECT?' ENDIF ;SMODEM OR SM1200 ; IF SMODEM OR (SM1200 AND S300) ;supporting 300 baud? JZ ANSWER ;yes, answer ENDIF ; IF SM1200 AND NOT S300 JZ HANGUP2 ;if not, hang up on 'em ENDIF ; IF SM1200 CPI '5' ;'1200 CONNECT?' JZ ANSWER ENDIF ;SM1200 ; IF SMODEM OR SM1200 POP PSW ;not a response code XRA A IF MULTI STA LDFLG ENDIF JMP RINGWT ;ignore it ; CLRFLG: STA GAMFLG IF MULTI STA TF1 STA TF2 STA TF5 STA TF6 STA TF7 STA TF8 STA TF9 STA TF0 ENDIF RET ; CLKPT: IF CLK PUSH B PUSH D PUSH H PUSH PSW LDA RTCBUF+2 MOV B,A MVI A,2 OUT 20H IN 24H CMP B JZ NOTYT LDA RTCBUF+3 LXI D,SPMSG MVI C,9 CALL 5 CALL CVT1 LDA RTCBUF+3 CALL CVT MVI E,'/' CALL CNPRT LDA RTCBUF+4 CALL CVT1 LDA RTCBUF+4 CALL CVT MVI E,' ' CALL CNPRT MVI E,' ' CALL CNPRT LDA RTCBUF CALL CVT1 LDA RTCBUF CALL CVT MVI E,':' CALL CNPRT LDA RTCBUF+1 CALL CVT1 LDA RTCBUF+1 CALL CVT MVI E,':' CALL CNPRT LDA RTCBUF+2 CALL CVT1 LDA RTCBUF+2 CALL CVT MVI E,' ' CALL CNPRT MVI E,' ' CALL CNPRT MVI E,'[' CALL CNPRT LDA RTCBUF+1 MOV B,A CALL CLOCK LDA RTCBUF+1 CMP B JZ PH PUSH H LXI H,RTCBUF+7 XRA A MOV A,M INR A DAA MOV M,A INX H MOV A,M INR A DAA MOV M,A POP H PH: LDA RTCBUF+7 CALL CVT1 LDA RTCBUF+7 CALL CVT MVI E,']' CALL CNPRT MVI E,9 CALL CNPRT MVI E,CR CALL CNPRT NOTYT: POP PSW POP H POP D POP B ENDIF ; ; This routine polls Modem #2 during #1's silent states. If #2 rings, it ; answers and tells them to call #1. Insert your Line #1 number below ; in ASCII ; IF MULTI TEL2: PUSH PSW PUSH B LDA LDFLG ORA A JNZ TNR CALL TRNG JZ TNR MVI B,10 CALL DELAY CALL TRNG JZ TNR MVI A,5 OUT 15 MVI A,234 OUT 15 MVI A,16 OUT 33 MVI B,10 CALL DELAY CALL SMDLAY CALL SMDLAY CALL TCAR JNZ TELLIT CALL SMDLAY CALL SMDLAY CALL TCAR JNZ TELLIT CALL SMDLAY CALL SMDLAY CALL TCAR JNZ TELLIT ALLD: CALL MDINIT CALL MDANSW TNR: POP B POP PSW ENDIF ;MULTI JMP RINGWT ; IF MULTI TCAR: MVI A,16 OUT 15 IN 15 ANI 8 RET TRNG: MVI A,16 OUT 15 IN 15 ANI 32 RET TELLIT: MVI A,CR CALL DELA2 MVI A,LF CALL DELA2 MVI A,67 CALL DELA2 MVI A,97 CALL DELA2 MVI A,108 CALL DELA2 MVI A,108 CALL DELA2 MVI A,32 CALL DELA2 MVI A,55 ;7 -- first digit CALL DELA2 MVI A,50 ;2 -- second CALL DELA2 MVI A,53 ;5 -- third CALL DELA2 MVI A,45 ;- CALL DELA2 MVI A,55 ;7 -- fourth CALL DELA2 MVI A,52 ;4 -- fifth CALL DELA2 MVI A,54 ;6 -- sixth CALL DELA2 MVI A,49 ;1 -- seventh CALL DELA2 MVI A,CR CALL DELA2 MVI A,LF CALL DELA2 JMP ALLD ENDIF ;MULTI ; IF CLK ; CVT1: RAR ! RAR ! RAR ! RAR CVT: ANI 0FH ADI 30H MOV E,A CNPRT: MVI C,2 CALL BDOS RET ENDIF ; CSFMSG: DB 27,67,52,0 CSOMSG: DB 27,66,52,0 IF CLK CFMSG: DB LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,0 SPMSG DB 9,9,9,' $' ; ANSWSM: ; ENDIF ; IF (SMODEM OR SM1200) AND USRLOG LXI H,OLDUSR ;count this as "attempted log on" CALL BOPLOG ENDIF ; IF SMODEM OR SM1200 IF MULTI ; prevents checking #2 while #1 is being answered MOV B,A MVI A,ON STA LDFLG MOV A,B ENDIF MVI B,3 ;wait a little CALL SMDLP1 LXI H,SMAMSG ;send "ATA", CALL MDMPRT JMP RINGWT ;wait for response code ENDIF ; ;------------------- end of callback routines -------------------------- ; ; Modem setup ; ANSWER0: ;if "A" or "C" at "OPTION?" or BYE /A or BYE /C ; CALL CLRSCRN ;make sure local console screen is clear ; IF SMODEM OR SM1200 JMP ANSWSM ;if it's "SMART", tell it to answer.. ENDIF ;(& wait for it to say connect/no connect) ; IF NORING AND NOT (SMODEM OR SM1200) CALL MDANSW ;if auto answer modem, raise DTR JMP RINGWT ;wait for carrier ENDIF ; ANSWER: ;setup the modem ; LXI H,CSOMSG CALL LCLPRT ; CALL CURSET IF BYELOW CALL BDCHEK ENDIF ;BYELOW ; XRA A ;clear STA LOSTFLG ;carrier lost flag ; STA WHEEL ;answer the phone in non-wheel mode ; IF FKEYS STA SAVFLG ;clear saved byte flag ENDIF ; IF USRLOG AND NOT (SMODEM OR SM1200) ;count logon attempt LXI H,OLDUSR ;get # of attempts CALL BOPLOG ;call routine to add one ENDIF ; CALL PATCH ;patch BIOS table ; IF CPM2 AND NOT USEZCPR MVI A,MAXUSR ;reset maximum user area STA MXUSR ENDIF ;CPM2 AND NOT USEZCPR ; IF CPM2 AND USEZCPR MVI A,MAXUSR STA MAXUSER ENDIF ; IF NOT USEZCPR MVI A,MAXDRV ;reset maximum drive STA MXDRV ENDIF ; IF USEZCPR MVI A,MAXDRV-1 STA MAXDRIV ENDIF ;NOT USEZCPR ; XRA A ;make sure line feeds are on again STA LFEEDS ; MVI A,INULLS ;assume this many nulls in case of error STA NULLS ; IF FKEYS OR (RTC AND MBBS) MVI A,ON ;set STA MDMFLG ;MDMFLG ENDIF ; IF TIMEOUT LXI H,0 ;if TIMEOUT, clear it SHLD TOCNT MVI A,TMINS STA TOVAL ENDIF ; IF RTC XRA A STA RTCFLG ;clear RTCFLG STA NOLFLG ;CLEAR NO-TIME LIMIT FLAG STA RTCBUF+5 STA RTCBUF+6 MVI A,MAXTIML STA MXTFLG ENDIF ; IF NOT NORING CALL MDANSW ;set up for answer ENDIF ; IF SMODEM OR SM1200 CALL FRSTCR ;check for initial carrier JC HANGUP2 ;no carrier, forget it... CALL MINPUT ;get carriage return (from modem) POP PSW ;restore response code ENDIF ; IF SM1200 CPI '5' ;if '5' and SM1200 JZ SM12 ;is 120 baud ENDIF ; IF SMODEM OR SM1200 CALL SET300 ;else is 300 ENDIF ; IF (SMODEM OR SM1200) AND SPDBYTE MVI A,BP300 STA MSPEED ENDIF ; IF SMODEM OR SM1200 JMP SMCLR ENDIF ; IF SM1200 SM12: CALL SET1200 ENDIF ; IF SM1200 AND SPDBYTE MVI A,BP1200 STA MSPEED ENDIF ; IF SMODEM OR SM1200 SMCLR: MVI B,5 CALL SMDLP1 ;wait a 1/2 sec for line to settle CALL MDINP ;clear garbage characters CALL MDINP JMP WELCOME ;go for it... ENDIF ; IF NOT (SMODEM OR SM1200) ; ANSWERA: ; CALL SET300 ;set speed initially at 300 CALL MDINP ;clear garbage characters CALL MDINP CALL FRSTCR ;check for carrier the first time JC HANGUP2 ;wasn't a voice call ENDIF ; ; ; Now test input for baud rate - FIRST, check for 300 bps. ; IF (NOT (SMODEM OR SM1200)) AND S300 CALL SET300 ;set speed at 300 JNZ ANS0 ENDIF ; IF (NOT (SMODEM OR SM1200)) AND SPDBYTE AND S300 MVI A,BP300 ;set MSPEED value STA MSPEED ENDIF ; IF (NOT (SMODEM OR SM1200)) AND S300 CALL TSTBAUD ;see if bps=300 JZ WELCOME ;yes, exit ENDIF ; ; ; Now check for 1200 bps ; ANS0: ; IF (NOT SM1200) AND S1200 CALL SET1200 ;now check 1200 bps JNZ ANS1 ENDIF ; IF (NOT SM1200) AND SPDBYTE AND S1200 MVI A,BP1200 ;set the MSPEED pointer STA MSPEED ENDIF ; IF (NOT SM1200) AND S1200 CALL TSTBAUD ;check baud rate JZ WELCOME ENDIF ; ANS1: ; IF S450 CALL SET450 ;try 450 bps next JNZ ANS2 ENDIF ; IF SPDBYTE AND S450 MVI A,BP450 ;set MSPEED pointer STA MSPEED ENDIF ; IF S450 CALL TSTBAUD ;check baudrate JZ WELCOME ENDIF ; ANS2: ; IF S600 CALL SET600 ;try 600 bps now JNZ ANS3 ENDIF ; IF SPDBYTE AND S600 MVI A,BP600 ;set MSPEED STA MSPEED ENDIF ; IF S600 CALL TSTBAUD ;check baudrate JZ WELCOME ENDIF ; ANS3: ; IF S710 CALL SET710 ;try 710 bps (PMMI S-100 modems only) JNZ ANS4 ENDIF ; IF SPDBYTE AND S710 MVI A,BP710 ;set MSPEED STA MSPEED ENDIF ; IF S710 CALL TSTBAUD ;check baudrate JZ WELCOME ENDIF ; ANS4: ; IF (NOT (SMODEM OR SM1200)) AND S110 CALL SET110 ;finally try 110 bps JNZ ANSWERA ;try again...*sigh* ENDIF ; IF (NOT (SMODEM OR SM1200)) AND SPDBYTE AND S110 MVI A,BP110 STA MSPEED ;set MSPEED ENDIF ; IF (NOT (SMODEM OR SM1200)) AND S110 CALL TSTBAUD ;check baudrate JZ WELCOME ;ok?? ENDIF ; IF NOT (SMODEM OR SM1200) ; JMP ANSWERA ;if not, try again... ; ENDIF ;NOT (SMODEM OR SM1200) ; CLRSCRN: LXI H,CLRSMSG ;Clear screen CALL LCLPRT RET ; ; ; Following are the usrlog routines ; IF USRLOG ;reset all logon counters ; RSTULC: LXI H,55AAH ;set USRLOG initialization flags SHLD USRFLG ;to be sure LXI H,0 ;clear SHLD OLDUSR ;attempt counter SHLD NEWUSR ;logon counter RET ENDIF ; IF FKEYS RESIT: XRA A STA RTCBUF+7 STA RTCBUF+8 RET ENDIF ; ; PRNLOG is called to print out the BYE version # and USRLOG info. It ; can be called from outside the program, using the vector after MCBOOT. ; PRNLOG: ;print out program version number LXI H,VMSG CALL LCLPRT ; IF USRLOG ;print # of logon attempts LXI H,ATMSG CALL LCLPRT LXI H,OLDUSR+1 ;point to high byte CALL HXOUT LXI H,SUMSG CALL LCLPRT LXI H,NEWUSR+1 ;print # of callers CALL HXOUT ENDIF ;USRLOG ; IF USRLOG LXI H,LFMSG ;finish off with CR/LF CALL LCLPRT ENDIF ; RET ;if no log, null PRNLOG routine ;..... ; USRCHK: CALL MDMHANG ;lower DTR, hang up modem ; PRNIT: CALL CLRSCRN ;clear screen CALL PRNLOG ;give info LXI H,RS1MSG CALL LCLPRT ;prompt to resume waiting for ring ; PRNREL: CALL VCONIN ;get reply CPI 60H ;lower case? JC PRNSAV ;nope, ok.. SBI 20H ;if yes, make upper PRNSAV: STA OPTION ;save reply for later CPI 'A' ;is answer requested JZ ANSWER0 ;go to answer routine ; IF COMFILE CPI 'C' ;answer/run .COM file? JZ ANSWER0 ;also go answer... CPI 'E' ;execute .COM file locally? JZ EXCPM ;set up for local exit ENDIF ; CPI 'R' ;"R" for resume? JZ START1 ;go do it if so ; IF USRLOG CPI 'Z' ;"Z" for zero counters? JNZ EXCPM ;if not, exit to cpm CALL RSTULC ;else, reset 'em JMP PRNIT ;and show result.. ENDIF ; ; Here to exit to CP/M, first reset the modem to default status XCPM: XRA A STA EXFLG LXI H,EXOFMSG CALL LCLPRT LXI H,EXMSG CALL LCLPRT ; EXCPM: ; Exit with BOTH modems off-hook if local exit ; IF SMODEM OR SM1200 OR ANCHOR OR USR LXI H,CSOMSG CALL LCLPRT ; IF SM1200 ; CALL SET1200 ; ENDIF IF MULTI MVI A,16 OUT 33 ENDIF LXI H,SMQMSG CALL MDMPRT CALL SMDLAY LXI H,SMOFMSG ;send "ATZ" CALL MDMPRT CALL SMDLAY ;wait a bit... ENDIF ; ; IF SM1200 OR ANCHOR OR USR ; CALL SET1200 ;if SM1200, ATZ = 1200 baud ; ENDIF ; ; IF SMODEM OR SM1200 OR ANCHOR OR USR ; CALL SMDLAY ; LXI H,SMZMSG ; CALL MDMPRT ;send "AT H1" ; ENDIF ; MVI A,ON STA WHEEL ;restore wheel byte for SYSOP ; IF USEZCPR MVI A,SMAXUSR STA MAXUSER ;and MAXUSR MVI A,SMAXDRV STA MAXDRIV ;and MAXDRIV ENDIF ; IF COMFILE LDA OPTION CPI 'E' ;If not "E" option JNZ EXEX ;exit direct to CP/M CALL LODCOM ;else, make sure .COM file loaded ENDIF ; IF COMFILE CALL TPA ;execute .COM file locally ENDIF ; EXEX: ; MVI A,' ' ;clear STA YESITS ;'B' in 'BYE' to force reload ; JMP VWARMBT ;warm boot to unpatched CP/M ; ; ; BOPLOG increments the 16 bit counter pointer at by HL. If the decimal ; option is n use, the number is kept as 4 BCD digits. ; IF USRLOG BOPLOG: MOV A,M ;get low byte INR A ;increment ENDIF ;USRLOG ; IF USRLOG AND DECIMAL DAA ;decimal adjust ENDIF ;USRLOG AND DECIMAL ; IF USRLOG MOV M,A ;replace low order byte RNC ;if no carry, bop done INX H ; else carry to high order byte MOV A,M ;get high order byte INR A ; and bop it ENDIF ;USRLOG ; IF USRLOG AND DECIMAL DAA ;decimal adjust ENDIF ;USRLOG AND DECIMAL ; IF USRLOG MOV M,A ;replace high order byte RET ENDIF ;USRLOG ;..... ; ; IF USRLOG HXOUT: PUSH H ;save pointer CALL HXHAF ;do high order half of # POP H ;restore pointer DCX H ;point to low, then do low half ; HXHAF: MOV A,M ;get half # in a MOV B,A ;save number RAR ;rotate right 4 bits RAR ;to move MS byte RAR ;to LS byte position RAR CALL ONEOUT ;output MSB to console MOV A,B ;get number back ; ONEOUT: ANI 0FH ;get LS byte for output ADI 30H ;convert to ASCII MOV C,A ;(if DECIMAL, is BCD already CALL CONOUT ;so no need for adjust on display) RET ENDIF ;USRLOG ; ; ; Welcome to the system ; WELCOME: ;welcome to the system ; IF MULTI MVI A,16 ; Take #2 off-hook until #1 re-enables vis RBBS OUT 33 ENDIF ; IF LGONMSG LXI H,LOGMSG ;msg before "HOW MANY NULLS?" CALL CONPRT ENDIF ; ; ; Print the welcome file ; PRNWEL: ; LXI H,BELMSG CALL CONPRT LXI H,LFMSG CALL CONPRT ;CR/LF after NULLS/ULC questions ; IF WELFILE LXI H,WELFILN ;source LXI D,FCB ;destination MVI B,13 ;length CALL MOVE ;move the name LXI D,80H ;set DMA address to 80H MVI C,STDMA CALL BDOS ENDIF ;WELFILE ; IF CPM2 AND WELFILE MVI E,WELUSR MVI C,SETUSR ;set user number for welcome file CALL BDOS ENDIF ;CPM2 AND WELFILE ; ; ; Open the welcome file ; IF WELFILE LXI D,FCB MVI C,OPEN CALL BDOS ; ; ; Did it exist? ; INR A ;A=> 0 means "no" JZ PASSINT ;no welcome file ; ; ; Got a file, type it ; XRA A ;A=0 STA FCBRNO ;zero record number LXI H,100H ;get initial buffer pointer ; ; ; Type the welcome file ; WELTYLP:CALL RDBYTE ;get a byte CPI 1AH ;EOF? JZ PASSINT ;yes, done MOV C,A ;setup for type CALL MOUTPUT ;type the character CALL MSTAT ;check for character typed ORA A JZ WELTYLP ;no, loop CALL MINPUT ;yes, get character ENDIF ;WELFILE ; IF WELFILE CPI 020H ;Look for spacebar JZ NOPASS ;dump out if so CPI 'S'-40H ;CTL-S to delay listing? JNZ WELTYLP ;no, loop until EOF ; WAIT: CALL MSTAT ORA A ;has another char been typed? JZ WAIT ;no, wait CALL MINPUT ;yes, check character CPI '`'-40H ;spacebar to end listing? JNZ WELTYLP ;no, loop until eof ENDIF ;WELFILE ; ; ; Get the password ; PASSINT: ;get the password ; IF PWRQD MVI D,3 ;3 tries at password ; PASSINP:LXI H,PWMSG ;password message CALL CONPRT ;send this message LXI H,PASSWD ;point to password MVI E,0 ;no missed letters ; PWMLP: CALL MINPUT ;get a character CPI 60H ;lower case? JC NOTLC ;no, ANI 5FH ;make upper case alpha ; NOTLC: ENDIF ;PWRQD ; IF DUAL$IO AND PWRQD PUSH PSW ;save character input CPI 20H ;is character a control code? JNC PWDIS ;pass if displayable MVI C,'^' ;if control map to up arrow then display CALL CONOUT POP PSW PUSH PSW ADI 40H ; PWDIS: MOV C,A CALL CONOUT ;output character locally POP PSW ;restore 'A' reg. ENDIF ;DUAL$IO AND PWRQD ; IF PWRQD CPI EXKEY ;CTL-U? JZ PASSINP ;yes, abort, and retry CMP M ;match password? JZ PWMAT MVI E,1 ;no, show miss CPI CR ;CR? JNZ PWMLP ;no, wait for CR ; ; ; Password did not match ; PWNMAT: LXI H,WRGMSG ;wrong password message CALL CONPRT ;send this message DCR D ;more tries? JNZ PASSINP ;yes JMP BADPASS ;no, go hang up ; ; ; Character matched in password ; PWMAT: INX H ;to next character CPI CR ;end? JNZ PWMLP ;no, loop ; ; ; End of password. Any missed chars? ; MOV A,E ;get flag ORA A JNZ PWNMAT ;not right ENDIF ;PWRQD ; NOPASS: IF USRLOG ;count number of successful logins LXI H,NEWUSR ;get last value CALL BOPLOG ;call routine to add one ENDIF ;USRLOG ; IF COMFILE MVI A,20H ;fool the system so that the .COM file STA FCB+1 ; will see a space at FCB+1 for default LDA OPTION ; purposes. CPI 'A' ;SYSOP can bypass .COM file by typing JZ 0000H ; BYE /A CPI 'C' ;SYSOP can also go to .COM file loaded JNZ RUNCOM ; with BYE /C CALL LODCOM ENDIF ;COMFILE ; ; ; Everyone else gets com file ; RUNCOM: ; IF COMFILE AND NOT REENTR XRA A ;If .COM file not re-entrant, clear STA COMFLG ;loaded flag now to force re-load STA RTCBUF+5 STA RTCBUF+6 ENDIF ; IF COMFILE CALL TPA ENDIF ; JMP MBOOT ;warm boot now for "normal" CP/M use ; IF NOT (SMODEM OR SM1200) ; ; TSTBAUD attempts to read a CR, LF or CTL-C and returns with zero flag ; if the character read is one of these three. ; TSTBAUD: CALL MDINP ;clear any garbage CALL MDINP ENDIF ; IF (NOT (SMODEM OR SM1200)) AND SINGLE XRA A ;if only a single baud rate RET ;skip checking for CR/LF/^C ENDIF ; IF NOT (SMODEM OR SM1200) CALL MINPUT ;get character from modem CPI CR ;if a CR RZ CPI LF ;if a LF RZ CPI 'C'-40H ;if a CTL-C RET ;return with proper flags set ; ENDIF ;..... ; ; MDMHANG: ; IF SMODEM OR SM1200 OR ANCHOR OR USR CALL MDOUTST ;if SM JZ MDMHANG ;send MVI A,20H ;a space just in case CALL MDOUTP ;waiting for call IF MULTI MVI A,64 OUT 33 ENDIF CALL MDCARCK ;skip everything else RZ ;if no carrier ENDIF ; HANGIT: CALL MDINIT ;lower DTR to hangup CKCAR: MVI B,10 ;check carrier 10 times HNGLP: CALL DELAY ;every 10th sec CALL MDCARCK ;check carrier JZ HUNG ;if gone, we're hung up DCR B JNZ HNGLP ; IF NOT (SMODEM OR SM1200 OR ANCHOR OR USR) JMP HANGIT ;still there? try again ENDIF ; IF SMODEM OR SM1200 OR ANCHOR OR USR CALL MDANSW ;raise DTR CALL MDCARCK ;check carrier again RZ ;hung up now? CALL SMDLAY ;wait a sec LXI H,SMEMSG ;send ^C^C^C CALL MDMPRT CALL SMDLAY ;wait a sec or so again LXI H,SMHMSG ;send 'AT H0' message CALL MDMPRT CALL SMDLAY CALL MDINP CALL MDINP ;clear out garbage JMP MDMHANG ENDIF ; HUNG: IF SMODEM OR SM1200 OR ANCHOR OR USR CALL MDANSW ;make sure DTR/RTS are on... ENDIF ; RET ;all done... ; ;..... ; ; ; Test to see if carrier is there. If after CWAIT seconds, no carrier, ; then return, saying so. This routine is only called just after we as- ; swered the phone. ; FRSTCR: CALL MDCARCK ;carrier there? JNZ CARCK2 ;yes, jump to regular routine PUSH B ;save BC MVI B,CWAIT*10 ;set for "cwait" seconds JMP CARLP ;from here on, same as other routine ; ; ; Loss of connection test ; CARCK: CALL MDCARCK ;carrier there? JNZ CARCK2 ;yep, go onto other checks... PUSH B ;preserve so we can use it MVI B,CLOSS*10 ;set for 'CLOSS' seconds ; CARLP: CALL DELAY ;wait .1 seconds CALL MDCARCK ;check for carrier MOV A,B ;get count back in a POP B ;fix stack, restore B if all well JNZ CARCK2 ;got carrier, continue on DCR A ;count time down STC ;in case this is the end of 'time' RZ ;return w/ carry set if timed out PUSH B ;preserve 'BC' MOV B,A ;get counter value in 'B' JMP CARLP ;keep checking ; ; ; Now test drive #'s and (if CP/M 2.x) user #'s to insure that maximums ; are not exceeded. ; CARCK2: ; IF MULTI ;here's where we monitor #2's carrier LDA TF1 ORA A JZ NTW CALL CKTW JNZ NTW CALL SMDLAY CALL CKTW JNZ NTW CALL HTW JMP NTW CKTW MVI A,16 OUT 15 IN 15 ANI 8 RET HTW: XRA A ; #2 is gone. Ask #1 for a reset STA TF1 STA TF2 STA TF4 MVI A,91 CALL DELA MVI A,35 CALL DELA MVI A,50 CALL DELA MVI A,32 CALL DELA MVI A,103 CALL DELA MVI A,111 CALL DELA MVI A,110 CALL DELA MVI A,101 CALL DELA CALL RSTM RET ENDIF ;MULTI NTW: IF ZCPR2 OR NZCPR ;if ZCPR2 or NZCPR LDA WHEEL ;WHEEL byte set, ORA A ;clr carry flag RNZ ;and return (allow all disk/user areas) ENDIF ;ZCPR2 OR NZCPR ; PUSH H ;save HL ; IF (NOT USEZCPR) AND CHKDSK LDA 0004H ;check disk/user # ANI 0FH ;isolate drive LXI H,MXDRV ;point to allowed # of drives CMP M ;valid drive? JC CARCK3 ;yes, skip this junk LDA 0004H ;get whole login byte ANI 0F0H ;retain user # & force drive to A: STA 0004H ;update login byte LXI H,IDMSG ;Incorrect Drive Message CALL CONPRT ;tell user what he did JMP MBOOT ;warm boot ENDIF ;(NOT USEZCPR) AND CHKDSK ;..... ; ; CARCK3: ; IF CPM2 AND (NOT USEZCPR) AND CHKUSR LDA 0004H ;get login byte ANI 0F0H ;isolate user # RRC ;move to low bits RRC RRC RRC LXI H,MXUSR ;point to maximum user number CMP M ;valid user #? JC CARCK4 ;yes, don't change JZ CARCK4 LDA 0004H ;get login byte again ANI 0FH ;keep drive, zero user area STA 0004H ;update login byte LXI H,IUMSG ;Invalid User message CALL CONPRT ;tell him what happened MVI E,0 ;and reset user # MVI C,SETUSR ;via CALL BDOS ;call to BDOS JMP MBOOT ;warm boot ENDIF ;CPM2 AND (NOT USEZCPR) AND CHKUSR ; CARCK4: ; IF RTC AND TIMEUP LDA NOLFLG ;Flag to defeat clock for spl. users ORA A JNZ CARCK5 LDA RTCFLG ;RTCFLG set? ORA A JNZ CARCK5 ;avoid loop if so LXI H,RTCBUF+6 MVI A,MAXTIMH CMP M JC TIMUP ;if times up.. JNZ CARCK5 DCX H ;if high bytes equal, LDA MXTFLG ;check low bytes CMP M JC TIMUP DCR A CMP M JZ ONEMIN INR A JNZ CARCK5 TIMUP: MVI A,ON ;set STA RTCFLG ;RTCFLG to avoid loop LXI H,TIMUPM ;tell 'em what happened CALL CONPRT XRA A STA RTCFLG JMP DROPCAR ;and hang up... ENDIF ; CARCK5: ; POP H ;restore 'HL' ORA A ;clear carry flag if all ok RET ;..... ONEMIN: LDA TIMEIT ORA A JNZ CARCK5 MVI A,ON STA TIMEIT LXI H,WARNM CALL CONPRT JMP CARCK5 ; ; ;.1 sec delay routine ; DELAY: PUSH B LXI B,(4167*(MHZ/10))+(417*(MHZ MOD 10)) ; constant * MHz10x ; DELAY1: DCX B MOV A,B ORA C JNZ DELAY1 POP B RET ;..... ; ; Patch in remote BIOS JMP table ; PATCH: CALL TBLADDR ;HL= CP/M BIOS jump table XCHG ;move it to 'DE' LXI H,NEWJTBL ;point to new jump table CALL MOVE ;move it RET ;..... ; ; Restore BIOS JMP table to original values ; UNPATCH: CALL TBLADDR ;HL= CP/M BIOS jump table XCHG ;move to DE LXI H,VCOLDBT ;get saved table CALL MOVE ;move original table back ; IF LOSER LXI H,WMSTRT ;load old call location SHLD WBCALL+1 ;restore old call ENDIF ;LOSER ; RET ;..... ; ; ; Calculate HL=CP/M's jump table, B=length ; TBLADDR: LHLD 1 ;get BIOS pointer DCX H ;skip to cold boot DCX H DCX H ; IF (NOT PRINTER) AND (NOT ALLDEV) AND (NOT NODEV) MVI B,18 ;# of bytes to move ENDIF ;(NOT PRINTER) AND (NOT ALLDEV) AND (NOT NODEV) ; IF PRINTER ;patch list device? MVI B,15 ;don't patch RDR: & PUN: ENDIF ;PRINTER ; IF ALLDEV OR NODEV ;patch all devices MVI B,24 ;move all jumps ENDIF ;ALLDEV OR NODEV ; RET ;..... ; ; ; Move (HL) to (DE), length in (B) ; MOVE: MOV A,M ;get a byte STAX D ;put at new home INX D ;bump pointers INX H DCR B ;decrement byte count JNZ MOVE ;if more, do it RET ;if not, return ;..... ; ; IF LOSER NWBCALL:CALL WMSTRT ;warm boot disk read CALL PATCH ;fix BIOS again after WMSTRT RET ENDIF ;LOSER ;..... ; ; ; Common routine to check for carrier lost - called from console out ; CHECK: ;check for carrier lost ; IF MINICK LDA IOBYTE ;get IOBYTE ANI 80H ;test for disk update RNZ ;busy, wait until done ENDIF ;MINICK ; IF RBBSCK OR MBBS LDA WRTLOC ;get write in progress flag ORA A RNZ ;busy, wait until done ENDIF ;RBBSCK ; IF FKEYS OR (RTC AND MBBS) LDA MDMFLG ;modem I/O in progress? ORA A RZ ;forget it if no.. ENDIF ; CALL CARCK ;see if carrier/drive/user ok IF NOT MULTI RNC ENDIF ; ; This routine polls #2 for a ring, pauses #1's operation (with msg) and waits ; up to ten seconds for a carrier. If a carrier IS detected, #1 is given ; message "[CONNECT]" and should return to menu to go into a logon for #2, ; the first thing being done is to poke TF2, 255 to ernable #2 I/O. ; If #2 fails to connect, #1 is given the option to re-enable #2 modem. The ; CARCK2 routine above handles disconnect by #2, asking for a reset also. ; (#2 receives message "WAIT" after a sucessful connect) ; IF MULTI JC BADPASS ;all ok ; ANTW: LDA TF5 ORA A RZ PUSH B PUSH D PUSH H PUSH PSW LDA TF5 ORA A JZ NRN MVI A,16 OUT 15 IN 15 ANI 32 JZ NRN MVI B,10 CALL DELAY MVI A,16 OUT 15 IN 15 ANI 32 JZ NRN MVI A,5 OUT 15 MVI A,234 OUT 15 MVI A,16 OUT 33 MVI A,91 CALL DELA MVI A,82 CALL DELA MVI A,73 CALL DELA MVI A,78 CALL DELA MVI A,71 CALL DELA MVI A,93 CALL DELA CALL SMDLAY CALL CKTW JNZ OKT CALL SMDLAY CALL SMDLAY CALL CKTW JNZ OKT CALL SMDLAY CALL SMDLAY CALL CKTW JZ NOTW OKT: MVI A,ON STA TF1 XRA A STA TF5 CALL BDCHEK MVI A,91 CALL DELA MVI A,67 CALL DELA MVI A,79 CALL DELA MVI A,78 CALL DELA MVI A,78 CALL DELA MVI A,69 CALL DELA MVI A,67 CALL DELA MVI A,84 CALL DELA MVI A,93 CALL DELA MVI A,91 CALL DELA2 MVI A,87 CALL DELA2 MVI A,97 CALL DELA2 MVI A,105 CALL DELA2 MVI A,116 CALL DELA2 MVI A,93 CALL DELA2 JMP NRN ; NOTW: CALL BDCHEK MVI A,91 CALL DELA MVI A,70 CALL DELA MVI A,97 CALL DELA MVI A,105 CALL DELA MVI A,108 CALL DELA MVI A,101 CALL DELA MVI A,100 CALL DELA CALL RSTM JMP NRN RSTM: MVI A,32 CALL DELA MVI A,45 CALL DELA MVI A,32 CALL DELA MVI A,82 CALL DELA MVI A,101 CALL DELA MVI A,115 CALL DELA MVI A,101 CALL DELA MVI A,116 CALL DELA MVI A,32 CALL DELA MVI A,63 CALL DELA MVI A,62 CALL DELA CALL MDINP CALL MDINP LLP: CALL MDCARCK RZ CALL MDINST JZ LLP CALL MDINP ORA A CPI 89 JZ RTW CPI 121 JZ RTW MVI A,78 CALL DELA MVI A,79 CALL DELA MVI A,93 CALL DELA XRA A STA TF5 RET NRN: POP PSW POP H POP D POP B RET ; RTW: MVI A,64 OUT 33 MVI B,10 CALL DELAY MVI A,5 OUT 15 CALL DELAY MVI A,104 OUT 15 MVI A,79 CALL DELA MVI A,75 CALL DELA MVI A,93 CALL DELA MVI A,ON STA TF5 RET ; DELA: CALL MDOUTP DLA: MOV C,A CALL CONOUT MVI B,10 CALL DELAY RET DELA2: OUT 13 JMP DLA ENDIF ;MULTI ; Carrier is lost. Type message so local console shows the reason. ; Come come here on bad password. ; BADPASS: LDA LOSTFLG ;check carrier lost flag ORA A JNZ DROPCAR ;so we don't repeat ourselves ; MVI A,1 ;show carrier lost - do not check again STA LOSTFLG XRA A STA CHTFLG ; LXI SP,STACK ;ensure valid stack ; LXI H,CLMSG ;carrier lost message CALL LCLPRT ;Send this Message ; DROPCAR: IF MULTI XRA A STA TF2 ENDIF LXI SP,STACK CALL UNPATCH PUSH B PUSH D PUSH H PUSH PSW ; ; IF EXFILE CALL LODEX CPI '*' ;test that file was really loaded JNZ TPA ;EXITFIL was't loaded, so run it ENDIF ;EXFILE POP PSW POP H POP D POP B ; XRA A JMP HANGUP ; ; ; Readbyte routine - used to read the welcome file ; IF WELFILE RDBYTE: MOV A,H ;time to read? ORA A ;if at 100H, no read required JZ NORD ; ; ; Have to read a sector ; LXI D,FCB MVI C,READ CALL BDOS ORA A ;ok? MVI A,1AH ;fake up EOF RNZ ;return EOF if bad LXI H,80H ; NORD: MOV A,M ;get character INX H ;point to next byte RET ENDIF ;WELFILE ; ; ; Keyboard/modem status test routine ; MSTAT: ; IF BYELOW CALL BDCHEK ENDIF ; IF DUAL$IO ;WANT LOCAL CONSOLE? CALL CONSTAT ;GET LOCAL STATUS ORA A ENDIF ; IF DUAL$IO AND (NOT FKEYS) JNZ MSTAT1 ;IF LOCAL CHAR ENDIF ; IF DUAL$IO AND FKEYS JZ MSTAT0 ;NO CHAR, CONT. CALL CONIN ;IF FUNCTION KEYS, GET CHAR. ORA A ;CHECK IT JZ MSTAT0 ;IGNORE IT IF FUNCTION KEY STA SAVBYT ;ELSE, SAVE IT MVI A,ON ;SET SAVFLG STA SAVFLG JMP MSTAT1 ;SAY WE GOT ONE... ENDIF ;DUAL$IO AND FKEYS ; MSTAT0: ; IF RTC LDA RTCBUF+1 ;get mins CALL CLOCK ;update date/time PUSH H ;save HL CPI 99H ;was clock started? JZ MSTATC ;if not, skip increment LXI H,RTCBUF+1 ;else, check if mins. CMP M ;has changed JZ MSTATC ;if not, skip incr CALL INCCL LDA NOLFLG ORA A JNZ MSTACC LDA GAMFLG ORA A JZ MSTACC MVI A,4 OUT 32 IN 36 CPI 3 JM INCX CPI 20 JP INCX JMP MSTACC INCX: CALL INCCL JMP MSTACC INCCL: LXI H,RTCBUF+5 ;else, increment XRA A ;(clr carry for DAA) MOV A,M INR A ;mins on sys DAA ;low byte MOV M,A RNC INX H ;high byte also if carry MOV A,M INR A DAA MOV M,A RET MSTACC: PUSH B LDA MDMFLG ORA A JZ NOTM XRA A STA MDMFLG LXI H,PTTON CALL CONPRT CALL WBTIM LXI H,PTTOFF CALL CONPRT MVI A,ON STA MDMFLG NOTM: IF MULTI ; increments Caller #2 TOS at location incremented ; ; by value poked into 28 via RBBS LDA TF1 ORA A JZ NOTCW LDA 28 CPI 0 JZ NOTCW CPI 1 CZ C1T CPI 2 CZ C2T CPI 3 CZ C3T CPI 4 CZ C4T CPI 5 CZ C5T ENDIF ;MULTI NOTCW: XRA A POP B MSTATC: POP H ENDIF ;RTC ; IF FKEYS LDA MDMFLG ;CHECK FOR MODEM I/O FLAG ORA A ;IF NOT SET, RZ ;IGNORE MODEM DATA... ENDIF ;FKEYS ; CALL CHECK ;ELSE, CHECK FOR CARRIER LOST CALL MDINST ;IF CARRIER, CHECK MODEM INPUT STATUS JNZ MSTAT1 ;WE GOT A CHAR? ; IF TIMEOUT PUSH H ;SAVE HL LXI H,TOCNT ;NO DATA, INCR. TIMEOUT COUNTER INR M JNZ NDATA ;DON'T TIMEOUT YET INX H INR M ;NEXT BYTE OF COUNTER JNZ NDATA LXI H,TOVAL ;1 "MINUTE", NO DATA DCR M JNZ NDATA ;STILL NOT TIMED OUT... LXI H,ITOMSG CALL CONPRT JMP DROPCAR ;FINALLY... TIMED OUT... ; IF MULTI C1T: LDA TF6 ADI 1 STA TF6 XRA A RET C2T: LDA TF7 ADI 1 STA TF7 XRA A RET C3T: LDA TF8 ADI 1 STA TF8 XRA A RET C4T: LDA TF9 ADI 1 STA TF9 XRA A RET C5T: LDA TF0 ADI 1 STA TF0 XRA A RET ENDIF ; NDATA: POP H ;RESTORE HL ; ENDIF ;TIMEOUT ; ; Reads a character from Modem #2 into SAVBYT, which I thought was kinda ; clever . . . ; IF MULTI LDA TF4 ORA A JZ GOBA LDA SAVFLG ORA A JNZ GOBA LDA TF3 CALL MNP2B STA SAVBYT MVI A,ON STA SAVFLG XRA A STA TF3 STA TF4 ENDIF GOBA: XRA A ;SAY NO DATA RET ;AND RETURN ; MSTAT1: ; IF TIMEOUT XRA A ;DATA AVAIL? CLEAR TIMEOUT STA TOCNT STA TOCNT+1 MVI A,TMINS STA TOVAL ENDIF ;TIMEOUT ; ORI ON ;SHOW READY RET ; ;Modem input function, checks local console first ; MINPUT: ; IF BYELOW CALL BDCHEK ENDIF ; IF DUAL$IO AND FKEYS LDA SAVFLG ;CHECK IF BYTE SAVED ORA A JZ NOSAV ;NOPE, CONT. XRA A ;YES, CLEAR SAVFLG STA SAVFLG LDA SAVBYT ;GET SAVED BYTE RET ;AND RETURN WITH IT ENDIF ;DUAL$IO AND FKEYS ; NOSAV: ; IF DUAL$IO OR FKEYS ;CHECK IF DUAL OR FKEYS CALL CONSTAT ;CHECK LOCAL CONSOLE ORA A ;CHAR? JNZ MINP2B ;GET IT ENDIF ;DUAL$IO OR FKEYS ; CALL MSTAT0 ;ANYTHING FROM REMOTE USER? ; JZ MINPUT ;IF NO DATA, NO TIMEOUT, LOOP ; ; ;Modem data ready, get it... ; MINP2A: ; CALL MDINP ;GET DATA CPI 0 JZ MINPUT ;IGNORE NULLS ; MNP2B: IF HARDLOG PUSH B MOV B,A ;put a copy of the character in b LDA HARDON ;if HARDON=0 then turn HARDLOG off (so ORA A ;..SYSOP does not waste paper while he MOV A,B ;..playing ZORK from work.) POP B JZ NOLOG ; CPI 20H JNC MINPUT3 CPI CR JNZ NOLOG ; MINPUT3: CALL LISTOUT ;echo on printer CPI CR JNZ NOLOG ;return needs linefeed MVI A,LF CALL LISTOUT ;so send it MVI A,CR ;get back CR ENDIF ;HARDLOG ; TRXX: IF TRAPCP ;CTRL-P TRAPPING? CPI 60H JNZ TRCP MVI A,20H RET TRCP: CPI 'P'-40H ;IS IT CTRL-P? JNZ CKCC ;NOPE, CHK ^C'S IF MULTI LDA TF2 ORA A JNZ DUMPT STA 23 ENDIF IF NOT MULTI XRA A STA 23 ENDIF LXI SP,STACK CALL LODEX CALL TPA LXI SP,STACK RET DUMPT: XRA A RET CKCC: ENDIF ;TRAPCP ; IF TRAPCC ;CTRL-C TRAPPING? CPI 'C'-40H ;IS IT CONTROL-C? RNZ ;NO, PASS IT THRU LDA 0 ;SEE IF WARM BOOT DISABLED CPI 0C3H ;JMP MEANS WARM BOOT OK MVI A,3 ;SO RETURN CONTROL-C RZ LDA 26 ORA A RZ LDA CHTFLG ADI 1 ORA A RZ IF MULTI LDA TF2 ORA A RNZ ENDIF LXI SP,STACK MVI E,COMUSR MVI C,SETUSR CALL BDOS LXI H,GOFCB SHLD CURRFCB LXI H,GOFCB+12 MVI B,21 CALL ZLOOP LXI D,GOFCB CALL OPENF CALL TPA LXI SP,STACK ENDIF ;TRAPCC ; RET ;AND RETURN ; MINP2B: ; IF DUAL$IO CALL CONIN ;read local data ENDIF ; IF DUAL$IO AND FKEYS ORA A ;CHECK IF FUNCTION KEY JZ MINPUT ;THEN IGNORE THIS KEY ENDIF ; IF DUAL$IO RET ;USE CONSOLE KEY FOR INPUT ENDIF ; ; ; Modem output function ; MOUTPUT: ; ; If we already know carrier is lost, don't check ; for it again or loop trying to output. ; LDA LOSTFLG ;KNOWN LOSS OF CARRIER? ORA A JNZ SILENT ;AVOID LOOP IN CASE CARRIER LOST ; IF FKEYS LDA MDMFLG ;OK TO OUTPUT TO MODEM? ORA A JZ SILENT ;NOPE... ENDIF ;FKEYS ; CALL MSTAT ;CARRIER STILL ON?/FUNC KEY? ; CALL MDOUTST JZ MOUTPUT ;LOOP IF NOT READY ; IF TIMEOUT XRA A ;READY? CLEAR TIMEOUT STA TOCNT STA TOCNT+1 MVI A,TMINS STA TOVAL ENDIF ;TIMEOUT ; MOV A,C ;GET CHAR ANI 7FH ;STRIP PARITY BIT CPI 7 JNZ MOUTP3 LDA BELFLG ORA A JZ OKBEL XRA A JMP MOUTP3 OKBEL: MOV A,C ANI 7FH ; MOUTP2: ; MOUTP3: ; CALL MDOUTP ;OUTPUT TO MODEM ; SILENT: ; IF FKEYS AND DUAL$IO MOV A,C CPI 7 JNZ SILEN2 PUSH PSW LDA KILBEL ORA A JZ SENBEL GOBACK: POP PSW RET ; SENBEL: ; POP PSW ; SILEN2: ; ENDIF ;FKEYS AND DUAL$I0 ; IF NULSPRT AND DUAL$IO CPI 0 ;CHECK IF NULL RZ ;IF SO, SKIP DISPLAY ON KAYPRO SCREEN.... ENDIF ;NULSPRT AND DUAL$IO ; IF DUAL$IO ;TO LOCAL ALSO? PUSH PSW ;SAVE CHAR CALL CONOUT ;SEND TO REGULAR BIOS NOPT: POP PSW ;GET CHAR AGAIN ENDIF ;DUAL$IO NULLP: RET ; ;..... ; ; Warm Boot, checks location 0 to determine if ok to warm boot or not. ; If location is a C3H (JMP), warm boot permitted, else, there is an ; immediate disconnect. ; MBOOT: ; LXI SP,STACK ;reset stack to be sure... ; IF BYELOW CALL BDCHEK ;check JMP BDOS... ENDIF ; LDA 0 ;Look at JMP from JMP WARMBOOT in page zero CPI 0C3H ;still a JMP instruction? JNZ HANGUP1 ;if not, say goodbye immediately! XRA A ;else, STA COMFLG ;clear .COM file loaded flag... ; ; Special warm-boot routine - print a message or something - even run a ; program if you want to!!! ; WMBMSGPRT: ; IF WBRTN OR TIMEUP PUSH PSW PUSH B PUSH D PUSH H ENDIF ; IF RTC AND TIMEUP CALL WBTM JMP WBSKIP WBTM: LXI H,MINMSG CALL CONPRT WBTIM: LDA RTCBUF+6 ANI 0FH ADI 30H MOV C,A CALL MOUTPUT LDA RTCBUF+5 RAR ! RAR ! RAR ! RAR ANI 0FH ADI 30H MOV C,A CALL MOUTPUT LDA RTCBUF+5 ANI 0FH ADI 30H MOV C,A CALL MOUTPUT RET WBSKIP: MVI C,']' CALL MOUTPUT ENDIF ; IF PRNTWB AND FKEYS LDA MDMFLG ;if modem I/O enabled, ORA A JZ WBFIN ENDIF ;PRINTWB AND FKEYS ; IF PRNTWB LXI H,WBMSG CALL MDMPRT ;print "Warm Boot" massage ENDIF ;PRNTWB ; WBFIN: ; IF WBRTN OR TIMEUP POP H POP D POP B POP PSW ENDIF ;WBRTN ; JMP VWARMBT ;go do a warm boot ;..... ; ; ; Console print routine ; ; The following code has been modified to accomodate the automatic ; loader. (The loader may modify a constant, so all messages have ; been placed at the end of the program and just moved to high memory.) ; CONPRT: PUSH B ;save BC CONPLP: MOV C,M ;get character CALL MOUTPUT ;output it INX H ;point to next character MOV A,M ;test for end of message ORA A JNZ CONPLP POP B ;restore BC RET ;return ;..... ; ; ; Routine to load the com file ; LODCOM: ;routine to load the .COM file ; IF COMFILE LDA COMFLG ;check COMFLG ORA A RNZ ;skip load if already loaded LXI H,LSMSG CALL LCLPRT ;tell sysop what's up XRA A MOV E,A MVI C,SELDSK CALL BDOS ;select A: drive ENDIF ;COMFILE ; IF COMFILE AND CPM2 MVI E,COMUSR MVI C,SETUSR CALL BDOS ENDIF ;COMFILE AND CPM2 ; IF COMFILE LXI H,COMFCB SHLD CURRFCB XRA A ;initialize FCB STA COMFCB LXI H,COMFCB+12 MVI B,21 CALL ZLOOP LXI D,COMFCB CALL OPENFIL JZ ABORT ;if can't load file.. MVI A,ON STA COMFLG ;else set flag now... JMP LOADFIL ENDIF ;COMFILE ; LODEX: IF EXFILE IF EXFILE AND CPM2 MVI E,EXUSR ;switch to exit .COM file user area MVI C,SETUSR CALL BDOS ENDIF LXI H,EXFCB SHLD CURRFCB LXI H,EXFCB+12 MVI B,21 CALL ZLOOP LXI D,EXFCB OPENF: CALL OPENFIL MVI A,'*' ;do not try to run unloaded file RZ ;cannot open file, finish BYE hangup XRA A ;else, clear STA COMFLG ;COMFLG to indicate .COM file not loaded ENDIF ;EXFILE ; ; ; Now load the file ; IF COMFILE OR EXFILE LOADFIL:LHLD 6 ;get top of memory LXI D,-80H DAD D PUSH H ;save on stack LXI D,80H ;TPA-80H LXI B,0 ;keep a record counter PUSH B ;save counter PUSH D ;and load address ; GLOOP: POP D ;get TPA address LXI H,80H ;point to next address to read to DAD D ;HL has the address POP B ;increment the counter ; ; ; Check for load past top-of-memory ; POP D ;get (top-of-memory) PUSH D ;resave for next time MOV A,E ;subtract: (top) - (address) SUB L MOV A,D ;only the carry needed SBB H JNC SIZEOK ;CY=better MOVCPM LXI H,PTSMSG JMP ERRXIT ; SIZEOK: INX B PUSH B PUSH H ;save TPA address XCHG ;align registers MVI C,STDMA ;tell BDOS where to put record CALL BDOS LHLD CURRFCB ;point to aprropriate FCB XCHG MVI C,READ CALL BDOS ORA A JZ GLOOP ;a=0 if more to read POP B ;unjunk stack POP B ;this is our counter POP H ;more junk on stack MOV A,B ;check for zero ORA C JZ ABORT ;we should have read something LXI D,80H ;we did, reset DMA to 80H MVI C,STDMA CALL BDOS RET ;all done... ;..... ; ; ZLOOP: MVI M,0 INX H DCR B JNZ ZLOOP RET ;..... ; ; OPENFIL:MVI C,OPEN ;open file pointed to by 'DE' CALL BDOS INR A RET ;..... ; ; ABORT: LXI H,CNFMSG ; ERRXIT: CALL LCLPRT ;print the abort message JMP EXCPM ;warm boot ENDIF ;COMFILE OR EXFILE ; ; ; This area is used for vectoring calls to the user's CBIOS, but saving ; the registers first in case they are destroyed. ; CONSTAT: PUSH B PUSH D PUSH H CALL VCONSTAT POP H POP D POP B RET ;..... ; ; CONIN: PUSH B PUSH D PUSH H CALL VCONIN ; IF FKEYS MOV C,A LDA CHTFLG ORA A JNZ IGN MOV A,C CALL CKFUNC JMP INN IGN: MOV A,C ENDIF ;FKEYS ; INN: POP H POP D POP B RET ;..... ; ; CKFUNC: IF FKEYS CPI BLNKKEY ;BLANK OUT REMOTE CALLER JZ BLNKTOG ;TOGGLE? PUSH PSW LDA MDMFLG ORA A JZ GOBACK POP PSW CPI TIMEKEY ;Send 'em packing JZ TIMUP ;Polite twitkey CPI SYSDKEY ;SYSTEM GOING DOWN? JZ SYSDOWN ;TELL CALLER TO LEAVE CPI TWITKEY ;CALLER A TWIT JZ XANGUP ;MAKE CALLER LEAVE IF MULTI CPI TWT2KEY JZ HANG2 ENDIF CPI BELKEY ;CONTROL-G? JZ TOGBEL ;THEN TOGGLE BELL FLAG CPI CHATKEY ;CHAT MODE JZ CMODE ; CPI BLLLKEY ; JZ BLLKEY CPI EXKEY JZ EXON ENDIF ; IF FKEYS AND RTC CPI CALKEY ;CONTROL-W? JZ USRDSP ;THEN DISPLAY USER ENDIF ; IF FKEYS CPI MSGKEY RNZ ;IF NOT MSGKEY, RET LDA CHTFLG ORA A RNZ ; LXI H,MFSMSG CALL CONPRT ;SEND CALLER A MESSAGE ; SYSMSGL: CALL VCONIN ;INPUT MESSAGE (WHILE PAUSED) CPI 15 ;IF CTRL-O JZ SYSMSGX ; EXIT MSG FROM SYSOP MODE... MOV C,A ;ELSE PUSH PSW CALL MOUTPUT ;SEND TO SYSOP/USER POP PSW CPI BS ;IF BACKSPACE JZ SYSMBS ; ECHO SP/BS AFTER BS CPI CR ;IF CR JZ SYSMCR ; ECHO LF AFTER CR JMP SYSMSGL ;IF NONE OF ABOVE, CONT. ; IF MULTI HANG2: PUSH PSW PUSH B MVI A,64 OUT 33 POP B POP PSW RET ENDIF ; EXON: LDA EXFLG CPI 02H JZ EXOFF MVI A,02 STA EXFLG XRA A STA MDMFLG LXI H,EXONMSG CALL LCLPRT MVI A,ON STA MDMFLG XRA A RET ; EXOFF: XRA A STA EXFLG XRA A STA MDMFLG LXI H,EXOFMSG CALL LCLPRT MVI A,ON STA MDMFLG XRA A RET ; SYSMSGX: MVI C,CR ;CTRL-C EXIT, SEND CR CALL MOUTPUT MVI C,LF ;LF CALL MOUTPUT XRA A ;FLAG TO IGNORE THIS KEY RET ;AND RETURN ; SYSMCR: MVI C,LF ;AFTER CR, ECHO LF JMP SYSECH ; SYSMBS: MVI C,' ' ;IF BACKSPACE, ECHO BS/SP/BS CALL MOUTPUT MVI C,BS ; SYSECH: CALL MOUTPUT JMP SYSMSGL ; XANGUP: XRA A STA CHTFLG JMP DROPCAR ; CMODE: MVI A,ON STA CHTFLG XRA A STA 014H STA MDMFLG STA WWFLAG LXI H,CLCHT CALL LCLPRT MVI A,ON STA MDMFLG LXI H,CHTMSG CALL CONPRT ; CTMSGL: CALL MINPUT CPI CHXKEY JZ CHTEX CPI TWITKEY JZ XANGUP CPI CALKEY CZ USRDSP MOV C,A PUSH PSW CALL MOUTPUT POP PSW CPI BS JZ CTMBS CPI CR JZ CTMCR PUSH PSW LDA WWFLAG INR A STA WWFLAG CPI 04BH JP XXYY CPI 041H JP WWRAP POP PSW XXXX: MVI A,ON STA PMTFLG JMP CTMSGL ; WWRAP: POP PSW CPI 027H JZ XXXX CPI 040H JP XXXX XXZZ: MVI C,CR CALL MOUTPUT JMP CTMCR XXYY: POP PSW JMP XXZZ CTMCR: XRA A STA WWFLAG MVI C,LF CALL MOUTPUT LDA PMTFLG ORA A JZ CTMSX JMP CTMSGX CTMSX: LXI H,CHTPMT CALL CONPRT XRA A STA PMTFLG JMP CTMSGL ; CTMSGX: XRA A STA PMTFLG MVI C,020H CALL MOUTPUT MVI C,020H CALL MOUTPUT JMP CTMSGL ; CTMBS: MVI C,' ' CALL MOUTPUT LDA WWFLAG CPI 01H JM CTMSGL DCR A STA WWFLAG MVI C,BS CALL MOUTPUT JMP CTMSGL ; CHTEX: XRA A STA CHTFLG STA WWFLAG LXI H,CHTXMSG CALL CONPRT JMP SYSMSGX ; SYSDOWN: LXI H,WARNM CALL CONPRT XRA A RET ; ENDIF ;FKEYS ; IF FKEYS AND RTC USRDSP: LDA MXTFLG ADI INCFLG STA MXTFLG XRA A STA RTCFLG STA TIMEIT RET ENDIF ;FKEYS AND RTC ; IF FKEYS BLLKEY: PUSH B MVI C,7 CALL MOUTPUT POP B RET ; BLNKTOG: LDA MDMFLG ORA A ;if zero, make 0FFH ENDIF ;FKEYS ; IF FKEYS STA WHEEL ;set/reset wheel appropriate ENDIF ; IF FKEYS JZ BLNKT1 XRA A ;if not zero, make it zero STA MDMFLG LXI H,UOFMSG JMP FKEX ; BLNKT1: MVI A,ON STA MDMFLG LXI H,UONMSG JMP FKEX ; TOGBEL: LDA KILBEL ;check KILBEL flag ORA A JZ BELOFF ;if off, turn on (BELL OFF) XRA A STA KILBEL LXI H,BONMSG ;if on, turn off (BELL ON) JMP FKEX ; BELOFF: MVI A,ON ;if off, turn on STA KILBEL LXI H,BOFMSG ; FKEX: CALL LCLPRT XRA A RET ; ENDIF ;FKEYS ;..... ; ; CONOUT: PUSH B PUSH D PUSH H PUSH PSW MOV A,C ANI 07FH MOV C,A POP PSW CALL VCONOUT POP H POP D POP B RET ;..... ; IF HARDLOG ; LISTOUT: PUSH B PUSH D PUSH H PUSH PSW ENDIF ; IF HARDLOG AND BYELOW CALL BDCHEK ENDIF ; IF HARDLOG MOV C,A CALL VLISTOUT POP PSW POP H POP D POP B RET ENDIF ; ; IF BYELOW BDCHEK: PUSH H ;to make truly universal, (???) this DB LXIH ; program always re-stores the BDOS ; BDADDR: DW 0000H ; pointer at 6&7 set up location for SHLD 6 ; beginning address of CONSOLX CTL ; at every chance. This replaces the POP H ; WMLOCK & OLDBD as in BYE2 AND BYE3 RET ENDIF ;BYELOW ;..... ; ; ; This is the jmp table which is copied on top of the one pointed to by ; location 1 in CP/M. ; NEWJTBL:JMP MCBOOT ;cold boot JMP MBOOT ;warm boot JMP MSTAT ;modem status test JMP MINPUT ;modem input routine JMP MOUTPUT ;modem output routine ; IF PRINTER RET ! NOP ! NOP ;dummy list device (retain RDR:,PUN:) ENDIF ;NOT ALLDEV ; IF ALLDEV ;LST:, RDR: & PUN: to modem JMP MOUTPUT ;modem list device JMP MOUTPUT ;modem punch device JMP MINPUT ;modem reader device ENDIF ;ALLDEV ; IF NODEV ;no LST:, RDR: or PUN: RET ! NOP ! NOP ;dummy LST: RET ! NOP ! NOP ;dummy RDR: RET ! NOP ! NOP ;dummy PUN: ENDIF ; ; ; ;*********************************************************************** ; IF SMODEM OR SM1200 OR ANCHOR OR USR ; ; SWITCH SETTINGS: ; 1 2 3 4 5 6 7 8 ; HAYES Smartmodem 300/1200 -- UP DN DN DN DN UP UP DN ; ; RNG 8HI BAL DTR ; USR Password -- OFF OFF OFF OFF ; ; Delay about 2 seconds to let modem get stabilized before or after a ; command string. ; SMDLAY: MVI B,20 ;wait about 2.0 seconds to "be sure" SMDLP1: CALL DELAY DCR B JNZ SMDLP1 RET ; ENDIF ; IF (SMODEM OR SM1200 OR ANCHOR OR USR) OR PRNTWB ; ; Send a string to the modem (similar to CONPRT) ; MDMPRT: CALL MDOUTST ;modem ready for character? JZ MDMPRT ;no, go check again MOV A,M ;get the character CALL MDOUTP ;send it INX H ;point to next MOV A,M ;Get next character CPI 80H ;Has all been sent JNZ MDMPRT ;no, go send another character RET ;return ;..... ; ; ENDIF ; LCLPRT: PUSH B ;save 'BC' registers ; LCPLP: MOV C,M ;get the character CALL CONOUT ;send it INX H ;point to next MOV A,M ;Get next character ORA A ;Has all been sent JNZ LCPLP ;no, go send another character POP B ;restore the BC registers RET ;return ;----------------------------------------------------------------------- ; MODEM INSTALLATION FOR KAYPRO UART ;----------------------------------------------------------------------- ; KAYPRO: EQU YES ;yes, if Kaypro, Xerox 820 or BigBoard ; IF KAYPRO CTC: EQU NO C8116: EQU YES ;BigBoards use the 8116 baud rate clock ENDIF ; ; Set base ports for SIO/DART & baud rate clock ; IF KAYPRO DART: EQU NO ;BigBoards use a true SIO BASEP: EQU 04H ;Base port for SIO BASEC: EQU 00H ;Base port for 8116 ENDIF ; ; The following define the port addresses to use. ; DPORT: EQU BASEP ;Data port SPORT: EQU BASEP+2 ;Status/Control port BPORT: EQU BASEC ;Baud rate port ; ; ; The following are SPORT commands (output these to SPORT) ; ; WR0: RESCHN: EQU 00011000B ;Reset channel RESSTA: EQU 00010000B ;Reset ext/status RESERR: EQU 00110000B ;Error reset ; WRREG1: EQU 00000000B ;WR1 - No interrupts WRREG3: EQU 11000001B ;WR3 - Rx 8 bits/char, Rx enable WRREG4: EQU 01000100B ;WR4 - 16x, 1 stop bit, no parity ; ; WR5: DTROFF: EQU 01101000B ;DTR off, Tx 8 bits, Tx enable, RTS off DTRON: EQU 11101010B ;DTR on, Tx 8 bits, Tx enable, RTS on ; ; ; The following are SPORT status masks ; ; RR0: DAV: EQU 00000001B ;Data available TBMT: EQU 00000100B ;Transmit buffer empty DCD: EQU 00001000B ;Data carrier detect RI: EQU 00100000B ;Ring Indicator (DARTs only) ; ; ; RR1: OE: EQU 00100000B ;Overrun error FE: EQU 01000000B ;Framing error ERR: EQU OE+FE ;Overrun and framing errors ; IF KAYPRO ; ; 8116 (on Kaypros at least) is initialized by system on cold boot, ; only need to set baud rate as single command to baud rate port. ; BD110: EQU 02H BD300: EQU 05H BD600: EQU 06H BD1200: EQU 07H BD2400: EQU 0AH ;2400 - 19.2 K baud values BD4800: EQU 0CH ;not currently supported, but could be BD9600: EQU 0EH ;used on a high speed link so are BD19K: EQU 0FH ;included for informational purposes ; ENDIF ;KAYPRO ; ; Simultaneous initialization of Modems ; IF MULTI MDINIT: MVI A,00001111B OUT 35 MVI A,01011111B OUT 33 MVI B,10 CALL DELAY MVI A,11011111B OUT 33 MVI B,10 CALL DELAY MVI A,01011111B OUT 33 MVI A,10000110B OUT 35 MVI A,01000000B OUT 33 XRA A OUT 15 MVI A,RESCHN ;Reset channel (DTR, RTS off) OUT SPORT OUT 15 MVI A,4 ;Setup to write register 4 OUT SPORT OUT 15 MVI A,WRREG4 ;set 16x clock, 1 stop bit, no parity OUT SPORT OUT 15 MVI A,1 ;Setup to write register 1 OUT SPORT OUT 15 MVI A,WRREG1 ;set no interrupts OUT SPORT OUT 15 MVI A,3 ;Setup to write register 3 OUT SPORT OUT 15 MVI A,WRREG3 ;set Rx 8 bits, enable recv OUT SPORT OUT 15 MVI A,5 ;Setup to write register 5 OUT SPORT OUT 15 MVI A,DTROFF ;leave DTR OFF initially OUT SPORT OUT 15 RET ;Return ENDIF IF MULTI ;..... ; ; The following routine will raise DTR. (and RTS) ; MDANSW: MVI A,5 ;address WR5 OUT SPORT MVI A,DTRON ;raise DTR, RTS OUT SPORT LXI H,SMXMSG CALL MDMPRT RET ;Return ; ; ; The following routine checks to make sure we still have carrier. If ; there is no carrier, it will return with the Zero flag set. ; MDCARCK: MVI A,RESSTA ;Reset status OUT SPORT IN SPORT ;Get status ANI DCD ;Check for data carrier RET ;Return ; ; ; The following routine determines if there is a character waiting to ; be received. If no character is waiting, the Zero flag will be set, ; otherwise, 255 will be returned in register A. (Error conditions are ; checked, and, if present, the character is ignored.) ; MDINST: IN SPORT ;Get status ANI DAV ;Got a character? JZ CHKT ;Return if none MVI A,1 ;else, check error bits OUT SPORT ;(address RR1) IN SPORT ;read RR1 ANI ERR ;mask error bits JZ MDINST1 ;no error, ok MVI A,RESERR ;else, reset error bits OUT SPORT IN DPORT ;clear out garbage XRA A ;say no data JMP CHKT ;and return MDINST1: ORI 0FFH ;say we got one ; RET ;...and return CHKT: PUSH PSW LDA TF2 ORA A JZ PRT IN 15 ANI DAV JZ PRT MVI A,ON STA TF4 MVI A,1 OUT 15 IN 15 ANI ERR JZ MDI MVI A,48 OUT 15 IN 13 JMP PRT MDI: IN 13 ANI 7FH STA TF3 PRT: POP PSW RET ;..... ; ; ; The following is a routine that will input one character from the ; modem port. If there is nothing there, it will return garbage... so ; use the MDINST routine first. ; ENDIF IF MULTI MDINP: IN DPORT ;Get character ANI 7FH ;Strip parity RET ;Return ;..... ; ; ; The following is a routine to determine if the transmit buffer is ; empty. If it is empty, it will return with the Zero flag clear. If ; the transmitter is busy, then it will return with the Zero flag set. ; MDOUTST: IN SPORT ANI TBMT ;Mask it RET ;Return ;..... ; ; ; The following is a routine that will output one character in register ; A to the modem. REMEMBER, that is register A, not register C. ; ; **** Use MDOUTST first to see if buffer is empty **** ; MDOUTP: OUT DPORT ;Send it MDOT: PUSH PSW LDA TF2 ORA A JZ SKOUT LR: IN 15 ANI 4 JZ LR POP PSW OUT 13 RET SKOUT: POP PSW RET ;Return ;..... ; ENDIF ;MULTI IF NOT MULTI MDINIT: MVI A,RESCHN ;Reset channel (DTR, RTS off) OUT SPORT MVI A,4 ;Setup to write register 4 OUT SPORT MVI A,WRREG4 ;set 16x clock, 1 stop bit, no parity OUT SPORT MVI A,1 ;Setup to write register 1 OUT SPORT MVI A,WRREG1 ;set no interrupts OUT SPORT MVI A,3 ;Setup to write register 3 OUT SPORT MVI A,WRREG3 ;set Rx 8 bits, enable recv OUT SPORT MVI A,5 ;Setup to write register 5 OUT SPORT MVI A,DTROFF ;leave DTR OFF initially OUT SPORT RET ;Return ;..... ; ; The following routine will raise DTR. (and RTS) ; MDANSW: MVI A,5 ;address WR5 OUT SPORT MVI A,DTRON ;raise DTR, RTS OUT SPORT LXI H,SMXMSG CALL MDMPRT RET ;Return ; ; ; The following routine checks to make sure we still have carrier. If ; there is no carrier, it will return with the Zero flag set. ; MDCARCK: MVI A,RESSTA ;Reset status OUT SPORT IN SPORT ;Get status ANI DCD ;Check for data carrier RET ;Return ; ; ; The following routine determines if there is a character waiting to ; be received. If no character is waiting, the Zero flag will be set, ; otherwise, 255 will be returned in register A. (Error conditions are ; checked, and, if present, the character is ignored.) ; MDINST: IN SPORT ;Get status ANI DAV ;Got a character? RZ ;Return if none MVI A,1 ;else, check error bits OUT SPORT ;(address RR1) IN SPORT ;read RR1 ANI ERR ;mask error bits JZ MDINST1 ;no error, ok MVI A,RESERR ;else, reset error bits OUT SPORT IN DPORT ;clear out garbage XRA A ;say no data RET ;and return MDINST1: ORI 0FFH ;say we got one RET ;...and return ;..... ; ; ; The following is a routine that will input one character from the ; modem port. If there is nothing there, it will return garbage... so ; use the MDINST routine first. ; MDINP: IN DPORT ;Get character ANI 7FH ;Strip parity RET ;Return ;..... ; ; ; The following is a routine to determine if the transmit buffer is ; empty. If it is empty, it will return with the Zero flag clear. If ; the transmitter is busy, then it will return with the Zero flag set. ; MDOUTST: IN SPORT ANI TBMT ;Mask it RET ;Return ;..... ; ; ; The following is a routine that will output one character in register ; A to the modem. REMEMBER, that is register A, not register C. ; ; **** Use MDOUTST first to see if buffer is empty **** ; MDOUTP: OUT DPORT ;Send it RET ;Return ;..... ENDIF ;NOT MULTI ; ; These next routines set the proper baud rates for the modem. If you ; do not support the particular rate, then simply put the label in front ; of the ORI 0FFH / RET. If the baud rate change was successful, make ; SURE the Zero flag is set (XRA A). ; IF CTC ; SET300: MVI A,BDCMD1 ;Get first byte of command OUT BPORT ;send it MVI A,BD300 ;Load rate JMP SETBAUD ; SET1200: MVI A,BDCMD2 ;Get first byte of command OUT BPORT ;send it MVI A,BD1200 ;Load rate ; SETBAUD: OUT BPORT ;Send 2nd byte of command (rate) XRA A ;Say rate is OK RET ;Return ; ; The following routine returns a 255 because we were not able to set to ; the proper baud rate because either the serial port or the modem can't ; handle it. ; SET110: SET450: SET600: SET710: ORI 0FFH ;Make sure zero flag is not set RET ;Return ; ENDIF ;CTC ;..... ; ; IF C8116 ; SET110: MVI A,BD110 JMP SETBAUD ; SET300: MVI A,BD300 JMP SETBAUD ; SET600: MVI A,BD600 JMP SETBAUD ; SET1200: MVI A,BD1200 ; SETBAUD: OUT BPORT ;set baud rate XRA A ;say rate ok RET ;and return ; ; The following rates, (450 & 710), are not supported for the 8116/SIO ; SET450: SET710: ORI 0FFH ;say rate ng RET ; ENDIF ;C8116 ;..... ; ; Ok, that's all of the modem dependent routines that MBYE uses, so if ;cbase equ 0e0h ;cyear equ 1985h ; you patch this file into your copy of MBYE, then it should work out CLOCK: push PSW PUSH H PUSH D PUSH B ; EQLOOP: LXI H,RTCBUF CALL RDCLOCK LXI H,TRTCBUF CALL RDCLOCK ; LXI H,RTCBUF LXI D,TRTCBUF MVI B,5 CMPLP: LDAX D CMP M JNZ EQLOOP INX H INX D DCR B JNZ CMPLP ; POP B POP D POP H POP PSW RET ; TRTCBUF: DB 99H,99H,99H,99H,99H,0,0 ; RDCLOCK: MVI A,15 OUT 22H MVI A,4 OUT 20H IN 24H MOV M,A INX H MVI A,3 OUT 20H IN 24H MOV M,A INX H MVI A,2 OUT 20H IN 24H MOV M,A INX H MVI A,7 OUT 20H IN 24H MOV M,A INX H MVI A,6 OUT 20H IN 24H MOV M,A RET ; ENDOBJ: ; ; Program version number message. ; VMSG: DB CR,LF,'MBO - 9/23/86 - AMY <> BBS' IF MULTI DB cr,lf,cr,lf,'K4+13 - Hayes, Internal, RAM DISK, KP Clk',CR,LF,0 ENDIF IF NOT MULTI DB CR,LF,CR,LF,'K4+13 - SM1200, Ram Disk, KP Clk',cr,lf,0 ENDIF ; ; Clear screen string. ; CLRSMSG: ;put clear screen control code or DB 'Z'-40H ;escape sequence here, end with 0 DB 0 ; IF PRNTGB GBMSG: DB ' Minutes on system.' DB CR,LF,CR,LF,0 ENDIF ;PRNTGB ; RS1MSG: DB CR,LF,'OPTION? A)ns, ' IF COMFILE DB 'C)om, E)xec, ' ENDIF DB 'R)sm, ' IF USRLOG DB 'Z)ro',0 ENDIF ; IF USRLOG ATMSG: DB CR,LF,' Attempts: ',0 SUMSG: DB CR,LF,' Logons: ',0 ENDIF ; IF LGONMSG LOGMSG: DB CR,LF,'MBBS Headquarters RCP/M' DB CR,LF,0 ENDIF ;LGOMSG ; ; ; Access password (ends in carriage return) - keep password here ; IF PWRQD PASSWD: DB 'DDT' ;the password itself DB CR ;end of password, CR-only to erase it ; ; ; (Allow room for larger password to be patched in) ; DB 0,0,0,0,0,0,0,0,0,0,0,0,0 ; PWMSG: DB CR,LF,'Enter password: ',0 WRGMSG: DB CR,LF,'Incorrect password',CR,LF,0 ; ENDIF ;PWRQD ; IF COMFILE LSMSG: DB CR,LF,'[Loading RDIR]',CR,LF,0 ENDIF ;COMFILE ; IF CHKDSK IDMSG: DB '++ BAD DRIVE # ++',0 ENDIF ; IF CPM2 AND CHKUSR IUMSG: DB '++ BAD USER # ++',0 ENDIF ; CLMSG: DB CR,LF,'[Disconnect]',CR,LF,7,7,0 ; IF TIMEOUT ITOMSG: DB CR,LF,'[Input timed out]',CR,LF,7,0 ENDIF ;TIMEOUT ; IF RTC AND TIMEUP TIMUPM: DB CR,LF,' Sorry, time`s up',CR,LF,7 DB ' Call again soon!',CR,LF,7,0 MINMSG: DB CR,LF,'[',0 RTCFLG: DB 0 ENDIF ; IF RTC AND TIMEUP WARNM: DB CR,LF,' Two minutes left!',CR,LF,0 ENDIF ; IF FKEYS ; MFSMSG: DB CR,LF,'Message from Sysop: ',0 ; BONMSG: DB CR,LF,'[Bell ON]',CR,LF,0 ; BOFMSG: DB CR,LF,'[Bell OFF]',CR,LF,0 ; UONMSG: DB CR,LF,'[Rmt ON]',CR,LF,0 ; UOFMSG: DB CR,LF,'[Rmt OFF]',CR,LF,0 ; CHTMSG: DB 26,CR,LF,CR,LF,CR,LF,' ------===> Let',39,'s Chat! <===------' DB CR,LF,CR,LF,'?> Hi!',CR,LF,CR,LF CHTPMT: DB '?> ',0 ; CLCHT: DB 27,'=',56,85,24,CR,LF DB 27,'=',55,32,0 ; CHTXMSG:DB CR,LF,CR,LF,' See you later . . .',CR,LF,CR,0 ; PTTON: DB 27,66,54,27,'=',56,87,'[',0 ; PTTOFF: DB ']',27,67,54,0 ; EXONMSG:DB 27,66,54,27,'=',56,33,27,66,50,27,66,48 DB ' EXIT ',27,67,48,27,67,50,CR,LF DB 27,67,54,0 ; EXOFMSG: DB 27,66,54,27,'=',56,32,' ',CR,LF DB 27,67,54,0 ; EXMSG: DB 7,26,7,26,7,26,7,26,7,0 ; ENDIF ;FKEYS ; IF NOT MBBS ; CURUSR: DS 0 ;to avoid Undefined label if not MBBS, ;can be expanded and used by another BBS ;system, if you wish ; ENDIF ; LFMSG: DB CR,LF,0 ; IF PRNTWB WBMSG: DB CR,LF,0,0,0,0,0 ;INCLUDE NULLS IF NEEDED DB CR,LF,0,0,0,0,0,'ZCPR2' ;AT HIGHEST SPEED ON SOME DB CR,LF,0,0,0,0,0 ;SYSTEMS DB 80H ;ENDING CHARACTER = 80H ; ; ENDIF ;PRNTWB ; IF SMODEM OR SM1200 OR ANCHOR OR USR ;SMARTMODEM CMD STRINGS ; SMOFMSG: DB 'ATH1M0',CR,80H ; SMEMSG: DB 3,3,3,80H ; SMAMSG: DB 'ATA',CR,80H ; SMHMSG: DB 'ATH0',CR,80H ; SMQMSG: DB 'ATZ',CR,80H ; SMXMSG: DB 'AT S10=30',CR,LF,0 ; SMZMSG: DB 'AT S0=0',CR,80H ; BELMSG: DB 7,26,7,26,7,0 ; BLLMSG: DB 7,0 ENDIF OTMSG: DB CR,LF,'[Connect!]',CR,LF,0 FTMSG: DB CR,LF,'[Failed]',CR,LF,0 ; IF COMFILE OR EXFILE PTSMSG: DB 'P A T S',7,0 ; CNFMSG: DB CR,LF DB '++ NO RDIR! ++',7,0 ; ENDIF ;COMFILE OR EXFILE ; IF WELFILE WELFILN:DB 0,'WELCOME ' ;welcome file name, must be 11 chars. ; ^^^^^^^^^^^ DB 0 ENDIF ; IF COMFILE AND NOT MBBS COMFCB: DB 0,'RDIR COM' ;.COM file name, must be 11 chars. ; ^^^^^^^^^^^ DS 21 ;rest of .COM FCB ENDIF ;COMFILE ; IF EXFILE EXFCB: DB 0,'BYE COM' ;exit filename, must be 11 chars. DS 21 ;rest of exit fcb ENDIF ;EXFILE IF MULTI GOFCB: DB 0,'MULTI COM' DS 21 ENDIF IF NOT MULTI GOFCB: DB 0,'RBBS COM' DS 21 ENDIF ; ;RTCBUF: ; ; Real-Time clock buffer - convert (if necessary) and poke the proper ; BCD values into this area in your CLOCK routine if you have an RTC. ; ; (NOTE: 99:99:99 INDICATES CLOCK IS NOT RUNNING OR NO RTC IS AVAILABLE) ; ; IF RTC OR MBBS ; ; DB 99H,99H,99H ;HH:MM:SS (BCD 24HR TIME) 00:00:00-23:59:59 ; DB 99H,99H ;YYYY/MM/DD (BCD ISO DATE) ; DW 0000H ;MMMM (SWAPPED BCD) (TOTAL MINS ON SYSTEM) ; ENDIF ; ; These areas are not initialized ; PEND: ;The following area is not initialized ; IF COMFILE OR EXFILE CURRFCB:DS 2 ENDIF ;COMFILE OR EXFILE ; OPTION: DS 1 ;SAVE BYE /OPTION HERE ; ; IF FKEYS OR (RTC AND MBBS) EXFLG: DS 1 ;0 IF MODEM I/O DISABLED PMTFLG: DS 1 WWFLAG: DS 1 TIMEIT: DS 1 CHTFLG: DS 1 IF MULTI TF3: DS 1 TF4: DS 1 LDFLG: DS 1 ENDIF ; IF DUAL$IO AND FKEYS SAVFLG: DS 1 SAVBYT: DS 1 ENDIF ;DUAL$IO AND FKEYS ; IF TIMEOUT TOCNT: DS 2 ENDIF ;TIMEOUT ; ; ; Save the CP/M jump table here ; VCOLDBT: DS 3 VWARMBT: DS 3 VCONSTAT:DS 3 VCONIN: DS 3 VCONOUT: DS 3 VLISTOUT:DS 3 VPUNCH: DS 3 VREADER: DS 3 ; ; ; Since these areas are not initialized, the following counters will not ; be changed by subsequent loads of this program ; IF USRLOG USRFLG: DS 2 ;= '*U' (DW 55AAH) if initialized OLDUSR: DS 2 NEWUSR: DS 2 ENDIF ; IF USRLOG AND CALLBAK NONUSR: DS 2 ENDIF ; IF RKEYS BYTEA: DS 2 BYTEB: DS 1 ENDIF ; DS 80 STACK: DS 3 ;local stack ; OBJEND: ; IF BYELOW OOPS: EQU NO ;don't worry bout below if BYELOW ENDIF ; IF NOT BYELOW ; ; This should trap any problems... You can select fewer BYE options or ; move your system up some more if you get the message below at assembly ; time... (THIS CODE IS ONLY FOR BYE RUNNING ABOVE THE BIOS, (BYELOW NO)) ; BYESIZE: EQU OBJEND-BEGOBJ ;(used below to trap dangerous BYESTRT: EQU RAMTOP-BYESIZE+1 ;stomp on the BIOS condition...) GAP: EQU BYESTRT-BIOSEND ;if GAP is negative, OOPS: EQU (GAP AND 8000H) SHR 15 ;then OOPS will equ 1 (TRUE) ; ENDIF ; IF OOPS ; !!! DANGER, DANGER, WILL ROBINSON... BIOS STOMPER !!! ENDIF ;..... ; ; FINI, (or is it only... nah, it's the end...) ; END