; ; SENDRECV.A86 ; ;Christensen protocol routines for MODEM9.xx. ; ;SEND A CP/M FILE ; SENDFIL: MOV CKSUMFLG,TRUE ;ALWAYS FORCE CHECKSUM MODE INITIALLY ON SEND CALL CKMODM ;REMOVE GARBAGE FROM LINE SENDFIL1: TEST BATCHFLG,0FFH ;CHECK IF MULTIPLE FILE.. JNZ SENDC1 CALL ILPRT DB 'Ready to send in the batch mode',CR,LF,0 MOV SENDFLG,TRUE ;INDICATE SEND FOR BATCH MODE MOV AL,FSTFLG ;IF FIRST TIME THRU.. OR AL,AL ;..SCAN THE COMMAND LINE.. JZ SENDFIL2 CALL TNMBUF ;..FOR MULTIPLE NAMES. SENDFIL2: CALL SENDFN ;SENDS FILE NAME TO RECEIVER JNC SENDC2 ;CARRY SET MEANS NO MORE FILES. MOV BATCHFLG,'B' ;STOP BATCH ....MODE OPTION. MOV AL,EOT ;FINAL XFER END CALL SEND JMP DONE ; SENDC1: CMP BYTE PTR .FCB+1,' ' JNZ SENDC2 JMP BLKFILE SENDC2: CALL CNREC ;GET NUMBER OF RECORDS CALL OPENFIL MOV DL,80 CALL WAITNAK SENDLP: CALL CKABORT ;WANT TO TERMINATE WHLE SENDING FILE? CALL RDSECT JC SENDEOF CALL INCRSNO MOV ERRCT,1 SENDRPT: CALL CKABORT ;WANT TO TERMINATE WHILE SENDING FILE? CALL SENDHDR CALL SENDSEC MOV AL,CKSUMFLG OR AL,AL JNZ SENDRPT1 CALL SENDCRC JMPS SENDRPT2 SENDRPT1: CALL SENDCKS SENDRPT2: CALL GETACK JC SENDRPT JMP SENDLP ; SENDEOF: MOV AL,EOT CALL SEND CALL GETACK JC SENDEOF JMP DONE ; ;RECEIVE A FILE ; RCVFIL: MOV AL,CKSUMDFLT ;GET MODE REQUESTED BY OPERATOR MOV CKSUMFLG,AL ;STORE IT CALL CKMODM ;CATCH ANY GARBAGE CHARACTERS RCVFIL1: MOV AL,BATCHFLG ;CHECK IF MULT.. OR AL,AL ;..FILE MODE. JNZ RCVC1 MOV AL,FALSE ;FLAG WHERE TO RETURN.. MOV SENDFLG,AL ;..FOR NEXT FILE TRANS. CALL GETFN ;GET THE FILE NAME. JNC RCVC2 ;CARRY SET MEANS NO MORE FILES. MOV AL,'B' ;STOP BATCH.. MOV BATCHFLG,AL ;..MODE OPTION. JMP DONE ; RCVC1: MOV AL,BYTE PTR .FCB+1 ;MAKE SURE FILE IS NAMED CMP AL,' ' JNZ RECV1A JMP BLKFILE RECV1A: JMP RCVC3 ; RCVC2: CALL CKCPM2 CALL CKBAKUP RCVC3: CALL ERASFIL CALL MAKEFIL MOV AL,BATCHFLG ;DON'T PRINT MSG IF IN BATCH OR AL,AL JZ RCVFST CALL ILPRTQ DB 'File open, ready to receive',CR,LF,0 RCVFST: MOV AL,CKSUMFLG OR AL,AL MOV AL,NAK JNZ RCVFIL2 MOV AL,CRC RCVFIL2: CALL SEND MOV AL,CKSUMFLG OR AL,AL 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 MOV DL,80 CALL WAITNLP MOV AL,ACK ;GOT NAK, SEND ACK CALL SEND MOV BX,OFFSET FILECT DEC BYTE PTR [BX] JS NOMRNM MOV BX,NBSAVE ;GET FILE NAME.. MOV DX,OFFSET FCB ;..IN FCB MOV CH,12 CALL MOVE MOV NBSAVE,BX CALL SENDNM ;SEND IT OR AL,AL ;CLEAR CARRY RET ; NOMRNM: MOV AL,EOT CALL SEND STC RET ; SENDNM: PUSH BX SENDNM1: MOV DH,11 ;COUNT CHARS IN NAME MOV CL,0 ;INIT CHECKSUM MOV AL,CL MOV FTYCNT,AL ;INITIATE FILE TYPE COUNT MOV BX,OFFSET FCB+1 ;ADDRESS NAME NAMLPS: MOV AL,BYTE PTR [BX] ;SEND NAME AND AL,07FH ;STRIP HIGH ORDER BIT SO CP/M 2.. CALL SEND ;..WON'T SEND R/O FILE DESIGNATION. MOV AL,QFLG ;SHOW NAME IF.. OR AL,AL ;..QFLG NOT SET. MOV AL,BYTE PTR [BX] JZ ACKLP CALL FTYTST ;TYPE CHARACTER ETC. ACKLP: PUSH CX ;SAVE CKSUM MOV CH,1 ;WAIT FOR RECEIVER.. CALL RECV ;..TO ACKNOWLEDGE.. POP CX ;..GETTING LETTER. JC SCKSER CMP AL,ACK JNZ ACKLP INC BX ;NEXT CHAR DEC DH JNZ NAMLPS MOV AL,EOFCHAR ;TELL RECEIVER END OF NAME CALL SEND MOV AL,QFLG OR AL,AL JZ ACKLP1 CALL CRLF ACKLP1: MOV DH,CL ;SAVE CHECKSUM MOV CH,1 CALL RECV ;GET CHECKSUM.. CMP AL,DH ;..FROM RECEIVER. JZ NAMEOK SCKSER: MOV AL,BDNMCH ;BAD NAME-TELL RECEIVER CALL SEND CALL ILPRTQ DB 'Checksum error',CR,LF,0 MOV DL,80 ;DO HANDSHAKING OVER CALL WAITNLP ;DON'T PRINT "AWAITING NAK" MSG MOV AL,ACK CALL SEND JMP SENDNM1 ; NAMEOK: MOV AL,OKNMCH ;GOOD NAME, TELL RECEIVER CALL SEND POP BX RET ; GETFN: MOV BX,OFFSET 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 CMP AL,EOT ;IF EOT, THEN NO MORE FILES JZ NOMRNMG OR AL,AL ;CLEAR CARRY RET ; NOMRNMG: STC RET ; GETNM: PUSH BX GETNM1: MOV CL,0 ;INIT CHECKSUM MOV AL,CL MOV FTYCNT,AL ;INITIATE COUNT FOR FILE TYPE MOV BX,OFFSET FCB+1 NAMELPG: MOV CH,5 CALL RECV ;GET CHAR JNC GETNM3 CALL ILPRTQ DB 'Time out receiving filename',CR,LF,0 JMP GCKSER ; GETNM3: CMP AL,EOT ;IF EOT, THEN NO MORE FILES JNZ GETNM4 JMP GNRET GETNM4: CMP AL,EOFCHAR ;GOT END OF NAME JZ ENDNAME MOV BYTE PTR [BX],AL ;PUT NAME IN FCB MOV AL,QFLG ;CAN TYPE IT IF NO QFLG OR AL,AL JZ SKPTYP CALL FTYTST SKPTYP: PUSH CX ;SAVE CKSUM MOV AL,ACK ;ACK GETTING LETTER CALL SEND POP CX INC BX ;GET NEXT CHAR MOV AL,BL ;DON'T LET NOISE... CMP AL,7FH ;..CAUSE OVERFLOW.. JZ GCKSER ;..INTO PROGRAM AREA. JMP NAMELPG ; FTYTST: INC FTYCNT CMP FTYCNT,9 ; ARE WE AT THE FILE TYPE? JZ SPCTST ;GO IF SO ENDSPT: MOV AL,BYTE PTR [BX] CMP AL,' ' ;TEST FOR SPACE JZ ENDSPT1 CALL TIPE ;TYPE IF NOT ENDSPT1: RET ; SPCTST: MOV AL,BYTE PTR [BX] CMP AL,' ' ;TEST FOR SPACE IN FIRST FILE TYPE BYTE JZ ENDSPT1 ;DON'T OUTPUT PERIOD IF SPACE ; MJM 9.01.05 WAS JMPS MOV AL,'.' CALL TIPE JMP ENDSPT ;OUTPUT FIRST FILE TYPE BYTE ; ENDNAME: MOV AL,QFLG OR AL,AL JZ ENDNAME1 CALL CRLF ENDNAME1: MOV AL,CL ;SEND CHECKSUM CALL SEND MOV CH,1 CALL RECV ;CHECKSUM GOOD? CMP AL,OKNMCH ;YES IF OKNMCH SENT.. JZ GNRET ;..ELSE DO OVER. GCKSER: MOV BX,OFFSET 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 BX RET ; HSNAK: MOV DL,180 ;3-MINUTE MAXIMUM WAIT FOR A FILE NAME HSNAK1: CALL CKABORT ;WANT TO ABORT? MOV AL,NAK ;SEND NAK UNTIL RECEIVING ACK CALL SEND MOV CH,1 ;WAIT UP TO 1 SECOND FOR A CHARACTER CALL RECV CMP AL,ACK ;'ACK' IS WHAT WE WERE WAITING FOR JNZ HSNAK2 RET HSNAK2: DEC DL ;ONE LESS TO TRY JNZ HSNAK1 JMP ABORT ;TIMED OUT, ABORT BACK TO COMMAND LINE ; TNMBUF: MOV AL,FALSE ;CALL FROM SENDFIL ONLY ONCE. MOV FSTFLG,AL MOV FILECT,AL CALL SCAN MOV BX,OFFSET NAMEBUF MOV NBSAVE,BX ;SAVE ADDR OF 1ST NAME TNLP1: CALL TRTOBUF MOV BX,OFFSET FCB MOV DX,OFFSET FCBBUF CALL CPMLINE ;PARSE NAME TO CP/M FORMAT TNLP2: CALL MFNAME ;SEARCH FOR NAMES (* FORMAT) JC NEXTNM MOV AL,BYTE PTR .FCB+10 ;IF CP/M 2 $SYS FILE.. AND AL,80H ;..DON'T SEND JNZ TNLP2 MOV BX,NBSAVE ;GET NAME MOV DX,OFFSET FCB ;MOVE IT TO FCB XCHG BX,DX MOV CH,12 CALL MOVE XCHG BX,DX MOV NBSAVE,BX ;ADDR OF NEXT NAME MOV BX,OFFSET FILECT ;COUNT FILES FOUND INC BYTE PTR [BX] JMP TNLP2 ; NEXTNM: MOV BX,OFFSET SNAMECT ;COUNT NAMES FOUND DEC BYTE PTR [BX] JNZ TNLP1 MOV BX,OFFSET NAMEBUF ;SAVE START OF BUFFER MOV NBSAVE,BX MOV AL,FILECT CMP AL,65 ;NO MORE THAN 64 TRANSFERS JNC NEXTNM1 RET NEXTNM1: MOV AL,64 ;ONLY X'FER FIRST 64 MOV FILECT,AL RET ; ;SCANS CMDBUF COUNTING NAMES AND PUTTING DELIMITER (SPACE) ;AFTER LAST NAME ; SCAN: PUSH BX MOV BX,OFFSET SNAMECT MOV BYTE PTR [BX],0 MOV BX,OFFSET CMDBUF+1 ;FIND END OF CMD LINE.. MOV CL,BYTE PTR [BX] ;..AND PUT SPACE THERE. MOV CH,0 MOV BX,OFFSET CMDBUF+2 ADD BX,CX MOV BYTE PTR [BX],20H MOV BX,OFFSET CMDBUF+1 MOV CH,BYTE PTR [BX] INC CH INC CH SCANLP1: INC BX DEC CH JZ DNSCAN MOV AL,BYTE PTR [BX] CMP AL,20H JNZ SCANLP1 SCANLP2: INC BX ;EAT EXTRA SPACES DEC CH JZ DNSCAN MOV AL,BYTE PTR [BX] CMP AL,20H JZ SCANLP2 MOV BGNMS,BX ;SAVE START OF NAMES IN CMDBUF INC CH DEC BX SCANLP3: INC BX DEC CH JZ DNSCAN MOV AL,BYTE PTR [BX] CMP AL,20H JNZ SCANLP3 MOV AL,SNAMECT ;COUNTS NAMES INC AL MOV SNAMECT,AL SCANLP4: INC BX ;EAT SPACES DEC CH JZ DNSCAN MOV AL,BYTE PTR [BX] CMP AL,20H JZ SCANLP4 JMP SCANLP3 ; DNSCAN: MOV BYTE PTR [BX],20H ;SPACE AFTER LAST CHAR POP BX RET ; ;PLACES NEXT NAME IN BUFFER SO 'CPMLINE' MAY PARSE IT ; TRTOBUF: MOV BX,BGNMS MOV CH,0 MOV DX,OFFSET FCBBUF+2 TBLP: MOV AL,BYTE PTR [BX] CMP AL,20H JZ TRBFEND XCHG BX,DX MOV BYTE PTR [BX],AL XCHG BX,DX INC BX INC DX INC CH ;COUNT CHARS IN NAME JMP TBLP ; TRBFEND: INC BX MOV AL,BYTE PTR [BX] ;EAT EXTRA SPACES CMP AL,20H JZ TRBFEND MOV BGNMS,BX MOV BX,OFFSET FCBBUF+1 ;PUT # CHARS BEFORE NAME MOV BYTE PTR [BX],CH RET ; RCVSECT: MOV AL,1 MOV ERRCT,AL RCVRPT: CALL CKABORT ;WANT TO STOP RECEIVING FILE? MOV AL,QFLG OR AL,AL JZ RCVSQ CALL ILPRT DB CR,'Awaiting # ',0 PUSH BX ;SAVE IT MOV BX,SECTNO ;GET SECTOR NUMBER INC BX ;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 AL,BL ;ONLY LOW BYTE USED BY PROGRAM POP BX ;RESTORE IT RCVSQ: ;WAIT FOR SOH OR EOT MOV CH,10 ;10 SECONDS CALL RECV JNC RCVSQ1 JMP RCVSTOT RCVSQ1: CMP AL,SOH JNZ RCVSQ2 JMP RCVSOH RCVSQ2: OR AL,AL JZ RCVSQ CMP AL,EOT STC JNZ RCVSQ3 RET RCVSQ3: MOV CH,AL MOV AL,QFLG OR AL,AL JZ RCVSERR RCVSEH: MOV AL,CH CALL CRLF CALL HEXO CALL ILPRT DB 'H received not SOH - ',0 RCVPRN: CALL SHOWERR ;DISPLAY ERROR COUNT RCVSERR: MOV CH,1 ;WAIT FOR 1 SEC.. CALL RECV ;..WITH NO CHARS JNC RCVSERR ;LOOP UNTIL SENDER DONE CALL CKABORT ;WANT TO STOP RECEIVING NOW? MOV AL,CKSUMFLG ;GET CHECKSUM FLAG OR AL,AL ;CRC IN EFFECT? MOV AL,NAK ;PUT NAK IN ACCUM JNZ RCVSER2 ;NO, SEND THE NAK MOV AL,FIRSTME ;GET FIRST TIME SWITCH OR AL,AL ;HAS FIRST SOH BEEN RECEIVED? MOV AL,NAK ;PUT NAK IN ACCUM JZ RCVSER2 ;YES, THEN SEND NAK MOV AL,CRC ;TELL SENDER CRC IS IN EFFECT RCVSER2: CALL SEND ;..THE NAK or CRC request MOV AL,ERRCT ;ABORT IF.. INC AL ;..WE HAVE REACHED.. MOV ERRCT,AL ;..THE ERROR.. CMP AL,ERRLIM ;..LIMIT? JNC RCVSER3 JMP RCVRPT ;..NO, TRY AGAIN RCVSER3: MOV AL,QFLG OR AL,AL JZ RCVSABT RCVCKQ: CALL CKQUIT JNZ RCVSABT JMP RCVSECT RCVSABT: 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: MOV AL,QFLG OR AL,AL 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: MOV AL,ERRCT CMP AL,ERRCRC JNZ RCVSCRC3 MOV AL,FIRSTME OR AL,AL JZ RCVSCRC3 MOV AL,CKSUMFLG OR AL,AL JNZ RCVSCRC3 NOT AL MOV CKSUMFLG,AL MOV CKSUMDFLT,AL CALL ILPRTQ DB '++ Switching to Checksum mode ++',CR,LF DB '++ Sender may not be CRC capable ++',CR,LF,BELL,0 RCVSCRC3: RET ; ;Got SOH - get block #, block # complemented ; RCVSOH: XOR AL,AL ;ZERO ACCUM MOV FIRSTME,AL ;INDICATE FIRST SOH RECV'D MOV CH,1 ;TIMEOUT = 1 SEC CALL RECV ;GET SECTOR JNC RCVSOH1 JMP RCVSTOT ;GOT TIMEOUT RCVSOH1: MOV DH,AL MOV CH,1 CALL RECV JNC RCVSOH2 JMP RCVSTOT RCVSOH2: NOT AL CMP AL,DH JZ RCVDATA MOV AL,QFLG OR AL,AL JNZ RCVBSE JMP RCVSERR RCVBSE: CALL ILPRT DB CR,LF,'++ Bad sector # in Header ',0 JMP RCVPRN ; RCVDATA: MOV AL,DH MOV RCVSNO,AL MOV AL,1 MOV DATAFLG,AL MOV CL,0 CALL CLRCRC ;CLEAR CRC COUNTER MOV BX,OFFSET 80H RCVCHR: MOV CH,1 CALL RECV JNC RCVCHR1 JMP RCVSTOT RCVCHR1: MOV BYTE PTR [BX],AL INC BL JNZ RCVCHR MOV AL,CKSUMFLG OR AL,AL JZ RCVCRC MOV DH,CL ; 9.01.02 MJM 7/8/83 XOR AL,AL MOV DATAFLG,AL MOV CH,1 CALL RECV JNC RCVCHR2 JMP RCVSTOT RCVCHR2: CMP AL,DH JNZ RCVCERR CHKSNUM: MOV AL,RCVSNO MOV CH,AL MOV AX,SECTNO CMP AL,CH JZ RECVACK INC AL CMP AL,CH JZ CHKSNUM1 JMP ABORT CHKSNUM1: RET ; RCVCRC: MOV DL,2 ;NUMBER OF CRC BYTES RCVCRC2: MOV CH,1 CALL RECV JNC RCVCRC3 JMP RCVSTOT RCVCRC3: DEC DL JNZ RCVCRC2 CALL CHKCRC OR AL,AL JZ CHKSNUM MOV AL,QFLG OR AL,AL JNZ RCVCRER JMP RCVSERR RCVCRER: CALL ILPRT DB CR,LF,'++ CRC error ',0 JMP RCVPRN ; RCVCERR: MOV AL,QFLG OR AL,AL JNZ RCVCPR JMP RCVSERR RCVCPR: CALL ILPRT DB CR,LF,'++ Checksum error ',0 JMP RCVPRN ; RECVACK: CALL SENDACK JMP RCVSECT ; SENDACK: MOV AL,ACK CALL SEND RET ; SENDHDR: MOV AL,QFLG OR AL,AL JZ SENDHNM CALL ILPRT DB CR,'Sending # ',0 PUSH BX MOV BX,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 BX SENDHNM: MOV AL,SOH CALL SEND MOV AX,SECTNO CALL SEND MOV AX,SECTNO NOT AL CALL SEND RET ; SENDSEC: MOV AL,1 MOV DATAFLG,AL MOV CL,0 CALL CLRCRC MOV BX,OFFSET 80H SENDC: MOV AL,BYTE PTR [BX] CALL SEND INC BL JNZ SENDC XOR AL,AL MOV DATAFLG,AL RET ; SENDCKS: MOV AL,CL CALL SEND RET ; SENDCRC: CALL FINCRC MOV AL,DH CALL SEND MOV AL,DL CALL SEND XOR AL,AL 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: MOV CH,12 ;12 SECONDS CALL RECVDG ;WAIT FOR ACK OR NAK JNC GETACK1 JMP GETATOT ;NO CHARACTER, TIMED OUT GETACK1: CMP AL,ACK JNZ NOTACK RET ;IF ACK RETURN AND SEND NEXT RECORD NOTACK: ; ;If the ACKNAK option is FALSE it will resend the sector when any char- ;acter other than ACK is received (including NAK). ; MOV CH,AL MOV AL,NAKONLY OR AL,AL JZ ALLOTH CMP AL,NAK ;WAS IT AN AUTHENTIC 'NAK'? JNZ GETACK ;IGNORE IF NEITHER 'ACK' NOR 'NAK' ;WILL EVENTUALLY TIME OUT ALLOTH: MOV AL,QFLG OR AL,AL JZ ACKERR CALL ILPRT DB CR,LF,'++ ',0 MOV AL,CH CMP AL,NAK ;IS IT A 'NAK'? JZ GETACK2 ;SHOW 'NAK' IN THAT CASE CALL HEXO MOV AL,'H' CALL TIPE 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: MOV AL,ERRCT INC AL MOV ERRCT,AL DEC AL CMP AL,ERRLIM JNC ACKERR1 RET ACKERR1: MOV AL,QFLG OR AL,AL JZ CSABORT GACKV: CALL CKQUIT STC JNZ CSABORT RET CSABORT: CALL ERXIT DB CR,LF,'Can''t send sector -- Aborting',CR,LF,'$' GETATOT: MOV AL,QFLG OR AL,AL JZ ACKERR CALL ILPRT DB CR,LF,'++ Timeout on ACK - ',0 CALL SHOWERR ;DISPLAY ERROR COUNT JMP ACKERR ; CKABORT: MOV AL,QFLG OR AL,AL JNZ CKABGO RET CKABGO: CALL STAT JNZ CKABGO1 RET CKABGO1: CALL KEYIN CMP AL,CAN JZ ABORT RET ABORT: MOV CH,1 CALL RECV JNC ABORT MOV AL,CAN CALL SEND ABORTW: MOV CH,1 CALL RECV JNC ABORTW MOV AL,' ' CALL SEND MOV AL,'B' ;TURN MULTI-FILE MODE.. MOV BATCHFLG,AL ;..OFF SO ROUTINE ENDS. MOV AL,OPTION ;RECEIVING A FILE NOW? CMP AL,'R' JNZ ABORTW1 JMP RCVSABT ;IF YES, CANCEL THE UNFINISHED FILE ABORTW1: CALL ILPRT DB CR,LF,LF,'++ File send cancelled ++',CR,LF,BELL,0 JMP DONETCA ; INCRSNO: INC SECTNO ; INCREMENT SECTOR NUMBER MOV AX,SECTNO ; NEED IT IN LOW BYTE, DON'T CARE ABOUT HIGH 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 DX MSEC: PUSH BX MOV BX,OFFSET 5000 CALL FIXCNT PUSH BX POP DX POP BX CALL CKABORT MWTI: CALL RCVREADY JZ MCHAR DEC DL JNZ MWTI DEC DH JNZ MWTI DEC CH JNZ MSEC POP DX STC RET ; MCHAR: CALL INMODDATP POP DX PUSH AX CALL UPDCRC ;CALCULATE CRC ADD CL,AL MOV AL,RSEEFLG OR AL,AL JZ MONIN MOV AL,VSEEFLG OR AL,AL JNZ NOMONIN MOV AL,DATAFLG OR AL,AL JZ NOMONIN MONIN: POP AX PUSH AX CALL SHOW NOMONIN: POP AX OR AL,AL RET ; SEND: PUSH AX MOV AL,SSEEFLG OR AL,AL JZ MONOUT MOV AL,VSEEFLG OR AL,AL JNZ NOMONOT MOV AL,DATAFLG OR AL,AL JZ NOMONOT MONOUT: POP AX PUSH AX CALL SHOW NOMONOT: POP AX PUSH AX CALL UPDCRC ;CALCULATE CRC ADD CL,AL SENDW: CALL SENDREADY JNZ SENDW POP AX CALL OUTMODDATP RET ; WAITNAK: CALL ILPRTQ DB 'Awaiting initial NAK',CR,LF,0 WAITNLP: CALL CKABORT MOV CH,1 CALL RECV CMP AL,NAK JNZ WAITNLP1 RET WAITNLP1: CMP AL,CRC ;CRC REQUEST? JZ WAITCRC ;YES, GO SET CRC FLAG CMP AL,CAN JNZ WAITNLP2 JMP ABORT WAITNLP2: DEC DL JNZ WAITNLP JMP ABORT ; WAITCRC: CALL ILPRTQ DB 'CRC request received',CR,LF,0 XOR AL,AL MOV CKSUMFLG,AL RET ; ;RETURNS W/ ZERO SET IF RETRY ASKED. IF MULTI-FILE MODE, THEN ;NO QUESTIONS ASKED, JUST QUIT ; CKQUIT: MOV AL,BATCHFLG OR AL,AL JNZ CKQTASK ;ASK FOR RETRY INC AL ;RESET ZERO FLG RET ; CKQTASK: MOV ERRCT,1 CALL ILPRT DB CR,LF,'Multiple errors encountered.',CR,LF DB 'Type Q to quit, R to retry: ',BELL,0 CALL KEYIN CALL CRLF CALL UCASE ;INSTEAD OF "ANI 5FH" CMP AL,'R' JZ CKQTASK1 CMP AL,'Q' JNZ CKQUIT OR AL,AL CKQTASK1: RET ; ;Get the error count and display on CRT ; SHOWERR: PUSH BX ;SAVE THE CURRENT ADDRESS MOV BL,ERRCT ;GET THE CURRENT ERROR NUMBER MOV BH,0 ;ONLY A 8-BIT NUMBER, NOW IN 'L' REG. CALL DECOUT ;DISPLAY THE ERROR IN DECIMAL POP BX ;RESTORE THE CURRENT ADDRESS CALL ILPRT DB ' ++',CR,LF,0 ;FINISH THE ERROR MESSAGE RET ; ERXIT: POP DX CALL PRTMSG MOV AL,BELL CALL TIPE MOV AL,BATCHFLG OR AL,AL JZ ERXIT1 JMP DONETCA ERXIT1: MOV AL,'Q' ;RESET QFLG MOV QFLG,AL JMP ABORT ;ABORT OTHER COMPUTER ; DONE: MOV AL,BATCHFLG OR AL,AL JZ DONE1 JMP DONETC DONE1: MOV AL,QFLG OR AL,AL JZ NMSTRNS MOV CH,12 ;ZERO OUT FTRNMSG MOV BX,OFFSET FTRNMSG ZEROLP: MOV BYTE PTR [BX],' ' ; mjm 9.01.05 FIX BATCH NAME REPORT INC BX DEC CH JNZ ZEROLP MOV CH,12 ;PUT FILE NAME IN FTRNMSG MOV BX,OFFSET FCB+1 MOV DX,OFFSET FTRNMSG LOADMSG: MOV AL,4 ;START OF FILE TYPE? CMP AL,CH JZ PERIOD ;PUT IN PERIOD IF SO MOV AL,BYTE PTR [BX] CMP AL,' ' ;DON'T PUT IN SPACE JZ SKPSP XCHG BX,DX MOV BYTE PTR [BX],AL ;STORE IN FTRNMSG XCHG BX,DX INC DX SKPSP: INC BX DEC CH MOV AL,CH OR AL,AL ;END OF FILE NAME? JZ FTRNMSG0 ;DISPLAY FILE NAME JMP LOADMSG ;LOOP FOR ANOTHER CHARACTER ; PERIOD: MOV AL,BYTE PTR [BX] CMP AL,' ' ;IS FILE TYPE EMPTY? JZ FTRNMSG0 ;GO IF SO MOV AL,'.' ;ELSE PUT PERIOD IN MESSAGE XCHG BX,DX MOV BYTE PTR [BX],AL XCHG BX,DX INC DX DEC CH JMP LOADMSG ; FTRNMSG0: CALL ILPRT DB CR,LF FTRNMSG RB 12 DB 0 CALL ILPRT DB ' Transferred',CR,LF,LF,0 NMSTRNS: MOV AL,BYTE PTR .FCB ;SAVE DRIVE NO. MOV DISKNO,AL MOV BX,OFFSET FCB ;BLANK OUT FILE CONTROL BLOCKS CALL INITFCBS MOV AL,DISKNO ;PUT DRIVE NUMBER BACK MOV BYTE PTR .FCB,AL MOV BX,OFFSET RESTSN ;RESTORE SECTORE NUMBERS.. MOV DX,OFFSET SECTNOB ;..FOR NEW FILE TRANSFER. MOV CH,OFFSET SECTNOE-OFFSET SECTNOB ;ROUTINE ALSO DONE IN MENU. CALL MOVE CALL CKMODM ;CATCH ANY GARBAGE CHARACTERS MOV AL,SENDFLG ;GOES TO EITHER SEND OR.. OR AL,AL ;..RECEIVE FILE, DEPENDING.. JZ NMSTRNS1 JMP SENDFIL1 ;..UPON WHICH ROUTINE SET.. NMSTRNS1: 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: MOV AL,TRUE MOV FIRSTME,AL ;SET FIRST-TIME FLAG MOV FSTFLG,AL ;RESET MULTIFILE TRANS MOV NFILFLG,AL ;..USED IN TERMINAL ROUTINE NOT AL MOV SAVEFLG,AL ;STOP MEMORY SAVE IN TERM ROUTINE MOV LISTMOR,AL ;STOP ANY BUFFERED OUTPUT TO PRINTER MOV BX,OFFSET BOTTRAM ;RESET PRINTER BUFFER POINTERS MOV HLSAVE1,BX MOV HLSAVE2,BX MOV AL,TERMFLG ;SEE IF RETURN TO.. OR AL,AL ;..TERMINAL MODE.. JNZ DONETCA1 ;..AFTER X'FER. CALL ILPRT DB CR,LF,'** Entering terminal mode **',CR,LF,LF,BELL,0 JMP TERM DONETCA1: JMP MENU ; ;Shows the time to transfer a file at various baud rates ; SENDTIM: CALL ILPRT ;PRINT: DB 'File open: ',0 MOV BX,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 MOV AL,MSPEED ;GET THE SPEED INDICATOR MOV DH,0 MOV DL,AL ;SET UP FOR TABLE ACCESS MOV BX,OFFSET BTABLE ;POINT TO BAUD FACTOR TABLE ADD BX,DX ;INDEX TO PROPER FACTOR ADD BX,DX MOV DL,BYTE PTR [BX];FACTOR IN DE INC BX MOV DH,BYTE PTR [BX] MOV BX,RCNT ;GET # OF RECORDS CALL DIVHLDE ;DIVIDE HL BY VALUE IN A (RECORDS/MIN) PUSH BX MOV BX,CX CALL DECOUT ;PRINT THE MINUTES PORTION CALL ILPRT DB ' mins, ',0 MOV BX,OFFSET SECTBL ;POINT TO DIVISORS FOR SECONDS MOV DX,0 ; CALCULATION MOV AL,MSPEED ;GET INDEX FOR BAUD RATE MOV DL,AL ADD BX,DX ;INDEX INTO TABLE MOV AL,BYTE PTR [BX];GET MULTIPLIER = (SEC/REC) x 16 POP BX ;GET REMAINDER CALL MULHLA ;MULTIPLY THE 'HL' x 'A' CALL SHFTHL ;DIVIDE BY 16 CALL SHFTHL CALL SHFTHL CALL SHFTHL MOV BH,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 ; ; CORRECTED BY M.J. MELLINGER FOR 9.01.05 11/25/83 BTABLE DW 5,13,25,48,96,192,384,0 ;RECORDS/MIN FOR 110-9600 BAUD SECTBL DB 192,74,38,20,11,5,3,0 ; ; ;----> DIVHLDE: DIVIDES 'HL' BY VALUE IN 'DE', ; UPON EXIT: 'BC'=QUOTIENT,'L'=REMAINDER ; DIVHLDE: PUSH DX ;SAVE DIVISOR ; MOV AL,DL ; NOT AL ;NEGATE DIVISOR ; MOV DL,AL ; MOV AL,DH ; NOT AL ; MOV DH,AL ; INC DX ;DE IS NOW TWOS COMPLEMENTED NEG DX MOV CX,0 ;INITIATE QUOTIENT DIVL1: ADD BX,DX ;SUBTRACT DIVISOR FROM DIVIDEND INC CX ;INCREASE QUOTIENT JC DIVL1 ;LOOP UNTIL SIGN CHANGES DEC CX ;ADJUST QUOTIENT POP DX ;RETRIEVE DIVISOR ADD BX,DX ;ADJUST REMAINDER RET ; ;----> MULHLA: MULTIPLY THE VALUE IN 'HL' BY THE VALUE IN 'A' ; RETURN WITH ANSWER IN 'HL' ; MULHLA: XCHG BX,DX ;MULTIPLICAND TO DE MOV BX,OFFSET 0 ;INITIALIZE PRODUCT INC AL ;ADJUST MULTIPLIER MULLP: DEC AL JNZ MULLP1 RET MULLP1: ADD BX,DX JMPS MULLP ; ; SHIFT 'HL' REGISTER PAIR ONE BIT TO THE RIGHT ; SHFTHL: CLC ;CLEAR THE CARRY RCR BX,1 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. * ;* * ;**************************************************************** ; ; CLRCRC: ;RESET CRC ACCUMULATOR FOR A NEW MESSAGE. MOV CRCVAL,0 RET ; UPDCRC: ;UPDATE CRC ACCUMULATOR USING BYTE IN (A). PUSH AX PUSH CX PUSH BX MOV CH,8 MOV CL,AL MOV BX,CRCVAL UPDLOOP: ROL CL,1 ; MOV AL,CL ; ROL AL,1 ; MOV CL,AL RCL BX,1 JNC SKIPIT XOR BX,1021H SKIPIT: DEC CH ;AND XOR 05H FOR XOR 21H IN THE ADJACENT CODE JNZ UPDLOOP MOV CRCVAL,BX POP BX POP CX POP AX RET ; FINCRC: ;FINISH CRC CALCULATION FOR OUTPUT MESSAGE PUSH AX XOR AL,AL CALL UPDCRC CALL UPDCRC MOV DX,CRCVAL POP AX RET ; CHKCRC: ;CHECK CRC BYTES OF RECEIVED MESSAGE MOV AX,CRCVAL OR AL,AH JZ CHKCRCRT MOV AL,0FFH CHKCRCRT: RET ; CRCVAL DW 0 ;