; ;MODEM.ASM V3.0, BY WARD CHRISTENSEN ; ;CP/M - CP/M FILE TRANSFER PROGRAM, AND ;TERMINAL PROGRAM. ; ; * * * * * * * * * * * * * * * * * * * * * * * * ; * ; THIS PROGRAM DOCUMENTED IN "MODEM.DOC" * ; * ; * * * * * * * * * * * * * * * * * * * * * * * * ; THIS PROGRAM WAS "MODEM.ASM" BUT IS * ; TEMPORARILY NAMED "MODEM2.ASM" SO PEOPLE * ; WILL REALIZE IT IS AN ENHANCEMENT OF * ; THE ORIGINAL PROGRAM "MODEM.ASM" ON CP/M * ; USER'S GROUP DISK 25. * ; * * * * * * * * * * * * * * * * * * * * * * * * ; ;PLEASE PASS ON MODS, BUGS, ETC, SO YOUR ;FIXES OR ENHANCEMENTS MAY BE SHARED BY ALL, ; TO: ; Ward Christensen ; 688 E. 154th St. #5D ; Dolton, Il. 60419 ; ; (312) 849-6279 ; ;You may send a self-addressed stamped postcard ;to be informed of changes/bugs as they become ;known. ; ; -------------- ; ; 09/23/77 ;ORIGINALLY WRITTEN BY WARD CHRISTENSEN ; ; 04/26/79 ;REWRITTEN BY WARD CHRISTENSEN TO COMBINE ;IMPROVEMENTS TO THE ORIGINAL MADE BY WARD ;AND BY KEITH PETERSEN, W8SDZ, AND SUGGESTIONS ;BY JIM BELL WHICH KEITH IMPLEMENTED. SEE ;MODEM.DOC FOR ADDITIONAL HISTORICAL ;INFORMATION AND DOCUMENTATION. ; ; 05/09/79 ;ALLOW 'T' AND 'E' SUB-OPTIONS TO GO TO TERMINAL ;OR ECHO MODEM AFTER TRANSFERRING A FILE. (WLC) ; ; 05/22/79 ;ADD FEATURE TO MAKE RECEIVE FILE ROUTINE SAY ;FILE SUCCESSFULLY OPENED, WHEN IN QUIET MODE. ;MOVE INITIAL GOBBLE GARBAGE INPUTS TO BEFORE ;COMMAND CPI'S SO ALL MODES ARE CLEARED. CHANGE ;INITIAL SEND WAIT TO 80 SECS TO ALLOW MORE TIME ;FOR RECEIVING END TO COME UP. ADD 'H' AFTER MSG ;THAT SHOWS NUMBER OF SECTORS IN EXTENT ABOUT TO ;BE SENT. (KBP) ; ; 05/24/79 ;FIX MISSING RETURN INSTRUCTION AT END OF ;INITIALIZATION ROUTINE. (KBP) ; ; 07/13/79 ;PUT IN RESET OF DMA ADDR TO 80H AFTER ;FILE RECEIVE, BECAUSE "SUBMIT" UNDER CP/M ;DOESN'T RESET IT BEFORE READING THE ;NEXT SUBMITTED COMMAND. /// ALSO DELETE ;CODE FOR "CANCEL" AS IT'S JUST TOO EASY ;TO INTENTIONALLY GET A CANCEL AS A ;GARBAGED LINE CHARACTER. ; ; 07/07/82 17:41:54 mods for cp/m by rjs ; CANFLG EQU 0ffh ;nO CANCEL ABILITY ; PMMI EQU 0 ;TRUE, IS PMMI ; MODCTLP EQU 0C0H ;PMMI VALUES MODSNDB EQU 1 ;BIT TO TEST FOR SEND MODSNDR EQU 1 ;VALUE WHEN READY MODRCVB EQU 2 ;BIT TO TEST FOR RECEIVE MODRCVR EQU 2 ;VALUE WHEN READY MODDATP EQU 0C1H ;DATA PORT BAUDRP EQU 0C2H ;BAUD RATE OUTPUT MODCTL2 EQU 0C3H ;SECOND CTL PORT ; ORIGMOD EQU 1DH ;8 DATA, NO PARITY, ORIG ANSWMOD EQU 1EH ;8 DATA, NO PARITY, ANSW ; INITREQ EQU 0 ;MODEM INIT. REQ'D? INITC1 EQU 64H ;FIRST INIT CHAR TO CTL PORT INITC2 EQU 64H ;2ND INIT CHAR TO CTL PORT ; ERRLIM EQU 10 ;MAX ALLOWABLE ERRORS EXITCHR EQU 'E'-40H ;CTL-E EXIT FROM T OR C DISCCHR EQU 'D'-40H ;CTL-D DISCONNECTS MODEM T/C ; FASTCLK EQU 1 ;PUT 1 HERE FOR 4 MHZ CLOCK ; ;DEFINE ASCII CHARACTERS USED ; SOH EQU 1 ;START OF HEADER EOT EQU 4 ;END OF TRANSMISSION ACK EQU 6 ;ACKNOWLEDGE NAK EQU 15H ;NEG ACKNOWLEDGE CAN EQU 18H ;CANCEL LF EQU 10 ;LINEFEED CR EQU 13 ;CARRIAGE RETURN ; ORG 100H CALL START ;GO PRINT ID DB 'MODEM PROGRAM V3.0 AS OF ' DB '07/07/82',CR,LF,'$' ; START: POP DX ;GET ID MESSAGE MOV CL,PRINT CALL BDOS ;PRINT ID MESSAGE ; ; ;SAVE PRIMARY OPTION, VALIDATE SECONDARY OPT. ; CALL PROCOPT ; ;INIT THE MODEM OR SERIAL PORT ; CALL INITMOD ; ;MOVE THE FILENAME FROM FCB 2 TO FCB 1 ; CALL MOVEFCB ; ;GOBBLE UP GARBAGE CHARS FROM THE LINE ;PRIOR TO RECEIVE OR SEND ; IN AL,MODDATP IN AL,MODDATP ; ;JMP TO APPROPRIATE FUNCTION ; MOV AL,OPTION ;GET PRIMARY OPTION ; CMP AL,'C' ;(COMPAT W/EARLIER JNZ L@00001 JMP TRMECHO ;OPTION "COMPUTER") L@00001: ; CMP AL,'E' ;TERMINAL IN ECHO JNZ L@00002 JMP TRMECHO ;..MODE? L@00002: ; CMP AL,'T' ;TERMINAL.. JNZ L@00003 JMP TERM ;..MODE? L@00003: ; CMP AL,'D' JNZ L@00004 JMP DISCONN L@00004: ; CMP AL,'X' JNZ L@00005 JMP EXAM ;GIVE EXAMPLES L@00005: ; CMP AL,'S' ;SEND.. JNZ L@00006 JMP SENDFIL ;..A FILE? L@00006: ; CMP AL,'R' ;RECEIVE.. JNZ L@00007 JMP RCVFIL ;..A FILE? L@00007: ; ;INVALID OPTION ; JMP BADOPT ; * * * * * * * * * * * * * * * * * * * * ; * ; TERM: TERMINAL MODE * ; * ; * * * * * * * * * * * * * * * * * * * * ; ;THIS PROGRAM SIMPLY SENDS KEYED CHARACTERS ;DOWN THE LINE, AND DISPLAYS CHARACTERS ;RECEIVED FROM THE LINE. THIS MAKES IT ;SUITABLE FOR COMMUNICATION WITH TIME SHARING ;COMPUTERS, CBBS'S, OR ANOTHER PROGRAM ;RUNING "MODEM E" (ECHO MODE) ; ;tipe THE "EXITCHR" (ORIGINALLY CTL-E) TO EXIT. ;OR THE "DISCCHR" (ORIGINALLY CTL-D) TO DISCONN. ; ;A FUTURE ENHANCEMENT WILL BE TO WRITE THE ;RECEIVED DATA IN MEMORY, AND ALLOW IT TO ;BE WRITTEN TO DISK ; TERM: CALL STAT ;LOCAL CHAR KEYED? JNZ L@00008 JMP TERML ;..NO, CHECK LINE L@00008: CALL KEYIN ;GET CHAR CMP AL,EXITCHR ;TIME TO END? JNZ L@00009 JMP CKDIS ;YES, CK DISCONN L@00009: CMP AL,DISCCHR ;DISCONNECT REQUEST? JNZ L@00010 JMP DISCONN ;YES, DO IT L@00010: OUT MODDATP,AL ;SEND THE CHAR ; ;SEE IF CHAR FROM LINE ; TERML: IN AL,MODCTLP ;READ STATUS AND AL,MODRCVB ;ISOLATE BIT CMP AL,MODRCVR ;READY? JZ L@00011 JMP TERM ;..NO, LOOP L@00011: IN AL,MODDATP ;READ DATA CALL tipe ;tipe IT JMP TERM ;LOOP ; ; * * * * * * * * * * * * * * * * * * * * ; * ; TRMECHO: TERMINAL WITH ECHO * ; * ; * * * * * * * * * * * * * * * * * * * * ; ;TERMINAL PROGRAM WITH ECHO - SEE NOTES ;UNDER "TERM" ABOVE ; ;C A U T I O N DON'T RUN WITH BOTH COMPUTERS ;IN "ECHO" MODE - LINE ERRORS (OR ANY CHAR) ;WILL BE ECHOED BACK AND FORTH AD INFINITUM. ; TRMECHO: IN AL,MODCTLP ;GET STATUS AND AL,MODRCVB ;ISOLATE READY BIT CMP AL,MODRCVR ;ARE WE READY? JNZ L@00012 JMP LINECHR ;YES, READ THE CHR L@00012: CALL STAT ;CHECK LOCAL KB JNZ L@00013 JMP TRMECHO ;..NO CHAR L@00013: CALL KEYIN ;GET LOCAL CHAR CMP AL,EXITCHR ;END? JNZ L@00014 JMP CKDIS ;YES, CK DISCONN, EXIT L@00014: CMP AL,DISCCHR ;DISCONN? JNZ L@00015 JMP DISCONN ;..YES, DO IT. L@00015: OUT MODDATP,AL ;SEND CHAR CALL tipe ;ECHO IT LOCALLY JMP TRMECHO ;..AND LOOP ; ;GOT CHAR FROM LINE ; LINECHR: IN AL,MODDATP ;GET CHAR OUT MODDATP,AL ;ECHO IT CALL tipe ;tipe IT JMP TRMECHO ;LOOP ; ; * * * * * * * * * * * * * * * * * * * * ; * ; SENDFIL: SENDS A CP/M FILE * ; * ; * * * * * * * * * * * * * * * * * * * * ; ;THE CP/M FILE SPECIFIED IN THE MODEM COMMAND ;IS TRANSFERRED OVER THE PHONE TO ANOTHER ;COMPUTER RUNNING MODEM WITH THE "R" (RECEIVE) ;OPTION. THE DATA IS SENT ONE SECTOR AT A ;TIME WITH HEADERS AND CHECKSUMS, AND RE- ;TRANSMISSION ON ERRORS. ; SENDFIL: CALL OPENFIL ;OPEN THE FILE MOV DL,80 ;WAIT 80 SEC.. CALL WAITNAK ;..FOR INITIAL NAK SENDLP: CALL RDSECT ;READ A SECTOR JAE L@00016 JMP SENDEOF ;SEND EOF IF DONE L@00016: CALL INCRSNO ;BUMP SECTOR # XOR AL,AL ;ZERO ERROR.. MOV ERRCT,AL ;..COUNT SENDRPT: CALL SENDHDR ;SEND A HEADER CALL SENDSEC ;SEND DATA SECTOR CALL SENDCKS ;SEND CKSUM CALL GETACK ;GET THE ACK JAE L@00017 JMP SENDRPT ;REPEAT IF NO ACK L@00017: JMP SENDLP ;LOOP UNTIL EOF ; ;FILE SENT, SEND EOT'S ; SENDEOF: MOV AL,EOT ;SEND.. CALL SEND ;..AN EOT CALL GETACK ;GET THE ACK JAE L@00018 JMP SENDEOF ;LOOP IF NO ACK L@00018: JMP DONE ;ALL DONE ; ; * * * * * * * * * * * * * * * * * * * * ; * ; RCVFIL: RECEIVE A FILE * ; * ; * * * * * * * * * * * * * * * * * * * * ; ;RECEIVES A FILE IN BLOCK FORMAT AS SENT ;BY ANOTHER PERSON DOING "MODEM S FN.FT". ; RCVFIL: CALL ERASFIL ;ERASE THE FILE CALL MAKEFIL ;..THEN MAKE NEW MOV AL,QFLG ;SEE IF IN QUIET MODE OR AL,AL JZ L@00019 JMP RCVLP ;NOT IN QUIET MODE, SKIP MSG L@00019: CALL ILPRT ;PRINT: DB 'FILE OPEN, READY TO RECEIVE',CR,LF,0 RCVLP: CALL RCVSECT ;GET A SECTOR JAE L@00020 JMP RCVEOT ;GOT EOT L@00020: CALL WRSECT ;WRITE THE SECTOR CALL INCRSNO ;BUMP SECTOR # CALL SENDACK ;ACK THE SECTOR JMP RCVLP ;LOOP UNTIL EOF ; ;GOT EOT ON SECTOR - FLUSH BUFFERS, END ; RCVEOT: CALL WRBLOCK ;WRITE THE LAST BLOCK CALL SENDACK ;ACK THE SECTOR CALL CLOSFIL ;CLOSE THE FILE MOV AL,QFLG ;QUIET.. OR AL,AL ;..MODE? JNZ L@00021 JMP CKDIS ;YES, CK DISCONN, END. L@00021: JMP DONE ;DISCONN IF REQ'D ; ; * * * * * * * * * * * * * * * * * * * * ; * ; SUBROUTIES * ; * ; * * * * * * * * * * * * * * * * * * * * ; ; ;----> RCVSECT: RECEIVE A SECTOR ; ;RETURNS WITH CARRY SET IF EOT RECEIVED. ; RCVSECT: XOR AL,AL ;GET 0 MOV ERRCT,AL ;INIT ERROR COUNT RCVRPT: MOV AL,QFLG ;QUIET? OR AL,AL JNZ L@00022 JMP RCVSQ ;YES, NO STAT MSG. L@00022: CALL ILPRT ;PRINT: DB 'AWAITING #',0 MOV AL,SECTNO ;GET SECTOR # INC AL ;(REAL INR LATER) CALL HEXO ;PRINT IN HEX CALL CRLF ;..THEN CRLF ; RCVSQ: MOV CH,10 ;10 SEC TIMEOUT CALL RECV ;GET SOH/EOT JAE L@00023 JMP RCVSTOT ;TIMEOUT L@00023: CMP AL,SOH ;GET SOH? JNZ L@00024 JMP RCVSOH ;..YES L@00024: ; ;EARLIER VERS. OF MODEM PROG SENT SOME NULLS - ;IGNORE THEM ; OR AL,AL ;00 FROM SPEED CHECK? JNZ L@00025 JMP RCVSQ ;YES, IGNORE IT L@00025: CMP AL,EOT ;END OF TRANSFER? STC ;RETURN WITH CARRY.. JNZ L@00026 RET ;..SET IF EOT L@00026: ; ;DIDN'T GET SOH OR EOT - ; MOV CH,AL ;SAVE CHAR MOV AL,VSEEFLG ;VIEWING.. OR AL,AL ;..MODE? JNZ L@00027 JMP RCVSEH ;YES, PRT.MSG L@00027: MOV AL,QFLG ;QUIET.. OR AL,AL ;..MODE? JNZ L@00028 JMP RCVSERR ;YES, SKIP MSG L@00028: RCVSEH: MOV AL,CH ;GET CHAR CALL HEXO ;SHOW IN HEX CALL ILPRT ;PRINT: DB 'H RCD, NOT SOH',CR,LF,0 ; ;DIDN'T GET VALID HEADER - PURGE THE LINE, ;THEN SEND NAK. ; RCVSERR: MOV CH,1 ;WAIT FOR 1 SEC.. CALL RECV ;..WITH NO CHARS JNAE L@00029 JMP RCVSERR ;LOOP UNTIL SENDER DONE L@00029: MOV AL,NAK ;SEND.. CALL SEND ;..THE NAK MOV AL,ERRCT ;ABORT IF.. INC AL ;..WE HAVE REACHED.. MOV ERRCT,AL ;..THE ERROR.. CMP AL,ERRLIM ;..LIMIT? JAE L@00030 JMP RCVRPT ;..NO, TRY AGAIN L@00030: ; ;10 ERRORS IN A ROW - ; MOV AL,VSEEFLG ;VIEWING.. OR AL,AL ;..FILE? JNZ L@00031 JMP RCVCKQ ;YES, ASK RETRY/QUIT L@00031: MOV AL,QFLG ;QUIET.. OR AL,AL ;..MODE? JNZ L@00032 JMP RCVSABT ;ABORT L@00032: RCVCKQ: CALL CKQUIT ;RETRY/QUIT? JNZ L@00033 JMP RCVSECT ;TRY AGAIN L@00033: ; RCVSABT: CALL CLOSFIL ;KEEP WHATEVER WE GOT CALL ERXIT DB '++UNABLE TO RECEIVE BLOCK' DB CR,LF,'++ABORTING++$' ; ;TIMEDOUT ON RECEIVE ; RCVSTOT: MOV AL,VSEEFLG ;VIEWING.. OR AL,AL ;..MODE? JNZ L@00034 JMP RCVSPT ;YES, PRT MSG L@00034: MOV AL,QFLG ;QUIET.. OR AL,AL ;..MODE? JNZ L@00035 JMP RCVSERR ;YES, NO MSG L@00035: RCVSPT: CALL ILPRT DB '++TIMEOUT++ ',0 RCVPRN: MOV AL,ERRCT ;PRINT ERROR.. CALL HEXO ;..COUNT CALL CRLF JMP RCVSERR ;BUMP ERR CT, ETC. ; ;GOT SOH - GET BLOCK #, BLOCK # COMPLEMENTED ; RCVSOH: MOV CH,1 ;TIMEOUT = 1 SEC CALL RECV ;GET SECTOR JAE L@00036 JMP RCVSTOT ;GOT TIMEOUT L@00036: MOV DH,AL ;D=BLK # MOV CH,1 ;TIMEOUT = 1 SEC CALL RECV ;GET CMA'D SECT # JAE L@00037 JMP RCVSTOT ;TIMEOUT L@00037: NOT AL ;CALC COMPLEMENT CMP AL,DH ;GOOD SECTOR #? JNZ L@00038 JMP RCVDATA ;YES, GET DATA L@00038: ; ;GOT BAD SECTOR # ; MOV AL,VSEEFLG ;VIEWING.. OR AL,AL ;..MODE? JNZ L@00039 JMP RCVBSE ;..YES, PRT MSG L@00039: MOV AL,QFLG ;QUIET.. OR AL,AL ;..MODE? JNZ L@00040 JMP RCVSERR ;..YES, NO MSG L@00040: ; RCVBSE: CALL ILPRT ;PRINT: DB '++BAD SECTOR # IN HDR',CR,LF,0 JMP RCVSERR ;BUMP ERROR CT. ; ; RCVDATA: MOV AL,DH ;GET SECTOR # MOV RCVSNO,AL ;SAVE IT MOV AL,1 ;SHOW.. MOV DATAFLG,AL ;GETTING DATA MOV CL,0 ;INIT CKSUM MOV BX,OFFSET 80H ;POINT TO BUFFER RCVCHR: MOV CH,1 ;1 SEC TIMEOUT CALL RECV ;GET CHAR JAE L@00041 JMP RCVSTOT ;TIMEOUT L@00041: MOV BYTE PTR [BX],AL ;STORE CHAR INC BL ;DONE? JZ L@00042 JMP RCVCHR ;NO, LOOP L@00042: ; ;VERIFY CHECKSUM ; MOV DH,CL ;SAVE CHECKSUM XOR AL,AL ;SHOW.. MOV DATAFLG,AL ;..END OF DATA MOV CH,1 ;TIMEOUT LEN. CALL RECV ;GET CHECKSUM JAE L@00043 JMP RCVSTOT ;TIMEOUT L@00043: CMP AL,DH ;CHECKSUM OK? JZ L@00044 JMP RCVCERR ;NO, ERROR L@00044: ; ;GOT A SECTOR, IT'S A DUP IF = PREV, ; OR OK IF = 1 + PREV SECTOR ; MOV AL,RCVSNO ;GET RECEIVED MOV CH,AL ;SAVE IT MOV AL,SECTNO ;GET PREV CMP AL,CH ;PREV REPEATED? JNZ L@00045 JMP RECVACK ;ACK TO CATCH UP L@00045: INC AL ;CALC NEXT SECTOR # CMP AL,CH ;MATCH? JZ L@00046 JMP ABORT ;NO MATCH - STOP SENDER, EXIT L@00046: RET ;CARRY OFF - NO ERRORS ; ;GOT CKSUM ; RCVCERR: MOV AL,VSEEFLG ;VIEWING.. OR AL,AL ;..MODE? JNZ L@00047 JMP RCVCPR ;..YES, PRT MSG L@00047: MOV AL,QFLG ;QUIET.. OR AL,AL ;..MODE? JNZ L@00048 JMP RCVSERR ;YES, NO MSG L@00048: RCVCPR: CALL ILPRT DB '++CKSUM++ ',0 JMP RCVPRN ;PRINT ERROR # ; ;PREV SECT REPEATED, DUE TO THE LAST ACK ;BEING GARBAGED. ACK IT SO SENDER WILL CATCH UP ; RECVACK: CALL SENDACK ;SEND THE ACK, JMP RCVSECT ;GET NEXT BLOCK ; ;SEND AN ACK FOR THE SECTOR ; SENDACK: MOV AL,ACK ;GET ACK CALL SEND ;..AND SEND IT RET ; ;----> SENDHDR: SEND THE SECTOR HEADER ; ;SEND: (SOH) (BLOCK #) (COMPLEMENTED BLOCK #) ; SENDHDR: MOV AL,QFLG ;QUIET.. OR AL,AL ;..MODE? JNZ L@00049 JMP SENDHNM ;YES, SKIP STATUS MSG. L@00049: CALL ILPRT ;PRINT: DB 'SEND # ',0 MOV AL,SECTNO ;PRINT.. CALL HEXO ;..SECT # CALL CRLF ;..THEN CR/LF ; SENDHNM: MOV AL,SOH ;SEND.. CALL SEND ;..SOH, MOV AL,SECTNO ;THEN SEND.. CALL SEND ;..SECTOR # MOV AL,SECTNO ;THEN SENDOR # NOT AL ;..COMPLEMENTED.. CALL SEND ;..SECTOR # RET ;FROM SENDHDR ; ;----> SENDSEC: SEND THE DATA SECTOR ; ;WHILE SENDING THE SECTOR, THE "DATAFLG" IS SET ;SUCH THAT IF "V" (VIEW THE FILE) WAS REQUESTED, ;THE "SHOW" ROUTINE WILL PRINT THE DATA, BUT NOT ;THE HDR OR CKSUM, OR ANY NON-FATAL MSGS. ; SENDSEC: MOV AL,1 ;SHOW NOW AT DATA.. MOV DATAFLG,AL ;..FOR VIEW COMMAND MOV CL,0 ;INIT CKSUM MOV BX,OFFSET 80H ;POINT TO BUFFER SENDC: MOV AL,BYTE PTR [BX] ;GET A CHAR CALL SEND ;SEND IT INC BL ;POINT TO NEXT CHAR JZ L@00050 JMP SENDC ;LOOP IF <100H L@00050: XOR AL,AL ;SHOW NOT INTO DATA.. MOV DATAFLG,AL ;..FOR VIEW COMMAND RET ;FROM SENDSEC ; ;----> SENDCKS: SEND THE CHECKSUM ; SENDCKS: MOV AL,CL ;SEND THE.. CALL SEND ;..CHECKSUM RET ;FROM SENDCKS ; ;----> GETACK: GET THE ACK ON THE SECTOR ; ;RETURNS WITH CARRY CLEAR IF ACK RECEIVED. ;IF AN ACK IS NOT RECEIVED, THE ERROR COUNT ;IS INCREMENTED, AND IF LESS THAN "ERRLIM", ;CARRY IS SET AND CONTROL RETURNS. IF THE ;ERROR COUNT IS AT "ERRLIM", THE PROGRAM ;ABORTS IF IN "QUIET" MODE, OR ASKS THE ;USER FOR QUIT/RETRY IF NOT. ; GETACK: MOV CH,10 ;WAIT 10 SECONDS MAX CALL RECVDG ;RECV W/GARBAGE COLLECT JAE L@00051 JMP GETATOT ;TIMED OUT L@00051: CMP AL,ACK ;OK? (CARRY OFF IF =) JNZ L@00052 RET ;YES, RET FROM GETACK L@00052: ; IF CANFLG CMP AL,CAN ;CANCEL TRANSMISSION? JNZ L@00053 JMP ABORT ;..YES L@00053: ENDIF ; MOV CH,AL ;SAVE CHAR MOV AL,QFLG ;QUIET.. OR AL,AL ;..MODE? JNZ L@00054 JMP ACKERR ;..YES, NO MSG L@00054: MOV AL,CH ;GET CHAR CALL HEXO ;PRINT IN HEX CALL ILPRT ;PRINT: DB 'H RCD, NOT ACK',CR,LF,0 ; ;TIMEOUT OR ERROR ON ACK - BUMP ERROR COUNT ; ACKERR: MOV AL,ERRCT ;GET COUNT INC AL ;BUMP IT MOV ERRCT,AL ;SAVE BACK CMP AL,ERRLIM ;AT LIMIT? JNB L@00055 RET ;NOT AT LIMIT L@00055: ; ;REACHED ERROR LIMIT ; MOV AL,VSEEFLG ;VIEWING.. OR AL,AL ;..FILE? JNZ L@00056 JMP GACKV ;YES, ASK QUIT/RETRY L@00056: MOV AL,QFLG ;QUIET.. OR AL,AL ;..MODE? JNZ L@00057 JMP CSABORT ;..YES, NO MCG L@00057: GACKV: CALL CKQUIT ;SEE IF WANT TO QUIT STC ;TO SHOW NO ACK JNZ L@00058 RET ;KEEP ON TRYIN' L@00058: CSABORT: CALL ERXIT DB 'CAN''T SEND SECTOR ' DB '- ABORTING',CR,LF,'$' ; ;TIMEOUT GETTING ACK ; GETATOT: MOV AL,QFLG ;QUIET.. OR AL,AL ;..MODE? JNZ L@00059 JMP ACKERR ;YES, NO MSG L@00059: CALL ILPRT ;PRINT: DB 'TIMEOUT ON ACK',0DH,0AH,0 JMP ACKERR ; ;----> CKABORT: CHECK FOR LOCAL ABORT ; ;IF THE USER WANTS TO CANCEL THE TRANSMISSION, ;TYPING CTL-X WILL ABORT IT. NOTE THIS TEST ;IS NOT MADE IF IN QUIET (NO CONSOLE I/O) MODE. ; CKABORT: MOV AL,VSEEFLG ;VIEWING? OR AL,AL JNZ L@00060 JMP CKABGO ;YES, CHECK L@00060: MOV AL,QFLG ;SUPPRESSED.. OR AL,AL ;..CONSOLE I/O? JNZ L@00061 RET ;YES, NO TEST L@00061: ; IF NOT CANFLG RET ENDIF ; CKABGO: CALL STAT ;KEY PRESSED? JNZ L@00062 RET ;NOTHING FROM KEYBOARD L@00062: CALL KEYIN ;GET DATA CMP AL,EXITCHR ;TIME TO END? JZ L@00063 RET ;NO, CONTINUE L@00063: ; ABORT: ABORTL: MOV CH,1 ;1 SEC. W/O CHARS. CALL RECV JNAE L@00064 JMP ABORTL ;LOOP UNTIL SENDER DONE L@00064: MOV AL,CAN ;CONTROL X CALL SEND ;STOP SENDING END ABORTW: MOV CH,1 ;1 SEC W/O CHARS. CALL RECV JNAE L@00065 JMP ABORTW ;LOOP UNTIL SENDER DONE L@00065: MOV AL,' ' ;GET A SPACE... CALL SEND ;TO CLEAR OUT CONTROL X CALL ILPRT ;EXIT WITH ABORT MSG DB 'MODEM PROGRAM CANCELLED',0DH,0AH,0 JMP CKDIS ;CHECK FOR DISCONN. ; ;----> INCRSNO: INCREMENT SECTOR # ; INCRSNO: MOV AL,SECTNO ;INCR.. INC AL ;..SECT.. MOV SECTNO,AL ;..NUMBER RET ; ;----> ERASFIL: ERASE THE INCOMING FILE. ; ;IF IT EXISTS, ASK IF IT MAY BE ERASED. ; ERASFIL: MOV DX,OFFSET FCB ;POINT TO CTL BLOCK MOV CL,SRCHF ;SEE IF IT.. CALL BDOS ;..EXISTS INC AL ;FOUND? JNZ L@00066 RET ;..NO, RETURN L@00066: CALL ILPRT ;PRINT: DB '++FILE EXISTS, tipe Y TO ERASE: ',0 CALL KEYIN ;GET CHAR LAHF XCHG AL,AH PUSH AX XCHG AL,AH CALL tipe ;ECHO POP AX XCHG AL,AH SAHF AND AL,5FH ;MAKE UPPER CASE CMP AL,'Y' ;WANT ERASED? JZ L@00067 JMP CKDIS ;QUIT IF NOT ERASE L@00067: CALL CRLF ;BACK TO START OF LINE ; ;ERASE OLD FILE ; MOV DX,OFFSET FCB ;POINT TO FCB MOV CL,ERASE ;GET BDOS FNC CALL BDOS ;DO THE ERASE RET ;FROM "ERASFIL" ; ;----> MAKEFIL: MAKES THE FILE TO BE RECEIVED ; MAKEFIL: MOV DX,OFFSET FCB ;POINT TO FCB MOV CL,MAKE ;GET BDOS FNC CALL BDOS ;TO THE MAKE INC AL ;FF=BAD? JZ L@00068 RET ;OPEN OK L@00068: ;DIRECTORY FULL - CAN'T MAKE FILE CALL ERXIT DB '++ERROR - CAN''T MAKE FILE',CR,LF DB '++DIRECTORY MUST BE FULL',CR,LF,'$' ; ;----> OPENFIL: OPENS THE FILE TO BE SENT ; OPENFIL: MOV DX,OFFSET FCB ;POINT TO FILE MOV CL,OPEN ;GET FUNCTION CALL BDOS ;OPEN IT INC AL ;OPEN OK? JZ L@00069 JMP OPENOK ;..YES L@00069: CALL ERXIT ;..NO, ABORT DB 'CAN''T OPEN FILE$' ; OPENOK: CALL ILPRT ;PRINT: DB 'FILE OPEN, EXTENT LENGTH: ',0 MOV AL,FCB+15 ;GET # SECTORS CALL HEXO ;PRINT IN HEX MOV AL,'H' CALL tipe ;PRINT 'H' AFTER NUMBER CALL CRLF ;..THEN CRLF RET ; ;----> CLOSFIL: CLOSES THE RECEIVED FILE ; CLOSFIL: MOV DX,OFFSET FCB ;POINT TO FILE MOV CL,CLOSE ;GET FUNCTION CALL BDOS ;CLOSE IT INC AL ;CLOSE OK? JZ L@00070 RET ;..YES, RETURN L@00070: CALL ERXIT ;..NO, ABORT DB 'CAN''T CLOSE FILE$' ; ;----> RDSECT: READS A SECTOR ; ;FOR SPEED, THIS ROUTINE BUFFERS UP 16 ;SECTORS AT A TIME. ; RDSECT: MOV AL,SECINBF ;GET # SECT IN BUFF. DEC AL ;DECREMENT.. MOV SECINBF,AL ;..IT JNS L@00071 JMP RDBLOCK ;EXHAUSTED? NEED MORE. L@00071: MOV BX,SECPTR ;GET POINTER MOV DX,OFFSET 80H ;TO DATA CALL MOVE128 ;MOVE TO BUFFER MOV SECPTR,BX ;SAVE BUFFER POINTER RET ;FROM "READSEC" ; ;BUFFER IS EMPTY - READ IN ANOTHER BLOCK OF 16 ; RDBLOCK: MOV AL,EOFLG ;GET EOF FLAG CMP AL,1 ;IS IT SET/ STC ;TO SHOW EOF JNZ L@00072 RET ;GOT EOF L@00072: MOV CL,0 ;SECTORS IN BLOCK MOV DX,OFFSET DBUF ;TO DISK BUFFER RDSECLP: PUSH CX PUSH DX MOV CL,STDMA ;SET DMA.. CALL BDOS ;..ADDR MOV DX,OFFSET FCB MOV CL,READ CALL BDOS POP DX POP CX OR AL,AL ;READ OK? JNZ L@00073 JMP RDSECOK ;YES L@00073: DEC AL ;EOF? JNZ L@00074 JMP REOF ;GOT EOF L@00074: ; ;READ ERROR ; CALL ERXIT DB '++FILE READ ERROR$' ; RDSECOK: MOV BX,OFFSET 80H ADD BX,DX ;TO NEXT BUFF XCHG BX,DX ;BUFF TO DE INC CL ;MORE SECTORS? MOV AL,CL ;GET COUNT CMP AL,16 ;DONE? JNZ L@00075 JMP RDBFULL ;..YES, BUFF IS FULL L@00075: JMP RDSECLP ;READ MORE ; REOF: MOV AL,1 MOV EOFLG,AL ;SET EOF FLAG MOV AL,CL ; ;BUFFER IS FULL, OR GOT EOF ; RDBFULL: MOV SECINBF,AL ;STORE SECTOR COUNT MOV BX,OFFSET DBUF ;INIT BUFFER.. MOV SECPTR,BX ;..POINTER MOV DX,OFFSET 80H ;RESET.. MOV CL,STDMA ;..DMA.. CALL BDOS ;..ADDR JMP RDSECT ;PASS SECT TO CALLER ; ;----> WRSECT: WRITE A SECTOR ; ;WRITES THE SECTOR INTO A BUFFER. WHEN 16 ;HAVE BEEN WRITTEN, WRITES THE BLOCK TO DISK. ; ;ENTRY POINT "WRBLOCK" FLUSHES THE BUFFER AT EOF. ; WRSECT: MOV BX,SECPTR ;GET BUFF ADDR XCHG BX,DX ;TO DE FOR MOVE MOV BX,OFFSET 80H ;FROM HERE CALL MOVE128 ;MOVE TO BUFFER XCHG BX,DX ;SAVE NEXT.. MOV SECPTR,BX ;..BLOCK POINTER MOV AL,SECINBF ;BUMP THE.. INC AL ;..SECTOR #.. MOV SECINBF,AL ;..IN THE BUFF CMP AL,16 ;HAVE WE 16? JZ L@00076 RET ;NO, RETURN L@00076: ; ;----> WRBLOCK: WRITES A BLOCK TO DISK ; WRBLOCK: MOV AL,SECINBF ;# SECT IN BUFFER OR AL,AL ;0 MEANS END OF FILE JNZ L@00077 RET ;NONE TO WRITE L@00077: MOV CL,AL ;SAVE COUNT MOV DX,OFFSET DBUF ;POINT TO DISK BUFF DKWRLP: PUSH BX PUSH DX PUSH CX MOV CL,STDMA ;SET DMA CALL BDOS ;TO BUFFER MOV DX,OFFSET FCB ;THEN WRITE MOV CL,WRITE ;..THE.. CALL BDOS ;..BLOCK POP CX POP DX POP BX OR AL,AL JZ L@00078 JMP WRERR ;OOPS, ERROR L@00078: MOV BX,OFFSET 80H ;LENGTH OF 1 SECT ADD BX,DX ;HL= NEXT BUFF XCHG BX,DX ;TO DE FOR SETDMA DEC CL ;MORE SECTORS? JZ L@00079 JMP DKWRLP ;..YES, LOOP L@00079: XOR AL,AL ;GET A ZERO MOV SECINBF,AL ;RESET # OF SECTORS MOV BX,OFFSET DBUF ;RESET BUFFER.. MOV SECPTR,BX ;..POINTER ; MOV DX,OFFSET 80H ;07/13/79 MOD.. MOV CL,STDMA ;..TO RESET.. CALL BDOS ;..DMA ADDR. ; RET ; WRERR: MOV CL,CAN ;CANCEL.. CALL SEND ;..SENDER CALL ERXIT ;EXIT W/MSG: DB '++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 $ ;RECEIVE W/GARBAGE DELETE IN AL,MODDATP ;GET A CHAR IN AL,MODDATP ;..TOTALLY PURGE UART ; RECV: PUSH DX ;SAVE ; IF FASTCLK ;4MHZ? MOV AL,CH ;GET TIME REQUEST ADD AL,AL ;DOUBLE IT MOV CH,AL ;NEW TIME IN B ENDIF ; MSEC: MOV DX,OFFSET 50000 ;1 SEC DCR COUNT CALL CKABORT ;CHECK FOR EXIT REQUEST MWTI: IN AL,MODCTLP ;CHECK STATUS AND AL,MODRCVB ;ISOLATE BIT CMP AL,MODRCVR ;READY? JNZ L@00080 JMP MCHAR ;GOT CHAR L@00080: DEC DL ;COUNT.. JZ L@00081 JMP MWTI ;..DOWN.. L@00081: DEC DH ;..FOR.. JZ L@00082 JMP MWTI ;..TIMEOUT L@00082: DEC CH ;MORE SECONDS? JZ L@00083 JMP MSEC ;YES, WAIT L@00083: ; ;MODEM TIMED OUT RECEIVING ; POP DX ;RESTORE D,E STC ;CARRY SHOWS TIMEOUT RET ; ;GOT CHAR FROM MODEM ; MCHAR: IN AL,MODDATP ;READ THE CHAR POP DX ;RESTORE DE ; ;CALC CHECKSUM ; LAHF XCHG AL,AH PUSH AX XCHG AL,AH ;SAVE THE CHAR ADD AL,CL ;ADD TO CHECKSUM MOV CL,AL ;SAVE CHECKSUM ; ;CHECK IF MONITORING REC'D DATA ; MOV AL,RSEEFLG ;SEE RECEIVED.. OR AL,AL ;..DATA? JNZ L@00084 JMP MONIN ;..YES L@00084: ; ;CHECK IF "VIEWING" AND THIS IS A DATA CHAR ; MOV AL,VSEEFLG ;VIEWING.. OR AL,AL ;..DATA? JZ L@00085 JMP NOMONIN ;..NO L@00085: ; ;"VIEW" REQUESTED. SHOW THE CHAR IT IS DATA ; MOV AL,DATAFLG ;GET DATA FLAG OR AL,AL ;TEST IT JNZ L@00086 JMP NOMONIN ;..OFF, NOT DATA L@00086: MONIN: POP AX XCHG AL,AH SAHF ;..IS DATA, LAHF XCHG AL,AH PUSH AX XCHG AL,AH ;GET IT, CALL SHOW ;..AND SHOW IT NOMONIN: POP AX XCHG AL,AH SAHF ;RESTORE CHAR OR AL,AL ;CARRY OFF: NO ERROR RET ;FROM "RECV" ; ;----> SEND: SEND A CHARACTER TO THE MODEM ; SEND: LAHF XCHG AL,AH PUSH AX XCHG AL,AH ;SAVE THE CHAR ; ;CHECK IF MONITORING SENT DATA ; MOV AL,SSEEFLG ;CHECK IF MONITORING.. OR AL,AL ;..SENT DATA JNZ L@00087 JMP MONOUT ;..YES L@00087: ; ;CHECK IF "VIEWING" THE FILE ; MOV AL,VSEEFLG ;GET VIEW FLAG OR AL,AL ;TEST IT JZ L@00088 JMP NOMONOT ;NO L@00088: MOV AL,DATAFLG ;IS THIS OR AL,AL ;..DATA? JNZ L@00089 JMP NOMONOT ;..NO. L@00089: MONOUT: POP AX XCHG AL,AH SAHF ;GET THE CHAR LAHF XCHG AL,AH PUSH AX XCHG AL,AH ;SAVE IT CALL SHOW ;SHOW IT NOMONOT: POP AX XCHG AL,AH SAHF ;RESTORE CHAR LAHF XCHG AL,AH PUSH AX XCHG AL,AH ;SAVE IT ADD AL,CL ;CALC CKSUM MOV CL,AL ;SAVE CKSUM SENDW: IN AL,MODCTLP ;GET STATUS AND AL,MODSNDB ;ISOLATE READY BIT CMP AL,MODSNDR ;READY? JZ L@00090 JMP SENDW ;..NO, WAIT L@00090: POP AX XCHG AL,AH SAHF ;GET CHAR OUT MODDATP,AL ;OUTPUT IT RET ;FROM "SEND" ; ;----> WAITNAK: WAITS FOR INITIAL NAK ; ;TO ENSURE NO DATA IS SENT UNTIL THE RECEIVING ;PROGRAM IS READY, THIS ROUTINE WAITS FOR THE ;THE FIRST TIMEOUT-NAK FROM THE RECEIVER. (E) ;CONTAINS THE # OF SECONDS TO WAIT. ; WAITNAK: MOV AL,VSEEFLG ;VIEWING? OR AL,AL JNZ L@00091 JMP WAITNPR ;PRINT MSG L@00091: MOV AL,QFLG ;QUIET.. OR AL,AL ;..MODE? JNZ L@00092 JMP WAITNLP ;YES, SKIP MSG L@00092: WAITNPR: CALL ILPRT ;PRINT: DB 'AWAITING INITIAL NAK',CR,LF,0 WAITNLP: CALL CKABORT ;ABORT IF LOCAL CTL-X MOV CH,1 ;TIMEOUT DELAY CALL RECV ;DID WE GET.. CMP AL,NAK ;..A NAK? JNZ L@00093 RET ;YES, SEND BLOCK L@00093: ; IF CANFLG CMP AL,CAN ;CTL-X FROM REMOTE? JNZ L@00094 JMP ABORT ;..YES, ABORT L@00094: ENDIF ; DEC DL ;80 TRIES? JNZ L@00095 JMP ABORT ;YES, ABORT L@00095: JMP WAITNLP ;NO, LOOP ; ;----> INITADR: INIT'S CP/M BDOS ADDRESSES ; ;THIS ROUTINE FILLS IN THE ADDRESSES OF VARIOUS ;JMP AND CALL INSTRUCTIONS, SO THAT CP/M BDOS ;IS BYPASSED WHILE ACCESSING THE CONSOLE. THIS ;IS DONE TO ALLOW CHARACTERS SUCH AS CONTROL-C ;AND CONTROL-S TO BE KEYED WHILE IN TERMINAL ;MODE, WITHOUT CP/M INTERPRETING THEM. ; ; ;----> PROCOPT: PROCESS COMMAND OPTIONS ; ;1) SAVES THE PRIMARY OPTION IN 'OPTION'; ;2) IF OPTION 'H' (HELP) IS ASKED FOR, ;TRANSFERS DIRECTLY TO THE HELP PRINT; ;3) SCANS THE SUB-OPTION CHARACTERS, AND FOR ;EACH FOUND, ZEROS THE APPROPRIATE ENTRY IN ;THE OPTION TABLE. FOR EXAMPLE, IF 'D' IS ;CODED (DISCONNECT) THEN THE 'D' STORED AT ;'DISCFLG' IS SET TO 0 SO IT CAN BE TESTED ;LATER. ; PROCOPT: MOV DX,OFFSET FCB+1 ;TO PRIMARY OPT. XCHG BX,DX MOV AL,[BX] XCHG BX,DX ;GET PRIMARY MOV OPTION,AL ;SAVE IT CMP AL,'H' ;MODEM H(ELP)? JNZ L@00096 JMP HELP ;..YES, GIVE HELP L@00096: ; OPTLP: INC DX ;TO SECONDARY OPTION XCHG BX,DX MOV AL,[BX] XCHG BX,DX ;GET CHAR ; ;IF YOU MOD THIS PROGRAM FOR >7 OPTIONS, ;YOU MUST CHANGE THE FOLLOWING, SINCE ;THERE WON'T BE A ' ' AFTER THE OPTION ;IF A BAUD RATE WAS SPECIFIED. ; CMP AL,' ' ;NO MORE OPT'NS? JNZ L@00097 JMP ENDOPT ;..YES L@00097: ;SET THE APPROP. OPT: STORE 0 IN IT MOV BX,OFFSET OPTBL ;HL = ADDR OF 'OAQDSRV' MOV cx,tablesize ;OPT TABLE LEN OPTCK: CMP AL,BYTE PTR [BX] ;FOUND THE OPTION? JZ L@00098 JMP OPTNO ;NO, DON'T SET IT L@00098: MOV BYTE PTR [BX],0 ;SET THE OPTION JMP OPTLP ;GET NEXT OPTION OPTNO: INC BX ;TO NEXT DEC CH ;MORE? JZ L@00099 JMP OPTCK L@00099: ;OPTION NOT IN TABLE JMP BADOPT ;SHOW BAD SUB OPTION ; ;IF "VIEW" WAS ASKED FOR, SET QUIET FLAG ; ENDOPT: MOV AL,VSEEFLG ;VIEW.. OR AL,AL ;..ASKED FOR? JZ L@00100 RET ;..NO, RET FROM 'PROCOPT' L@00100: MOV QFLG,AL ;YES, NO HDR/CKSUM PRT RET ;FROM 'PROCOPT' ; ;DONE - CLOSE UP SHOP ; DONE: MOV AL,VSEEFLG ;VIEWING? OR AL,AL JNZ L@00101 JMP DONETC ;SHOW MSG L@00101: MOV AL,QFLG ;QUIET OR AL,AL ;..MODE? JNZ L@00102 JMP DONECTE ;YES, CK TERM/ECHO L@00102: DONETC: CALL ILPRT DB CR,LF,'TRANSFER COMPLETE' DB CR,LF,0 ; ;CHECK IF TERMINAL OR ECHO SUB COMMAND ;WAS SPECIFIED ; DONECTE: MOV AL,TERMFLG ;TERM? OR AL,AL JNZ L@00103 JMP TERM ;..YES L@00103: MOV AL,ECHOFLG ;ECHO? OR AL,AL JNZ L@00104 JMP TRMECHO ;..YES L@00104: ; ;FALL INTO 'CKDIS' ; ;----> CKDIS: CHECK IF DISCONNECT REQUESTED ; ;THIS ROUTINE IS JUMPED TO AT THE END OF ;PROCESSING, AND DISCONNECTS THE PHONE IF ;'D' WAS SPECIFIED AS A SUB-OPTION. ; CKDIS: MOV AL,DISCFLG ;CHECK 'D' FLAG OR AL,AL ;REQUESTED? ; IF PMMI JZ L@00105 JMP NDIS ;..NO, JUST EXIT L@00105: ENDIF ; IF NOT PMMI JZ L@00106 JMP EXIT L@00106: ENDIF ; ;AWAIT C/R TO DISC. SO WE DON'T LOSE THE PHONE ; CALL ILPRT DB CR,LF,'PRESS RETURN TO DISCONNECT:',0 CALL KEYIN LAHF XCHG AL,AH PUSH AX XCHG AL,AH CALL CRLF POP AX XCHG AL,AH SAHF CMP AL,0DH JZ L@00107 JMP CKDIS ;ASK AGAIN L@00107: ; ;----> DISCONN: DISCONNECT THE PHONE ; DISCONN EQU $ ; IF PMMI XOR AL,AL ;GET DISCONN VALUE OUT MODCTLP,AL ;RESET ORIG/ANSW OUT MODCTL2,AL ;TURN OFF DTR, DO BREAK ENDIF ;PMMI ; CALL ILPRT ;PRINT: DB '++DISCONNECTED++',0 JMP EXIT ; ;NO DISCONNECT, tipe MSG AS REMINDER THAT PHONE'S ;ON HOOK ; IF PMMI NDIS: MOV AL,QFLG ;QUIET.. OR AL,AL ;..MODE? JNZ L@00108 JMP EXIT ;..YES, NO MSG L@00108: CALL ILPRT DB CR,LF,'++Don''t forget - The modem is ' DB 'NOT DISCONNECTED++',CR,LF DB 'USE "MODEM D" to disconnect',CR,LF,0 JMP EXIT ; ENDIF ; ;----> INITMOD: INITIALIZED THE MODEM ; ;THIS ROUTINE IS USED TO INITIALIZE SERIAL ;BOARDS, OR SETUP S-100 MODEM BOARDS. ;JUST RETURNS IF NO INITIALIZATION REQUIRED. ; INITMOD: ; IF INITREQ ;REQUIRE INIT? MOV AL,INITC1 ;GET 1ST INIT CHAR OUT MODCTLP,AL ;OUTPUT IT MOV AL,INITC2 ;GET 2ND INIT CHAR OUT MODCTLP,AL ;OUTPUT IT ENDIF ; IF PMMI CALL GETBAUD ;GET THE BAUD RATE OUT BAUDRP,AL ;OUT BAUD RATE PORT ; ;SET THE MOTOROLA MODEM CHIP BIT FOR >300 IF REQ'D ; CMP AL,52 ;>300? MOV AL,5FH ;VALUE FOR >300 JAE L@00109 JMP GT300 L@00109: MOV AL,7FH ;VALUE FOR <= 300 GT300: OUT MODCTL2,AL ;SET IT ; ;SET ORIG/ANSW IF REQUESTED ; MOV AL,ORIGFLG ;ORIGINATE.. OR AL,AL ;..MODE? MOV AL,ORIGMOD JNZ L@00110 JMP OFFHOOK ;..YES, DO IT L@00110: MOV AL,ANSWFLG ;ANSWER.. OR AL,AL ;..MODE? MOV AL,ANSWMOD JZ L@00111 RET ;NEITHER ORIG NOR ANSW. L@00111: ; ;GO OFFHOOK IN REQUESTED (ORIG/ANSW) MODE ; OFFHOOK: MOV BX,OFFSET 4000 ;DELAY AMT OFFDLY: DEC BL JZ L@00112 JMP OFFDLY L@00112: DEC BH JZ L@00113 JMP OFFDLY L@00113: OUT MODCTLP,AL ;GO OFF HOOK RET ; ;----> GETBAUD: GETS BAUD RATE FROM COMMAND ; ;THIS ROUTINE CHECKS IF A BAUD RATE HAS ;BEEN ASKED FOR, (SUCH AS MODEM T.450), ;AND IF SO, CALCULATES THE PMMI BAUD RATE ;VALUE TO BE OUTPUT. DEFAULTS TO 300. ; GETBAUD: MOV AL,FCB+9 ;GET 'FILEtipe' CMP AL,' ' ;DEFAULT? MOV AL,52 ;300 BAUD VALUE JNZ L@00114 RET ;NO BAUD RATE, USE 300 L@00114: ; ;GOT BAUD RATE - CONVERT TO PROPER TIMER VALUE ; ;FIRST, CONVERT THE NUMBER TO BINARY ; MOV DX,OFFSET FCB+9 ;TO ASCII VALUE MOV BX,OFFSET 0 ;INIT BINARY RESULT DECLP: XCHG BX,DX MOV AL,[BX] XCHG BX,DX ;GET ASCII DIGIT INC DX ;TO NEXT DIGIT CMP AL,' ' ;BLANK ONE? JNZ L@00115 JMP DECLP ;..YES, SKIP IT L@00115: CMP AL,'0' ;VALIDATE IT JAE L@00116 JMP BADRATE ;ERROR L@00116: CMP AL,'9'+1 ;VALIDATE JNAE L@00117 JMP BADRATE ;ERROR L@00117: SUB AL,'0' ;MAKE DIGIT BINARY ; ;MULTIPLY PREV VALUE BY 10 ; MOV CH,BH ;SET UP FOR MOV CL,BL ;MULTIPLY BY 10 ADD BX,BX ;MULTIPLY BY 2 ADD BX,BX ;X 2 = 4 ADD BX,CX ;+ 1 = 5 ADD BX,BX ;X 2 = 10 ADD AL,BL ;ADD IN DIGIT MOV BL,AL ;SAVE BACK JZ L@00118 JMP DIGNC ;NO CARRY? L@00118: INC BH ;ADD IN CARRY ;CHECK IF DONE? DIGNC: MOV AL,DL ;SEE IF PAST CMP AL,FCB+12 ;..LAST DIGIT JZ L@00119 JMP DECLP ;NO, LOOP L@00119: ; ;CALCULATE THE VALUE TO OUTPUT: ; ; RATE = 250000/16/BAUD RATE ; ; DIVIDE BY REPETITIVE SUBTRACTION ; ------ ;COMPLEMENT THE BAUD RATE ; MOV AL,BH ;GET HI NOT AL ;COMPLEMENT MOV DH,AL ;SAVE MOV AL,BL ;GET LO NOT AL ;COMPLEMENT MOV DL,AL ;SAVE INC DX ;DE=2'S COMPLEMENT ;DIVIDE MOV BX,OFFSET 15625 ;250000/16 MOV CX,OFFSET -1 ;INIT QUOTIENT DIVLP: INC CX ;BUMP QUOTIENT ADD BX,DX ;'SUBTRACT' JAE L@00120 JMP DIVLP ;LOOP 'TILL DONE L@00120: ;VALIDATE THE RESULT MOV AL,CH ;CAN'T HAVE >255 OR AL,AL MOV AL,CL ;GET ACTUAL JNZ L@00121 RET ;RET IF <256 L@00121: ; ;INVALID BAUD RATE ; BADRATE: CALL ERXIT DB '++INVALID BAUD RATE++$' ENDIF ;PMMI RET ; ;----> MOVEFCB: MOVES FCB(2) TO FCB ; ;I ATTEMPTED TO MAKE THE MODEM COMMAND 'NATURAL', ;I.E. MODEM SEND FILENAME (MODEM S FN.FT) RATHER ;THAT MODEM FILENAME SEND (MODEM FN.FT S) SO THIS ;ROUTINE MOVES THE FILENAME FROM THE SECOND FCB ;TO THE FIRST ; MOVEFCB: MOV BX,OFFSET FCB+16 ;FROM MOV DX,OFFSET FCB ;TO MOV CH,16 ;LEN CALL MOVE ;DO THE MOVE XOR AL,AL ;GET 0 MOV FCBSNO,AL ;ZERO SECTOR # MOV FCBEXT,AL ;..AND EXTENT RET ; ;----> SHOW: SHOWS CHAR SENT/RECEIVED ; ;CR, LF, AND TAB ARE SHOWN. ALL OTHER ;NON-PRINTABLE CHARACTERS ARE SHOWN IN ;HEX AS (XX) ; SHOW: CMP AL,LF ;LF? JNZ L@00122 JMP Ctipe ;..YES, tipe IT L@00122: CMP AL,CR ;CR? JNZ L@00123 JMP Ctipe ;..YES, tipe IT L@00123: CMP AL,09 ;TAB JNZ L@00124 JMP Ctipe ;..YES, tipe IT L@00124: CMP AL,' ' ;CTL-CHR? JAE L@00125 JMP SHOWHEX ;YES, SHOW IN HEX L@00125: CMP AL,7FH ;DEL? JAE L@00126 JMP Ctipe ;NO, tipe THE CHAR L@00126: SHOWHEX: LAHF XCHG AL,AH PUSH AX XCHG AL,AH ;SAVE THE CHAR MOV AL,'(' ;tipe.. CALL Ctipe ;..'(' POP AX XCHG AL,AH SAHF ;THEN.. CALL HEXO ;..THE CHAR MOV AL,')' ;THEN.. JMP Ctipe ;..')' AND RETURN. ; ;----> Ctipe: tipeS VIA CP/M SO TABS ARE EXPANDED ; Ctipe: PUSH CX ;SAVE.. PUSH DX ;..ALL.. PUSH BX ;..REGS MOV DL,AL ;CHAR TO E MOV CL,WRCON ;GET BDOS FNC CALL BDOS ;PRIN THE CHR POP BX ;RESTORE.. POP DX ;..ALL.. POP CX ;..REGS RET ;FROM "Ctipe" ; CRLF: MOV AL,CR CALL tipe MOV AL,LF ; ;----> tipe: tipe VIA DIRECT BDOS ACCESS ; ;THIS ROUTINE BYPASSES CP/M'S CTL-S, CTL-C ;TESTS. ; tipe: LAHF XCHG AL,AH PUSH AX XCHG AL,AH ;SAVE CHAR PUSH CX ;AND B Vtipe: mov cl,6 call bdos POP CX ;RESTORE BC POP AX XCHG AL,AH SAHF ;..AND CHAR RET ;FROM "tipe" ; ;KEYBOARD STATUS ; Stat: mov cl,6 mov dl,0feh call bdos OR AL,AL ;0 => NOT READY RET ; ;KEYBOARD INPUT ; keyin: mov cl,6 mov dl,0ffh call bdos or al,al jz keyin ret ; ;HEX OUTPUT ; HEXO: LAHF XCHG AL,AH PUSH AX XCHG AL,AH ;SAVE FOR RIGHT DIGIT RCR AL,1 ;RIGHT.. RCR AL,1 ;..JUSTIFY.. RCR AL,1 ;..LEFT.. RCR AL,1 ;..DIGIT.. CALL NIBBL ;PRINT LEFT DIGIT POP AX XCHG AL,AH SAHF ;RESTORE RIGHT NIBBL: AND AL,0FH ;ISOLATE DIGIT CMP AL,10 ;IS IS <10? JAE L@00127 JMP ISNUM ;YES, NOT ALPHA L@00127: ADD AL,7 ;ADD ALPHA BIAS ISNUM: ADD AL,'0' ;MAKE PRINTABLE JMP tipe ;..THEN tipe IT ; ;----> CKQUIT: QUIT/RETRY AFTER MULTIPLE ERRS. ; ;RETURNS W/ ZERO SET IF "RETRY" ASKED FOR ; CKQUIT: XOR AL,AL ;ZERO.. MOV ERRCT,AL ;..ERROR COUNT CALL ILPRT ;PRINT: DB 'MULTIPLE ERRORS ENCOUNTERED. ' DB 'tipe Q TO QUIT, R TO RETRY: ',0 CALL KEYIN ;QUIT/RETRY LAHF XCHG AL,AH PUSH AX XCHG AL,AH CALL CRLF POP AX XCHG AL,AH SAHF AND AL,5FH ;MAKE UPPER CASE CMP AL,'R' ;RETRY? JNZ L@00128 RET ;'KEEP ON TRUCKIN' L@00128: CMP AL,'Q' ;QUIT? JZ L@00129 JMP CKQUIT ;NO, ASK AGAIN L@00129: OR AL,AL ;SET NON-ZERO RET ; ;----> ILPRT: INLINE PRINT OF MSG ; ;THE CALL TO ILPRT IS FOLLOWED BY A MESSAGE, ;BINARY 0 AS THE END. BINARY 1 MAY BE USED TO ;PAUSE (MESSAGE 'PRESS RETURN TO CONTINUE') ; ILPRT: POP SI XCHG BX,SI PUSH SI ;SAVE HL, GET HL=MSG ILPLP: MOV AL,BYTE PTR [BX] ;GET CHAR OR AL,AL ;END OF MSG? JNZ L@00130 JMP ILPRET ;..YES, RETURN L@00130: CMP AL,1 ;PAUSE? JNZ L@00131 JMP ILPAUSE ;..YES L@00131: CALL Ctipe ;tipe THE MSG ILPNEXT: INC BX ;TO NEXT CHAR JMP ILPLP ;LOOP ; ;PAUSE WHILE TYPING HELP SO INFO DOESN'T ; SCROLL OFF OF VIDEO SCREENS ; ILPAUSE: CALL ILPRT ;PRINT: DB CR,LF,'PRESS RETURN TO CONTINUE' DB CR,LF,0 CALL KEYIN ;GET ANY CHAR CMP AL,'C'-40H ;REBOOT? JNZ L@00132 JMP EXIT ;YES. L@00132: JMP ILPNEXT ;LOOP ; ILPRET: INC BX POP SI XCHG BX,SI PUSH SI ;RESTORE HL RET ;PAST MSG ; ;----> PRTMSG: PRINTS MSG POINTED TO BY (DE) ; ;A '$' IS THE ENDING DELIMITER FOR THE PRINT. ;NO REGISTERS SAVED. ; PRTMSG: MOV CL,PRINT ;GET BDOS FNC JMP BDOS ;PRINT MESSAGE, RETURN ; ;----> ERXIT: EXIT PRINTING MSG FOLLOWING CALL ; ERXIT: POP DX ;GET MESSAGE CALL PRTMSG ;PRINT IT CALL CKDIS ;DISCONNECT? ; EXIT: mov cl,0 mov dl,0 call bdos ; ;MOVE 128 CHARACTERS ; MOVE128: MOV CH,128 ;SET MOVE COUNT ; ;MOVE FROM (HL) TO (DE) LENGTH IN (B) ; MOVE: MOV AL,BYTE PTR [BX] ;GET A CHAR XCHG BX,DX MOV [BX],AL XCHG BX,DX ;STORE IT INC BX ;TO NEXT "FROM" INC DX ;TO NEXT "TO" DEC CH ;MORE? JZ L@00133 JMP MOVE ;..YES, LOOP L@00133: RET ;..NO, RETURN ; ---------------- OPTION DB 0 ;PRIMARY OPTION ; ;DATAFLG IS USED BY THE "V" SUBCOMMAND - ;IT IS 0 WHEN A HEADER OR CKSUM IS BEING ;SENT/RCD, AND 1 IF "VIEWABLE" DATA (THE ;SECTOR ITSELF) IS ; DATAFLG DB 0 ;AT HEADER, FIRST ; ; ;SUB-OPTION TABLE. IF AN OPTION IS IN EFFECT, ; THE CHARACTER IS SET TO BINARY 0 ; OPTBL EQU offset $ ANSWFLG DB 'A' ;ANSWER MODE DISCFLG DB 'D' ;DISCONNECT WHEN DONE ECHOFLG DB 'E' ;TO ECHO AFTER XFER ORIGFLG DB 'O' ;ORIGINATE MODE QFLG DB 'Q' ;QUIET TRANSFER (NO MSGS) RSEEFLG DB 'R' ;SEE WHAT'S RECEIVED SSEEFLG DB 'S' ;SEE WHAT'S SENT TERMFLG DB 'T' ;TO TERM AFTER XFER VSEEFLG DB 'V' ;VIEW MESSAGES (NO HDR, ETC) ; OPTBE EQU offset $ ;END OF OPTIONS tablesize equ optbe-optbl ; RCVSNO DB 0 ;SECT # RECEIVED SECTNO DB 0 ;CURRENT SECTOR NUMBER ERRCT DB 0 ;ERROR COUNT ;FOLLOWING 3 USED BY DISK BUFFERING ROUTINES EOFLG DB 0 ;EOF FLAG (1=TRUE) SECPTR DW DBUF SECINBF DB 0 ;# OF SECTORS IN BUFFER ; ;16 SECTOR DISK BUFFER (OVERLAYS HELP MSGS) ; DBUF EQU $ ;16 SECTOR DISK BUFFER ; ;INVALID COMMAND ; BADOPT: CALL tipe CALL ILPRT ;EXIT W/ERROR DB ': INVALID OPTION ON MODEM ' DB 'COMMAND - ',CR,LF DB 'PRESS RETURN FOR HELP, CTL-C IF NOT',CR,LF,1,0 ; HELP: CALL ILPRT DB 'Format for command is:',cr,lf,cr,lf DB 'MODEM # FILENAME',CR,LF,CR,LF DB 'Where # is a 1 character primary option,',cr,lf DB ' which may be followed by sub-options,',cr,lf DB ' and by ".xxx" to set baud rate to xxx' DB cr,lf,cr,lf,1 DB 'Primary Options:',cr,lf DB ' S to send a file',cr,lf DB ' R to receive a file',cr,lf DB ' T to act as a terminal',cr,lf DB ' E to act as a computer (echo data)',cr,lf DB ' D to disconnect the phone' DB ' (S100 modems only)',cr,lf DB ' H to print this help file' DB cr,lf,cr,lf,1 DB 'Secondary options:',cr,lf DB ' A answer mode',cr,lf DB ' O originate mode',cr,lf DB ' D disconnect after execution',cr,lf DB ' T go to terminal mode after file xfer',cr,lf DB ' E go to echo mode after file xfer',cr,lf DB ' Q quiet mode - no status msgs',cr,lf DB ' R show chars received',cr,lf DB ' S show chars sent',cr,lf DB ' V view file sent/received (no status)',cr,lf DB CR,LF,'FOR EXAMPLES, tipe: MODEM X',cr,lf,0 JMP EXIT ; EXAM: CALL ILPRT DB 'Send file, originate mode, 300 baud:',CR,LF DB ' MODEM SO fn.ft',cr,lf DB 'Send another file:',CR,LF DB ' MODEM S fn.ft',cr,lf DB 'Then send a third file at 450 baud and disconnect' DB CR,LF,' MODEM SD.450 fn.ft',cr,lf DB 'Act as a terminal at 110 baud',cr,lf DB ' MODEM T.110',CR,LF DB ' Use ctl-D to disconnect)',cr,lf DB 'Receive file, answ mode, view it, 600 baud:',cr,lf DB ' MODEM RAV.600 fn.ft',cr,lf,0 JMP: EXIT bdos: int 224 ret ; ; ; BDOS EQUATES (VERSION 2) ; RDCON EQU 1 WRCON EQU 2 PRINT EQU 9 CONST EQU 11 ;CONSOLE STAT OPEN EQU 15 ;0FFH=NOT FOUND CLOSE EQU 16 ; " " SRCHF EQU 17 ; " " SRCHN EQU 18 ; " " ERASE EQU 19 ;NO RET CODE READ EQU 20 ;0=OK, 1=EOF WRITE EQU 21 ;0=OK, 1=ERR, 2=?, 0FFH=NO DIR SPC MAKE EQU 22 ;0FFH=BAD REN EQU 23 ;0FFH=BAD STDMA EQU 26 ;SET DMA REIPL EQU 0 ; org 5ch FCB rb 34 FCBEXT EQU FCB+12 ;FILE EXTENT FCBSNO EQU FCB+32 ;SECTOR # FCB2 EQU fcb+10h