home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
BEEHIVE
/
COMMS
/
MODEM9.ARC
/
SENDRECV.ASM
< prev
next >
Wrap
Assembly Source File
|
1991-02-02
|
23KB
|
1,231 lines
;
; SENDRECV.ASM
;
;Christensen protocol routines for MODEM9.xx.
;
;SEND A CP/M FILE
;
SENDFIL:
MVI A,TRUE ;ALWAYS FORCE CHECKSUM MODE INITIALLY ON SEND
STA CKSUMFLG
CALL CKMODM ;REMOVE GARBAGE FROM LINE
SENDFIL1:
LDA BATCHFLG ;CHECK IF MULTIPLE FILE..
ORA A ;..MODE IS SET.
JNZ SENDC1
CALL ILPRT
DB 'Ready to send in the batch mode',CR,LF,0
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 CKABORT ;WANT TO TERMINATE WHLE SENDING FILE?
CALL RDSECT
JC SENDEOF
CALL INCRSNO
MVI A,1
STA ERRCT
SENDRPT:
CALL CKABORT ;WANT TO TERMINATE WHILE SENDING FILE?
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
CALL CKMODM ;CATCH ANY GARBAGE CHARACTERS
RCVFIL1:
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
JMP RCVC3
;
RCVC2: CALL CKCPM2
CALL CKBAKUP
RCVC3: CALL ERASFIL
CALL MAKEFIL
LDA BATCHFLG ;DON'T PRINT MSG IF IN BATCH
ORA A
JZ RCVFST
CALL ILPRTQ
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 CKSUMFLG
ORA A
JNZ RCVNAKM ;IF IN CRC MODE
CALL ILPRTQ ;THEN SAY SO
DB 'CRC in effect',CR,LF,0
JMP RCVLP
RCVNAKM:
CALL ILPRTQ ;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: CALL ILPRTQ
DB 'Awaiting name NAK',CR,LF,0
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
CNZ 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
CALL ILPRTQ
DB 'Checksum error',CR,LF,0
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
CALL ILPRTQ
DB 'Awaiting file name',CR,LF,0
GNAMELP:
CALL HSNAK
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
CALL ILPRTQ
DB 'Time out receiving filename',CR,LF,0
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..
CALL ILPRTQ
DB CR,LF,'++ Checksum error ++',CR,LF,0
CALL HSNAK ;DO HANDSHAKING OVER
JMP GETNM1
;
GNRET: POP H
RET
;
HSNAK: MVI E,180 ;3-MINUTE MAXIMUM WAIT FOR A FILE NAME
HSNAK1: CALL CKABORT ;WANT TO ABORT?
MVI A,NAK ;SEND NAK UNTIL RECEIVING ACK
CALL SEND
MVI B,1 ;WAIT UP TO 1 SECOND FOR A CHARACTER
CALL RECV
CPI ACK ;'ACK' IS WHAT WE WERE WAITING FOR
RZ
DCR E ;ONE LESS TO TRY
JNZ HSNAK1
JMP ABORT ;TIMED OUT, ABORT BACK TO COMMAND LINE
;
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,SNAMECT ;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,SNAMECT
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 SNAMECT ;COUNTS NAMES
INR A
STA SNAMECT
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
;
RCVSECT:
MVI A,1
STA ERRCT
RCVRPT: CALL CKABORT ;WANT TO STOP RECEIVING FILE?
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
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 received not SOH - ',0
RCVPRN: CALL SHOWERR ;DISPLAY ERROR COUNT
RCVSERR:
MVI B,1 ;WAIT FOR 1 SEC..
CALL RECV ;..WITH NO CHARS
JNC RCVSERR ;LOOP UNTIL SENDER DONE
CALL CKABORT ;WANT TO STOP RECEIVING NOW?
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:
LXI SP,STACK ;RESET THE STACK JUST IN CASE
CALL CLOSFIL ;CLOSE THE PARTIAL FILE
CALL NOASK ;DELETE PARTIAL FILE
CALL ILPRT
DB CR,LF,LF
DB '++ File receive cancelled and unfinished file deleted ++'
DB BELL,CR,LF,0
JMP DONETCA
;
RCVSTOT:
LDA QFLG
ORA A
RCVSPT: CALL ILPRT
DB CR,LF,'++ Timeout ',0
CALL SHOWERR
RCVSCRC:
CALL RCVSCRC2
JMP RCVSERR
;
;ROUTINE WILL SWITCH FROM CRC TO CHECKSUM IF ERCNT REACHES ERRCRC
;AND FIRSTME IS TRUE
;
RCVSCRC2:
LDA ERRCT
CPI ERRCRC
RNZ
LDA FIRSTME
ORA A
RZ
LDA CKSUMFLG
ORA A
RNZ
CMA
STA CKSUMFLG
STA CKSUMDFLT
CALL ILPRTQ
DB '++ Switching to Checksum mode ++',CR,LF
DB '++ Sender may not be CRC capable ++',CR,LF,BELL,0
RET
;
;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
MOV D,A
MVI B,1
CALL RECV
JC RCVSTOT
CMA
CMP D
JZ RCVDATA
LDA QFLG
ORA A
JZ RCVSERR
RCVBSE:
CALL ILPRT
DB CR,LF,'++ Bad sector # in Header ',0
JMP RCVPRN
;
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
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
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
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
CALL SEND
RET
;
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
CALL SEND
RET
;
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
CALL SEND
RET
;
SENDCRC:
CALL FINCRC
MOV A,D
CALL SEND
MOV A,E
CALL SEND
XRA A
RET
;
;
;After a record is sent, a character is returned telling if it was re-
;ceived properly or not. An ACK allows the next record to be sent. A
;NAK sends an error message and the current record is again repeated.
;This occurs until the error limit has been reached. If the first NAK
;is missed, it waits up to 12 seconds before declaring a 2nd error.
;This insures there is no collision with the station attempting to send
;the NAK, since it waits only 10 seconds.
;
GETACK: MVI B,12 ;12 SECONDS
CALL RECVDG ;WAIT FOR ACK OR NAK
JC GETATOT ;NO CHARACTER, TIMED OUT
CPI ACK
RZ ;IF ACK RETURN AND SEND NEXT RECORD
;
;If the ACKNAK option is FALSE it will resend the sector when any char-
;acter other than ACK is received (including NAK).
;
MOV B,A
LDA NAKONLY
ORA A
JZ ALLOTH
CPI NAK ;WAS IT AN AUTHENTIC 'NAK'?
JNZ GETACK ;IGNORE IF NEITHER 'ACK' NOR 'NAK'
;WILL EVENTUALLY TIME OUT
ALLOTH: LDA QFLG
ORA A
JZ ACKERR
CALL ILPRT
DB CR,LF,'++ ',0
MOV A,B
CPI NAK ;IS IT A 'NAK'?
JZ GETACK2 ;SHOW 'NAK' IN THAT CASE
CALL HEXO
MVI A,'H'
CALL TYPE
JMP GETACK3
GETACK2:
CALL ILPRT
DB 'NAK',0
GETACK3:
CALL ILPRT ;PRINT THE ERROR MESSAGE
DB ' received not ACK - ',0
CALL SHOWERR ;SHOW THE ERROR NUMBER
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 - ',0
CALL SHOWERR ;DISPLAY ERROR COUNT
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
MVI A,'B' ;TURN MULTI-FILE MODE..
STA BATCHFLG ;..OFF SO ROUTINE ENDS.
LDA OPTION ;RECEIVING A FILE NOW?
CPI 'R'
JZ RCVSABT ;IF YES, CANCEL THE UNFINISHED FILE
CALL ILPRT
DB CR,LF,LF,'++ File send cancelled ++',CR,LF,BELL,0
JMP DONETCA
;
INCRSNO:
PUSH H
LHLD SECTNO ;GET SECTOR NUMBER
INX H ;BUMP IT
SHLD SECTNO ;STORE IT
MOV A,L
POP H
RET
;
;----> 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: CALL CKMODM ;CATCH ANY GARBAGE CHARACTERS
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:
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
CALL OUT$MODDATP
RET
;
WAITNAK:
CALL ILPRTQ
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
JZ ABORT
DCR E
JZ ABORT
JMP WAITNLP
;
WAITCRC:
CALL ILPRTQ
DB 'CRC request received',CR,LF,0
XRA A
STA CKSUMFLG
RET
;
;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
;
;Get the error count and display on CRT
;
SHOWERR:
PUSH H ;SAVE THE CURRENT ADDRESS
LHLD ERRCT ;GET THE CURRENT ERROR NUMBER
MVI H,0 ;ONLY A 8-BIT NUMBER, NOW IN 'L' REG.
CALL DECOUT ;DISPLAY THE ERROR IN DECIMAL
POP H ;RESTORE THE CURRENT ADDRESS
CALL ILPRT
DB ' ++',CR,LF,0 ;FINISH THE ERROR MESSAGE
RET
;
ERXIT: POP D
CALL PRTMSG
MVI A,BELL
CALL TYPE
LDA BATCHFLG
ORA A
JNZ DONETCA
MVI A,'Q' ;RESET QFLG
STA QFLG
JMP ABORT ;ABORT OTHER COMPUTER
;
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
CALL CKMODM ;CATCH ANY GARBAGE CHARACTERS
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 CKABORT ;SLIGHT DELAY FOR NEXT MESSAGE
CALL ILPRT
DB CR,LF,'All transfers completed',CR,LF,BELL,0
DONETCA:
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 ILPRT
DB CR,LF,'** Entering terminal mode **',CR,LF,LF,BELL,0
JMP TERM
;
;Shows the time to transfer a file at various baud rates
;
SENDTIM:
CALL ILPRT ;PRINT:
DB 'File open: ',0
LHLD RCNT ;GET RECORD COUNT.
CALL DECOUT ;PRINT DECIMAL NUMBER OF RECORDS
CALL ILPRT
DB ' (',0
CALL DHXOUT ;NOW PRINT SIZE IN HEX.
CALL ILPRT
DB ' Hex) Records',CR,LF
DB 'Send time: ',0
LDA MSPEED ;GET THE SPEED INDICATOR
MVI D,0
MOV E,A ;SET UP FOR TABLE ACCESS
LXI H,BTABLE ;POINT TO BAUD FACTOR TABLE
DAD D ;INDEX TO PROPER FACTOR
DAD D
MOV E,M ;FACTOR IN DE
INX H
MOV D,M
LHLD RCNT ;GET # OF RECORDS
CALL DIVHLDE ;DIVIDE HL BY VALUE IN A (RECORDS/MIN)
PUSH H
MOV L,C
MOV H,B
CALL DECOUT ;PRINT THE MINUTES PORTION
CALL ILPRT
DB ' mins, ',0
LXI H,SECTBL ;POINT TO DIVISORS FOR SECONDS
LXI D,0 ; CALCULATION
LDA MSPEED ;GET INDEX FOR BAUD RATE
MOV E,A
DAD D ;INDEX INTO TABLE
MOV A,M ;GET MULTIPLIER = (SEC/REC) x 16
POP H ;GET REMAINDER
CALL MULHLA ;MULTIPLY THE 'HL' x 'A'
CALL SHFTHL ;DIVIDE BY 16
CALL SHFTHL
CALL SHFTHL
CALL SHFTHL
MVI H,0
CALL DECOUT ;PRINT THE SECONDS PORTION
CALL ILPRT
DB ' secs at ',0
CALL BAUDPRT
CALL ILPRT
DB 'To cancel use ctrl-X',CR,LF,0
RET
;
BTABLE: DW 5,13,19,25,29,48,96,192,384,0 ;RECORDS/MIN FOR 110-9600 BAUD
SECTBL: DB 192,74,51,38,33,20,11,5,3,0
;
;
;----> DIVHLDE: DIVIDES 'HL' BY VALUE IN 'DE',
; UPON EXIT: 'BC'=QUOTIENT,'L'=REMAINDER
;
DIVHLDE:
PUSH D ;SAVE DIVISOR
MOV A,E
CMA ;NEGATE DIVISOR
MOV E,A
MOV A,D
CMA
MOV D,A
INX D ;DE IS NOW TWOS COMPLEMENTED
LXI B,0 ;INITIATE QUOTIENT
DIVL1: DAD D ;SUBTRACT DIVISOR FROM DIVIDEND
INX B ;INCREASE QUOTIENT
JC DIVL1 ;LOOP UNTIL SIGN CHANGES
DCX B ;ADJUST QUOTIENT
POP D ;RETRIEVE DIVISOR
DAD D ;ADJUST REMAINDER
RET
;
;----> MULHLA: MULTIPLY THE VALUE IN 'HL' BY THE VALUE IN 'A'
; RETURN WITH ANSWER IN 'HL'
;
MULHLA: XCHG ;MULTIPLICAND TO DE
LXI H,0 ;INITIALIZE PRODUCT
INR A ;ADJUST MULTIPLIER
MULLP: DCR A
RZ
DAD D
JMP MULLP
;
; SHIFT 'HL' REGISTER PAIR ONE BIT TO THE RIGHT
;
SHFTHL: ORA A ;CLEAR THE CARRY
MOV A,H
RAR
MOV H,A
MOV A,L
RAR ;PUT CARRY INTO HIGH BIT
MOV L,A
RET
;
;****************************************************************
;* *
;* 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
;
;
LINK FILES
;USH H
LXI H,0
SHLD CRCVAL
POP H
RET
;
UPDCRC: EQU $ ;UPDATE CRC ACCUMULATOR USING BYTE IN (