home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
simtel
/
sigm
/
vols000
/
vol093
/
modem798.asm
< prev
next >
Wrap
Assembly Source File
|
1984-04-29
|
85KB
|
4,721 lines
TITLE 'CP/M MODEM PROGRAM Version 7.98 12/31/82'
;
;THE FOLLOWING IS AN EXTENSIVE REVISION OF THE CP/M MODEM PROGRAM
;CREATED BY WARD CHRISTENSEN FOR THE CP/M USERS LIBRARY. IT ALSO
;INCORPORATES ROUTINES FOUND IN THE POTOMAC MICRO-MAGIC MODEM
;MANUAL WHICH MAY BE USED IF YOU HAVE A PMMI MODEM BOARD.
;
; ********* N O T I C E S *********
;
; Revisers releasing new versions should only
; change the version number by 1 digit in the
; last place.
;
; Except for PMMI routines, revisers should
; only make nonspecialized changes for
; distribution. Please make configuration files,
; such as MCNFG7xx.ASM and MCOSB7xx.ASM, for
; particular computers, uarts or modems.
;
; **********************************
;
;##### This file requires MODEM797.LIB and MAC.COM to assemble. #####
;
;##### The file MCNFG797.ASM can be used to overlay the HEX #####
;##### or COM file versions with your own modem routines and #####
;##### configuration options. The file MODEM797.SET can be used #####
;##### as a reference for directly setting the modem equates #####
;##### and configuration options with the S command in DDT. #####
;
;Fix log in MODEM797.HIS
;
;
MACLIB MODEM797 ;Contains the CMDLINE, INBUF, INLNCOMP,
;DIRLIST, SENDTIME, PRTBAUD, and MFACCESS
;routines.
;
;Note that the library has not been changed since version 7.97.
;
;
TRUE EQU 0FFH
FALSE EQU 0
;
CPM2X EQU TRUE ;TRUE IF CP/M 2.X
DBUFSIZ EQU 16 ;BUFFER SIZE FOR FILE TRANSFER IN KBYTES
;
ERRCRC EQU 6 ;NUMBER OF TIMES TO TRY CRC MODE BEFORE
;SWITCHING TO CHECKSUM
ERRLIM EQU 10 ;NUMBER OF TIMES TO RETRY
;SEND/RECEIVE ERRORS BEFORE QUIT
;
; PMMI EQUATES
PORT EQU 0C0H ;PMMI BASE ADDRESS
;
MODCTLP EQU PORT ;MODEM CONTROL PORT
MODDATP EQU PORT+1 ;MODEM DATA PORT
BAUDRP EQU PORT+2 ;BAUD RATE PORT
MODCTL2 EQU PORT+3 ;2ND MODEM CONTROL PORT
MODRCVB EQU 02H ;MODEM RECEIVE BIT (DAV)
MODRCVR EQU 02H ;MODEM RECEIVE READY
MODSNDB EQU 01H ;MODEM SEND BIT (XMIT BUFF EMPTY)
MODSNDR EQU 01H ;MODEM SEND READY
NOPARMSK EQU 10H ;MASK TO RESET TO NO PARITY
EVPARMSK EQU 20H ;MASK TO SET EVEN PARITY
ODPARMSK EQU 0CFH ;MASK TO SET ODD PARITY
BRKMSK EQU 0FBH ;MASK TO SET BREAK
ERRCDMSK EQU 38H ;MASK TO BLOCK ALL BITS EXCEPT ERROR CODES
FRMER EQU 20H ;FRAMING ERROR MASK
ORUNER EQU 10H ;OVERRUN ERROR MASK
PARER EQU 08H ;PARITY ERROR MASK
ANSWMOD EQU 1EH ;ANSWER MODE
ORIGMOD EQU 1DH ;ORIGINATE MODE
WAITCTS EQU 255 ;NUMBER OF SECONDS X 10 TO WAIT FOR COMPUTER
;TONE AFTER PMMI AUTO-DIAL FUNCTION 255 MAX.
;
CRC EQU 'C' ;USED TO REQUEST 'CRC' INSTEAD OF 'CKSUM'
ESC EQU '['-40H ; ^[ = ESCAPE
SOH EQU 'A'-40H ; ^A = START OF HEADER
EOT EQU 'D'-40H ; ^D = END OF TEXT
ACK EQU 'F'-40H ; ^F = ACKNOWLEDGE
OKNMCH EQU 'F'-40H ; ^F = OKAY 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
CAN EQU 'X'-40H ; ^X = CANCEL SEND/RECEIVE
EOFCHAR EQU 'Z'-40H ; ^Z = END OF FILE
BDNMCH EQU 75H ; BAD NAME MATCH
RUB EQU 7FH ; RUB
;
BOTTRAM SET LAST+100H AND 0FF00H
;
ORG 0100H
;
JMP START
;
;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.
;
PMMIBYTE: DB TRUE ;true=PMMI modem
SETUPTST: DB FALSE ;true=non-PMMI setup routine
SCRNTEST: DB FALSE ;true=if home cursor and clear screen
;routine at CLRSCRN
CLOCK: DB 4 ;clock speed in MHz, 8 MHz maximum
BAKUPBYTE: DB FALSE ;true=make .BAK file
CKSUMDFLT: DB FALSE ;true=default to Checksum checking
;false=default to CRC checking
TOGGLECRC: DB TRUE ;true=allow toggling of Checksum to CRC
CONVBKSP: DB FALSE ;true=convert backspace to rub
TOGGLEBK: DB TRUE ;true=allow toggling of bksp to rub
ADDLF: DB FALSE ;true=add LF after CR
TOGGLELF: DB TRUE ;true=allow toggling of LF after CR
TRANLOGON: DB FALSE ;true=allow transmission of logon
;write logon sequence at location LOGON
SAVCCP: DB TRUE ;true=do not overwrite CCP
LOCONEXTCHR: DB FALSE ;true=local command if EXTCHR precedes
;false=not local command if EXTCHR precedes
TOGGLELOC: DB TRUE ;true=allow toggling of LOCONEXTCHR
LSTTST: DB TRUE ;true=allow toggling of printer on/off
;in terminal mode. Set to false if your
;printer can't keep up with the modem
XOFFTST: DB FALSE ;true=allow testing of XOFF from remote
;while transmitting a file in terminal mode
XONWAIT: DB FALSE ;true=wait for XON after sending CR while
;transmitting a file in terminal mode
TOGXOFF: DB TRUE ;true=allow toggling of XOFF/XON testing
MSPEED: DB 1 ;sets the display time to send a file
;0=110 1=300 2=450 3=600 4=710 5=1200
;6=2400 7=4800 8=9600
BYTDLY: DB 0 ;default time to send character in
;terminal mode file transfer
;0=0 delay, 1=0.02 sec, -- ,9=0.18 sec
CRDLY: DB 0 ;default time for extra wait after CR
;in terminal mode file transfer
;0=0 delay, 1=0.02 sec, -- ,9=0.18 sec
BELRPT: DB 30 ;bell repeat time = value*0.03 sec
EXITCHR: DB 'E'-40H ; ^E = Exit without disconnect
LOGCHR: DB 'O'-40H ; ^O = Send logon
LSTCHR: DB 'P'-40H ; ^P = Toggle printer
UNSAVECHR: DB 'R'-40H ; ^R = Close input text buffer
TRANCHR: DB 'T'-40H ; ^T = Transmit file to remote
SAVECHR: DB 'Y'-40H ; ^Y = Open input text buffer
EXTCHR: DB '^'-40H ; ^^ = Send next character
;
;Equates used only by PMMI routines grouped together here.
PULSERATE: DB 125 ;125 for 20pps, 250 for 10pps on PMMI
;not used if PMMI FALSE
CLDBOOT: DW 00000H ;currently set to warm boot with
;BYE routine for PMMI, put your cold
;boot entry here if you have one and
;desire to do on BYE
BRKCHR: DB '@'-40H ; ^@ = Transmit "BREAK" with PMMI
CHGBAUD: DB 'B'-40H ; ^B = Used with PMMI in terminal
; mode to change baud rate on fly
DISCCHR: DB 'D'-40H ; ^D = PMMI Disconnect
;
;
IN$MODCTLP: IN MODCTLP ! RET ;in modem control port
OUT$MODDATP: OUT MODDATP ! RET ;out modem data port
IN$MODDATP: IN MODDATP ! RET ;in modem data port
ANI$MODSNDB: ANI MODSNDB ! RET ;bit to test for send ready
CPI$MODSNDR: CPI MODSNDR ! RET ;value of send bit when ready
ANI$MODRCVB: ANI MODRCVB ! RET ;bit to test for receive ready
CPI$MODRCVR: CPI MODRCVR ! RET ;value of receive bit when ready
;
;THE FOLLOWING ARE TYPICALLY USED ONLY BY PMMI
IN$BAUDRP: IN BAUDRP ! RET ;in baudrate port
OUT$BAUDRP: OUT BAUDRP ! RET ;out baudrate port
OUT$MODCTL2: OUT MODCTL2 ! RET ;out modem control port #2
OUT$MODCTLP: OUT MODCTLP ;out modem control port
STA UARTCTLB ! RET ;and store control byte
;
LOGONPTR: DW LOGON
JMP$INITMOD: JMP INITMOD
JMP$SETUPR: JMP SETUPR
;Clear sequences are for H19. Change to yours.
CLREOS: CALL JMP$ILPRT
DB ESC,'J',0,0,0
RET
CLRSCRN: CALL JMP$ILPRT
DB ESC,'E',0,0,0
RET
;
;NEXT THREE LINES SHOULD NOT BE CHANGED BY USER OVERLAY
JMP$ILPRT: JMP ILPRT
JMP$ILCOMP: JMP ILCOMP
JMP$INBUFF: JMP INBUFF
JMP$SYSVER: JMP SYSVER
JMP$DIALPL: JMP DIALPL
JMP$DISCONNT: JMP DISCONNT
;
SYSVER:
LDA PMMIBYTE ;USING THE PMMI S-100 MODEM?
ORA A
JZ SYSVER1 ;GO IF NOT
CALL ILPRT
DB 'Version for: PMMI S-100 MODEM Starting at Port ',0
LDA IN$MODCTLP+1
CALL HEXO
CALL ILPRT
DB 'H',CR,LF,0
RET
;
SYSVER1:
CALL ILPRT ;IF NOT USING THE PMMI S-100 BOARD
DB 'Version for: Non-PMMI MODEM',CR,LF,0
RET
;
;INSERT YOUR LOGON HERE, MUST END IN 0.
LOGON: DB 0
;
;INSERT YOUR INITIALIZATION ROUTINE HERE IF NEEDED.
;CAN REPLACE THE FOLLOWING SECTION WHICH IS PRESENTLY
;USED FOR THE PMMI BOARD.
;
INITMOD:
LDA PMMIBYTE
ORA A
RZ
LDA ANSWFLG ;IF ANSWER OR ORIGINATE MODE..
ORA A ;..IS NOT REQUESTED OR NO..
JNZ SKIPB1 ;..BAUDRATE SPECIFIED, THEN..
CALL GETBAUD ;..ROUTINE RETURNS WITH CHANGE..
JMP FIXBAUD ;..OF BAUD. IF OPT REQUESTED,..
;
SKIPB1: LDA ORIGFLG ;..A BLANK FORCES 300 BAUD..
ORA A ;..ELSE A 0 FROM NEWBAUD..
RNZ ;..FORCES 300 BAUD.
CALL GETBAUD
FIXBAUD:
CALL OUT$BAUDRP
CALL CHGMSPD
MOV A,C
STA MSPEED
MOV A,B
CPI 52
MVI A,5FH
JC GT300
MVI A,7FH
GT300: CALL OUT$MODCTL2
STA MODCTLB ;SAVE MODEM CONTROL BYTE
LDA ORIGFLG
ORA A
MVI A,ORIGMOD
JZ OFFHOOK
LDA ANSWFLG
ORA A
MVI A,ANSWMOD
RNZ
OFFHOOK:
LXI H,4000
OFFDLY: DCR L
JNZ OFFDLY
DCR H
JNZ OFFDLY
CALL OUT$MODCTLP
RET
;
GETBAUD:
LDA FCB+9
CPI ' '
MVI A,52
RZ
LDA FCB+9
CPI 0
MVI A,52
RZ
LXI D,FCB+9
LXI H,0
DECLP: LDAX D
INX D
CPI ' '
JZ DECLP
CPI '0'
JC BADRATE
CPI '9'+1
JNC BADRATE
SUI '0'
MOV B,H
MOV C,L
DAD H
DAD H
DAD B
DAD H
ADD L
MOV L,A
JNZ DIGNC
INR H
DIGNC: MOV A,E
CPI FCB+12
JNZ DECLP
MOV A,H
CMA
MOV D,A
MOV A,L
CMA
MOV E,A
INX D
LXI H,15625
LXI B,-1
DIVLP: INX B
DAD D
JC DIVLP
MOV A,B
ORA A
MOV A,C
RZ
BADRATE:
CALL ERXIT
DB '++ Invalid baud rate ++$'
;
CHGMSPD: ;CHANGES MSPEED FOR 110-710 BAUD
MVI C,0 ;CONTAINS MSPEED
MOV B,A ;SAVE BAUD RATE DIVISOR
CPI 100 ; < 300 BAUD
RNC
INR C
CPI 40 ; < 450 BAUD
RNC
INR C
CPI 30 ; < 600 BAUD
RNC
INR C
CPI 24 ; < 710 BAUD
RNC
INR C ;MUST BE 710 BAUD
RET
;
;DIALING ROUTINES TAKEN (AND GREATLY MODIFIED) FROM PMMI MANUAL.
;MODEM CONTROL COMMAND WORDS
;
CLEAR EQU 3FH ;IDLE MODE
MAKEM EQU 1 ;TELE LINE MAKE (OFF HOOK)
BRKM EQU 0 ;TELE LINE ON HOOK (BREAK DURING DIALING)
DTMSK EQU 1 ;DIAL TONE MASK
RBLMT EQU 70 ;# OF SEC*10 TO WAIT BEFORE GIVING NO RING HEARD MSG
RBWAIT EQU 50 ;# OF SEC*10 DELAY BEFORE REDIALING NUMBER
TMPUL EQU 80H ;TIMER PULSES MASK BIT
TRATE EQU 250 ;VALUE FOR 0.1 SECOND
;
DIALPL:
LDA PMMIBYTE ;FLAG FOR PMMI OPERATION
ORA A ;SET FLAGS
RZ ;PMMI FALSE, RETURN
XRA A ;0
STA CRFLAG ;CONTINUOUS REDIAL FLAG
DPL1: LXI H,CMDBUF+1 ;POINT # OF CHARS IN BUFF
MOV A,M ;GET # OF CHARS
CPI 4 ;4 OR MORE CHARS TYPED BEFORE <CR>?
JC ENTNUM ;NO, ASK FOR NUMBER
LXI H,CMDBUF+6 ;POINT TO NUMBER TO DIAL
JMP DIAL10 ;CHECK IF LIB #, & DIAL
;
DIALPL0:
CALL DISCONNT
CALL ILPRT
DB CR,LF,'Waiting for dial tone',CR,LF,0
MVI A,MAKEM ;MAKE MAKE (OFF-HOOK)
CALL OUT$MODCTLP ;DO IT
MVI D,DTMSK ;DIAL TONE MASK
MVI C,100 ;10 SECOND WAIT
CALL WAIT ;WAIT FOR DIAL TONE
NOP ;DELAY
;
; WAIT SUBROUTINE WILL RETURN WITH CARRY SET IF UNABLE TO
; GET DIALTONE, ELSE CARRY NOT SET MEANS DIALTONE RECEIVED
;
RNC ;IF DIAL TONE WITHIN 10 SECONDS
CALL ILPRT ;ELSE, MESSAGE AND RETURN WITH CARRY SET
DB CR,LF,'<< No dial tone >>',CR,LF,0
CALL DISCONNT
STC
RET
;
;THIS IS ALL THE SET-UP FOR THE PRINT AT 'ENTNUM2'.
;
ENTNUM:
MVI C,13 ;NUMBER OF LINES TO MOVE
LXI H,NUMBLIB ;ADDRESS OF SOURCE MEMORY
LXI D,DBUF ;ADDRESS OF TARGET MEMORY
CALL NEWLINE ;START WITH CRLF
STAX D ;+LF
INX D ;AND BUMP IT
ENTNUM1:
MVI B,32 ;NUMBER OF BYTES TO MOVE
CALL MOVE ;MOVE TO BUFFER
CALL SPACES ;2 ENTRIES + 3 SPACES = 67 CHARACTERS
MVI B,32
CALL MOVE
CALL NEWLINE
DCR C ;NUMBER OF LINES TO PRINT
JZ ENTNUM2
JMP ENTNUM1
;
ENTNUM2:
MVI A,'$'
STAX D
CALL CLRTST
MVI C,PRINT
LXI D,DBUF ;POINT TO TABLE OF NUMBERS TO PRINT
CALL BDOS
CALL ILPRT
DB CR,LF,'Enter number or library letter - <CR> when finished,'
DB CR,LF,'Ctrl-X cancels while dialing: ',0
LXI D,CMDBUF
CALL INBUFF
DIALLP1:
LDA CMDBUF+1
ORA A ;NULL MEANS <CR> WAS TYPED
JZ BORTIT ;ABORT DIALING, RETURN TO MENU
LXI H,CMDBUF+2 ;FIRST TYPED CHAR OF NUMBER TO DIAL
;
; ENTER THIS ROUTINE WITH HL POINTING TO NUMBER TO DIAL
;
DIAL10:
PUSH H ;SAVE HL
CALL DIALPL0 ;DISCONNECT, RECONNECT, WAIT FOR DIAL TONE
POP H ;GET HL
JC DILAGN ;NO DIALTONE?, ASK RETRY
MVI B,'A' ;FIRST LETTER OF ALPHABET
MVI E,0 ;COUNTS NUMBER OF LETTERS TO MATCH
MVI C,26 ;NUMBER OF LETTERS IN ALPHABET
MOV A,M ;GET CHAR BUFFER
DIAL11:
CMP B ;NUMBER FROM TABLE?
JZ LIBSET
INR B ;MAKE NEXT LETTER (A-Z)
INR E ;COUNT UP
DCR C ;COUNT DOWN
JZ DIALLPX ;NOT A LETTER
JMP DIAL11 ;LOOP
;
LIBSET:
LXI H,NUMBLIB ;PHONE NUMBER LIBRARY
LXI B,32 ;LENGTH OF LIBRARY ENTRY
MOV A,E ;NUMBER OF TIMES TO ADD 32 TO HL
ORA A ;SET FLAGS
JZ DIAL13
DIAL12:
MOV A,M ;GET FIRST CHAR OF SELECTED LIB ENTRY
ORA A ;SET FLAGS
JZ DIALLPA ;SEND BAD LIBRARY MSG AND ABORT
DAD B ;INCREMENT HL BY 32
DCR E ;COUNTDOWN
JNZ DIAL12 ;NOT THERE YET, LOOP
DIAL13:
MVI B,32 ;NUMBER OF CHARACTERS TO GET FROM TABLE
LXI D,CMDBUF+1 ;POINT TO BUFFER
XCHG ;HL POINTS TO CMDBUF+1
MOV M,B ;STORE # OF BYTES IN A TABLE ENTRY
XCHG ;RESTORE REG.
INX D ;POINT TO FIRST CHAR POSITION IN BUFFER
CALL MOVE ;MOVE TABLE ENTRY TO BUFFER
DIALLPX:
LDA CMDBUF+1
MOV E,A ;NUMBER OF CHARS IN BUFF
LXI H,CMDBUF+2 ;POINT FIRST CHAR
DIALLP2:
MOV A,M ;GET FIRST # FROM BUFFER
ORA A ;SET FLAGS
JNZ NOBLMSG
;
; PRINT BAD LIBRARY MESSAGE AND ABORT IF NULL ENCOUNTERED
DIALLPA:
CALL ILPRT
DB CR,LF,'++ Bad library number called ++',CR,LF,0
JMP BORTIT ;ABORT
;
; DIAL A DIGIT, CHECK KBD FOR ABORT
;
NOBLMSG:
CALL DIAL ;DIAL IT
CALL STAT ; KEYPRESS?
ORA A ;SET FLAGS
CNZ KEYIN ;YES, GO GET IT
CPI CAN ;^X?
JZ BORTIT ;YES, ABORT
INX H ;BUMP POINTER
PUSH D ;SAVE DE
PUSH H ;SAVE HL
MVI B,1 ;WAIT 1 TIME INTERVAL
CALL TIMER
POP H ;RESTORE HL
POP D ;RESTORE DE
DCR E ;COUNT DOWN CHARS IN BUFF
JNZ DIALLP2 ;NOT DONE, LOOP
JZ DIALDN ;DIALING DONE
DISCONNT:
XRA A ;0
CALL OUT$MODCTL2 ;CLEAR DAV, ESD, ETC
CALL OUT$MODCTLP ;HANG-UP
PUSH B
MVI B,8 ;WAIT FOR PMMI TO DISCONNECT
CALL TIMER
POP B
RET
TIMER:
MVI A,TRATE ;TRATE 250, VALUE FOR .1 SEC INTERVAL
CALL OUT$BAUDRP ;B-REG CONTAINS NUMBER OF .1 SEC INTERVALS
TIMES:
CALL IN$BAUDRP ;TO COUNT
ANI TMPUL
JZ TIMES ;WAIT FOR TIMER TO GO HIGH
TIMEE:
CALL IN$BAUDRP
ANI TMPUL
JNZ TIMEE ;WAIT FOR TIMER TO GO LOW
DCR B
JNZ TIMES
RET
BORTIT:
CALL DISCONNT
CALL CRLF
JMP MENU
;
;AUTO DIALER
;
DIAL:
CALL TYPE ;PRINT WHATEVER CHARACTER, DASHES, ETC.
CPI 30H
RC ;DIGIT MUST BE AT LEAST 0..
CPI 'R' ;COULD IT BE A RINGBACK CHARACTER
JNZ DIAL1 ;NO? - JUMP
PUSH PSW ;SAVE ACCUMULATOR & FLAGS
MOV A,E ;GET # OF CHAR LEFT INTO ACC.
CPI 01H ;IS THIS THE LAST CHARACTER?
JZ RINGBK ;IF SO, IT MUST BE RINGBACK CHAR - DO RINGBACK
POP PSW ;EVERYTHING BACK AS IT WAS
DIAL1: CPI 3AH
RNC ;..AND NOT MORE THAN 9
ANI 0FH ;STRIP ASCII -- COULD ALSO DO SUI 30H ('0')
JNZ DIALS
MVI A,10 ;CONVERT ZERO TO 10 PULSES
DIALS: MOV C,A
LDA PULSERATE ;CONTAINS VALUE FOR DIAL SPEED
CALL OUT$BAUDRP
DIALC: CALL IN$BAUDRP
ANI TMPUL
JNZ DIALC
DIALB: CALL IN$BAUDRP
ANI TMPUL
JZ DIALB
MAKEP: MVI A,MAKEM
CALL OUT$MODCTLP
TIMEM: CALL IN$BAUDRP
ANI TMPUL
JNZ TIMEM
MVI A,BRKM
CALL OUT$MODCTLP
TIMEB: CALL IN$BAUDRP
ANI TMPUL
JZ TIMEB
DCR C
JNZ MAKEP
MVI A,MAKEM
CALL OUT$MODCTLP
MVI B,2
CALL TIMER
RET
;
RINGBK:
POP PSW ;TO GET IT OFF THE STACK
LDA CMDBUF+1 ;GET # OF CHAR IN BUFFER
SUI 01H ;SUBTRACT 1 TO AVOID THE RINGBACK CHAR
STA CMDBUF+1 ;STORE THE NEW VALUE
MVI D,DTMSK ;LOAD TONE DETECT MASK
MVI C,RBLMT ;SET TIMER FOR RBLMT NUMBER OF SECONDS
CALL WAIT
JC RBTIME ;JUMP IF NO RING DETECTED
MVI B,25 ;WAIT 2.5 SEC
CALL TIMER
CALL IN$BAUDRP ;IS TONE STILL PRESENT?
ANA D
JNZ RNGBK1
JMP DILAGN ;YES, MUST BE BUSY
;
RNGBK1:
CALL HANGP ;HANG UP THE PHONE
MVI B,RBWAIT ;WAIT X SEC
CALL TIMER
CALL DIALPL0 ;GO OFF HOOK & LISTEN FOR DIAL TONE
JNC DIALLPX ;GO REDIAL NUMBER
JMP DILAGN ;NO DIAL TONE HEARD
;
RBTIME:
CALL CRLF
JMP RNGBK1 ;HANGUP, REDIAL, & LISTEN FOR CARRIER
;
;TIME OUT ROUTINE. MUST BE CALLED WITH MASK IN D REG FOR INPUT
;AT RELATIVE PORT 2 AND NUMBER OF SECONDS * 10 IN C REG.
;
WAIT:
MVI B,1
CALL TIMER ;WAIT FOR TIMER TO GO HIGH THEN LOW
CALL IN$BAUDRP ;PMMIADDR+2 (MODEM STATUS PORT)
ANA D ;(CTS or DIALTONE MASK)
RZ ;ACTIVE LOW, SO RETURN ON 0
PUSH B ;SAVE..
PUSH D ;..ACTIVE REG'S
CALL STAT ;KEYPRESS?
ORA A ;SET FLAGS
CNZ KEYIN ;YES, GET CHAR
CPI CAN ;^X?
JZ WAIT1 ;YES, DISCONNECT, JMP TO MENU
POP D ;RESTORE..
POP B ;..REGS
DCR C ;COUNT-DOWN
JNZ WAIT
STC ;SET CARRY TO INDICATE MASK NOT SET
RET
;
WAIT1:
POP D ;RESET..
POP B ;..STACK
JMP DISCON1 ;DISCONNECT
;
HANGP:
MVI A,CLEAR
CALL OUT$MODCTL2
MVI A,0
CALL OUT$MODCTLP
RET
;
DIALDN:
CALL CRLF
MVI A,07FH ;TURN ON DTR
CALL OUT$MODCTL2 ;TIMER RATE?
MVI B,1
CALL TIMER ;WAIT FOR MODEM TO TURN ON DTR
MVI A,5DH ;2 STOP BITS, NO PARITY, 8 DATA BITS
CALL OUT$MODCTLP
MVI D,4 ;CLEAR TO SEND MASK
MVI C,WAITCTS ;WQAIT TIME FOR CTS (25.5 SEC MAX)
CALL WAIT
JNC CONMADE ;CONNECTION MADE
CALL DISCONNT
DILAGN: LDA CRFLAG ;CONTINUOUS REDIAL FLAG
ORA A
JNZ DILAGN0
CALL ILPRT
DB CR,LF,'No answer after time-out. Redial? (Y/N/C): ',BELL,0
CALL KEYIN ;GET RESPONSE
CALL TYPE ;ECHO IT
CALL UCASE ;ANI 5FH
CALL CRLF ;NEW LINE
CPI 'N' ;REDIAL?
JZ MENU ;NO, GO MENU
CPI 'Y' ;REDIAL?
JZ DILAGN0 ;YES, REDIAL
CPI 'C' ;CONTINUOUS REDIAL?
JNZ DILAGN ;INVALID RESPONSE, ASK AGAIN
XRA A
CMA ;0FFH
STA CRFLAG ;CONTINUOUS REDIAL FLAG
DILAGN0:
MVI B,70 ;7 SECONDS WAIT FOR PMMI RESET
CALL TIMER ;ELSE BUSY TONE MAY BE SENSED AS DIALTONE
LXI H,CMDBUF+1 ;CHECK IF 'CAL LIBNUM'
MOV A,M
CPI 4 ;MORE THAN 4 CHARACTERS TYPED
JC DIALLP1 ;NO, THEN GET MENU CHOICE
JMP DPL1 ;YES, THEN USE CAL LETTER
;
CONMADE:
CALL ILPRT
DB CR,LF,'Connection established - Select options: ',BELL,0
DILAGN1:
CALL STAT ;KEYPRESS?
ORA A ;SET FLAGS
JNZ GETCMD ;KEY PRESSED, GO GET OPTIONS
MVI A,BELL
CALL TYPE ;RING BELL
LXI B,2000H
DILAGN2:
DCR C
JNZ DILAGN2 ;KILL SOME TIME FOR TERMINAL TO PROCESS BELL
DCR B
JNZ DILAGN2
JMP DILAGN1 ;LOOP
;
CRFLAG: DB 0 ;CONTINUOUS REDIAL FLAG
;
; END OF PMMI ROUTINES
;
;
;THE NON PMMI SETUP ROUTINES ARE INTENDED TO COME FROM
;THE USER OVERLAY. THE FOLLOWING IS A SAFETY NET
;
SETUPR: RET
;
; PHONE NUMBER LIBRARY TABLE FOR DIALING FROM LIBRARY
; OF NUMBERS STORED IN THESE DB'S AT ASSEMBLY-TIME.
; EACH DB MUST BE 32 CHARACTERS LONG FOR PROPER OPERATION.
; A 'DB 0' INDICATES NO DIALING, PROGRAM WILL DISCONNECT
; AND RETURN TO COMMAND MODE. LAST DB MUST BE DB 0. UP TO
; 26 NUMBERS ARE ALLOWED.
;
NUMBLIB:
; '----5---10---15---20---25-----32'
DB 'A=Amrad 1-703-734-1387' ;'A'
DB 'B=Ben Bronson 1-312-955-4493' ;'B'
DB 'C=CBBS Pasadena 1-213-799-1632' ;'C'
DB 'D=PMMI 1-703-379-0303' ;'D'
DB 'E=Tech. CBBS 1-313-846-6127' ;'E'
DB 'F=Ron Fowler 1-313-729-1905R' ;'F'
DB 'G=Gasnet NASA 1-301-344-9156' ;'G'
DB 'H=Dave Hardy 1-313-846-6127' ;'H'
DB 'I=Wayne Hammerly 1-301-953-3753' ;'I'
DB 'J=RBBS Pasadena 1-213-356-1034' ;'J'
DB 'K=David Kozinn 1-216-334-4604' ;'K'
DB 'L=Program Store 1-202-337-4694' ;'L'
DB 'M=Kelly Smith 1-805-527-9321' ;'M'
DB 'N=SuperBrain Sys 1-617-862-0781' ;'N'
DB 'O=R.L.Plouffe 1-703-524-2549' ;'O'
DB 'P=K.Petersen 1-313-759-6569R' ;'P'
DB 'Q=Bruce Ratoff 1-201-272-1874' ;'Q'
DB 'R=Mark Pulver 1-312-789-0499' ;'R'
DB 'S= ' ;'S'
DB 'T= ' ;'T'
DB 'U= ' ;'U'
DB 'V= ' ;'V'
DB 'W= ' ;'W'
DB 'X= ' ;'X'
DB 'Y= ' ;'Y'
DB 'Z= ' ;'Z'
DB 0 ; end
; '----5---10---15---20---25-----32'
;
START:
LXI H,0
DAD SP ;GET CP/M'S STACK
SHLD STACK ;SAVE IT
LXI SP,STACK ;START LOCAL STACK
CALL ILPRT
DB CR,LF,'MODEM 7.98 - 12/31/82',CR,LF,0
CALL INITADR ;INITIALIZE ADDRESSES
CALL JMP$SYSVER ;GIVE CONFIGURATION MESSAGE
CALL GETUSR ;GET USER
STA SAVUSR ;SAVE FOR EXIT
MVI A,TRUE ;0FFH
STA NFILFLG
CMA ;0
STA SAVEFLG
LDA FCB+1 ;IS THERE A COMMAND TAIL?
STA OPTION
CPI ' '
JNZ START0 ;IF YES, DIGEST IT
SUB A
STA EXITFLG ;ELSE SAY WE WANT MENU
JMP START1
START0:
LXI H,80H ;SIMULATE COMMAND LINE INPUT FROM MENU
MOV B,M ;SAVE CHAR CNT
STARTA:
INX H
MOV A,M ;SKIP OVER LEADING SPACES IN COMMAND TAIL
CPI ' '
JNZ STARTB
DCR B
JMP STARTA
STARTB:
MOV A,B
STA CMDBUF+1 ;STORE COMMAND CHAR COUNT LESS LEADING SPACES
INR B ;MOVE 1 EXTRA BYTE (SHOULD BE A NULL)
LXI D,CMDBUF+2
CALL MOVE
CALL SETFCB ;DIGEST COMMAND LINE AND OPTIONS
START1:
LDA UARTFLG
ORA A
MVI A,ANSWMOD
STA UARTCTLB
JNZ RESTART
MVI A,ORIGMOD
STA UARTCTLB
;
RESTART:
LXI SP,STACK;MAKE SURE WE HAVE A CLEAN STACK
LXI D,CMDBUF+1 ;MAY BE USEFUL WHERE WE ARE GOING
LDA OPTION ;GET MAIN OPTION
MOV B,A ;SAVE IT
LDA PMMIBYTE ;PMMI?
ORA A ;SET FLAGS
MOV A,B ;GET OPTION BACK
JZ S1 ;NOT PMMI
CPI 'C' ;CALL (DIAL) FUNCTION?
JZ JMP$DIALPL ;YES, GO TO IT
CPI 'D' ;DISCONNECT?
JZ DISCON1 ;YES, DISCONNECT & GO MENU
S1: CPI ' ' ;NO OPTION SPEC'D?
JZ MENU ;TRUE, GO MENU
CPI 'H' ;MENU ASKED FOR?
JZ MENU2 ;YES, GO MENU2
CALL JMP$INITMOD
CALL MOVEFCB
CALL IN$MODDATP ;GOBBLE UP GARBAGE..
CALL IN$MODDATP ;..CHARACTERS ON LINE
XRA A
STA ECHOFLG ;RESET ECHO FLAG
STA LOCFLG ;RESET LOCAL FLAG
LDA OPTION ;PROCESS MAIN OPTION
CPI 'E' ;ECHO MODE?
JNZ NOECH ;JUMP IF NOT
MVI A,TRUE ;SET ECHO TO TRUE
STA ECHOFLG
JMP DSKSAVE
NOECH: CPI 'L' ;LOCAL ECHO MODE
JNZ NOLOC
MVI A,TRUE
STA LOCFLG
JMP DSKSAVE
NOLOC: CPI 'T' ;TERMINAL MODE?
JZ DSKSAVE ;YES
CPI 'S' ;SEND A FILE?
JZ SENDFIL ;YES
CPI 'R' ;RECEIVE A FILE?
JZ RCVFIL ;YES
CALL NOTVLDMSG ;SAY NOT A VALID OPTION
JMP MENU ;NO VALID OPTION SPEC'D, GO MENU
;
;REVISED TERMINAL ROUTINE ALLOWING MEMORY SAVE
;
DSKSAVE:
LDA FCB+1 ;FIRST CHAR OF FILENAME
CPI ' ' ;FILE SPEC'D
JNZ GOODNM ;YES, GOOD NAME
MVI A,TRUE ;0FFH
STA NFILFLG
CMA ;0
STA SAVEFLG
JMP TERM
;
GOODNM:
CALL ERASFIL
CALL MOVE2
LXI D,FCB3
MVI C,MAKE
CALL BDOS
LXI D,FCB3
MVI C,OPEN
CALL BDOS
LXI H,BOTTRAM
SHLD HLSAVE
XRA A
STA NFILFLG
STA LISTMOR ;STOP ANY BUFFERED PRINTER OUTPUT
TERM: LDA UARTFLG
STA ORIGSAV
ORA A
MVI A,ANSWMOD
STA UARTCTLB
JNZ TERM2
MVI A,ORIGMOD
STA UARTCTLB
TERM2: LDA LISTMOR ;ANY BUFFERED PRINTER OUTPUT?
ORA A
CNZ GOLIST ;GO IF SO
CALL STAT ;KEYPRESS?
JZ TERML ;NO, CHECK LINE
CALL KEYIN ;GET CHAR FROM KBD
CPI ' '
JNC NOTOG ;GO IF NOT CONTROL CHARACTER
MOV B,A ;SAVE
CPI BKSP ;TEST FOR BACKSPACE
JNZ NOBKSP
LDA CONVBKSP ;CONVERT BACKSPACE TO RUB?
ORA A
JZ NOBKSP ;GO IF NO CONVERSION
MVI A,RUB
JMP NOTOG
NOBKSP: LDA EXACFLG
ORA A ;EXACT?
MVI A,0
STA EXACFLG ;CLR FOR NEXT TIME
JZ NOTEXAFLG ;GO OF EXAFLG FALSE
LDA LOCONEXTCHR
ORA A ;SHOULD WE SEND ON EXAFLG?
MOV A,B
JZ NOTOG ;YES, IF LOCONEXTCHR FALSE
LDA EXTCHR ;WE WANT TO SEND EXTCHR IN ANY CASE
CMP B
MOV A,B
JZ NOTOG ;SEND IF EXTCHR
JMP LOCCHK ;OTHERWISE DO LOCAL STUFF
NOTEXAFLG:
LDA EXTCHR ;TREAT NEXT CHARACTER IN SPECIAL WAY?
CMP B
JZ EXTFLG ;YES, SET EXAFLG FOR NEXT CHAR
LDA LOCONEXTCHR
ORA A ;SHOULD WE SEND IF NOT EXAFLG
MOV A,B
JNZ NOTOG ;YES, IF LOCONEXTCHR TRUE
LOCCHK: LDA EXITCHR ;RETURN TO MENU?
CMP B
JZ EXITMEN ;YES, RETURN TO MENU
LDA TRANCHR ;OUTPUT TEXT FILE TO REMOTE?
CMP B
CZ TRANSFER ;SEND-A-FILE (BLIND SEND)
JZ TERM2 ;LOOP
LDA TRANLOGON
ORA A
JZ SKPLOGON
LDA LOGCHR ;SEND LOGON?
CMP B
JZ SENDLOG
SKPLOGON:
LDA LSTTST
ORA A
JZ NOLST
LDA LSTCHR
CMP B
JNZ NOLST
LDA LISTFLG
CMA
STA LISTFLG
CALL CRLF
CALL CRLF
CALL LSTMSG
CALL CRLF
JMP TERML
NOLST: LDA PMMIBYTE
ORA A
JZ S2
LDA DISCCHR ;PMMI DISCONNECT?
CMP B
JZ DISCON1 ;YES, DISCONNECT & RETURN TO MENU
LDA BRKCHR ;PMMI BREAK?
CMP B
JZ BREAK
LDA CHGBAUD ;PMMI CHANGE BAUD?
CMP B
PUSH PSW
PUSH H
CZ NEWBAUD
POP H
POP PSW
JZ TERML
S2: LDA UNSAVECHR ;CLOSE INPUT BUFFER?
CMP B
JZ S2A ;IF YES, DISABLE COPY
LDA SAVECHR ;OPEN INPUT BUFFER?
CMP B
MOV A,B ;RESTORE CHARACTER TYPED
JNZ NOTOG
LDA NFILFLG ;DO NOT ALLOW SAVE IF..
CPI TRUE ;..THIS FLAG IS SET.
JZ TERML
MVI A,TRUE ;0FFH -- ALLOW COPY INTO FILE
JMP S2B
S2A: MVI A,FALSE ;0 -- STOP COPY INTO FILE
S2B: STA SAVEFLG
CALL BUFMSG
JMP TERML
;
BUFMSG: CALL ILPRT
DB CR,LF,LF,'** Memory buffer ',0
LDA SAVEFLG
ORA A
JZ BUFMSG2
CALL ILPRT
DB 'open **',CR,LF,LF,':',BELL,0
RET
;
BUFMSG2:
CALL ILPRT
DB 'closed **',CR,LF,LF,BELL,0
RET
;
EXITMEN:
CALL CRLF
CALL CLREOS ;CLEAR TO END OF SCREEN TO CLEAN UP ANY MESS
JMP MENU0
;
SENDREADY:
CALL IN$MODCTLP
CALL ANI$MODSNDB
JMP CPI$MODSNDR
;
SENDLF: CALL SENDREADY
JNZ NOLFYET ;GO IF NOT READY FOR OUTPUT YET
MVI A,LF
JMP NOTOG ;SEND LF
NOLFYET:
CALL EXITTEST
JNC EXITMEN ;GO IF SO, SO DON'T GET HUNG UP
JMP SENDLF ;ELSE KEEP TRYING TO SEND LF
;
SENDLOG:
PUSH H
LHLD LOGONPTR ;HL POINTS TO START OF LOGON MESSAGE
LOGLP: CALL SENDREADY
JNZ NOSENDLOG ;GO IF NOT READY
MOV A,M ;GET LOGON BYTE
INX H
CPI 0 ;IS IT THE END?
JZ ENDLOG ;GO IF SO
CALL OUT$MODDATP
JMP LOGLP
NOSENDLOG:
CALL EXITTEST ;TEST SO DON'T GET HUNG UP
JNC EXITLOG ;GO IF OPERATOR WANTS EXIT
JMP LOGLP
;
ENDLOG: POP H
JMP TERML
;
EXITLOG:
POP H
JMP EXITMEN
;
EXITTEST:
CALL STAT ;KEYPRESS?
JZ NOKEY
CALL KEYIN
MOV B,A
LDA EXITCHR ;SEE IF OPERATOR WANTS EXIT
CMP B
JNZ NOKEY ;GO IF WRONG KEY
STC
CMC ;RESET FOR EXIT
RET
NOKEY: STC ;SET FOR NO KEY OR WRONG KEY
RET
;
EXTFLG: MVI A,TRUE
STA EXACFLG
JMP TERML
;
RCVREADY:
CALL IN$MODCTLP
CALL ANI$MODRCVB
JMP CPI$MODRCVR
;
LSTMSG: LDA LISTFLG
ORA A
JZ LSTMSG2
CALL ILPRT
DB 'Printer is on',CR,LF,0
RET
LSTMSG2:
CALL ILPRT
DB 'Printer is off',CR,LF,0
RET
;
NOTOG: CALL OUT$MODDATP
MOV B,A
LDA LOCFLG
ORA A
JNZ LTYPE
LDA ECHOFLG
ORA A
JZ CHKCR
LTYPE: MOV A,B
CALL TYPE
CALL CHKSAVE ;TO STORE LOCAL IF BUFFER OPEN
CALL CHKPRNT
CHKCR: MVI A,CR
CMP B
JNZ TERML
LDA ADDLF
ORA A
JZ TERML
JMP SENDLF
;
TERML: CALL RCVREADY ;TEST FOR RECEIVED CHARACTER
JNZ TERM2
CALL IN$MODDATP
ANI 7FH ;STRIP PARITY
JZ TERM2
GIVLF: CALL TYPE
MOV B,A
CALL CHKSAVE
CALL CHKPRNT
LDA ECHOFLG
ORA A
JZ NOECHO
MOV A,B
CALL OUT$MODDATP
NOECHO: MVI A,CR
CMP B
JNZ TERM2
LDA ADDLF
JZ TERM2
LDA ECHOFLG
ORA A
JNZ SENDLF
MVI A,LF
JMP GIVLF
;
CHKSAVE:
LDA SAVEFLG
ORA A
RZ
MOV M,B
INX H
SHLD HLSAVE ;MENU COMMAND DESTROYS HL-REG..
MVI A,LF
CMP B
JNZ NOCOLON ;..TYPE ":" AFTER EACH LINE FEED..
MVI A,':' ;..WHEN MEMORY SAVE ACTIVE.
CALL TYPE
NOCOLON:
CALL GETMAX
CMP H
PUSH B
CZ INTDSKSV
POP B
RET
;
GETMAX: LDA SAVCCP
ORA A
LDA 7
JZ SUB1
SBI 8 ;..PAGE BELOW CCP ..
SUB1: DCR A ;..OR BDOS HAS BEEN..
RET ;..REACHED AND DISKSAVE IS NEEDED.
;
CHKPRNT:
LDA LISTFLG ;OUT TO PRINTER?
ORA A
RZ ;RETURN IF NOT
LDA NFILFLG ;IS BUFFER USED FOR FILE?
ORA A
JZ NOBUFF ;DON'T BUFFER PRINTER IF SO, HOWEVER CHARACTERS
;WILL BE LOST IF PRINTER IS SLOWER THAN MODEM
CALL GETMAX ;GET MAXIMUM FOR BUFFER
LHLD HLSAVE1
CMP H ;ARE WE THERE?
JNZ NOTMAX ;GO IF NOT
LXI H,BOTTRAM ;FLUSH BUFFER
SHLD HLSAVE1
SHLD HLSAVE2
NOTMAX:
MOV M,B ;SAVE CHARACTER IN BUFFER
INX H ;INCREMENT END OF BUFFER
SHLD HLSAVE1
MVI A,TRUE ;SET FLAG FOR PRINTER OUTPUT
STA LISTMOR
RET
;
NOBUFF:
CALL LSTSTAT
RZ ;RETURN IF PRINTER BUSY
MOV C,B ;ELSE PRINT CHARACTER
JMP LISTER
;
GOLIST:
CALL LSTSTAT
RZ ;RETURN IF PRINTER BUSY
LHLD HLSAVE2 ;GET LOCATION OF NEXT CHARACTER TO PRINT
MOV C,M ;GET CHARACTER
INX H ;INCREMENT POINTER
SHLD HLSAVE2
CALL CMPBUFF ;CHECK FOR END OF BUFFER
JMP LISTER ;PRINT
;
;ROUTINE CHECKS FOR END OF BUFFER, RESETS BUFFER IF SO AND STOPS
;PRINTER OUTPUT
;
CMPBUFF:
LHLD HLSAVE2
XCHG
LHLD HLSAVE1
MOV A,L
SUB E
MOV L,A
MOV A,H
SBB D
ORA L
RNZ
LXI H,BOTTRAM
SHLD HLSAVE1
SHLD HLSAVE2
XRA A
STA LISTMOR
RET
;
INTDSKSV:
MVI A,XOFF ;SEND A CTRL-S TO STOP..
CALL OUT$MODDATP ;..REMOTE COMPUTER OUTPUT.
MVI D,0 ;D IS THE BUFFER COUNT
CALL INMODEM ;GET LAST BYTES SENT..
STA LASTBYT1 ;..AFTER CTRL-S.
CALL INMODEM ;ADD MORE CALLS TO INMODEM..
STA LASTBYT2 ;..AND STA LASTBYT# IF YOU ARE..
PUSH D
CALL NUMREC1
CALL WRTDSK ;WRITE THE RECORDS
POP D
LXI H,BOTTRAM
INR D
DCR D ;TEST BUFFER COUNT FOR ZERO
JZ CTRLQ
LDA LASTBYT1 ;GET THE LAST BYTES THAT WERE..
MOV M,A ;..SAVED AND PUT THEM IN..
INX H ;..BOTTRAM.
CALL TYPE
DCR D
JZ CTRLQ
LDA LASTBYT2
MOV M,A
INX H
CALL TYPE
CTRLQ:
MVI A,XON ;SEND START CHARACTER..
JMP OUT$MODDATP ;..TO REMOTE COMPUTER.
;
BREAK:
PUSH D ;SAVE IT
LXI D,0 ;ZERO IT
LDA MODCTLB ;GET THE LAST MODEM CONTROL BYTE
ANI 0FBH ;SET THE TRANSMIT BREAK BIT LOW - ACTIVE LOW
CALL OUT$MODCTL2 ;SEND IT TO THE MODEM
PUSH H
LXI H,225
CALL FIXCNT
PUSH H
POP B
POP H
BRK1: CALL TIMERL
JZ BRK2 ;IF TIME IS UP RESET BREAK
CPI 0 ;CHECK FOR NULLS
JZ BRK1 ;DON'T PROCESS THEM
ANI 7FH ;STRIP PARITY
CALL TYPE
PUSH PSW
LDA SAVEFLG
CPI FALSE
JZ NOSAVEB
POP PSW
MOV M,A
INX H
SHLD HLSAVE ;MENU COMMAND DESTROYS HL-REG..
;..GET HL WHEN ENTERING VIA 'NOL' CMD.
COLONB:
CPI LF
JNZ BRK1 ;..TYPE ":" AFTER EACH LINE FEED..
MVI A,':' ;..WHEN MEMORY SAVE ACTIVE.
CALL TYPE
JMP BRK1
;
NOSAVEB:
POP PSW ;RESTORE IT
JMP BRK1
;
BRK2:
LDA MODCTLB ;GET MODEM CONTROL BYTE
CALL OUT$MODCTL2
POP D
LHLD HLSAVE ;LAST ADDRESS WRITTEN IF DATA BEING SAVED
LDA SAVCCP
ORA A
JZ SUB2
LDA 7 ;CHECK TO SEE IF..
SBI 8 ;..PAGE BELOW CCP ..
JMP SUB2A
;
SUB2:
LDA 7
SUB2A:
DCR A ;..OR BDOS HAS BEEN ..
CMP H ;..REACHED AND DISKSAVE IS NEEDED.
JNZ TERM2 ;NO PROBLEM - GO BACK TO NORMAL ROUTINE
CALL ILPRT
DB CR,LF,'Memory save buffer full',CR,LF,BELL,0
JMP TERM2
;
;THIS SUBROUTINE WILL LOOP UNTIL THE MODEM RECEIVES A CHARACTER
;OR 100 MILLISECONDS. IF A CHARACTER IS RECEIVED, A FLAG IS SET
;TO STORE THE CHARACTER. A MAXIMUM OF TWO CHARACTERS ARE STORED,
;BUT MORE MAY BE STORED IF DESIRED (SEE COMMENT IN "INTDSKSV"
;ABOVE).
;
INMODEM:
PUSH H
LXI H,625
CALL FIXCNT
PUSH H
POP B
POP H
TIMERL:
CALL RCVREADY
JZ GETBYTE
DCX B
MOV A,B
ORA C
JNZ TIMERL
RET
;
GETBYTE:
CALL IN$MODDATP
INR D
RET
;
NUMRECS:
MVI M,EOFCHAR
INX H
LXI D,127
DAD D
NUMREC1:
LXI D,-(BOTTRAM)
DAD D
MOV A,L ;DIVIDE HL BY 128..
ORA A
RAL ;..TO GET THE..
MOV L,H ;..NUMBER OF SECTORS
MVI H,0
PUSH PSW
DAD H
POP PSW
MVI A,0
ADC L
MOV L,A ;RETURNS WITH NUMBER OF..
RET ;..128 BYTE RECORDS IN HL.
;
WRTDSK: LXI D,BOTTRAM
NEXTWRT:
MVI C,STDMA
CALL BDOSRT
PUSH D
LXI D,FCB3
MVI C,WRITE
CALL BDOSRT
POP D
XCHG
PUSH D
LXI D,128
DAD D
POP D
XCHG
DCX H
MOV A,H
ORA L
JNZ NEXTWRT
RET
;
CLOSE3: LXI D,FCB3
MVI C,CLOSE
JMP BDOS
;
BDOSRT:
PUSH B
PUSH D
PUSH H
PUSH PSW
CALL BDOS
POP PSW
POP H
POP D
POP B
RET
;
MOVE2:
LXI H,FCB3
CALL INITFCBS
LXI H,FCB
LXI D,FCB3
MVI B,12
JMP MOVE
;
;FILE TRANSFER ROUTINE - CALLED WITH
;CONTROL-T FROM TERMINAL ROUTINE.
;TRANSFER MAY BE CANCELLED WHILE SENDING BY USING CONTROL-X.
;
TRANSFER:
PUSH H
PUSH D
PUSH B
PUSH PSW
LXI H,FCB4
CALL INITFCBS ;INITIALIZES FCBS POINTED..
LXI H,FCB+16 ;..TO BY HL REG.
CALL INITFCBS
GET:
CALL GETNAME
LDA CMDBUF+2 ;WAS FILE ENTERED
CPI 20H
JZ TRANSL2
CALL MOVE4
CALL OPEN4
CPI 0FFH ;RETURN WITH 0FFH MEANS
JNZ CONTIN ;FILE DOES NOT EXIST
TRANSL1:
CALL ILPRT
DB CR,LF,'++File does not exist++',CR,LF,0
TRANSL2:
CALL ILPRT
DB 'Type "R" to return to modem',CR,LF
DB 'Type "A" to re-enter name: ',BELL,0
CALL KEYIN
CALL UCASE
CALL TYPE ;ECHO RESPONSE
CALL CRLF
CPI 'A'
JZ GET
CPI 'R'
JZ RETURN
JMP TRANSL2
;
CONTIN:
LXI D,80H
MVI C,STDMA
CALL BDOS
READMR:
CALL READ80
CPI 1 ;END OF FILE
JZ RETURNS
CPI 2 ;BAD READ
JZ RETURNU
CALL SEND80C
CPI EOFCHAR ;END OF FILE - OMIT IF OBJECT..
JZ RETURNS ;..CODE IS TO BE SENT.
CPI CAN ;CANCELLATION?
JZ TRANCAN
JMP READMR
;
RETURNS:
CALL ILPRT
DB CR,LF,'++File transfer completed++',CR,LF,BELL,0
JMP RETURN
;
RETURNU:
CALL ILPRT
DB CR,LF,'++File transfer unsuccessful++',CR,LF,BELL,0
JMP RETURN
;
TRANCAN:
CALL ILPRT
DB CR,LF,LF,'++ Transfer cancelled ++',CR,LF,BELL,0
RETURN:
POP PSW
POP B
POP D
POP H
RET
;
INITFCBS: ;ENTRY AT +2 WILL LEAVE..
MVI M,0 ;..DRIVE NO. INTACT.
INX H ;WILL INITIALIZE AN FCB..
MVI B,11 ;..POINTED TO BY HL-REG. FILLS 1ST POS
LOOP10:
MVI M,' ' ;..WITH 0, NEXT 11 WITH..
INX H ;..WITH BLANKS, AND LAST..
DCR B ;..21 WITH NULLS.
JNZ LOOP10
MVI B,21
LOOP11:
MVI M,0
INX H
DCR B
JNZ LOOP11
RET
;
GETNAME:
CALL ILPRT
DB CR,LF,'Enter file name to be transferred - C/R TO QUIT: ',0
LXI D,CMDBUF
CALL INBUFF
JMP CRLF
;
MOVE4:
LXI D,CMDBUF
LXI H,FCB4
JMP CPMLINE
;
OPEN4:
LXI D,FCB4
MVI C,OPEN
JMP BDOS
;
READ80:
LXI D,FCB4
MVI C,READ
JMP BDOS
;
SEND80C:
MVI B,80H
LXI H,80H
SENDCH1:
PUSH D
CALL SPEED
POP D
MOV A,M
CALL MODOUT
CPI EOFCHAR
RZ
CALL STAT ;TEST TO SEE IF
ORA A ;CANCELLATION REQUESTED
JZ SKIP12
CALL KEYIN
CPI CAN
RZ
SKIP12:
INX H
DCR B
JNZ SENDCH1
RET
;
MODOUT:
PUSH PSW
MODOUTL:
LDA XOFFTST
ORA A
CNZ TXOFF
CALL SENDREADY
JNZ MODOUTL
POP PSW
CALL OUT$MODDATP
CALL TYPE
CPI CR
JZ DLYCR
RET
;
DLYCR: INX H ;ALWAYS DISPLAY LF AFTER CR
MVI A,LF
CMP M
DCX H
JZ LFSKIP
CALL TYPE
LFSKIP: LDA XONWAIT ;WAIT FOR XON AFTER CR?
ORA A
JNZ WAITXON
LDA CRDLY ;EXTRA DELAY AFTER CR
JMP DLYCR2
;
SPEED: LDA BYTDLY ;GET SPEED VALUE (0-9)
;DELAY IS FROM 0.02 SEC FOR SPDVAL = 1
;TO 0.18 SEC FOR SPDVAL = 9
DLYCR2: ORA A
RZ ;RETURN IF 0
MOV C,A
SPDLP: CALL SPD1 ;OUTER LOOP
DCR C
RZ
JMP SPDLP
;
SPD1: PUSH H
LXI H,357 ;ABOUT 0.02 SEC AT 2 MHZ
LDA XOFFTST
ORA A
JZ SPD2
LXI H,102 ;ADJUST FOR XOFF TESTING
LDA ECHOFLG
ORA A
JZ SPD2
LDA LOCFLG
ORA A
JZ SPD2
LXI H,76 ;ADJUST AGAIN FOR REMOTE ECHO
SPD2: CALL FIXCNT
PUSH H
POP D
POP H
SPDLP1: DCX D ;INNER LOOP
LDA XOFFTST
ORA A
CNZ TXOFF
MOV A,E
ORA D
RZ
JMP SPDLP1
;
TXOFF: CALL RCVREADY
RNZ
CALL IN$MODDATP
ANI 7FH
CPI XOFF
CZ WAITXON
RET
;
WAITXON:
CALL RCVREADY
JNZ WTXON2
CALL IN$MODDATP
ANI 7FH
CPI XON
RZ
WTXON2: CALL STAT ;TEST TO SEE IF
ORA A ;CANCELLATION REQUESTED
JZ WAITXON ;SO DON'T GET HUNG UP
CALL KEYIN
CPI CAN
RZ
JMP WAITXON
;
;SEND A CP/M FILE
;
SENDFIL:
MVI A,TRUE ;ALWAYS FORCE CHECKSUM MODE INITIALLY ON SEND
STA CKSUMFLG
SENDFIL1:
CALL PARITY ;SET PARITY IF REQUESTED
LDA BATCHFLG ;CHECK IF MULTIPLE FILE..
ORA A ;..MODE IS SET.
JNZ SENDC1
MVI A,TRUE ;INDICATE SEND FOR BATCH MODE
STA SENDFLG
LDA FSTFLG ;IF FIRST TIME THRU..
ORA A ;..SCAN THE COMMAND LINE..
CNZ TNMBUF ;..FOR MULTIPLE NAMES.
CALL SENDFN ;SENDS FILE NAME TO RECEIVER
JNC SENDC2 ;CARRY SET MEANS NO MORE FILES.
MVI A,'B' ;STOP BATCH..
STA BATCHFLG ;..MODE OPTION.
MVI A,EOT ;FINAL XFER END
CALL SEND
JMP DONE
;
SENDC1:
LDA FCB+1
CPI ' '
JZ BLKFILE
SENDC2:
CALL CNREC ;GET NUMBER OF RECORDS
CALL OPENFIL
MVI E,80
CALL WAITNAK
SENDLP:
CALL RDSECT
JC SENDEOF
CALL INCRSNO
MVI A,1
STA ERRCT
SENDRPT:
CALL SENDHDR
CALL SENDSEC
LDA CKSUMFLG
ORA A
CZ SENDCRC
CNZ SENDCKS
CALL GETACK
JC SENDRPT
JMP SENDLP
;
SENDEOF:
MVI A,EOT
CALL SEND
CALL GETACK
JC SENDEOF
JMP DONE
;
;RECEIVE A FILE
;
RCVFIL:
LDA CKSUMDFLT ;GET MODE REQUESTED BY OPERATOR
STA CKSUMFLG ;STORE IT
RCVFIL1:
CALL PARITY ;SET PARITY IF REQUESTED
LDA BATCHFLG ;CHECK IF MULT..
ORA A ;..FILE MODE.
JNZ RCVC1
MVI A,FALSE ;FLAG WHERE TO RETURN..
STA SENDFLG ;..FOR NEXT FILE TRANS.
CALL GETFN ;GET THE FILE NAME.
JNC RCVC2 ;CARRY SET MEANS NO MORE FILES.
MVI A,'B' ;STOP BATCH..
STA BATCHFLG ;..MODE OPTION.
JMP DONE
;
RCVC1:
LDA FCB+1 ;MAKE SURE FILE IS NAMED
CPI ' '
JZ BLKFILE
;
RCVC2:
CALL CKCPM2
CALL CKBAKUP
RCVC3:
CALL ERASFIL
CALL MAKEFIL
LDA BATCHFLG
ORA A ;DON'T PRINT MSG IF..
JZ RCVFST ;..IN BATCH
CALL ILPRT
DB 'File open, ready to receive',CR,LF,0
RCVFST:
LDA CKSUMFLG
ORA A
MVI A,NAK
JNZ RCVFIL2
MVI A,CRC
RCVFIL2:
CALL SEND
LDA QFLG
ORA A
JZ RCVLP
LDA CKSUMFLG
ORA A
JNZ RCVNAKM ;IF IN CRC MODE
CALL ILPRT ;THEN SAY SO
DB 'CRC in effect',CR,LF,0
JMP RCVLP
RCVNAKM:
CALL ILPRT ;ELSE SAY CHECKSUM MODE
DB 'Checksum in effect',CR,LF,0
RCVLP:
CALL RCVSECT
JC RCVEOT
CALL WRSECT
CALL INCRSNO
CALL SENDACK
JMP RCVLP
;
RCVEOT:
CALL WRBLOCK
CALL SENDACK
CALL CLOSFIL
JMP DONE
;
;SUBROUTINES
;
SENDFN:
LDA QFLG
ORA A
JZ SWNAK
CALL ILPRT
DB 'Awaiting name NAK',CR,LF,0
SWNAK:
MVI E,80
CALL WAITNLP
MVI A,ACK ;GOT NAK, SEND ACK
CALL SEND
LXI H,FILECT
DCR M
JM NOMRNM
LHLD NBSAVE ;GET FILE NAME..
LXI D,FCB ;..IN FCB
MVI B,12
CALL MOVE
SHLD NBSAVE
CALL SENDNM ;SEND IT
ORA A ;CLEAR CARRY
RET
;
NOMRNM: MVI A,EOT
CALL SEND
STC
RET
;
SENDNM: PUSH H
SENDNM1:
MVI D,11 ;COUNT CHARS IN NAME
MVI C,0 ;INIT CHECKSUM
MOV A,C
STA FTYCNT ;INITIATE FILE TYPE COUNT
LXI H,FCB+1 ;ADDRESS NAME
NAMLPS: MOV A,M ;SEND NAME
ANI 7FH ;STRIP HIGH ORDER BIT SO CP/M 2..
CALL SEND ;..WON'T SEND R/O FILE DESIGNATION.
LDA QFLG ;SHOW NAME IF..
ORA A ;..QFLG NOT SET.
MOV A,M
JZ ACKLP
CALL FTYTST ;TYPE CHARACTER ETC.
ACKLP: PUSH B ;SAVE CKSUM
MVI B,1 ;WAIT FOR RECEIVER..
CALL RECV ;..TO ACKNOWLEDGE..
POP B ;..GETTING LETTER.
JC SCKSER
CPI ACK
JNZ ACKLP
INX H ;NEXT CHAR
DCR D
JNZ NAMLPS
MVI A,EOFCHAR ;TELL RECEIVER END OF NAME
CALL SEND
LDA QFLG
ORA A
CNZ CRLF
MOV D,C ;SAVE CHECKSUM
MVI B,1
CALL RECV ;GET CHECKSUM..
CMP D ;..FROM RECEIVER.
JZ NAMEOK
SCKSER: MVI A,BDNMCH ;BAD NAME-TELL RECEIVER
CALL SEND
LDA QFLG
ORA A
JZ SKCSER1
CALL ILPRT
DB 'Checksum error',CR,LF,0
SKCSER1:
MVI E,80 ;DO HANDSHAKING OVER
CALL WAITNLP ;DON'T PRINT "AWAITING NAK" MSG
MVI A,ACK
CALL SEND
JMP SENDNM1
;
NAMEOK:
MVI A,OKNMCH ;GOOD NAME-TELL RECEIVER
CALL SEND
POP H
RET
;
GETFN: LXI H,FCB
CALL INITFCBS+2 ;DOES NOT INITIALIZE DRIVE
LDA QFLG
ORA A
JZ GNAMELP
CALL ILPRT
DB 'Awaiting file name',CR,LF,0
GNAMELP:
CALL HSNAK
JC GNAMELP
CALL GETNM ;GET THE NAME
CPI EOT ;IF EOT, THEN NO MORE FILES
JZ NOMRNMG
ORA A ;CLEAR CARRY
RET
;
NOMRNMG:
STC
RET
;
GETNM:
PUSH H
GETNM1:
MVI C,0 ;INIT CHECKSUM
MOV A,C
STA FTYCNT ;INITIATE COUNT FOR FILE TYPE
LXI H,FCB+1
NAMELPG:
MVI B,5
CALL RECV ;GET CHAR
JNC GETNM3
LDA QFLG
ORA A
JZ GETNM2
CALL ILPRT
DB 'Time out receiving filename',CR,LF,0
GETNM2: JMP GCKSER
;
GETNM3:
CPI EOT ;IF EOT, THEN NO MORE FILES
JZ GNRET
CPI EOFCHAR ;GOT END OF NAME
JZ ENDNAME
MOV M,A ;PUT NAME IN FCB
LDA QFLG ;CAN TYPE IT IF NO QFLG
ORA A
JZ SKPTYP
CALL FTYTST
SKPTYP: PUSH B ;SAVE CKSUM
MVI A,ACK ;ACK GETTING LETTER
CALL SEND
POP B
INX H ;GET NEXT CHAR
MOV A,L ;DON'T LET NOISE...
CPI 7FH ;..CAUSE OVERFLOW..
JZ GCKSER ;..INTO PROGRAM AREA.
JMP NAMELPG
;
FTYTST:
LDA FTYCNT
INR A
STA FTYCNT
CPI 9 ;ARE WE AT THE FILE TYPE?
JZ SPCTST ;GO IF SO
ENDSPT: MOV A,M
CPI ' ' ;TEST FOR SPACE
CNZ TYPE ;TYPE IF NOT
RET
;
SPCTST: MOV A,M
CPI ' ' ;TEST FOR SPACE IN FIRST FILE TYPE BYTE
RZ ;DON'T OUTPUT PERIOD IF SPACE
MVI A,'.'
CALL TYPE
JMP ENDSPT ;OUTPUT FIRST FILE TYPE BYTE
;
ENDNAME:
LDA QFLG
ORA A
CNZ CRLF
MOV A,C ;SEND CHECKSUM
CALL SEND
MVI B,1
CALL RECV ;CHECKSUM GOOD?
CPI OKNMCH ;YES IF OKNMCH SENT..
JZ GNRET ;..ELSE DO OVER.
GCKSER: LXI H,FCB ;CLEAR FCB (EXCEPT DRIVE)..
CALL INITFCBS+2 ;..SINCE IT MIGHT BE DAMAGED..
LDA QFLG ;..BY TOO MANY CHARS.
ORA A
JZ GCKSER1
CALL ILPRT
DB 'Checksum error',CR,LF,0
GCKSER1:
CALL HSNAK ;DO HANDSHAKING OVER
JC GCKSER1
JMP GETNM1
;
GNRET: POP H
RET
;
HSNAK: MVI A,NAK ;SEND NAK UNTIL..
CALL SEND ;..RECEIVING ACK.
CALL CKABORT ;DON'T GET HUNG UP HERE
MVI B,2 ;WAIT 2 SECONDS..
CALL RECV ;..IN RECEIVE.
CPI ACK ;IF ACK,RETURN WITH..
RZ ;..CARRY CLEAR.
STC
RET
;
TNMBUF: MVI A,FALSE ;CALL FROM SENDFIL ONLY ONCE.
STA FSTFLG
STA FILECT
CALL SCAN
LXI H,NAMEBUF
SHLD NBSAVE ;SAVE ADDR OF 1ST NAME
TNLP1: CALL TRTOBUF
LXI H,FCB
LXI D,FCBBUF
CALL CPMLINE ;PARSE NAME TO CP/M FORMAT
TNLP2: CALL MFNAME ;SEARCH FOR NAMES (* FORMAT)
JC NEXTNM
LDA FCB+10 ;IF CP/M 2 $SYS FILE..
ANI 80H ;..DON'T SEND
JNZ TNLP2
LHLD NBSAVE ;GET NAME
LXI D,FCB ;MOVE IT TO FCB
XCHG
MVI B,12
CALL MOVE
XCHG
SHLD NBSAVE ;ADDR OF NEXT NAME
LXI H,FILECT ;COUNT FILES FOUND
INR M
JMP TNLP2
;
NEXTNM: LXI H,NAMECT ;COUNT NAMES FOUND
DCR M
JNZ TNLP1
LXI H,NAMEBUF ;SAVE START OF BUFFER
SHLD NBSAVE
LDA FILECT
CPI 65 ;NO MORE THAN 64 TRANSFERS
RC
MVI A,64 ;ONLY X'FER FIRST 64
STA FILECT
RET
;
;SCANS CMDBUF COUNTING NAMES AND PUTTING DELIMITER (SPACE)
;AFTER LAST NAME
;
SCAN: PUSH H
LXI H,NAMECT
MVI M,0
LXI H,CMDBUF+1 ;FIND END OF CMD LINE..
MOV C,M ;..AND PUT SPACE THERE.
MVI B,0
LXI H,CMDBUF+2
DAD B
MVI M,20H
LXI H,CMDBUF+1
MOV B,M
INR B
INR B
SCANLP1:
INX H
DCR B
JZ DNSCAN
MOV A,M
CPI 20H
JNZ SCANLP1
SCANLP2:
INX H ;EAT EXTRA SPACES
DCR B
JZ DNSCAN
MOV A,M
CPI 20H
JZ SCANLP2
SHLD BGNMS ;SAVE START OF NAMES IN CMDBUF
INR B
DCX H
SCANLP3:
INX H
DCR B
JZ DNSCAN
MOV A,M
CPI 20H
JNZ SCANLP3
LDA NAMECT ;COUNTS NAMES
INR A
STA NAMECT
SCANLP4:
INX H ;EAT SPACES
DCR B
JZ DNSCAN
MOV A,M
CPI 20H
JZ SCANLP4
JMP SCANLP3
;
DNSCAN:
MVI M,20H ;SPACE AFTER LAST CHAR
POP H
RET
;
;PLACES NEXT NAME IN BUFFER SO 'CPMLINE' MAY PARSE IT
;
TRTOBUF:
LHLD BGNMS
MVI B,0
LXI D,FCBBUF+2
TBLP:
MOV A,M
CPI 20H
JZ TRBFEND
STAX D
INX H
INX D
INR B ;COUNT CHARS IN NAME
JMP TBLP
;
TRBFEND:
INX H
MOV A,M ;EAT EXTRA SPACES
CPI 20H
JZ TRBFEND
SHLD BGNMS
LXI H,FCBBUF+1 ;PUT # CHARS BEFORE NAME
MOV M,B
RET
;
;IN CP/M V.2, IF FILE IS R/O OR SYS, IT IS CHANGED TO 'BAK'.
;
CKCPM2:
MVI C,12
CALL BDOS
ORA A ;RETURN 0 MEANS CP/M 1
RZ
MVI C,STDMA
LXI D,80H
CALL BDOS
MVI C,SRCHF ;SEARCH FOR FILE
LXI D,FCB
CALL BDOS
CPI 0FFH
RZ
ADD A
ADD A ;MULT A-REG BY..
ADD A
ADD A ;..32 TO FIND..
ADD A ;..NAME IN DMA.
LXI H,80H
ADD L
MOV L,A ;HL POINTS TO DIR NAME
LXI D,9
DAD D ;POINT TO R/O ATTRIB BYTE
MOV A,M
ANI 80H ;TEST MSB
JNZ MKCHG ;IF SET, MAKE CHANGE
INX H ;CHECK SYSTEM ATTRIB BYTE
MOV A,M
ANI 80H
RZ ;NOT $SYS OR $R/O
DCX H
MKCHG: LXI D,-8
DAD D ;POINT HL TO FILENAME + 1
LXI D,FCB+1 ;MOVE DIR NAME TO FCB..
MVI B,11 ;..WITHOUT CHANGING DRIVE.
CALL MOVE
LXI H,FCB+9 ;R/O ATTRIB
MOV A,M
ANI 7FH ;STRIP R/O ATTRIB
MOV M,A
INX H ;SYS ATTRIB
MOV A,M
ANI 7FH
MOV M,A
LXI D,FCB
MVI C,30 ;SET NEW ATTRIBS IN DIR
CALL BDOS
;
;MAY BE CALLED BY CKBAKUP BELOW. ITS RETURN DONE HERE
;
PLANCHG:
LXI H,FCB ;CHANGE NAME TO TYPE "BAK"
LXI D,6CH
MVI B,9 ;MOVE DRIVE AND NAME (NOT TYPE)
CALL MOVE
LXI H,75H ;START OF TYPE IN FCB2
MVI M,'B'
INX H
MVI M,'A'
INX H
MVI M,'K'
LXI D,6CH
MVI C,ERASE ;ERASE ANY PREV BACKUPS
CALL BDOS
LXI H,6CH ;FCB2 DR FIELD SHOULD..
MVI M,0 ;..0 FOR RENAME.
LXI D,FCB
MVI C,23 ;RENAME
JMP BDOS
;
CKBAKUP:
LDA BAKUPBYTE
ORA A
RZ
MVI C,SRCHF
LXI D,FCB
CALL BDOS
INR A
RZ ;FILE NOT FOUND
JMP PLANCHG ;IN "CKCPM2" - RET DONE THERE
;
;MULTI-FILE ACCESS SUBROUTINE FROM CP/M USER'S GROUP
;FIXED BY MARK ZEIGER 8/17/80
;CARRY IS SET IF NO MORE NAMES CAN BE FOUND
;
MFNAME:
MFACCESS ;A MACRO IN MACROS.LIB
;
RCVSECT:
MVI A,1
STA ERRCT
RCVRPT:
XRA A ;ZERO ACCUM
STA ERRCDE ;CLEAR RECEIVE ERROR CODE
LDA QFLG
ORA A
JZ RCVSQ
CALL ILPRT
DB CR,'Awaiting # ',0
PUSH H ;SAVE IT
LHLD SECTNO ;GET SECTOR NUMBER
INX H ;BUMP IT
CALL DECOUT ;PRINT SECTOR NUMBER IN DECIMAL
CALL ILPRT
DB ' (', 0
CALL DHXOUT ;16 BIT HEX CONVERSION & OUTPUT
CALL ILPRT
DB 'H)',0
MOV A,L ;ONLY LOW BYTE USED BY PROGRAM
POP H ;RESTORE IT
;
RCVSQ: ;WAIT FOR SOH OR EOT
MVI B,10 ;10 SECONDS
CALL RECV
JC RCVSTOT
CALL RCVERR ;CHECK FOR ERRORS
JC RCVDERR ;JUMP IF THERE WAS AN ERROR
CPI SOH
JZ RCVSOH
ORA A
JZ RCVSQ
CPI EOT
STC
RZ
MOV B,A
LDA QFLG
ORA A
JZ RCVSERR
RCVSEH:
MOV A,B
CALL CRLF
CALL HEXO
CALL ILPRT
DB 'H recv''d, not SOH',CR,LF,0
RCVSERR:
MVI B,1 ;WAIT FOR 1 SEC..
CALL RECV ;..WITH NO CHARS
JNC RCVSERR ;LOOP UNTIL SENDER DONE
LDA CKSUMFLG ;GET CHECKSUM FLAG
ORA A ;CRC IN EFFECT?
MVI A,NAK ;PUT NAK IN ACCUM
JNZ RCVSER2 ;NO, SEND THE NAK
LDA FIRSTME ;GET FIRST TIME SWITCH
ORA A ;HAS FIRST SOH BEEN RECEIVED?
MVI A,NAK ;PUT NAK IN ACCUM
JZ RCVSER2 ;YES, THEN SEND NAK
MVI A,CRC ;TELL SENDER CRC IS IN EFFECT
RCVSER2:
CALL SEND ;..THE NAK or CRC request
LDA ERRCT ;ABORT IF..
INR A ;..WE HAVE REACHED..
STA ERRCT ;..THE ERROR..
CPI ERRLIM ;..LIMIT?
JC RCVRPT ;..NO, TRY AGAIN
LDA QFLG
ORA A
JZ RCVSABT
RCVCKQ: CALL CKQUIT
JZ RCVSECT
RCVSABT:
CALL CLOSFIL
CALL ERXIT
DB CR,LF,'++ Unable to receive block - Aborting ++',CR,LF,'$'
;
RCVSTOT:
LDA QFLG
ORA A
JZ RCVSCRC
RCVSPT: CALL ILPRT
DB CR,LF,'++ Timeout ++ ',0
RCVPRN: LDA ERRCT
PUSH H
MVI H,0
MOV L,A
CALL DECOUT
POP H
CALL CRLF
RCVSCRC:
CALL RCVSCRC2
JMP RCVSERR
;
;ROUTINE WILL SWITCH FROM CRC TO CHECKSUM IF ERCNT REACHES ERRCRC
;AND FIRSTME IS TRUE
;
RCVSCRC2:
LDA ERRCT
CPI ERRCRC
RNZ
LDA FIRSTME
ORA A
RZ
LDA CKSUMFLG
ORA A
RNZ
CMA
STA CKSUMFLG
STA CKSUMDFLT
LDA QFLG
ORA A
RZ
CALL ILPRT
DB '++ Switching to Checksum mode ++',CR,LF
DB '++ Sender may not be CRC capable ++',CR,LF,BELL,0
RET
;
;----> RCVERR:
;
; Checks for framing, overrun, and parity errors. Parity errors
; cannot be detected unless the parity option has been selected.
; 1.Error code (ERRCDE) was set in RECV routine.
; 2.ERRCDE=0 for no errors, ERRCDE<>0 for errors.
; 3.If there is an error, routine returns with carry flag set.
;
RCVERR: PUSH PSW ;SAVE CHAR TRANSMITTED
LDA ERRCDE ;GET RECEIVE ERROR CODE
ANA A ;IS IT ZERO?
JZ RCVERR2 ;YES, NO RECEIVE ERROR
POP PSW ;RESTORE CHAR TRANSMITTED
STC ;SET CARRY ON TO INDICATE AN ERROR
RET
RCVERR2:
POP PSW ;RESTORE CHAR TRANSMITTED
RET
;
;----> RCVDERR: Checks for a receive error and displays appropriate
; error message. Then goes to RCVSERR to purge the line
; and send a NAK.
;
RCVDERR:
LDA QFLG ;QUIET...
ORA A ;...MODE?
JZ RCVSERR ;YES, NO MSG
RCVDERRP:
CALL ILPRT
DB CR,LF,0
LDA ERRCDE ;GET RECEIVE ERR CODE
ANI FRMER ;WAS THERE A FRAMING ERROR?
JZ RCVDERR2 ;NO, GO CHECK FOR OVERRUN
CALL ILPRT
DB '++ Framing error ++ ',0
CALL RCVDERR5 ;PRINT # OF ERROR
RCVDERR2:
LDA ERRCDE ;GET RECEIVE ERR CODE
ANI ORUNER ;WAS THERE AN OVERRUN
JZ RCVDERR3 ;NO, GO CHECK FOR PARITY ERROR
CALL ILPRT
DB '++ Overrun error ++ ',0
CALL RCVDERR5
RCVDERR3:
LDA ERRCDE ;GET RECEIVE ERR CODE
ANI PARER ;WAS THERE A PARITY ERROR?
JZ RCVDERR4 ;NO, GO PURGE LINE
CALL ILPRT
DB '++ Parity error ++ ',0
CALL RCVDERR5
RCVDERR4:
JMP RCVSERR ;GO PURGE LINE, SEND NAK
;
;Display the number of the error, do a carriage return and line feed.
;
RCVDERR5:
LDA ERRCT ;GET ERROR NUMBER
PUSH H
MVI H,0
MOV L,A
CALL DECOUT ;DISPLAY IT
POP H
JMP CRLF ;DO CR, LF
;
;Got SOH - get block #, block # complemented
;
RCVSOH: XRA A ;ZERO ACCUM
STA FIRSTME ;INDICATE FIRST SOH RECV'D
MVI B,1 ;TIMEOUT = 1 SEC
CALL RECV ;GET SECTOR
JC RCVSTOT ;GOT TIMEOUT
CALL RCVERR ;CHECK FOR RECEIVE ERROR
JC RCVDERR
MOV D,A
MVI B,1
CALL RECV
JC RCVSTOT
CALL RCVERR ;CHECK FOR RECEIVE ERROR
JC RCVDERR
CMA
CMP D
JZ RCVDATA
LDA QFLG
ORA A
JZ RCVSERR
RCVBSE:
CALL ILPRT
DB CR,LF,'++ Bad sector # in Hdr',CR,LF,0
JMP RCVSERR
;
RCVDATA:
MOV A,D
STA RCVSNO
MVI A,1
STA DATAFLG
MVI C,0
CALL CLRCRC ;CLEAR CRC COUNTER
LXI H,80H
RCVCHR:
MVI B,1
CALL RECV
JC RCVSTOT
CALL RCVERR ;CHECK FOR RECEIVE ERROR
JC RCVDERR
MOV M,A
INR L
JNZ RCVCHR
LDA CKSUMFLG
ORA A
JZ RCVCRC
MOV D,C
XRA A
STA DATAFLG
MVI B,1
CALL RECV
JC RCVSTOT
CALL RCVERR ;CHECK FOR RECEIVE ERROR
JC RCVDERR
CMP D
JNZ RCVCERR
CHKSNUM:
LDA RCVSNO
MOV B,A
LDA SECTNO
CMP B
JZ RECVACK
INR A
CMP B
JNZ ABORT
RET
;
RCVCRC:
MVI E,2 ;NUMBER OF CRC BYTES
RCVCRC2:
MVI B,1
CALL RECV
JC RCVSTOT
CALL RCVERR
JC RCVDERR
DCR E
JNZ RCVCRC2
CALL CHKCRC
ORA A
JZ CHKSNUM
LDA QFLG
ORA A
JZ RCVSERR
RCVCRER:
CALL ILPRT
DB CR,LF,'++ CRC error ++',0
JMP RCVPRN
;
RCVCERR:
LDA QFLG
ORA A
JZ RCVSERR
RCVCPR:
CALL ILPRT
DB CR,LF,'++ Checksum error ++ ',0
JMP RCVPRN
;
RECVACK:
CALL SENDACK
JMP RCVSECT
;
SENDACK:
MVI A,ACK
JMP SEND
;
SENDHDR:
LDA QFLG
ORA A
JZ SENDHNM
CALL ILPRT
DB CR,'Sending # ',0
PUSH H
LHLD SECTNO ;GET SECTOR NUMBER
CALL DECOUT ;PRINT IT IN DECIMAL
CALL ILPRT
DB ' (',0
CALL DHXOUT ;16 BIT HEX CONVERSION & OUTPUT
CALL ILPRT
DB 'H)',0
POP H
SENDHNM:
MVI A,SOH
CALL SEND
LDA SECTNO
CALL SEND
LDA SECTNO
CMA
JMP SEND
;
SENDSEC:
MVI A,1
STA DATAFLG
MVI C,0
CALL CLRCRC
LXI H,80H
SENDC:
MOV A,M
CALL SEND
INR L
JNZ SENDC
XRA A
STA DATAFLG
RET
;
SENDCKS:
MOV A,C
JMP SEND
;
SENDCRC:
CALL FINCRC
MOV A,D
CALL SEND
MOV A,E
CALL SEND
XRA A
RET
;
GETACK: MVI B,10 ;10 SECONDS
CALL RECVDG
JC GETATOT
CPI ACK
RZ
MOV B,A
LDA QFLG
ORA A
JZ ACKERR
MOV A,B
CALL CRLF
CALL HEXO
CALL ILPRT
DB 'H Recv''d, not ACK',CR,LF,0
ACKERR: LDA ERRCT
INR A
STA ERRCT
DCR A
CPI ERRLIM
RC
LDA QFLG
ORA A
JZ CSABORT
GACKV: CALL CKQUIT
STC
RZ
CSABORT:
CALL ERXIT
DB CR,LF,'Can''t send sector -- Aborting',CR,LF,'$'
GETATOT:
LDA QFLG
ORA A
JZ ACKERR
CALL ILPRT
DB CR,LF,'Timeout on ACK',CR,LF,0
JMP ACKERR
;
CKABORT:
LDA QFLG
ORA A
RZ
CKABGO:
CALL STAT
RZ
CALL KEYIN
CPI CAN
RNZ
ABORT:
LXI SP,STACK
ABORTL:
MVI B,1
CALL RECV
JNC ABORTL
MVI A,CAN
CALL SEND
ABORTW:
MVI B,1
CALL RECV
JNC ABORTW
MVI A,' '
CALL SEND
CALL ILPRT
DB CR,LF,'Routine cancelled',CR,LF,BELL,0
MVI A,'B' ;TURN MULTI-FILE MODE..
STA BATCHFLG ;..OFF SO ROUTINE ENDS.
JMP DONETCE
;
INCRSNO:
PUSH H
LHLD SECTNO ;GET SECTOR NUMBER
INX H ;BUMP IT
SHLD SECTNO ;STORE IT
MOV A,L
POP H
RET
;
ERASFIL:
LDA BATCHFLG ;DON'T ASK FOR ERASE..
ORA A ;..IN MULTI-FILE MODE,..
JZ NOASK ;..JUST DO IT.
LXI D,FCB
MVI C,SRCHF
CALL BDOS
INR A
RZ
CALL ILPRT
DB 'File exists -- Type ''Y'' to erase: ',BELL,0
CALL KEYIN
PUSH PSW
CALL TYPE
POP PSW
CALL UCASE
CPI 'Y'
JNZ MENU
CALL CRLF
NOASK: LXI D,FCB
MVI C,ERASE
JMP BDOS
;
BLKFILE:
CALL ILPRT ;ROUTINE IF NO FILE IS NAMED FOR "SEND" OR "RECEIVE"
DB CR,LF,'No file specified',CR,LF,BELL,0
JMP MENU
MAKEFIL:
LXI D,FCB
MVI C,MAKE
CALL BDOS
INR A
RNZ
CALL ERXIT
DB 'Error - Can''t make file',CR,LF
DB 'Directory is likely full',CR,LF,'$'
;
IF CPM2X
;
CNREC: MVI C,FILSIZ ;COMPUTE FILE SIZE FUNCTION IN CP/M 2.x
LXI D,FCB ;POINT TO FILE CONTROL BLOCK
CALL BDOS
LHLD FCB+33 ;GET RECORD COUNT
SHLD RCNT ;STORE IT
LXI H,0 ;ZERO HL
SHLD FCB+33 ;RESET RANDOM RECORD IN FCB
RET
;
ENDIF ;CPM2X
;
IF NOT CPM2X
;
CNREC: MVI A,'?' ;MATCH ALL EXTENTS
STA FCBEXT
MVI A,0FFH
STA MAXEXT ;INIT MAX EXT NO.
MVI C,SRCHF ;GET 'SEARCH FIRST' FNC
LXI D,FCB
CALL BDOS ;READ FIRST
INR A ;WERE THERE ANY?
JNZ SOME ;GOT SOME
CALL ERXIT
DB '++ File not found ++$'
;
;READ MORE DIRECTORY ENTRIES
;
MOREDIR:
MVI C,SRCHN ;SEARCH NEXT
LXI D,FCB
CALL BDOS ;READ DIR ENTRY
INR A ;CHECK FOR END (0FFH)
JNZ SOME ;NOT END OF DIR...PROCESS EXTENT
LDA MAXEXT ;HIT END...GET HIGHEST EXTENT NO. SEEN
MOV L,A ;WHICH GIVES EXTENT COUNT -1
MVI H,0
MOV D,H
LDA RCNT ;GET RECORD COUNT OF MAX EXTENT SEEN
MOV E,A ;SAVE IT IN DE
DAD H
DAD H ;MULTIPLY # OF EXTENTS -1
DAD H ; TIMES 128
DAD H
DAD H
DAD H
DAD H
DAD D ;ADD IN SIZE OF LAST EXTENT
SHLD RCNT ;SAVE TOTAL RECORD COUNT
RET ;AND EXIT
;
;POINT TO DIRECTORY ENTRY
;
SOME: DCR A ;UNDO PREV 'INR A'
ANI 3 ;MAKE MODULUS 4
ADD A ;MULTIPLY...
ADD A ;..BY 32 BECAUSE
ADD A ;..EACH DIRECTORY
ADD A ;..ENTRY IS 32
ADD A ;..BYTES LONG
LXI H,80H POINT TO BUFFER
ADD L ;POINT TO ENTRY
ADI 15 ;OFFSET TO RECORD COUNT
MOV L,A ;HL NOW POINTS TO REC COUNT
MOV B,M ;GET RECORD COUNT
DCX H
DCX H ;BACK DOWN TO EXTENT NUMBER
DCX H
LDA MAXEXT ;COMPARE WITH CURRENT MAX.
ORA A ;IF NO MAX YET
JM BIGGER ;THEN SAVE RECORD COUNT ANYWAY
CMP M
JNC MOREDIR
BIGGER: MOV A,B ;SAVE NEW RECORD COUNT
STA RCNT
MOV A,M ;SAVE NEW MAX. EXTENT NO.
STA MAXEXT
JMP MOREDIR ;GO FIND MORE EXTENTS
;
ENDIF ;NOT CPM2X
;
OPENFIL:
XRA A
STA FCBEXT
LXI D,FCB
MVI C,OPEN
CALL BDOS
INR A
JNZ OPENOK
CALL ERXIT
DB 'Can''t open file$'
OPENOK:
LDA BATCHFLG
ORA A ;ONLY IF SINGLE FILE...
RZ
JMP SENDTIM ;A LIB MACRO SHOWS TIME TO SEND
;
CLOSFIL:
LXI D,FCB
MVI C,CLOSE
CALL BDOS
INR A
RNZ
CALL ERXIT
DB 'Can''t close file$'
RDSECT:
LDA SECINBF
DCR A
STA SECINBF
JM RDBLOCK
LHLD SECPTR
LXI D,80H
CALL MOVE128
SHLD SECPTR
RET
;
RDBLOCK:
LDA EOFLG
CPI 1
STC
RZ
MVI C,0
LXI D,DBUF
RDSECLP:
PUSH B
PUSH D
MVI C,STDMA
CALL BDOS
LXI D,FCB
MVI C,READ
CALL BDOS
POP D
POP B
ORA A
JZ RDSECOK
DCR A
JZ REOF
CALL ERXIT
DB '++ File read error ++$'
RDSECOK:
LXI H,80H
DAD D
XCHG
INR C
MOV A,C
CPI DBUFSIZ*8 ;BUFFER SIZE IN 128 BYTE SECTORS
JZ RDBFULL
JMP RDSECLP
;
REOF: MVI A,1
STA EOFLG
MOV A,C
RDBFULL:
STA SECINBF
LXI H,DBUF
SHLD SECPTR
LXI D,80H
MVI C,STDMA
CALL BDOS
JMP RDSECT
;
WRSECT:
LHLD SECPTR
XCHG
LXI H,80H
CALL MOVE128
XCHG
SHLD SECPTR
LDA SECINBF
INR A
STA SECINBF
CPI DBUFSIZ*8 ;BUFFER SIZE IN 128 BYTE SECTORS
RNZ
WRBLOCK:
LDA SECINBF
ORA A
RZ
MOV C,A
LXI D,DBUF
DKWRLP:
PUSH H
PUSH D
PUSH B
MVI C,STDMA
CALL BDOS
LXI D,FCB
MVI C,WRITE
CALL BDOS
POP B
POP D
POP H
ORA A
JNZ WRERR
LXI H,80H
DAD D
XCHG
DCR C
JNZ DKWRLP
XRA A
STA SECINBF
LXI H,DBUF
SHLD SECPTR
RET
;
WRERR: MVI C,CAN
CALL SEND
CALL ERXIT
DB CR,LF,'Error writing file',CR,LF,'$'
;
;----> RECV: Receive a character
;
;Timeout time is in B, in seconds. Entry via 'RECVDG' deletes garbage
;characters on the line. For example, having just sent a sector, calling
;RECVDG will delete any line noise induced characters LONG before the
;ACK/NAK would be received.
;
RECVDG: EQU $
CALL IN$MODDATP
CALL IN$MODDATP
RECV: PUSH D
MSEC: PUSH H
LXI H,7500
CALL FIXCNT
PUSH H
POP D
POP H
CALL CKABORT
MWTI:
CALL RCVREADY
JZ MCHAR
DCR E
JNZ MWTI
DCR D
JNZ MWTI
DCR B
JNZ MSEC
POP D
STC
RET
;
MCHAR:
LDA PMMIBYTE ;IS THE MODEM A PMMI?
ORA A ;SET FLAGS
JZ MCHAR1 ;YES, JUMP
CALL IN$MODCTLP ;GET ERROR-STATUS BYTE
ANI ERRCDMSK ;MASK OUT ALL EXCEPT ERROR BITS (3-5)
STA ERRCDE ;SAVE THE ERROR CODE
MCHAR1:
CALL IN$MODDATP
POP D
PUSH PSW
CALL UPDCRC ;CALCULATE CRC
ADD C
MOV C,A
LDA RSEEFLG
ORA A
JZ MONIN
LDA VSEEFLG
ORA A
JNZ NOMONIN
LDA DATAFLG
ORA A
JZ NOMONIN
MONIN: POP PSW
PUSH PSW
CALL SHOW
NOMONIN:
POP PSW
ORA A
RET
;
SEND: PUSH PSW
LDA SSEEFLG
ORA A
JZ MONOUT
LDA VSEEFLG
ORA A
JNZ NOMONOT
LDA DATAFLG
ORA A
JZ NOMONOT
MONOUT: POP PSW
PUSH PSW
CALL SHOW
NOMONOT:
POP PSW
PUSH PSW
CALL UPDCRC ;CALCULATE CRC
ADD C
MOV C,A
SENDW: CALL SENDREADY
JNZ SENDW
POP PSW
JMP OUT$MODDATP
;
WAITNAK:
LDA QFLG
ORA A
JZ WAITNLP
CALL ILPRT
DB 'Awaiting initial NAK',CR,LF,0
WAITNLP:
CALL CKABORT
MVI B,1
CALL RECV
CPI NAK
RZ
CPI CRC ;CRC REQUEST?
JZ WAITCRC ;YES, GO SET CRC FLAG
CPI CAN ;CANCEL?
JZ ABORT
DCR E
JZ ABORT
JMP WAITNLP
;
WAITCRC:
LDA QFLG
ORA A
JZ WAITCRC1
CALL ILPRT
DB 'CRC request received',CR,LF,0
WAITCRC1:
XRA A
STA CKSUMFLG
RET
;
;--->PARITY: Routine to setup PMMI for odd/even parity.
;
PARITY:
LDA PMMIBYTE ;IS MODEM A PMMI?
ORA A ;SET FLAGS
RZ ;NO, RETURN
LDA OPARITY ;GET ODD PARITY REQUEST BYTE
ORA A ;SET FLAGS
JNZ EVENPAR ;IF NOT ODD SEE IF IT IS EVEN
LDA UARTCTLB ;GET UART/MODEM CONTROL BYTE
ANI ODPARMSK
JMP PARITY1
;
EVENPAR:
LDA EPARITY ;GET EVEN PARITY REQUEST BYTE
ORA A ;SET FLAGS
RNZ ;IF EVEN PARITY NOT SPECIFIED RETURN
LDA UARTCTLB ;GET UART/MODEM CONTROL BYTE
ANI ODPARMSK ;SET FOR PARITY
ORI EVPARMSK ;NOW SET FOR EVEN PARITY
PARITY1:
JMP OUT$MODCTLP ;SEND TO PMMI -
;WHEN OUT$MODCTLP DOES RET IT
;WILL GO BACK TO CALLING ROUTINE
;
NOPARIT:
LDA PMMIBYTE
ORA A
RZ
LDA UARTCTLB ;GET UART/MODEM CONTROL BYTE
ORI NOPARMSK ;RESET PARITY BIT ON PMMI
JMP OUT$MODCTLP
;
INITADR:
LHLD 1
LXI D,3
DAD D
SHLD VSTAT+1
DAD D
SHLD VKEYIN+1
DAD D
SHLD VTYPE+1
DAD D
SHLD VLIST+1
LXI D,30
DAD D
SHLD VLSTAT+1
LDA PMMIBYTE
ORA A
RZ ;RETURN DONE FROM THIS ROUTINE..
LDA IN$MODCTLP+1 ;..IF NOT PMMI
STA OUT$MODCTLP+1
INR A
STA OUT$MODDATP+1
STA IN$MODDATP+1
INR A
STA IN$BAUDRP+1
STA OUT$BAUDRP+1
INR A
STA OUT$MODCTL2+1
RET
;
; CHECK OPTIONS, PUT 0 IN APPROPRIATE PLACES IN OPTION TABLE
; IF OPTION SELECTED
;
PROCOPT:
LXI D,FCB+1
LDAX D
STA OPTION
OPTLP: INX D
LDAX D
CPI ' '
JZ ENDOPT
LXI H,OPTBL
MVI B,OPTBE-OPTBL
OPTCK: CMP M
JNZ OPTNO
CPI 'O'
JNZ OPTCK1
XRA A
STA UARTFLG
JMP OPTCK2
;
OPTCK1: CPI 'A'
JNZ OPTCK2
MVI A,TRUE
STA UARTFLG
OPTCK2: MVI M,0
JMP OPTLP
;
OPTNO: INX H
DCR B
JNZ OPTCK
CALL NOTVLDMSG
POP PSW ;PRESERVE STACK
JMP MENU
;
ENDOPT: LDA VSEEFLG
ORA A
RNZ
STA QFLG ;IF VIEWING SUPPRESS ALL ELSE
RET
;
DONE:
LDA BATCHFLG
ORA A
JNZ DONETC
LDA QFLG
ORA A
JZ NMSTRNS
MVI B,12 ;ZERO OUT FTRNMSG
LXI H,FTRNMSG
MVI A,0
ZEROLP: MOV M,A
INX H
DCR B
JNZ ZEROLP
MVI B,12 ;PUT FILE NAME IN FTRNMSG
LXI H,FCB+1
LXI D,FTRNMSG
LOADMSG:
MVI A,4 ;START OF FILE TYPE?
CMP B
JZ PERIOD ;PUT IN PERIOD IF SO
MOV A,M
CPI ' ' ;DON'T PUT IN SPACE
JZ SKPSP
STAX D ;STORE IN FTRNMSG
INX D
SKPSP: INX H
DCR B
MOV A,B
ORA A ;END OF FILE NAME?
JZ FTRNMSG0 ;DISPLAY FILE NAME
JMP LOADMSG ;LOOP FOR ANOTHER CHARACTER
;
PERIOD:
MOV A,M
CPI ' ' ;IS FILE TYPE EMPTY?
JZ FTRNMSG0 ;GO IF SO
MVI A,'.' ;ELSE PUT PERIOD IN MESSAGE
STAX D
INX D
DCR B
JMP LOADMSG
;
FTRNMSG0:
CALL ILPRT
DB CR,LF
FTRNMSG:
DS 12
DB 0
CALL ILPRT
DB ' Transferred',CR,LF,LF,0
NMSTRNS:
LDA FCB ;SAVE DRIVE NO.
STA DISKNO
LXI H,FCB ;BLANK OUT FILE CONTROL BLOCKS
CALL INITFCBS
LDA DISKNO ;PUT DRIVE NUMBER BACK
STA FCB
LXI H,RESTSN ;RESTORE SECTORE NUMBERS..
LXI D,SECTNOB ;..FOR NEW FILE TRANSFER.
MVI B,SECTNOE-SECTNOB ;ROUTINE ALSO DONE IN MENU.
CALL MOVE
LDA SENDFLG ;GOES TO EITHER SEND OR..
ORA A ;..RECEIVE FILE, DEPENDING..
JNZ SENDFIL1 ;..UPON WHICH ROUTINE SET..
JMP RCVFIL1 ;..THE FLAG IN MULTI-FILE MODE.
;
DONETC:
CALL ILPRT
DB CR,LF,'Transfer completed',CR,LF,BELL,0
DONETCA:
LDA DISCFLG ;SEE IF DISCONNECT WHEN THROUGH
ORA A
JNZ DONETCE ;NO, DON'T DISCONNECT
DONETCB:
CALL ILPRT
DB CR,LF,'Press RETURN to disconnect',BELL,CR,LF,0
MVI C,RDCON
CALL BDOS ;WAIT FOR RESPONSE
CPI 0DH ;CARRIAGE RETURN
JNZ DONETCB ;NOPE
CALL ILPRT
DB CR,LF,'Disconnected',CR,LF,0
CALL JMP$DISCONNT ;HANG-UP THE PMMI
JMP EXIT ;GO TO CP/M
;
DONETCE:
CALL NOPARIT ;RESET TO NO PARITY
MVI A,TRUE
STA FIRSTME ;SET FIRST-TIME FLAG
STA FSTFLG ;RESET MULTIFILE TRANS
STA NFILFLG ;..USED IN TERMINAL ROUTINE
CMA
STA SAVEFLG ;STOP MEMORY SAVE IN TERM ROUTINE
STA LISTMOR ;STOP ANY BUFFERED OUTPUT TO PRINTER
LXI H,BOTTRAM ;RESET PRINTER BUFFER POINTERS
SHLD HLSAVE1
SHLD HLSAVE2
LDA TERMFLG ;SEE IF RETURN TO..
ORA A ;..TERMINAL MODE..
JNZ MENU ;..AFTER X'FER.
CALL CRLF
JMP TERM
;
MOVEFCB:
LXI H,FCB+16
LXI D,FCB
MVI B,16
CALL MOVE
XRA A
STA FCBSNO
STA FCBEXT
RET
;
SHOW: CPI LF
JZ CTYPE
CPI CR
JZ CTYPE
CPI 9
JZ CTYPE
CPI ' '
JC SHOWHEX
CPI 7FH
JC CTYPE
SHOWHEX:
PUSH PSW
MVI A,'('
CALL CTYPE
POP PSW
CALL HEXO
MVI A,')'
JMP CTYPE
;
CTYPE: PUSH B
PUSH D
PUSH H
MOV E,A
MVI C,WRCON
CALL BDOS
POP H
POP D
POP B
RET
;
CRLF: PUSH PSW
MVI A,CR
CALL TYPE
MVI A,LF
CALL TYPE
POP PSW
RET
;
TYPE: PUSH PSW
PUSH B
PUSH D
PUSH H
MOV C,A
VTYPE: CALL $-$
POP H
POP D
POP B
POP PSW
RET
;
STAT:
PUSH B
PUSH D
PUSH H
;
VSTAT: CALL $-$
POP H
POP D
POP B
ORA A
RET
;
KEYIN:
PUSH B
PUSH D
PUSH H
VKEYIN: CALL $-$
POP H
POP D
POP B
RET
;
LISTER:
PUSH B
PUSH D
PUSH H
VLIST: CALL $-$
POP H
POP D
POP B
RET
;
LSTSTAT:
PUSH B
PUSH D
PUSH H
VLSTAT: CALL $-$
POP H
POP D
POP B
ORA A
RET
;
UCASE:
CPI 61H ;CHANGES LOWER CASE CHARACTER..
RC ;..IN A-REG TO UPPER CASE.
CPI 7BH
RNC
ANI 5FH
RET
;
DECOUT: PUSH PSW
PUSH B
PUSH D
PUSH H
LXI B,-10
LXI D,-1
DECOU2: DAD B
INX D
JC DECOU2
LXI B,10
DAD B
XCHG
MOV A,H
ORA L
CNZ DECOUT
MOV A,E
ADI '0'
CALL CTYPE
POP H
POP D
POP B
POP PSW
RET
;
;----> DHXOUT: - DOUBLE PRECISION HEX OUTPUT ROUTINE.
;
DHXOUT:
PUSH H
PUSH PSW
MOV A,H ;GET MS BYTE
CALL HEXO ;OUTPUT HIGH ORDER BYTE
MOV A,L ;GET LS BYTE
CALL HEXO ;OUTPUT LOW ORDER BYTE
POP PSW
POP H
RET
;
HEXO:
PUSH PSW
RAR
RAR
RAR
RAR
CALL NIBBL
POP PSW
NIBBL:
ANI 0FH
CPI 10
JC ISNUM
ADI 7
ISNUM:
ADI '0'
JMP TYPE
;
;RETURNS W/ ZERO SET IF RETRY ASKED. IF MULTI-FILE MODE, THEN
;NO QUESTIONS ASKED, JUST QUIT
;
CKQUIT:
LDA BATCHFLG
ORA A
JNZ CKQTASK ;ASK FOR RETRY
INR A ;RESET ZERO FLG
RET
;
CKQTASK:
MVI A,1
STA ERRCT
CALL ILPRT
DB CR,LF,'Multiple errors encountered.',CR,LF
DB 'Type Q to quit, R to retry: ',BELL,0
CALL KEYIN
PUSH PSW
CALL CRLF
POP PSW
CALL UCASE ;INSTEAD OF "ANI 5FH"
CPI 'R'
RZ
CPI 'Q'
JNZ CKQUIT
ORA A
RET
;
SHFTYPE:
PUSH PSW
CALL ILPRT
DB 'ctrl-',0
POP PSW
ADI 40H
CALL TYPE
;
;WRITE A STRING OF CHARACTERS
;
ILPRT:
XTHL
ILPLP:
MOV A,M
ORA A
JZ ILPRET
CALL CTYPE
INX H
JMP ILPLP
ILPRET:
XTHL
RET
;
PRTMSG:
MVI C,PRINT
JMP BDOS
;
ERXIT:
POP D
CALL PRTMSG
MVI A,BELL
CALL TYPE
LDA BATCHFLG
ORA A
JNZ DONETCE
MVI A,'Q' ;RESET QFLG
STA QFLG
JMP ABORT ;ABORT OTHER COMPUTER
;
EXIT:
CALL ILPRT
DB '%%% Exiting MODEM %%%',0
LDA SAVUSR
MOV E,A
CALL SETUSR
LXI D,80H
MVI C,STDMA
CALL BDOS
LHLD STACK
SPHL
LDA SAVCCP
ORA A
JZ 0 ;WARM BOOT
RET
;
MOVE128:
MVI B,128
MOVE: MOV A,M
STAX D
INX H
INX D
DCR B
JNZ MOVE
RET
;
;INITIALIZES CP/M FILE CONTROL BLOCKS AT 5CH AND 6CH
;
SETFCB:
LXI D,CMDBUF
LXI H,FCB
CALL CPMLINE
CALL PROCOPT
CHECKNM:
LDA FCB+1 ;CHECK ON THE PRIMARY OPTION
CPI 'E' ;RETURN IF ECHO OPTION
RZ
CPI 'H' ;RETURN IF HELP OPTION
RZ
CPI 'L' ;RETURN IF LOCAL ECHO OPTION
RZ
MOV B,A
LDA PMMIBYTE
ORA A
MOV A,B
JZ S4
CPI 'C'
RZ
S4: CPI 'T'
JZ TERMSEL
CPI 'S'
JZ CKFILE
CPI 'R'
JNZ BDOPT
LDA BATCHFLG ;IF MULT FILE MODE, THEN..
ORA A ;..RECV OPT DOES NOT NEED..
RZ ;..NAME.
JMP CKFILE
BDOPT: CALL ILPRT
DB CR,LF,'++ Bad Option ++',CR,LF,0
JMP REENT
CKFILE: LDA FCB+17 ;IF OPTION THAT NEEDS FILE NAME,..
CPI ' ' ;..THEN CHECK TO SEE IF NAME..
RNZ ;..EXISTS. IF NOT..
REENT: CALL ILPRT ;..DO EVERYTHING OVER.
DB CR,LF,'Re-enter PRIMARY option and file name only: ',BELL,0
LXI D,CMDBUF
CALL INBUFF
JMP SETFCB
;
TERMSEL:
LDA FCB+17
CPI ' '
JNZ SAVAGN
MVI A,FALSE
STA SAVEFLG
MVI A,TRUE
STA NFILFLG
RET
;
SAVAGN:
MVI A,FALSE
STA NFILFLG
RET
;
NEWBAUD:
LDA PMMIBYTE
ORA A
RZ
CALL ILPRT
DB CR,LF,'Enter New Baudrate: ',0
LXI H,FCB+9
MVI M,0 ;PUTS A ZERO IN FIRST POSITION SO AS TO
LOOP5:
CALL KEYIN ;FORCE THE DEFAULT OPTION OF 300 BAUD.
CPI CR ;CARRIAGE RET ENTERS BAUD RATE
JNZ CONNEWB ;GOES TO THE ESTABLISHED ROUTINE - RETURN TO MAIN
CALL CRLF ;PROGRAM IS DONE THERE.
JMP JMP$INITMOD
;
CONNEWB:
CPI 30H ;MAKE SURE IT'S..
JC LOOP5 ;..A DIGIT, ELSE..
CPI 3AH ;..DON'T ACCEPT IT.
JNC LOOP5
MOV M,A
MOV C,A
CALL TYPE ;ECHO THE CHARACTER ENTERED
INX H
JMP LOOP5
;
;****************************************************************
;* *
;* CRCSUBS (Cyclic Redundancy Code Subroutines) version 1.20 *
;* 8080 Mnemonics *
;* *
;* These subroutines will compute and check a true 16-bit *
;* Cyclic Redundancy Code for a message of arbitrary length. *
;* *
;* The use of this scheme will guarantee detection of all *
;* single and double bit errors, all errors with an odd *
;* number of error bits, all burst errors of length 16 or *
;* less, 99.9969% of all 17-bit error bursts, and 99.9984% *
;* of all possible longer error bursts. (Ref: Computer *
;* Networks, Andrew S. Tanenbaum, Prentiss-Hall, 1981) *
;* *
;* Designed & coded by Paul Hansknecht, June 13, 1981 *
;* *
;* Copyright (c) 1981, Carpenter Associates *
;* Box 451 *
;* Bloomfield Hills, MI 48013 *
;* 313/855-3074 *
;* *
;* This program may be freely reproduced for non-profit use. *
;* *
;****************************************************************
;
; ENTRY CLRCRC,UPDCRC,FINCRC,CHKCRC
;
CLRCRC: EQU $ ;RESET CRC ACCUMULATOR FOR A NEW MESSAGE.
PUSH H
LXI H,0
SHLD CRCVAL
POP H
RET
;
UPDCRC: EQU $ ;UPDATE CRC ACCUMULATOR USING BYTE IN (A).
PUSH PSW
PUSH B
PUSH H
MVI B,8
MOV C,A
LHLD CRCVAL
UPDLOOP:
MOV A,C
RLC
MOV C,A
MOV A,L
RAL
MOV L,A
MOV A,H
RAL
MOV H,A
JNC SKIPIT
MOV A,H ;THE GENERATOR IS X^16 + X^12 + X^5 + 1
XRI 10H ;AS RECOMMENDED BY CCITT.
MOV H,A ;AN ALTERNATE GENERATOR WHICH IS OFTEN
MOV A,L ;USED IN SYNCHRONOUS TRANSMISSION PROTOCOLS
XRI 21H ;IS X^16 + X^15 + X^2 + 1. THIS MAY BE
MOV L,A ;USED BY SUBSTITUTING XOR 80H FOR XOR 10H
SKIPIT: DCR B ;AND XOR 05H FOR XOR 21H IN THE ADJACENT CODE
JNZ UPDLOOP
SHLD CRCVAL
POP H
POP B
POP PSW
RET
;
FINCRC: EQU $ ;FINISH CRC CALCULATION FOR OUTPUT MESSAGE
PUSH PSW
XRA A
CALL UPDCRC
CALL UPDCRC
PUSH H
LHLD CRCVAL
MOV D,H
MOV E,L
POP H
POP PSW
RET
;
CHKCRC: EQU $ ;CHECK CRC BYTES OF RECEIVED MESSAGE
PUSH H
LHLD CRCVAL
MOV A,H
ORA L
POP H
RZ
MVI A,0FFH
RET
;
CRCVAL:
DW 0
;
MENU0:
LDA NFILFLG
ORA A
JNZ MENU ;GO IF NO FILE ACTIVE
CALL ILPRT ;ELSE PRINT MESSAGE
DB CR,LF,LF
DB '** There may be text in the memory buffer **',CR,LF
DB '** It will be lost unless NOL or WRT commands are used **'
DB CR,LF,BELL,0
MVI B,2 ;2 MORE BELLS
BLOOP: LDA BELRPT ;GET TIME
MOV C,A
BCLOOP: LXI H,1000 ;ABOUT 0.03 SECONDS
CALL FIXCNT
BILOOP: MOV A,L
ORA H
DCX H
JNZ BILOOP
DCR C
JNZ BCLOOP
MVI A,BELL
CALL TYPE
DCR B
JNZ BLOOP
JMP MENU1
;
MENU:
LDA EXITFLG
ORA A
JNZ EXIT
MENU1:
LXI H,RESTSN ;RESTORE SECTOR NUMBERS..
LXI D,SECTNOB ;..FOR NEW FILE TRANSFER.
MVI B,SECTNOE-SECTNOB
CALL MOVE
LXI H,RESTROPT ;RESTORE OPTION TABLE
LXI D,OPTBL
MVI B,OPTBE-OPTBL
CALL MOVE
MVI A,0
STA MFFLG1 ;RESET MFACCESS ROUTINE..
CMA ;..AND MULTI TRANS IN CASE..
STA FSTFLG ;..OF ABORT.
JMP XPRT
;
MENU2:
CALL CLRTST
CALL ILPRT
DB ' Single Letter Commands',CR,LF,LF
DB ' H - Display this information',CR,LF
DB ' ? - Display current settings',CR,LF,LF
DB ' T - Terminal mode',CR,LF
DB ' E - Terminal mode with echo',CR,LF
DB ' L - Terminal mode with local echo',CR,LF
DB ' For capturing text use T(or E or L) FILENAME.TYP and'
DB CR,LF
DB ' Start & Stop toggles described on subsequent screen.'
DB CR,LF,LF
DB ' R - Receive file using Christensen Protocol',CR,LF
DB ' S - Send file using Christensen Protocol',CR,LF
DB ' Command is: R(or S) FILENAME.TYP',CR,LF
DB ' R and S can use the following subcommands:',CR,LF
DB ' B - Bulk transfer using wildcards (e.g. *.*)',CR,LF
DB ' Q - Quiet mode (no messages to console)',CR,LF
DB ' T - Return to terminal mode after transfer',CR,LF
DB ' V - View bytes transferred on console',CR,LF,LF
DB 'The single letter commands may also be used on the',CR,LF
DB 'command line when the program is initially executed.'
DB CR,LF,LF,0
;
CALL NXTSCRN
;
LDA PMMIBYTE
ORA A
JZ THREELTR
CALL ILPRT
DB ' Additional Subcommands for PMMI Modem',CR,LF,LF
DB ' Modem control:',CR,LF
DB ' O - Send or receive on Originate tone',CR,LF
DB ' A - Send or receive on Answer tone',CR,LF
DB ' D - Disconnect option',CR,LF,LF
DB ' Parity options:',CR,LF
DB ' 1 - Set and check for odd parity',CR,LF
DB ' 0 - Set and check for even parity',CR,LF
DB ' Both ends must be capable of these options',CR,LF
DB ' which are available only in S and R modes.',CR,LF
DB ' The parity checking will be part of the',CR,LF
DB ' file transfer protocol.',CR,LF,LF
DB ' Speed Options:',CR,LF
DB ' After entering your primary and secondary options,'
DB CR,LF
DB ' you can set the modem speed by placing a "." after'
DB CR,LF
DB ' the options followed by the speed e.g. 110, 300.',CR,LF
DB ' For example: SBO1T.600 will set the modem to run',CR,LF
DB ' at 600 baud.',CR,LF,LF,0
;
CALL NXTSCRN
;
THREELTR:
CALL ILPRT
DB ' Three Letter Commands',CR,LF,LF
DB 'DIR - List directory and space free (may specify drive)'
DB CR,LF
DB 'END - Exit from this program',CR,LF
DB 'ERA - Erase file (may specify drive)',CR,LF
DB 'LOG - Change default drive/user (specify drive/user)'
DB CR,LF
DB ' and reset disks. e.g. LOG A0, LOG B (user unchanged)'
DB CR,LF
DB 'SPD - Set speed of file output in terminal mode',CR,LF,0
;
CALL SORPTST
JNZ NOTIME
CALL ILPRT
DB 'TIM - Set S mode time-to-send message',CR,LF,0
;
NOTIME:
LDA TOGGLECRC
ORA A
JZ NOTOGCRC
CALL ILPRT
DB 'TCC - Toggle Checksum/CRC mode on receive',CR,LF,0
;
NOTOGCRC:
LDA TOGGLEBK
ORA A
JZ NOTOGBK
CALL ILPRT
DB 'TBR - Toggle backspace to rub conversion',CR,LF,0
;
NOTOGBK:
LDA TOGGLELOC
ORA A
JZ NOTOGLOC
CALL ILPRT
DB 'TLC - Toggle 1) local command immediate',CR,LF
DB ' 2) local command after ',0
LDA EXTCHR
CALL SHFTYPE
DB CR,LF,0
;
NOTOGLOC:
LDA TOGGLELF
ORA A
JZ NOTOGLF
CALL ILPRT
DB 'TLF - Toggle send linefeed after carriage return',CR,LF,0
;
NOTOGLF:
LDA TOGXOFF
ORA A
JZ NOTOGXOFF
CALL ILPRT
DB 'TXO - Toggle XOFF/XON testing in terminal mode file output'
DB CR,LF,0
;
NOTOGXOFF:
LDA PMMIBYTE
ORA A
JNZ NONUM
CALL ILPRT
DB 'NUM - List remote systems',CR,LF,0
LDA SETUPTST
ORA A
JZ NOSETUP
CALL ILPRT
DB 'SET - Set communication ports',CR,LF,0
;
NOSETUP:
MVI A,LF
CALL TYPE
JMP NOPMMI
;
NONUM:
CALL ILPRT
DB 'CAL - Dial number',CR,LF
DB 'DSC - Disconnect',CR,LF
DB 'BYE - Disconnect and reboot',CR,LF,LF,0
;
NOPMMI:
CALL ILPRT
DB ' The following are terminal text buffer commands:'
DB CR,LF,0
LDA PMMIBYTE
ORA A
JNZ SKIPLF
MVI A,LF
CALL TYPE
SKIPLF:
CALL ILPRT
DB 'DEL - Delete memory buffer and file',CR,LF
DB 'NOL - Return to terminal mode - no loss of data in buffer'
DB CR,LF
DB 'WRT - Write memory buffer to disk file',CR,LF,LF,0
CALL NXTSCRN
;
CALL ILPRT
DB ' Local Commands while in Terminal Mode',CR,LF,LF,0
LDA EXITCHR
CALL SHFTYPE
DB ' - Exit to command mode',CR,LF,LF,0
;
LDA PMMIBYTE
ORA A
JZ S5A
;
LDA DISCCHR
CALL SHFTYPE
DB ' - Disconnect',CR,LF,0
LDA BRKCHR
CALL SHFTYPE
DB ' - Send break',CR,LF,0
LDA CHGBAUD
CALL SHFTYPE
DB ' - Change baud rate',CR,LF,0
;
S5A:
LDA TRANLOGON
ORA A
JZ NOTRANLOG
LDA LOGCHR
CALL SHFTYPE
DB ' - Transmit logon',CR,LF,0
;
NOTRANLOG:
LDA LSTTST
ORA A
JZ NOLST2
LDA LSTCHR
CALL SHFTYPE
DB ' - Toggle printer',CR,LF,0
;
NOLST2:
MVI A,LF
CALL TYPE
LDA SAVECHR
CALL SHFTYPE
DB ' - Start copy into buffer',CR,LF,0
LDA UNSAVECHR
CALL SHFTYPE
DB ' - Stop copy into buffer',CR,LF
DB ' Start & Stop may be toggled as often as desired.',CR,LF
DB ' A ":" at start of line indicates buffer is open.',CR,LF
DB ' XOFF automatically used to stop input when writing',CR,LF
DB ' full buffer to disk, XON sent to resume.',CR,LF,LF,0
LDA TRANCHR
CALL SHFTYPE
DB ' - Transfer ASCII file to remote',CR,LF,LF,0
LDA LOCONEXTCHR
ORA A
LDA EXTCHR
JNZ REMDFLT
CALL SHFTYPE
DB ' - Send local control character to remote',CR,LF,0
JMP XPRT
REMDFLT:
CALL SHFTYPE
DB ' - Next character will be used for local control',CR,LF,0
;
XPRT:
CALL ILPRT
DB CR,LF,'Drive ',0
MVI C,CURDSK ;CURRENT DISK FUNCTION
CALL BDOS
ADI 'A' ;MAKE ASCII
CALL TYPE
;
IF CPM2X ;IF CPM VER 2.X
;
CALL GETUSR ;GET CURRENT USER NUMBER
CPI 0
JZ SR3B ;SKIP IF USER 0
PUSH PSW
CALL ILPRT
DB ', User ',0
POP PSW
MVI H,0
MOV L,A
CALL DECOUT ;REPORT USER
;
ENDIF ;CPM2X
;
SR3B: CALL CRLF
LDA NFILFLG
ORA A
JNZ NOBUFMSG
CALL GETSPC
CALL ILPRT
DB ' bytes of buffer free',CR,LF,0
NOBUFMSG:
CALL ILPRT
DB 'COMMAND (H for Help): ',0
GETCMD:
LXI D,CMDBUF ;ENTER COMMAND
CALL INBUFF
CALL CRLF
LXI D,CMDBUF+2 ;POINT TO COMMAND
CALL ILCOMP
DB 'END',0
JNC EXIT
CALL ILCOMP
DB 'LOG',0
JNC LOGNEW
CALL ILCOMP
DB 'DIR',0
JNC DIR
CALL ILCOMP
DB 'ERA',0
JNC ERASEF
CALL ILCOMP
DB '?',0
JNC CURPAR
CALL ILCOMP
DB 'SPD',0
JNC SETSPD
CALL ILCOMP
DB 'TIM',0
JNC SETTIM
CALL ILCOMP
DB 'TCC',0
JNC TOGCRC
CALL ILCOMP
DB 'TBR',0
JNC TOGBKSP
CALL ILCOMP
DB 'TLC',0
JNC TOGLOC
CALL ILCOMP
DB 'TLF',0
JNC TOGLF
CALL ILCOMP
DB 'TXO',0
JNC TOGTXOFF
LDA PMMIBYTE
ORA A
JNZ NONUM2
CALL ILCOMP
DB 'NUM',0
JNC NUMPRN
NONUM2: LDA SETUPTST
ORA A
JZ NOSETUP2
CALL ILCOMP
DB 'SET',0
JNC SETUPENT
NOSETUP2:
CALL ILCOMP
DB 'NOL',0
JC NXTOPT1 ;CARRY SET = NO MATCH
LDA NFILFLG
ORA A
JNZ NOFILOPN ;GO TELL OPERATOR IF NO FILE OPEN
LDA ORIGSAV
STA ORIGFLG
CALL BUFMSG
LHLD HLSAVE ;RETURN TO TERMINAL..
JMP TERM ;..MODE WITH SAVE OPTION..
;..IF PREVIOUSLY ENABLED.
;
NXTOPT1:
CALL ILCOMP
DB 'WRT',0
JNC WRTFIL
CALL ILCOMP
DB 'DEL',0
JNC NEWFILE
LDA PMMIBYTE
ORA A
JZ S6
CALL ILCOMP ;DE SET FROM 1ST ILCOMP CALL
DB 'DSC',0
JNC DISCON1
CALL ILCOMP
DB 'BYE',0
JNC BYEBYE
CALL ILCOMP
DB 'CAL',0
JC S6
MVI A,20H ;FOOL THE SYSTEM
STA CMDBUF+4 ;..CMDBUF SO THAT IT..
JMP DOOPT ;..LOOKS AT OPTION FOR DIAL
S6: PUSH H
LDA CMDBUF+2
LXI H,COMPLIST
CALL COMPARE ;COMPARES LIST POINTED TO BY HL..
POP H ;..TO CHAR IN A-REG.
JC NOTVLD ;CARRY SET = NO MATCH
DOOPT: PUSH H ;LOAD ORIGINAL FCB WITH TRANSFER..
CALL SETFCB ;..CMDS AND GO TO BEGINNING OF..
POP H ;..PROGRAM. WILL FOLLOW SAME LOGIC..
JMP RESTART ;..AS IF PROGRAM WERE CALLED WITH..
;..CP/M COMMAND LINE.
;
NOTVLD:
CALL NOTVLDMSG
JMP XPRT
;
NOTVLDMSG:
CALL ILPRT
DB '++ Invalid Command ++',CR,LF,BELL,0
RET
;
DISCON1:
CALL JMP$DISCONNT
CALL ILPRT
DB CR,LF,'<< Disconnected >>',CR,LF,BELL,0
JMP EXITMEN
;
BYEBYE:
CALL ILPRT
DB CR,LF,'Goodbye...',CR,LF,0
XRA A
CALL OUT$MODCTLP
CALL OUT$MODCTL2
LDA SAVUSR
MOV E,A
CALL SETUSR
LHLD CLDBOOT ;GET COLD BOOT PROM ADDRESS OR WARM BOOT
PCHL ;JUMP TO IT
;
DIR:
MVI C,CURDSK
CALL BDOS
STA DISKSAV
CALL DIRLST
LDA DISKSAV
MOV E,A
MVI C,SELDSK
CALL BDOS
JMP XPRT
;
LOGNEW: LDA NFILFLG
ORA A
JZ NORESET
LDA CMDBUF+6
CPI ' '
JNZ SPECIFD
MVI C,CURDSK
CALL BDOS
ADI 'A'
SPECIFD:
SUI 'A'
STA DISKSAV
CPI 16
JNC NOTVLD
;
IF CPM2X ;IF CPM VER. 2.X
;
CALL GETUSR ;PICK UP CURRENT USER NUMBER
MOV B,A ;SAVE IT
LDA CMDBUF+7 ;GET NEW USER NUMBER
CPI ' ' ;CHECK FOR SPACE
JZ SR7B ;EXIT IF NO NEW USER NUMBER SPECIFIED
CALL NUMCHK ;CHECK TO SEE IF IT IS A NUMBER
MOV B,A ;SAVE
LDA CMDBUF+8 ;GET SECOND DIGIT
CPI ' '
JZ SR7B ;GO IF SPACE
CALL NUMCHK
MOV C,A ;SAVE
MOV A,B ;GET SAVED FIRST DIGIT
ADD A ; X2
ADD A ; X4
ADD A ; X8
ADD B ; X9
ADD B ; X10
ADD C
MOV B,A ;SAVE
LDA CMDBUF+9 ;GET THIRD DIGIT
CPI ' '
JZ SR7B ;GO IF SPACE
CALL NUMCHK
MOV C,A ;SAVE
MOV A,B ;GET SAVED FIRST & SECOND DIGIT
ADD A ; X2
ADD A ; X4
ADD A ; X8
ADD B ; X9
ADD B ; X10
ADD C
; CPI 16 ;CHECK FOR < 16
; JNC NOTVLD ;GO IF NOT
MOV B,A
SR7B: MOV A,B
STA SAVUSR
;
ENDIF ;CPM2X
;
CALL ILPRT
DB 'Insert disk for drive ',0
LDA DISKSAV
ADI 'A'
CALL TYPE
NOTCR: CALL ILPRT
DB CR,LF,'Hit return when ready',0
CALL KEYIN
CPI 3 ;CTL-C ABORTS LOGIN
JZ XPRT
CPI CR
JNZ NOTCR
CALL CRLF
MVI C,RESET
CALL BDOS
LDA DISKSAV
MOV E,A
MVI C,SELDSK
CALL BDOS
;
IF CPM2X
LDA SAVUSR
MOV E,A
CALL SETUSR
ENDIF
;
JMP XPRT
;
IF CPM2X
;
GETUSR: MVI E,0FFH ;GET CURRENT USER
SETUSR: MVI C,USER ;SET-UP FUNCTION CALL
JMP BDOS ;NUMBER IN RETURNED IN A
;
ENDIF ;CPM2X
;
NORESET:
CALL ILPRT
DB '++ Terminal mode file open ++',CR,LF
DB '++ Use WRT or DEL before LOG command ++',CR,LF
DB CR,LF,LF,BELL,0
XRA A
JMP XPRT
;
ERASEF: LXI D,CMDBUF ;PUT CMD LINE INTO FCB AT HL
LXI H,FCB
CALL CPMLINE
CALL MOVEFCB ;MOVE FCB+16 TO FCB
LDA FCB+1
CPI ' '
JZ NOTVLD ;GO IF NO FILE SPECIFIED
LXI D,FCB
MVI C,SRCHF
CALL BDOS
INR A ;0 IF FILE NOT FOUND
JNZ ERAFILE ;OK, GO ERASE
CALL ILPRT
DB '++ File not found ++',CR,LF,BELL,0
JMP XPRT
;
ERAFILE:
LXI D,FCB
MVI C,ERASE
CALL BDOS
CALL ILPRT
DB 'File erased',CR,LF,0
JMP XPRT
;
SETSPD:
CALL ILPRT
DB 'Enter character output delay [0(none) - 9(longest delay)]: ',0
CALL NUMGET
JNC NOCHG1
STA BYTDLY
NOCHG1: CALL SPDMSG
CALL ILPRT
DB CR,LF,'Enter additional delay after <CR> [0-9]: ',0
CALL NUMGET
JNC NOCHG2
RLC ;X2
RLC ;X4
STA CRDLY
NOCHG2: CALL CRDLYMSG
JMP XPRT
;
NUMGET: LXI D,CMDBUF
CALL INBUFF
LDA CMDBUF+2 ;GET NUMBER
CPI ' '
RZ
NUMCHK: SUI '0'
CPI 10
RC
POP PSW ;PRESERVE STACK
JMP NOTVLD
;
SPDMSG: CALL ILPRT
DB 'Terminal mode file output delay is 0.',0
LDA BYTDLY
CALL GIVNUM
CALL ILPRT
DB ' seconds per character',CR,LF,0
RET
;
CRDLYMSG:
CALL ILPRT
DB 'Additional delay after <CR> is 0.',0
LDA CRDLY
CALL GIVNUM
CALL ILPRT
DB ' seconds',CR,LF,0
RET
;
GIVNUM: ADD A ;2X
CPI 10
MOV B,A
JNC NOZERO
MVI A,'0'
CALL TYPE
MOV A,B
NOZERO: PUSH H
MOV L,A
MVI H,0
CALL DECOUT
POP H
RET
;
SETTIM:
CALL SORPTST
JNZ NOTVLD
CALL ILPRT
DB 'Use 0-8 to give baud rate for S mode time-to-send message,'
DB CR,LF
DB 'where 0=110, 1=300, 2=450, 3=600, 4=710, 5=1200, 6=2400,'
DB CR,LF
DB ' 7=4800, and 8=9600 Baud.'
DB CR,LF,LF,'Enter value: ',0
CALL NUMGET
CPI 9
JNC NOTVLD
STA MSPEED
CALL SETTIM2
JMP XPRT
;
SETTIM2:
CALL SORPTST
JNZ SETTIM3
CALL ILPRT
DB 'Rate for the S mode time-to-send message is set to ',0
JMP SETTIM4
SETTIM3:
CALL ILPRT
DB 'Modem speed is ',0
SETTIM4:
JMP BAUDPRT
;
SORPTST:
LDA SETUPTST
MOV B,A
LDA PMMIBYTE
ORA B
RET
;
TOGCRC:
LDA TOGGLECRC
ORA A
JZ NOTVLD
LDA CKSUMDFLT
CMA
STA CKSUMDFLT
CALL TOGCRC2
JMP XPRT
;
TOGCRC2:
ORA A
JNZ CHEKMSG
CALL ILPRT
DB 'CRC mode set',CR,LF,0
RET
;
CHEKMSG:
CALL ILPRT
DB 'Checksum mode set',CR,LF,0
RET
;
TOGBKSP:
LDA TOGGLEBK
ORA A
JZ NOTVLD
LDA CONVBKSP
CMA
STA CONVBKSP
CALL TOGBKSP2
JMP XPRT
;
TOGBKSP2:
LDA CONVBKSP
ORA A
JZ NORUBMSG
CALL ILPRT
DB 'Backspace is rub',CR,LF,0
RET
;
NORUBMSG:
CALL ILPRT
DB 'Backspace is backspace',CR,LF,0
RET
;
TOGLOC: LDA TOGGLELOC
ORA A
JZ NOTVLD
LDA LOCONEXTCHR
CMA
STA LOCONEXTCHR
CALL TOGLOC2
JMP XPRT
;
TOGLOC2:
CALL ILPRT
DB 'Use ',0
LDA LOCONEXTCHR
ORA A
LDA EXTCHR
JZ LOCMSG
CALL SHFTYPE
DB ' before local command',CR,LF,0
RET
;
LOCMSG: CALL SHFTYPE
DB ' to send local command to remote',CR,LF,0
RET
;
TOGLF: LDA TOGGLELF
ORA A
JZ NOTVLD
LDA ADDLF
CMA
STA ADDLF
CALL TOGLF2
JMP XPRT
;
TOGLF2:
CALL ILPRT
DB 'Linefeed ',0
LDA ADDLF
ORA A
JNZ LFMSG
CALL ILPRT
DB 'NOT ',0
LFMSG: CALL ILPRT
DB 'sent after <CR>',CR,LF,0
RET
;
TOGTXOFF:
LDA TOGXOFF
ORA A
JZ NOTVLD
CALL ILPRT
DB 'Use XOFF testing? (Y/N): ',0
CALL GETANS
JC NOCHG3
STA XOFFTST
NOCHG3: CALL XOFFMSG
CALL ILPRT
DB CR,LF,'Use XON waiting after <CR> (Y/N): ',0
CALL GETANS
JC NOCHG4
STA XONWAIT
NOCHG4: CALL XONMSG
LDA XONWAIT
ORA A
JZ XPRT
CMA
STA XOFFTST ;DON'T ALLOW BOTH
CALL ILPRT
DB 'Therefore ',0
CALL XOFFMSG
JMP XPRT
;
GETANS:
LXI D,CMDBUF
CALL INBUFF
LDA CMDBUF+2 ;GET ANSWER
CPI ' '
CMC
RZ
MOV B,A
CPI 'N'
MVI A,FALSE
RZ
MOV A,B
CPI 'Y'
MVI A,TRUE
RZ
POP PSW ;PRESERVE STACK
JMP NOTVLD
;
XOFFMSG:
CALL ILPRT
DB 'XOFF testing ',0
LDA XOFFTST
ORA A
JNZ XOTSTON
CALL ILPRT
DB 'NOT ',0
XOTSTON:
CALL ILPRT
DB 'used',0
XONMSG3:
CALL ILPRT
DB ' in terminal mode file output',CR,LF,0
RET
;
XONMSG:
CALL ILPRT
DB 'XON ',0
LDA XONWAIT
ORA A
JNZ XONMSG2
CALL ILPRT
DB 'NOT ',0
XONMSG2:
CALL ILPRT
DB 'automatically tested after <CR>',0
JMP XONMSG3
;
SETUPENT:
LDA SETUPTST
ORA A
JZ NOTVLD
LXI D,CMDBUF+1
CALL JMP$SETUPR
JMP XPRT
;
NEWFILE:
LDA NFILFLG
ORA A
JNZ NOFILOPN
LDA FCB3+1 ;CHECK THAT FILE WAS REQUESTED
CPI ' '
JZ NOFILOPN ;IF NO FILE, DON'T ERASE
LXI D,FCB3
MVI C,ERASE
CALL BDOSRT
MVI A,TRUE ;DO NOT ALLOW TERMINAL..
STA NFILFLG ;..SAVE SINCE NO FILE..
CMA ;..SPECIFIED.
STA SAVEFLG
LXI H,FCB3
CALL INITFCBS
LXI H,BOTTRAM
SHLD HLSAVE
JMP XPRT
;
WRTFIL:
LDA NFILFLG
CPI TRUE
JZ NOFILOPN
LDA FCB3+1 ;CHECK THAT FILE WAS REQUESTED
CPI ' '
JZ NOFILOPN
LHLD HLSAVE
CALL NUMRECS ;DISK WRITE ROUTINE AS USED IN..
CALL WRTDSK ;..IN THE INTDSKSV ROUTINE.
CALL CLOSE3
MVI A,TRUE
STA NFILFLG
CMA
STA SAVEFLG
LXI H,FCB3
CALL INITFCBS ;BLANK OUT FCB SO WRITTEN FILE CAN'T BE ERASED.
LXI H,BOTTRAM
SHLD HLSAVE
JMP XPRT
;
NOFILOPN:
CALL ILPRT
DB '++ No File Open ++',CR,LF,BELL,0
JMP XPRT
;
;THIS ROUTINE DISPLAYS THE PHONE NUMBERS IN THE LIBRARY
;
NUMPRN:
PUSH H
CALL CLRTST
CALL ILPRT
DB ' Library of Phone Numbers of Remote Systems',0
MVI C,13 ;NUMBER OF LINES TO MOVE
LXI H,NUMBLIB ;ADDRESS OF SOURCE MEMORY
LXI D,DBUF ;ADDRESS OF TARGET MEMORY
CALL NEWLINE ;START WITH CRLF
STAX D ;+LF
INX D ;AND BUMP IT
NUMPRN1:
INX H ;SKIP PMMI DIALING LETTER
INX H ;AND EQUAL SIGN
MVI B,30 ;NUMBER OF BYTES TO MOVE
CALL MOVE ;MOVE TO BUFFER
CALL SPACES ;2 ENTRIES + 3 SPACES = 63 CHARACTERS
INX H
INX H
MVI B,30
CALL MOVE
CALL NEWLINE
DCR C ;NUMBER OF LINES TO PRINT
JZ NUMPRN2
JMP NUMPRN1
;
NEWLINE: ;PUTS CR-LF AT MEMORY POINTED BY 'DE'
MVI A,CR ;CR
STAX D ;STORE IT
MVI A,LF ;LF
INX D ;BUMP POINTER
STAX D ;STORE LF
INX D ;BUMP POINTER
RET
;
SPACES:
MVI A,20H ;SPACE
STAX D
INX D ;1
STAX D
INX D ;2
STAX D
INX D ;3
RET
;
NUMPRN2:
MVI A,'$'
STAX D
MVI C,PRINT
LXI D,DBUF ;POINT TO TABLE OF NUMBERS TO PRINT
CALL BDOS
CALL CRLF
CALL CRLF
POP H
JMP XPRT
;
COMPARE:
MOV B,M ;COMPARES A-REG WITH LIST..
COMPLP:
INX H ;..ADDRESSED BY HL. FIRST ELEMENT..
CMP M ;..OF LIST MUST BE NUMBER OF ELEMENTS..
JZ VALID ;..BEING COMPARED. RETURNS WITH..
DCR B ;..CARRY SET IF A-REG DOES NOT..
JNZ COMPLP ;.. CONTAIN AN ELEMENT IN LIST.
STC
VALID:
RET
;
NXTSCRN:
CALL ILPRT
DB 'HIT any KEY to CONTINUE',0
NOKEY1: CALL STAT ;GET KEYBOARD STATUS
JZ NOKEY1 ;KEEP LOOPING UNTIL KEYPRESS
CALL KEYIN ;GOBBLE UP KEYPRESS
CPI 3 ;QUIT?
JNZ CLRTST
POP PSW ;CLEAN RETURN ADR OFF OF STACK
JMP XPRT
;
CLRTST: LDA SCRNTEST
ORA A
JNZ CLRSCRN
;
LOTSALF:
MVI A,CR
CALL TYPE
MVI B,12
MVI A,LF
LFLOOP: CALL TYPE
DCR B
JNZ LFLOOP
RET
;
CURPAR:
CALL CLRTST
CALL ILPRT
DB ' Current Settings',CR,LF,LF,LF,0
LDA CKSUMDFLT
CALL TOGCRC2
LDA LSTTST
ORA A
JZ NOLST3
CALL LSTMSG
NOLST3:
CALL SETTIM2
CALL TOGBKSP2
CALL TOGLF2
CALL TOGLOC2
CALL ILPRT
DB 'Terminal mode file buffer is ',0
LDA NFILFLG
ORA A
JZ ACTIVE
CALL ILPRT
DB 'in',0
ACTIVE:
CALL ILPRT
DB 'active',CR,LF,'Unused portion of buffer is ',0
CALL GETSPC
CALL ILPRT
DB ' bytes',CR,LF,0
CALL XOFFMSG
CALL XONMSG
CALL SPDMSG
CALL CRDLYMSG
CALL CRLF
JMP XPRT
;
GETSPC: CALL GETMAX
MOV B,A
LHLD HLSAVE
STC
CMC
MVI A,0
SBB L
MOV L,A
MOV A,B
SBB H
MOV H,A
JMP DECOUT
;
;ADJUSTS LOOP COUNTERS FOR VARIOUS CLOCK SPEEDS
;
FIXCNT: LDA CLOCK
CPI 1
RZ
PUSH D
PUSH H
POP D
CNTMUL: DAD D
DCR A
JNZ CNTMUL
POP D
RET
;
COMPLIST:
DB 6, 'S', 'R', 'T', 'E', 'H', 'L'
ILCOMP:
INLNCOMP ;A LIB MACRO
INBUFF:
INBUF ;A LIB MACRO
;
;IF ABOVE ROUTINE DOES NOT LET YOU EDIT IN A PROPER MANNER,
;THEN THE MACRO MAY BE SUBSTITUTED FOR THE FOLLOWING ROUTINE:
;
;INBUFF:
; MVI C,RDBUF
; JMP BDOSRT ;BUT BE CAREFUL OF CONTROL-C
;
CPMLINE:
CMDLINE ;A LIB MACRO
DIRLST:
DIRLIST ;A LIB MACRO
SENDTIM:
SENDTIME ;A LIB MACRO
BAUDPRT:
PRTBAUD ;A LIB MACRO
NFILFLG:
DB FALSE ;NORMALLY SET TO FALSE. ALLOWS WRITE TO..
; ;..MEMORY IN TERMINAL MODE.
OPTION:
DB 0
;
OPTBL EQU $
;
ANSWFLG:
DB 'A'
DISCFLG:
DB 'D'
ORIGFLG:
DB 'O'
QFLG:
DB 'Q'
RSEEFLG:
DB 'R'
SSEEFLG:
DB 'S'
VSEEFLG:
DB 'V'
TERMFLG:
DB 'T'
LOCCHFLG:
DB 'L'
EPARITY:
DB '0' ;EVEN PARITY SUB-OPTION
;ONLY AVAILABLE IN 'S' AND 'R' MODES
OPARITY:
DB '1' ;ODD PARITY SUB-OPTION
;ONLY AVAILABLE IN 'S' AND 'R' MODES
BATCHFLG:
DB 'B' ;BATCH FLAG (WHY WAS THIS DISABLED IN EARLIER VERS?)
OPTBE EQU $
RESTROPT: ;MUST BE IN SAME ORDER AS TABLE ABOVE
DB 'A','D','O','Q','R','S','V','T','L'
DB '0','1','B'
;
;THE NEXT 13 BYTES EQUAL THE NUMBER OF BYTES BETWEEN SECTNOB AND SECTNOE
RESTSN:
DB 0,0,0,0,0,0
DW DBUF
DB 0,0,0,0,0
;
SECTNOB EQU $ ;START OF TABLE MARKER
RCVSNO: DB 0 ;\
SECTNO: DW 0 ; \
ERRCT: DB 0 ; \
ERRCDE: DB 0 ; \
EOFLG: DB 0 ; \ 13 BYTES BETWEEN TABLE MARKERS
SECPTR: DW DBUF ; /
SECINBF: DB 0 ; /
MAXEXT: DB 0 ; /
RCNT: DW 0 ; /
DATAFLG: DB 0 ;/
SECTNOE EQU $ ;END OF TABLE MARKER
;
MODCTLB: DB 07FH
UARTFLG: DB TRUE
UARTCTLB: DB ANSWMOD ;(WAS PREVIOUSLY ORIGMOD)
SAVEFLG: DB FALSE
LASTBYT1: DB 0
LASTBYT2: DB 0
EXACFLG: DB 0
ECHOFLG: DB FALSE
LOCFLG: DB FALSE
CKSUMFLG: DB TRUE
LISTFLG: DB FALSE
LISTMOR: DB FALSE
FSTFLG: DB TRUE
FIRSTME: DB TRUE ;FIRST SOH RECEIVED SWITCH (ZERO AFTER 1ST SOH)
EXITFLG: DB TRUE
HLSAVE: DW BOTTRAM
HLSAVE1: DW BOTTRAM
HLSAVE2: DW BOTTRAM
CMDBUF: DB 80H,0
DS 80H
DISKNO: DS 1
DISKSAV: DS 1
SAVUSR: DS 1
SENDFLG: DS 1
NBSAVE: DS 2
BGNMS: DS 2
FILECT: DS 1
NAMECT: DS 1
ORIGSAV: DS 1
FTYCNT: DS 1
DS 100
STACK: DS 2
FCB3: DS 33
FCB4: DS 33
FCBBUF: DS 15
DBUF EQU $
NAMEBUF EQU DBUF+(DBUFSIZ*1024) ;BUFFER FOR NAMES IN BATCH MODE.
; ;OVERFLOWS ABOVE PROGRAM CODE.
;
; BDOS EQUATES
;
RDCON EQU 1
WRCON EQU 2
LSTOUT EQU 5
PRINT EQU 9
RDBUF EQU 10
CONST EQU 11
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
USER EQU 32
FILSIZ EQU 35
BDOS EQU 5
REIPL EQU 0
FCB EQU 5CH
FCBEXT EQU FCB+12
FCBSNO EQU FCB+32
FCBRNO EQU FCB+32
FCB2 EQU 6CH
;
LAST END 100H