; TITLE 'CLINK - COMMUNICATIONS LINK FOR CP/M - V 3.0' ;;; CLINK - COMMUNICATIONS LINK - VERSION 3.0 ; ; LAWRENCE E. HUGHES OCTOBER, 1978 ; ; PATCHED 2/9/80 - CONFIG DISPLAY - DICK SMITH ; KILLED SMITH'S BUGS OF 2/9/80 -7/12/81 -DON EKSTEDT ; ; REVISION HISTORY ; ; 10/19 0.0 INITIAL VERSION - BASIC LINK FACILITY, ; CONFIGURATION FILE IMPLEMENTED. SITE, ; PHONE, BAUD, PARITY, DBITS, SBITS, MODE, ; DUPLEX, AUTOLF AND CAPS DIRECTIVES. ; ; 10/21 1.0 'LOCAL COMMANDS' IMPLEMENTED. ESCAPE, ; DEBUG, ERROR, LIST, RETURN AND ABORT ; DIRECTIVES ADDED. ; ; 10/22 2.0 ASR FILE TRANSMISSION IMPLEMENTED. ; GARBAGE, EXPAND, READ, CAPTURE, WRITE ; DIRECTIVES ADDED. ; ; 10/23 2.1 SAVE, BREAK, RESET, HELP DIRECTIVES. ; ; 10/29 2.2 ANSWER MODE CHECKED OUT, REMESC ADDED ; ; 10/30 2.3 BUGS FIXED, DIR COMMAND ADDED, HELP ; COMMAND EXPANDED. ; ; 11/04 2.4 VARIOUS BUGS FIXED ; ; 11/18 2.5 ANSWER MODE TIMEOUT ; ; 01/12 3.0 PROTOCOL FILE TRANSFERS. ; ; CLINK IS A CP/M TRANSIENT PROGRAM WHICH ALLOWS THE USER ; TO ESTABLISH A COMMUNICATIONS LINK TO A REMOTE DEVICE ; (TYPICALLY A REMOTE COMPUTER). ALL I/O IS DONE VIA THE ; BDOS OR BIOS ENTRY POINTS. THE ASSUMPTION IS MADE THAT ; THE BAUD RATE OF THE CONSOLE DEVICE IS MUCH GREATER (2X ; OR MORE) THAN THE SELECTED BAUD RATE OF THE MODEM. THIS ; IS ESPECIALLY IMPORTANT IF AUTO LINE-FEED IS SELECTED. ; ; CLINK EXPECTS AS INPUT A FILE WITH ONE OR MORE DIRECTIVES ; (ONE PER LINE) WHICH ALLOW THE USER TO 'PROGRAM' THE ; VARIOUS CONFIGURATION OPTIONS WHICH MIGHT VARY FROM DEVICE ; TO DEVICE. IF A GIVEN OPTION IS NOT SPECIFIED, THE DEFAULT ; VALUE WILL BE USED. THE SYNTAX OF THESE DIRECTIVES IS AS ; FOLLOWS: ; ; ; ; WHERE IS ONE OR MORE SPACES AND/OR TABS, Š; IS ONE OF THE WORDS IN THE FOLLOWING TABLE, AND IS ; ONE OF THE LEGAL VALUES SPECIFIED AFTER EACH KEYWORD. ; ; KEYWD POSSIBLE VALUE(S) DEFAULT ; ; SITE (UP TO 80 ALPHANUMERIC CHARS) NONE ; PHONE (UP TO 20 CHARACTERS) NONE ; BAUD 110,300 300 ; PARITY EVEN,ODD,NONE EVEN ; DBITS 7,8 7 ; SBITS 1,2 1 ; MODE ORIGINATE,ANSWER ORIGINATE ; DUPLEX FULL,HALF FULL ; AUTOLF ON,OFF OFF ; CAPS ON,OFF OFF ; ESCAPE (HEX VALUE, 00H=NONE) 1BH ; REMESC (HEX VALUE, 00H=NONE) 00H ; DEBUG ON,OFF OFF ; ERROR SUMMARY,(HEX VALUE, 00H=NONE) 00H ; GARBAGE (HEX VALUE, 00H=NONE) 00H ; EXPAND ON,OFF OFF ; BREAK (HEX VALUE, 00H=NONE) 00H ; ; 'SITE' IS USED ONLY BY THE LIST COMMAND, AND IS OPTIONAL. ; ; THE 'PHONE' NUMBER MAY CONTAIN DIGITS, PARENTHESIS, DASHES, ; BLANKS, AND/OR ASTERISKS. AN ASTERISK WILL CAUSE A ONE SECOND ; PAUSE DURING DIALING. IF NO NUMBER IS SPECIFIED, IT IS ASSUMED ; THAT A CONNECTION ALREADY EXISTS, AND THE DIALING CODE WILL BE ; SKIPPED. ; ; 'BAUD' SELECTS BAUD RATE, EITHER 110 OR 300 ; ; 'PARITY' MAY BE SPECIFIED AS ANY OF THE FOLLOWING: ; EVEN - PARITY BIT CHOSEN TO GIVE EVEN # OF 'ON' BITS ; ODD - PARITY BIT CHOSEN TO GIVE ODD # OF 'ON' BITS ; NONE - INHIBIT THE PARITY BIT ALTOGETHER ; ; 'DBITS' SELECTS THE NUMBER OF DATA BITS (7 OR 8) ; ; 'SBITS' SELECTS THE NUMBER OF STOP BITS (1 OR 2) ; ; NOTE THAT THE TOTAL NUMBER OF BITS IN EACH ASYNCHRONOUS CHAR- ; ACTER TO OR FROM THE MODEM WILL BE DBITS+SBITS+2 IF PARITY IS ; SELECTED, OTHERWISE DBITS+SBITS+1 (START BIT ALWAYS PRESENT). ; ; 'MODE' MAY BE USED TO SELECT CARRIER FREQUENCY. THIS SHOULD ; NORMALLY BE 'ORIGINATE', BUT MAY BE CHANGED TO 'ANSWER' TO ; ALLOW LINKING TO A REMOTE MODEM RUNNING IN 'ORIGINATE' MODE ; (SUCH AS ANOTHER CP/M USER RUNNING CLINK). ; ; 'DUPLEX' MAY BE SPECIFIED AS EITHER OF THE FOLLOWING: ; FULL - DO NOT ECHO CONSOLE CHARACTERS LOCALLY ; HALF - ECHO CONSOLE CHARACTERS LOCALLY ; Š; IF THE 'AUTOLF' IS SET TO 'ON', A LINE FEED CHARACTER ; WILL BE SENT TO THE CONSOLE FOLLOWING ANY CARRIAGE RETURN. ; ; THE 'CAPS' OPTION MAY BE USED TO TURN ON OR OFF THE AUTOMATIC ; TRANSLATION OF LOWER CASE LETTERS (TO UPPER CASE) IN BOTH ; DIRECTIONS (TO AND FROM MODEM). ; ; 'ESCAPE' ALLOWS THE USER TO SPECIFY WHICH (IF ANY) ASCII CODE ; WILL BE USED TO TRAP INTO THE 'LOCAL COMMAND' MODE. THE VALUE ; 00H MEANS ALL CODES WILL BE TRANSMITTED TRANSPARENTLY. ANYTIME ; THE SELECTED ESCAPE CODE IS TYPED (FROM THE CONSOLE), A LOCAL ; PROMPT ( -> ) WILL BE DISPLAYED, AFTER WHICH A COMMAND MAY BE ; ENTERED (ANY DIRECTIVE, PLUS 'ABORT' AND 'RETURN' FOR EXITING ; TO CP/M WITH AND WITHOUT DISCONNECT, RESPECTIVELY). WHEN A CR ; IS TYPED, THAT LOCAL COMMAND WILL BE EXECUTED AND CONTROL WILL ; BE RETURNED TO THE MAIN LINK. ; ; 'REMESC' ALLOWS THE USER TO SPECIFY WHICH (IF ANY) ASCII CODE ; WILL BE USED TO LET THE REMOTE USER TRAP INTO THE 'LOCAL ; COMMAND' MODE (FROM HIS REMOTE TERMINAL). OTHERWISE SAME AS ; THE 'ESCAPE' FUNCTION. NOTE THAT THIS FUNCTION IS CURRENLTY ; RESTRICTED TO ALLOWING AN ORIGINATE SYSTEM TO GENERATE A ; REMOTE COMMAND, AND AN ANSWER SYSTEM TO RESPOND TO IT. ; ; 'DEBUG' MAY BE USED TO SWITCH ON AND OFF THE OPTION OF HAVING ; ALL BYTES READ FROM THE MODEM BE DISPLAYED IN HEX, 16 PER LINE, ; FOR PURPOSES OF DEBUGGING PROTOCOLS, DETERMINING LINE CHARAC- ; TERISTICS, ETC. ; ; 'ERROR' MAY BE USED TO REQUEST A SUMMARY OF TRANSMISSION ; ERRORS (PARITY, OVERRUN AND FRAME) BY USING THE PARAMETER ; 'SUMMARY'. BY SPECIFIYING A HEX VALUE, THE CORRESPONDING ; ASCII CHARACTER WILL BE OUTPUT IN PLACE OF ANY CHARACTER ; RECEIVED IN ERROR. THE VALUE 00H IS SPECIAL CASED TO MEAN ; 'OUTPUT THE RECEIVED CHARACTER ANYWAY'. THE ERROR COUNTS ; WILL BE MAINTAINED REGARDLESS. ; ; 'GARBAGE' MAY BE USED TO SPECIFY THE NUMBER OF GARBAGE CHARS. ; TO IGNORE AFTER ANY LINE FEED IS SENT FROM THE HOST. THIS IS ; MOST USEFUL IN CONJUNCTION WITH THE 'SEND' COMMAND. NOTE THAT ; THE 'DEBUG' OPTION MAY BE USED TO DETERMINE WHAT CONSTANT TO ; USE IN THIS DIRECTIVE. ; ; 'LIST' MAY BE USED TO CAUSE THE CURRENT CONFIGURATION DETAILS ; TO BE LISTED TO THE CONSOLE. IT IS PRIMARILY USEFUL FROM WITHIN ; THE LINK (VIA ESCAPE CODE), BUT MAY BE USED IN A CONFIG. FILE. ; ; 'EXPAND' MAY BE USED TO SELECT OR DESELECT THE OPTION OF ; EXPANDING TABS TO BLANKS DURING A 'SEND' OPERATION. IT DOES ; NOT AFFECT TABS ANYWHERE ELSE. ; ; 'BREAK' MAY BE USED TO SPECIFY ANY ASCII CODE TO BE USED AS ; A TRIGGER TO BREAK THE COMMUNICATIONS LINE FOR 150 MS. MANY ; TIMESHARING SERVICES USE THIS CONDITION AS IF IT WERE A ; CHARACTER, SO PROVISIONS HAVE BEEN MADE TO GENERATE IT. Š; ; IT IS SUGGESTED THAT THE USER DETERMINE THE LINE CHARACTER- ; ISTICS FOR EACH POSSIBLE REMOTE SITE HE WILL BE DIALING INTO, ; AND CREATE A SEPARATE CONFIGURATION FILE FOR EACH. A TYPICAL ; FILE MIGHT BE AS FOLLOWS: ; ; SITE FSU CYBER 74, 300 BAUD ROTARY ; PHONE 1-904-644-6566 ; PARITY NONE ; DBITS 8 ; ESCAPE 18H (CTRL-X) ; ; ALL UNSPECIFIED OPTIONS WILL DEFAULT TO THE VALUES LISTED IN ; THE TABLE. IF THIS INFORMATION HAD BEEN WRITTEN TO THE FILE ; 'FSU74.CON', ONE COULD DIAL INTO THAT SITE WITH THE COMMAND: ; ; CLINK FSU74.CON ; ; IN ADDITION TO THE ABOVE DIRECTIVES, THE FOLLOWING DIRECTIVES ; MAY BE USED FROM WITHIN THE LINK, VIA THE ESCAPE CODE: ; ; RETURN RETURN TO CP/M WITHOUT DISCONNECT ; ABORT DISCONNECT AND RETURN TO CP/M ; READ D:FN.FT READ SPECIFIED FILE TO REMOTE HOST ; CAPTURE CAPTURE MODEM INPUT IN MEMORY BUFFER ; WRITE D:FN.FT WRITE MEMORY BUFFER TO DISK FILE ; SEND D:FN.FT SEND FILE USING PROTOCOL ; RECV D:FN.FT RECEIVE FILE USING PROTOCOL ; BLOCK N SET BLOCK SIZE TO N PAGES (SEND) ; LIST LIST CURRENT CONFIG. TO CONSOLE ; SAVE D:FN.FT WRITE CURRENT CONFIG. TO DISK FILE ; RESET RESET ERROR COUNTS ; DIR AFN SAME AS CP/M DIR COMMAND ; HELP REQUEST LIST OF ALL LOCAL COMMANDS ; ; 'READ' MAY BE USED TO SEND A FILE TO THE REMOTE DEVICE AS ; IF IT WERE COMING FROM THE CONSOLE KEYBOARD. IF RUNNING IN ; HALF DUPLEX, THE BYTES WILL JUST BE WRITTEN AS FAST AS THE ; MODEM WILL ACCEPT THEM. IF RUNNING IN FUL DUPLEX, THE BYTES ; ECHOED BY THE REMOTE DEVICE WILL BE COMPARED AGAINST THE ; BYTES SENT, AND AN ERROR COUNT MAINTAINED. WHEN EOF IS READ ; ON THE SPECIFIED FILE, AN ERROR SUMMARY WILL BE PRINTED (IN ; FULL DUPLEX ONLY) A BELL WILL BE WRITTEN TO THE CONSOLE, AND ; CONTROL WILL BE RETURNED TO THE MAIN LOOP. ; ; 'CAPTURE' MAY BE USED TO RESET THE MEMORY BUFFER POINTER AND ; SET A FLAG SO THAT ALL BYTES INPUT FROM THE MODEM WILL ALSO ; BE STORED SEQUENTIALLY IN MEMORY. ; ; 'WRITE' MAY BE USED TO WRITE 'CAPTURED' DATA TO A DISK FILE. ; NOTE THAT THIS ALSO CLEARS THE 'CAPTURE' FLAG. ; ; 'SEND' MAY BE USED TO TRANSMIT ANY CP/M FILE, INCLUDING .COM ; FILES (IF DATA PATH IS 8 BITS WIDE), USING AN ASYNCHRONOUS ; PROTOCOL WHICH HAS FAIRLY ELABORATE ERROR DETECTION AND AUTO Š; RECOVERY (VIA RE-TRANSMISSION). AT PRESENT THIS WILL WORK ; ONLY WITH ANOTHER CLINK 3.0 SYSTEM WHICH IS EXECUTING A RECV. ; ; 'RECV' MAY BE USED TO RECEIVE A FILE (DIRECTLY TO DISK) WHICH ; IS BEING TRANSMITTED BY A CLINK 3.0 SYSTEM DOING A SEND. ; ; 'BLOCK' MAY BE USED TO SET THE BLOCK (MESSAGE) SIZE IN 'SEND', ; IN TERMS OF 256 BYTE PAGES. DEFAULT VALUE IS 4 (1024 BYTES). ; ; 'LIST' MAY BE USED TO VIEW THE CURRENT CONFIGURATION DETAILS. ; ; 'SAVE' MAY BE USED TO WRITE THE CURRENT CONFIGURATION DETAILS ; TO THE SPECIFIED DISK FILE, WHICH MAY LATER BE USED AS A ; CONFIGURATION INPUT FILE. ; ; 'DIR' MAY BE USED TO DETERMINE WHICH FILES ARE CURRENTLY ; ON ANY MOUNTED DISKETTE. THE RULES FOR THE PARAMETER ARE ; THE SAME AS IN THE STANDARD CP/M DIR COMMAND. ; ; 'HELP' MAY BE USED AT ANY TIME TO REVIEW AVAILABLE COMMANDS ; SYMBOL DEFINITIONS ENTRY EQU 0005H ;BDOS ENTRY POINT RSFC EQU 10 ;READ STRING OFFC EQU 15 ;OPEN FILE CFFC EQU 16 ;CLOSE FILE SFFC EQU 17 ;SEACH FIRST SNFC EQU 18 ;SEARCH NEXT DFFC EQU 19 ;DELETE FILE RRFC EQU 20 ;READ RECORD WRFC EQU 21 ;WRITE RECORD MFFC EQU 22 ;MAKE FILE SAFC EQU 26 ;SET ADDRESS TFCB EQU 005CH ;DEFAULT FILE CONTROL BLOCK FN EQU 01 ;FILE NAME OFFSET FT EQU 09 ;FILE TYPE OFFSET EX EQU 12 ;EXTENT OFFSET NR EQU 32 ;NEXT RECORD OFFSET MDATA EQU 80H ;MODEM DATA PORT MSTAT EQU 81H ;MODEM STATUS PORT MCTRL EQU 82H ;MODEM CONTROL PORT ; MODEM STATUS INPUT PORT DEFINITIONS RI EQU 80H ;RING INDICATE CD EQU 40H ;CARRIER DETECT OE EQU 10H ;OVERRUN ERROR FE EQU 08H ;FRAMING ERROR PE EQU 04H ;PARITY ERROR ŠTRE EQU 02H ;TRANSMIT REG. EMPTY RRF EQU 01H ;RECEIVER REG. FULL ; MODEM STATUS OUTPUT PORT DEFINITIONS PI EQU 10H ;PARITY INHIBIT SBS EQU 08H ;STOP BIT SELECT LS2 EQU 04H ;LENGTH SELECT 2 LS1 EQU 02H ;LENGTH SELECT 1 EPE EQU 01H ;EVEN PARITY ENABLE ; MODEM CONTROL OUTPUT PORT DEFINITIONS OH EQU 80H ;OFF HOOK RID EQU 20H ;RING INDICATE DISABLE ST EQU 10H ;SELF TEST BK EQU 08H ;BREAK MS EQU 04H ;MODE SELECT (1 = ORIGINATE) TXE EQU 02H ;TRANSMIT ENABLE BRS EQU 01H ;BIT RATE SELECT ; ASCII CHARACTERS NULL EQU 00H ;NULL CHARACTER SOH EQU 01H ;START OF HEADER STX EQU 02H ;START OF TEXT ETX EQU 03H ;END OF TEXT EOT EQU 04H ;END OF TRANSMISSION ENQ EQU 05H ;ENQUIRE ACK EQU 06H ;ACKNOWLEDGE BEL EQU 07H ;BELL BS EQU 08H ;BACKSPACE TAB EQU 09H ;HORIZONTAL TAB LF EQU 0AH ;LINE FEED CR EQU 0DH ;CARRIAGE RETURN DLE EQU 10H ;DATA LINK ESCAPE NAK EQU 15H ;NEGATIVE ACKNOWLEDGE SYN EQU 16H ;SYNCH ETB EQU 17H ;END OF TEXT BLOCK CAN EQU 18H ;CANCEL ESC EQU 19H ;ESCAPE CRCPOL EQU 8005H ;CRC-16 POLYNOMIAL ORG 100H CLINK: LXI H,0 ;SAVE ENTRY STACK POINTER DAD SP SHLD OLDSP LXI SP,STACK+128 ;SETUP LOCAL STACK LHLD ENTRY+1 ;HL = FWA OF BDOS MOV A,L ;ROUND DOWN TO NEAREST MULT. OF 128 ANI 80H MOV L,A SHLD MAXADR ;SAVE AS MAX. ADDRESS LXI D,-1024 ;SUBTRACT 1024 Š DAD D SHLD CCPADR ;SAVE AS CCP ADDRESS XRA A ;CLEAR CCP OVERWRITE FLAG STA CCPF CALL CJV ;CREATE BIOS JUMP VECTOR XRA A ;CLEAR CONTROL PORT BYTES STA CR1 STA CR2 MVI A,IBUFL ;INITIALIZE IBUF STA IBUF+0 XRA A ;DEFAULT TO NO SITE, NO PHONE STA SITEL STA PHONEL MVI B,LS2+EPE ;EVEN PARITY, 7 DATA BITS, 1 STOP BIT CALL CR1ON MVI B,MS+BRS ;ORIGINATE, 300 BAUD IN MSTAT ;IF INCOMING CARRIER IS ON... ANI CD JZ $+5 MVI B,OH+MS+BRS+TXE ;...THEN LEAVE OUR CARRIER ON CALL CR2ON MVI A,'O' STA MODE XRA A STA COF ;DIRECT CONSOLE OUTPUT TO CONSOLE STA ECHO ;DEFAULT TO FULL DUPLEX STA AUTOLF ;DEFAULT TO NO AUTO LINE FEED STA CAPS ;DEFAULT TO UPPER/LOWER CASE STA DEBUG ;DEFAULT TO DEBUG OFF STA ERROR ;DEFAULT TO NO ERROR CODE STA GARBAGE ;DEFAULT TO NO GARBAGE CHARS. STA EXPAND ;DEFAULT TO NO TAB EXPANSION STA CAPTURE ;CLEAR CAPTURE FLAG STA BREAK ;DEFAULT TO NO 'BREAK' TRIGGER MVI A,11H ;DEFAULT TO CNTL Q REMESC STA REMESC MVI A,1BH ;DEFAULT TO ESCAPE CODE OF ESC STA ESCAPE MVI A,4 ;DEFAULT TO 4 PAGE MESSAGES STA BLKSZ LXI H,0 ;CLEAR ERROR COUNTS SHLD PERR SHLD OERR SHLD FERR LXI H,0FFFFH ;SETUP FOR INFINITE TIMEOUT SHLD TIME LXI H,MBUF ;CLEAR MEMORY BUFFER SHLD MBUFP LXI H,MSG0 ;PRINT 'CLINK VX.X' CALL WASC LDA TFCB+FN ;JUMP IF NO FILE NAME CPI ' ' JZ CLINKH LXI D,TFCB ;OPEN USER'S CONFIG. FILE CALL OPEN Š CPI 255 ;JUMP IF OK JNZ CLINK0 LXI H,MSG1 ;PRINT 'FILE NOT FOUND' CALL WASC JMP CLINKX ;EXIT CLINK0: XRA A ;'REWIND' FILE STA TFCB+NR STA DIBUFC ;RESET DISK INPUT BUFFER CALL WEOLC CLINK1: CALL RASS ;READ LINE FROM FILE JC CLINK2 ;JUMP ON END OF FILE CALL EASC ;ECHO ASCII STRING TO CONSOLE CALL PCD ;PROCESS CONFIGURATION DIRECTIVE JC DIRERR CNC MCD ;IF OK SEE IF MORE CD'S. CALL PCD ;YES SO PROCESS JNC CLINK1 ;LOOP IF OK DIRERR: LXI H,MSG2 ;PRINT 'DIRECTIVE ERROR' CALL WASC JMP CLINKX ;EXIT ; MCD: CALL GNC ;GET THE NEXT CHAR. JC CLINK1 ;CARRY SET SO NO MORE CHARS. CPI ' ' ;SPACE ? JNZ MCD ;NO SO LOOP MCD1: CALL SNB ;YES SO GET RID OF SPACES JC CLINK1 ;OUT OF CHARS LHLD IBUFP ;NOW WE GOT A CHAR. DCX H ;SO MOVE POINTER BACK SHLD IBUFP ;AND STORE IT LDA IBUFC ;GET THE COUNTER INR A ;BACK IT UP TOO STA IBUFC ;AND STORE IT RET ;RETURN SO WE CAN PCD AGAIN CLINK2: LXI D,TFCB ;CLOSE CONFIG. FILE CALL CLOSE CALL WEOLC CLINKH: LXI H,MSG14 ;PRINT 'ENTER DIRECTIVES' CALL WASC CLINKF: LXI H,MSG10 ;PRINT PROMPT CALL WASC CALL RASC CALL WEOLC LDA IBUFC ORA A JZ CLINKG CALL PCD JNC CLINKF MODERR: LXI H,MSG2 ;PRINT 'DIRECTIVE ERROR' CALL WASC JMP CLINKF CLINKG: LDA MODE ;JUMP IF ORIGINATE MODE Š CPI 'O' JZ CLINKB CLINK9: IN MSTAT ;WATCH FOR RING INDICATE ANI RI JZ CLINKM ;JUMP IF ACTIVE CALL CCA ;CHECK FOR ESCAPE FROM CONSOLE JNC CLINK9 MOV B,A LDA ESCAPE CMP B JZ CLINKH ;JUMP IF PRESENT JMP CLINK9 CLINKM: MVI B,OH+TXE ;GO OFF-HOOK AND BRING UP CARRIER CALL CR2ON LXI B,600 CLINKA: IN MSTAT ;CHECK FOR INCOMING CARRIER ANI CD JNZ CLINCA ;CARRIER DETECTED CALL WAIT50 DCX B MOV A,B ORA C JNZ CLINKA LXI H,MSG3 ;NO CARRIER DETECTED CALL WASC JMP EXIT CLINCA MVI A,1 ;DIRECT CONSOLE OUTPUT TO MODEM STA COF LXI H,MSG0 ;PRINT 'CLINK VX.X' CALL WASC CALL WEOLC LXI H,KWTAB+0*10 ;PRINT 'SITE ' CALL W8CC LXI H,SITE ;PRINT SITE NAME LDA SITEL MOV B,A INR B XXX1: DCR B JZ XXX2 MOV A,M INX H CALL WACC JMP XXX1 XXX2: CALL WEOLC LXI H,KWTAB+25*10 ;PRINT 'REMESC ' CALL W8CC LDA REMESC ;PRINT REMOTE ESCAPE CODE CALL WHBC MVI A,'H' CALL WACC CALL WEOLC CALL WEOLC XRA A ;REDIRECT CONSOLE OUTPUT TO CONSOLE STA COF JMP CLINK5 ;JUMP INTO MAIN LOOP ŠCLINKB: IN MSTAT ;CHECK FOR CARRIER ANI CD JZ CLINK8 ;JUMP IF NOT PRESENT LXI H,MSG9 ;PRINT 'CARRIER PRESENT, LINK RESUMED' CALL WASC JMP CLINK5 CLINK8: MVI B,OH ;GO OFF HOOK CALL CR2ON MVI B,40 ;DELAY FOR 2 SECONDS CALL WAIT50 DCR B JNZ $-4 CALL DIAL ;DIAL NUMBER, IF PRESENT LXI B,600 ;SETUP FOR 30 SECOND TIMEOUT CLINK3: IN MSTAT ;READ MODEM STATUS PORT ANI CD ;BRANCH ON CARRIER DETECT JNZ CLINK4 CALL WAIT50 ;PAUSE FOR 50 MS DCX B ;DECREMENT TIMEOUT COUNT MOV A,B ;LOOP UNTIL ZERO ORA C JNZ CLINK3 LXI H,MSG3 ;PRINT 'NO CARRIER DETECTED' CALL WASC MVI B,OH+TXE ;DISCONNECT CALL CR2OFF JMP CLINKX ;EXIT CLINK4: MVI B,TXE ;TURN ON OUTGOING CARRIER CALL CR2ON MVI A,BEL ;RING BELL ON CONSOLE CALL WACC CALL WEOLC ;WRITE END OF LINE TO CONSOLE CLINK5: CALL CCA ;CHECK FOR CONSOLE ACTIVITY JNC CLINK6 ;JUMP IF NONE STA CCHAR LDA BREAK ;IF 'BREAK' TRIGGER, SEND BREAK ORA A JZ CLINKE LXI H,CCHAR CMP M JNZ CLINKE CALL SBRK JMP CLINK6 CLINKE: LDA ESCAPE ;JUMP IF NO ESCAPE CODE ORA A JZ CLINKC LXI H,CCHAR CMP M JNZ CLINKC LXI H,MSG10 ;PRINT LOCAL PROMPT CALL WASC CALL RASC ;READ STRING FROM CONSOLE CALL WEOLC CALL PCD ;PROCESS DIRECTIVE JNC CLINK6 ;JUMP IF OK Š LXI H,MSG2 ;PRINT 'DIRECTIVE ERROR' CALL WASC JMP CLINK6 ;CONTINUE CLINKC: LDA CAPS ;CONVERT LOWER CASE IF CAPS LOCK ON ORA A LDA CCHAR CNZ CLC OUT MDATA ;WRITE CHAR TO MODEM LDA ECHO ;JUMP IF FULL DUPLEX ORA A JZ CLINKI LDA CCHAR ;ECHO CHARACTER TO CONSOLE CALL WACC CLINKI: LDA MODE ;JUMP IF ORIGINATE MODE CPI 'O' JZ CLINK6 LDA CCHAR CPI CR ;JUMP IF CHAR. NOT CR JNZ CLINK6 MVI A,LF ;SEND A LINE FEED CALL WACM CALL WACC CLINK6: IN MSTAT ;CHECK FOR MODEM RDA ANI RRF JZ CLINK7 ;JUMP IF NONE IN MDATA ;READ CHARACTER STA MCHAR LDA MODE ;JUMP IF WE'RE NOT IN ANSWER MODE CPI 'A' JNZ CLINKL LDA REMESC ORA A JZ CLINKL LXI H,MCHAR CMP M JNZ CLINKL MVI A,1 ;REDIRECT CONSOLE OUTPUT TO MODEM STA COF LXI H,MSG10 ;PRINT LOCAL PROMPT CALL WASC CALL RASM ;READ RESPONSE INTO IBUF CALL WEOLC CALL PCD ;PROCESS DIRECTIVE JNC CLINKK ;JUMP IF OK LXI H,MSG2 ;PRINT 'DIRECTIVE ERROR' CALL WASC CLINKK: MVI A,0 ;REDIRECT CONSOLE OUTPUT TO CONSOLE STA COF JMP CLINK5 ;DO NOT ECHO REMESC CHAR CLINKL: LDA MCHAR ;RESTORE MODEM CHAR CALL CAPT ;CAPTURE DATA IF FLAG SET CALL ERRCK ;CHECK FOR ERRORS LDA MODE ;JUMP IF ORIGINATE MODE CPI 'O' JZ CLINKJ Š LDA MCHAR CALL WACM ;ECHO CHARACTER TO REMOTE USER ANI 7FH CPI CR ;JUMP IF NOT CARRIAGE RETURN JNZ CLINKJ MVI A,LF ;WRITE LINE FEED TO REMOTE USER CALL WACM CALL WACC ;ECHO TO LOCAL TERMINAL TOO CALL CAPT ;CAPTURE GENERATED LINE FEED CLINKJ: LDA DEBUG ;JUMP IF DEBUG NOT ON ORA A JZ CLINKD LDA MCHAR CALL WHBC ;WRITE BYTE TO CONSOLE IN HEX MVI A,' ' ;PRINT ONE SPACE CALL WACC LDA DEBUGC ;INCREMENT DEBUG COUNT INR A STA DEBUGC CPI 16 ;CONTINUE IF DEBUGC < 16 JC CLINK7 XRA A ;RESET DEBUGC STA DEBUGC CALL WEOLC ;WRITE END OF LINE TO CONSOLE JMP CLINK7 ;CONTINUE CLINKD: LDA CAPS ;CONVERT LOWER CASE IF CAPS LOCK ON ORA A LDA MCHAR CNZ CLC CALL WACC ;WRITE TO CONSOLE ANI 7FH ;JUMP IF NOT CARRAIGE RETURN CPI CR JNZ CLINK7 LDA AUTOLF ;JUMP IF AUTOLF NOT SET ORA A JZ CLINK7 MVI A,LF ;WRITE LINEFEED TO CONSOLE CALL WACC CLINK7: IN MSTAT ;CHECK INCOMING CARRIER ANI CD JNZ CLINK5 ;LOOP IF STILL PRESENT CALL WEOLC LXI H,MSG4 ;PRINT 'CARRIER LOST' CALL WASC EXIT: MVI B,OH+TXE ;... ELSE DISCONNECT CALL CR2OFF LDA MODE ;IF MODE = ANSWER, CPI 'A' JZ CLINK9 ;... THEN GO BACK TO IDLE STATE CLINKX: LDA CCPF ;IF CCP OVERWRITE FLAG SET... ORA A JNZ 0000H ;... THEN RELOAD CP/M LHLD OLDSP ;ELSE JUST JUMP BACK INTO CCP SPHL RET ;RETURN TO CP/M Š ;; DIAL - DIAL SPECIFIED PHONE NUMBER ; ; ENTRY CONDITIONS ; ; PHONEL LENGTH OF PHONE NUMBER STRING ; ; PHONE PHONE NUMBER STRING DIAL: LDA PHONEL ;RETURN IF STRING EMPTY ORA A RZ LXI H,MSG5 ;PRINT 'NOW DIALING ' CALL WASC LXI H,PHONE ;POINT TO PHONE NUMBER STRING LDA PHONEL MOV C,A DIAL1: MOV A,M ;FETCH NEXT CHARACTER OF NUMBER INX H CALL WACC ;WRITE DIGIT TO CONSOLE CPI '*' ;JUMP IF NOT ASTERISK JNZ DIAL2 MVI B,20 ;PAUSE FOR 1 SECOND CALL WAIT50 DCR B JNZ $-4 DIAL2: SUI '0' ;CONVERT, IGNORE NON-NUMERICS JC DIAL4 CPI 10 JNC DIAL4 ORA A ;JUMP IF NON-ZERO DIGIT JNZ DIAL3 MVI A,10 ;'0' REQUIRES 10 CLICKS DIAL3: MVI B,OH ;GO BACK ON-HOOK CALL CR2OFF CALL WAIT50 ;PAUSE 50 MS MVI B,OH ;GO OFF-HOOK AGAIN CALL CR2ON CALL WAIT50 ;PAUSE 50 MS DCR A ;DECREMENT CLICK COUNT JNZ DIAL3 ;LOOP UNTIL ZERO MVI B,10 ;PAUSE FOR 500 MS CALL WAIT50 DCR B JNZ $-4 DIAL4: DCR C ;DECREMENT DIGIT COUNT JNZ DIAL1 ;LOOP UNTIL ZERO CALL WEOLC ;WRITE END OF LINE TO CONSOLE RET ;EXIT ;; CAPT - CAPTURE DATA IF FLAG SET ; CAPT: ORA A ;DO NOT CAPTURE NULLS RZ Š PUSH H PUSH PSW LDA CAPTURE ;EXIT IF FLAG NOT SET ORA A JZ CAPT1 POP PSW PUSH PSW LHLD MBUFP ;HL = MEMORY BUFFER POINTER MOV M,A ;SAVE BYTE IN MEMORY BUFFER INX H ;INCREMENT POINTER SHLD MBUFP CMA OUT 0FFH CMA LDA CCPADR+1 ;JUMP IF MBUFP < CCPADR CMP H JNC CAPT1 LDA CCPADR CMP L JNC CAPT1 MVI A,1 ;SET 'CCP OVERWRITE' FLAG STA CCPF LDA MAXADR+1 ;RETURN IF MBUFP < MAXADR CMP H JNC CAPT1 LDA MAXADR CMP L JNC CAPT1 LXI H,MSG19 ;PRINT 'MEMORY OVERFLOW' CALL WASC XRA A ;TURN OFF CAPTURE FLAG STA CAPTURE CAPT1: POP PSW POP H RET ;; ERRCK - ERROR CHECK ; ERRCK: PUSH H PUSH PSW IN MSTAT ;CHECK FOR PARITY ERROR ANI PE JZ ERRCK1 ;JUMP IF NOT PRESENT LHLD PERR ;INCREMENT PARITY ERROR COUNT INX H SHLD PERR JMP ERRCK4 ERRCK1: IN MSTAT ;JUMP IF NO OVERRUN ERROR ANI OE JZ ERRCK2 LHLD OERR ;INCREMENT OVERRUN ERROR COUNT INX H SHLD OERR JMP ERRCK4 ŠERRCK2: IN MSTAT ;JUMP IF NO FRAME ERROR ANI FE JZ ERRCK5 LHLD FERR ;INCREMENT FRAME ERROR COUNT INX H SHLD FERR ERRCK4: LDA ERROR ;CHECK ERROR CODE ORA A JZ ERRCK5 ;JUMP IF 00H POP H ;DISCARD TOP OF STACK (PSW/A) POP H ;RESTORE REAL HL RET ERRCK5: POP PSW ;RESTORE CHARACTER POP H ;RESTORE HL RET ;; SBRK - SEND BREAK ; SBRK: PUSH B MVI B,BK ;OPEN LINE CALL CR2ON MVI B,3 ;WAIT 150 MS SBRK1: CALL WAIT50 DCR B JNZ SBRK1 MVI B,BK ;CLOSE LINE CALL CR2OFF POP B RET ;; PCD - PROCESS CONFIGURATION DIRECTIVE ; ; ENTRY CONDITIONS ; ; IBUFC NUMBER OF BYTES IN INPUT BUFFER ; ; IBUFP POINTER TO NEXT BYTE IN INPUT BUFFER ; ; EXIT CONDITIONS ; ; C-FLAG SET IF ERROR PCD: LHLD IBUFP ;CONVERT IBUF TO ALL UPPER CASE LDA IBUFC MOV B,A PCD0: MOV A,M CALL CLC MOV M,A INX H DCR B JNZ PCD0 LXI H,KWBUF ;BLANK FILL KEYWORD BUFFER MVI B,8 PCD1: MVI M,' ' Š INX H DCR B JNZ PCD1 LXI H,KWBUF MVI B,8 PCD2: CALL GNC ;GET NEXT CHAR FROM IBUF JC PCD3 ;BRANCH ON END OF LINE CPI ' ' ;BRANCH ON BLANK JZ PCD3 CPI TAB ;BRANCH ON TAB JZ PCD3 MOV M,A ;STORE BYTE IN KWBUF INX H DCR B ;DECREMENT COUNT JP PCD2 ;LOOP IF STILL ROOM JMP PCDX1 ;FLAG ERROR AND EXIT PCD3: LXI H,KWTAB ;POINT TO KEYWORD TABLE PCD4: LXI D,KWBUF ;POINT TO KEYWORD MVI B,8 ;NUMBER OF BYTES TO COMPARE MVI C,0 ;START WITH NO DISCREPANCY PCD5: LDAX D ;FETCH NEXT BYTE OF KWBUF XRA M ;LOG. DIFF. WITH BYTE FROM TABLE ORA C ;ACCUMULATE DISCREPANCY MOV C,A INX D ;INCREMENT POINTERS INX H DCR B ;DECREMENT COUNT JNZ PCD5 ;LOOP UNTIL ZERO INR C ;JUMP IF NO DISCREPANCY DCR C JZ PCD6 INX H ;SKIP ADDRESS FIELD INX H MOV A,M ;LOOP IF NOT END OF TABLE ORA A JNZ PCD4 JMP PCDX1 ;FLAG ERROR AND EXIT PCD6: MOV E,M ;FETCH ADDRESS INTO DE INX H MOV D,M XCHG ;SWAP ADDRESS INTO HL PCHL ;AND AWAY WE GO! PCDX1: STC ;ERROR EXIT RET PCDX2: STC ;NORMAL EXIT CMC RET KWTAB: DB 'SITE ' DW PCDA DB 'PHONE ' DW PCDB DB 'PARITY ' DW PCDC DB 'DBITS ' Š DW PCDD DB 'SBITS ' DW PCDE DB 'MODE ' DW PCDF DB 'DUPLEX ' DW PCDG DB 'AUTOLF ' DW PCDH DB 'BAUD ' DW PCDI DB 'CAPS ' DW PCDJ DB 'ESCAPE ' DW PCDK DB 'ABORT ' DW PCDL DB 'RETURN ' DW PCDM DB 'DEBUG ' DW PCDN DB 'ERROR ' DW PCDO DB 'READ ' DW PCDP DB 'GARBAGE ' DW PCDQ DB 'LIST ' DW PCDR DB 'EXPAND ' DW PCDS DB 'CAPTURE ' DW PCDT DB 'WRITE ' DW PCDU DB 'BREAK ' DW PCDV DB 'SAVE ' DW PCDW DB 'RESET ' DW PCDX DB 'HELP ' DW PCDY DB 'REMESC ' DW PCDZ DB 'DIR ' DW PCEA DB 'SEND ' DW PCEB DB 'RECV ' DW PCEC DB 'BLOCK ' DW PCED DB 0 Š; PCDA - PROCESS 'SITE' DIRECTIVE PCDA: XRA A STA SITEL CALL SNB ;SCAN TO PARAMETER JC PCDX2 ;EXIT IF NO PARAMETER LXI H,SITE ;POINT TO 'SITE' BUFFER MVI B,60 ;MAX LENGTH PCDA1: MOV M,A ;STORE CHAR IN 'SITE' BUFFER INX H LDA SITEL ;INCREMENT 'SITE' LENGTH INR A STA SITEL CALL GNC ;GET NEXT CHARACTER JC PCDX2 ;BRANCH ON END OF LINE DCR B ;DECREMENT COUNT JP PCDA1 ;LOOP IF STILL ROOM JMP PCDX1 ; PCDB - PROCESS 'PHONE' DIRECTIVE PCDB: XRA A STA PHONEL CALL SNB ;SCAN TO PARAMETER JC PCDX2 ;EXIT IF NO PARAMETER LXI H,PHONE ;POINT TO 'PHONE' BUFFER MVI B,20 ;MAX SIZE PCDB1: MOV M,A ;STORE CHAR IN 'PHONE' BUFFER INX H LDA PHONEL ;INCREMENT 'PHONE' LENGTH INR A STA PHONEL CALL GNC ;GET NEXT CHAR JC PCDX2 ;BRANCH ON END OF LINE DCR B ;DECREMENT COUNT JP PCDB1 ;LOOP IF STILL ROOM JMP PCDX1 ; PCDC - PROCESS 'PARITY' DIRECTIVE PCDC: CALL SNB ;SKIP TO PARAMETER RC CPI 'E' ;JUMP IF NOT 'EVEN' JNZ PCDC1 MVI B,EPE ;ENABLE EVEN PARITY CALL CR1ON MVI B,PI CALL CR1OFF JMP PCDX2 ;EXIT PCDC1: CPI 'O' ;JUMP IF NOT 'ODD' JNZ PCDC2 MVI B,EPE+PI ;ENABLE ODD PARITY CALL CR1OFF JMP PCDX2 PCDC2: CPI 'N' ;JUMP IF NOT 'NONE' Š JNZ PCDX1 MVI B,PI ;INHIBIT PARITY CALL CR1ON JMP PCDX2 ; PCDD - PROCESS 'DBITS' DIRECTIVE PCDD: CALL SNB ;SCAN TO PARAMETER RC CPI '7' ;JUMP IF NOT '7' JNZ PCDD1 MVI B,LS2 ;SELECT 7 DATA BITS CALL CR1ON MVI B,LS1 CALL CR1OFF JMP PCDX2 PCDD1: CPI '8' ;JUMP IF NOT '8' JNZ PCDX1 MVI B,LS2+LS1 ;SELECT 8 DATA BITS CALL CR1ON JMP PCDX2 ; PCDE - PROCESS 'SBITS' DIRECTIVE PCDE: CALL SNB ;SCAN TO PARAMETER RC CPI '1' ;JUMP IF NOT '1' JNZ PCDE1 MVI B,SBS ;SELECT 1 STOP BIT CALL CR1OFF JMP PCDX2 PCDE1: CPI '2' ;JUMP IF NOT '2' JNZ PCDX1 MVI B,SBS ;SELECT 2 STOP BITS CALL CR1ON JMP PCDX2 ; PCDF - PROCESS 'MODE' DIRECTIVE PCDF: CALL SNB ;SCAN TO PARAMETER RC CALL CLC STA MODE CPI 'O' ;JUMP IF NOT 'ORIGINATE' JNZ PCDF1 MVI B,MS ;SELECT ORIGINATE MODE CALL CR2ON JMP PCDX2 PCDF1: CPI 'A' ;JUMP IF NOT 'ANSWER' JNZ MODERR MVI B,MS ;SELECT ANSWER MODE CALL CR2OFF MVI A,1 ;FORCE HALF DUPLEX STA ECHO JMP PCDX2 Š ; PCDG - PROCESS 'DUPLEX' DIRECTIVE PCDG: CALL SNB ;SCAN TO PARAMETER RC CPI 'F' ;JUMP IF NOT 'FULL' JNZ PCDG1 XRA A ;CLEAR ECHO FLAG STA ECHO JMP PCDX2 PCDG1: CPI 'H' ;JUMP IF NOT 'HALF' JNZ PCDX1 MVI A,1 ;SET ECHO FLAG STA ECHO JMP PCDX2 ; PCDH - PROCESS 'AUTOLF' DIRECTIVE PCDH: CALL SNB ;SCAN TO PARAMETER RC CPI 'O' ;ERROR IF 1ST CHAR NOT 'O' JNZ PCDX1 CALL GNC ;GET 2ND CHAR RC CPI 'N' ;JUMP IF NOT 'ON' JNZ PCDH1 MVI A,1 ;SET AUTOLF FLAG STA AUTOLF JMP PCDX2 PCDH1: CPI 'F' ;JUMP IF NOT 'OFF' JNZ PCDX1 XRA A ;CLEAR AUTOLF FLAG STA AUTOLF JMP PCDX2 ; PCDI - PROCESS 'BAUD' DIRECTIVE PCDI: CALL SNB ;SCAN TO PARAMETER RC CPI '1' ;JUMP IF NOT '110' JNZ PCDI1 MVI B,BRS ;SELECT 110 BAUD CALL CR2OFF JMP PCDX2 PCDI1: CPI '3' ;JUMP IF NOT '300' JNZ PCDX1 MVI B,BRS ;SELECT 300 BAUD CALL CR2ON JMP PCDX2 ; PCDJ - PROCESS 'CAPS' DIRECTIVE PCDJ: CALL SNB ;SCAN TO PARAMETER RC CPI 'O' ;ERROR IF 1ST CHAR NOT 'O' Š JNZ PCDX1 CALL GNC ;GET 2ND CHAR RC CPI 'N' ;JUMP IF NOT 'ON' JNZ PCDJ1 MVI A,1 ;TURN ON CAPS LOCK STA CAPS JMP PCDX2 PCDJ1: CPI 'F' ;JUMP IF NOT 'OFF' JNZ PCDX1 XRA A ;TURN OFF CAPS LOCK STA CAPS JMP PCDX2 ; PCDK - PROCESS 'ESCAPE' PARAMETER PCDK: CALL SNB ;SCAN TO PARAMETER RC CALL DHD ;DECODE FIRST HEX DIGIT RC ADD A ;LEFT SHIFT 4 (X 16) ADD A ADD A ADD A MOV B,A ;SAVE IT CALL GNC ;DECODE SECIND HEX DIGIT RC CALL DHD RC ADD B ;ADD TO SHIFTED 1ST DIGIT STA ESCAPE ;SAVE IT AS NEW ESCAPE CODE JMP PCDX2 ;NORMAL EXIT ; PCDL - PROCESS 'ABORT' DIRECTIVE PCDL: LXI H,MSG7 ;PRINT 'LINK TERMINATED' CALL WASC JMP EXIT ; PCDM - PROCESS 'RETURN' DIRECTIVE PCDM: LXI H,MSG8 ;PRINT 'LINK INTERUPPTED' CALL WASC JMP CLINKX ; PCDN - PROCESS 'DEBUG' DIRECTIVE PCDN: CALL SNB ;SCAN TO PARAMETER RC CPI 'O' ;ERROR IF FIRST CHAR NOT 'O' JNZ PCDX1 CALL GNC ;GET NEXT CHAR RC CPI 'N' ;JUMP IF NOT 'ON' JNZ PCDN1 Š MVI A,1 ;TURN ON DEBUG MODE STA DEBUG XRA A ;CLEAR DEBUG COUNT STA DEBUGC JMP PCDX2 PCDN1: CPI 'F' ;JUMP IF NOT 'OFF' JNZ PCDX1 XRA A ;TURN OFF DEBUG MODE STA DEBUG JMP PCDX2 ; PCDO - PROCESS 'ERROR' DIRECTIVE PCDO: CALL SNB ;SCAN TO PARAMETER RC CPI 'S' ;JUMP IF NOT 'SUMMARY' JNZ PCDO1 LHLD PERR ;PRINT PARITY ERROR COUNT CALL WDWC LXI H,MSG11 ;PRINT ' PARITY ERRORS' CALL WASC LHLD OERR ;PRINT OVERRUN COUNT CALL WDWC LXI H,MSG12 ;PRINT ' OVERRUN ERRORS' CALL WASC LHLD FERR ;PRINT FRAME ERROR COUNT CALL WDWC LXI H,MSG13 ;PRINT ' FRAME ERRORS' CALL WASC JMP PCDX2 ;EXIT PCDO1: CALL DHD ;DECODE 1ST HEX DIGIT RC ADD A ;LEFT SHIFT 4 ADD A ADD A ADD A MOV B,A ;SAVE IT CALL GNC ;GET 2ND DIGIT RC CALL DHD ;DECODE 2ND DIGIT RC ADD B ;BUILD COMPLETE BYTE STA ERROR ;SAVE AS ERROR CODE JMP PCDX2 ;EXIT ; PCDP - PROCESS 'READ' DIRECTIVE PCDP: CALL GFN ;GET FILE NAME INTO TFCB RC XRA A STA TFCB+EX LXI D,TFCB ;TRY TO OPEN FILE CALL OPEN CPI 255 JNZ PCDP1 Š LXI H,MSG1 ;PRINT 'FILE NOT FOUND' CALL WASC JMP PCDX2 ;NORMAL EXIT PCDP1: XRA A STA TFCB+NR STA DIBUFC LXI H,0 ;CLEAR TRANSMISSION ERROR COUNT SHLD TERR PCDP2: CALL RASS ;READ NEXT LINE FROM FILE JC PCDP6 ;BRANCH ON EOF CALL CCA ;CHECK FOR CONSOLE ACTIVITY JC PCDP6 ;ABORT TRANSMISSION IF PRESENT XRA A ;CLEAR COLUMN COUNT FOR TAB EXPANSION STA COL PCDP3: CALL GNC ;GET NEXT CHAR JC PCDP4 ;BRANCH ON END OF LINE MOV B,A LDA CAPS ;CONVERT L.C. IF CAPS LOCK ON ORA A MOV A,B CNZ CLC CPI TAB ;JUMP IF NOT TAB JNZ PCDP3C LDA EXPAND ;JUMP IF EXPAND NOT SELECTED ORA A MVI A,TAB JZ PCDP3C PCDP3A: MVI A,' ' ;SEND ANOTHER BLANK CALL WACM MOV B,A LDA ECHO ;CHECK DUPLEX FLAG ORA A MOV A,B CZ RACM ;AWAIT ECHO IF 'FULL' CALL XWACC ;WRITE CHAR TO CONSOLE CMP B ;COMPARE WITH CHAR WE SENT JZ PCDP3B ;JUMP IF IDENTICAL LHLD TERR ;ELSE INCREMENT TRANS. ERROR COUNT INX H SHLD TERR PCDP3B: LDA COL ;INCREMENT COLUMN COUNT INR A STA COL ANI 07H ;LOOP UNTIL MOD(COL,8)=0 JNZ PCDP3A JMP PCDP3 ;GO GET NEXT CHAR FROM FILE PCDP3C: CALL WACM ;WRITE CHAR TO MODEM MOV B,A LDA ECHO ;CHECK DUPLEX FLAG ORA A MOV A,B CZ RACM ;AWAIT REMOTE ECHO IF 'FULL' CALL XWACC ;WRITE CHAR TO CONSOLE CMP B ;COMPARE WITH CHAR WE SENT JZ PCDP3D ;JUMP IF IDENTICAL Š LHLD TERR ;INCREMENT ERROR COUNT INX H SHLD TERR PCDP3D: LDA COL ;INCREMENT COLUMN COUNT INR A STA COL JMP PCDP3 ;LOOP UNTIL EOF PCDP4: MVI A,CR ;SEND CARRIAGE RETURN CALL WACM MOV B,A LDA ECHO ;CHECK DUPLEX FLAG ORA A MOV A,B CZ RACM ;AWAIT REMOTE ECHO IF 'FULL' CALL XWACC ;WRITE CHAR TO CONSOLE CMP B ;COMPARE WITH CHAR WE SENT JZ PCDP9 ;JUMP IF IDENTICAL LHLD TERR ;ELSE INCREMENT ERROR COUNT INX H SHLD TERR PCDP9: LDA MODE ;JUMP IF ORIGINATE MODE CPI 'O' JZ PCDP5 MVI A,LF CALL WACM ;SEND LF TO MODEM CALL XWACC ;SEND LF TO CONSOLE JMP PCDP2 ;LOOP UNTIL EOF PCDP5: CALL RACM ;AWAIT REMOTE LINE FEED ANI 7FH CPI LF JNZ PCDP5 CALL XWACC ;ECHO LF TO CONSOLE LXI H,500 ;SETUP FOR HALF-SECOND TIMEOUT SHLD TIME LDA GARBAGE ;GET GARBAGE COUNT MOV B,A INR B PCDP8: DCR B ;DECREMENT COUNT JZ PCDP7 ;JUMP WHEN ZERO CALL RACM ;DISCARD ANOTHER CHAR JMP PCDP8 ;LOOP UNTIL COUNT = 0 PCDP7: LXI H,0FFFFH ;RESET TO INF. TIMEOUT SHLD TIME JMP PCDP2 ;LOOP UNTIL EOF PCDP6: LXI D,TFCB ;CLOSE FILE CALL CLOSE MVI A,BEL ;RING BELL CALL WACC CALL WEOLC ;RETURN CARRIAGE LDA ECHO ;RETURN IF HALF DUPLEX ORA A JNZ PCDX2 LHLD TERR ;PRINT TRANS. ERROR COUNT CALL WDWC LXI H,MSG15 ;PRINT ' TRANSMISSION ERRORS' Š CALL WASC JMP PCDX2 ;EXIT ; PCDQ - PROCESS 'GARBAGE' DIRECTIVE PCDQ: CALL SNB ;SCAN TO PARAMETER RC CALL DHD ;DECODE FIRST HEX DIGIT RC STA GARBAGE ADD A ;LEFT SHIFT 4 ADD A ADD A ADD A MOV B,A ;SAVE IT CALL GNC ;DECODE SECOND HEX DIGIT JC PCDX2 ;RETURN IF NO SECOND DIGIT CALL DHD RC ADD B ;ADD TO SHIFTED 1ST DIGIT STA GARBAGE ;SAVE AS NEW GARBAGE COUNT JMP PCDX2 ; PCDR - PROCESS 'LIST' DIRECTIVE PCDR: LXI H,KWTAB+0*10 ;PRINT 'SITE ' CALL W8CC LXI H,SITE ;PRINT SITE STRING LDA SITEL MOV B,A INR B PCDR1: DCR B JZ PCDR2 MOV A,M INX H CALL WACC JMP PCDR1 PCDR2: CALL WEOLC LXI H,KWTAB+1*10 ;PRINT 'PHONE ' CALL W8CC LXI H,PHONE ;PRINT PHONE NUMBER LDA PHONEL MOV B,A INR B PCDR3: DCR B JZ PCDR4 MOV A,M INX H CALL WACC JMP PCDR3 PCDR4: CALL WEOLC LXI H,KWTAB+5*10 ;PRINT 'MODE ' CALL W8CC LDA CR2 ;JUMP IF NOT ORIGINATE ANI MS Š JZ PCDR5 LXI H,MSG24 ;PRINT 'ORIGINATE' JMP PCDR6 PCDR5: LXI H,MSG25 ;PRINT 'ANSWER' PCDR6: CALL WASC LXI H,KWTAB+6*10 ;PRINT 'DUPLEX ' CALL W8CC LDA ECHO ;JUMP IF HALF DUPLEX ORA A JNZ PCDR7 LXI H,MSG26 ;PRINT 'FULL' JMP PCDR8 PCDR7: LXI H,MSG27 ;PRINT 'HALF' PCDR8: CALL WASC MVI B,9 ;SPACE OVER 9 CALL WSPC LXI H,KWTAB+2*10 ;PRINT 'PARITY ' CALL W8CC LDA CR1 ;JUMP IF NO PARITY INHIBIT ANI PI JZ PCDR9 LXI H,MSG21 ;PRINT 'NONE' JMP PCDRB PCDR9: LDA CR1 ;JUMP IF NOT EVEN ANI EPE JZ PCDRA LXI H,MSG22 ;PRINT 'EVEN' JMP PCDRB PCDRA: LXI H,MSG23 PCDRB: CALL WASC LXI H,KWTAB+3*10 ;PRINT 'DBITS ' CALL W8CC LDA CR1 ;PRINT # OF DATA BITS ANI LS2+LS1 RRC ADI '5' CALL WACC MVI B,12 ;SPACE 12 CALL WSPC LXI H,KWTAB+4*10 ;PRINT 'SBITS ' CALL W8CC LDA CR1 ;PRINT # OF STOP BITS ANI SBS RRC RRC RRC ADI '1' CALL WACC CALL WEOLC LXI H,KWTAB+7*10 ;PRINT 'AUTOLF ' CALL W8CC LDA AUTOLF ;PRINT STATE CALL ONOFF MVI B,10 ;SPACE OVER 10 CALL WSPC Š LXI H,KWTAB+8*10 ;PRINT 'BAUD ' CALL W8CC LDA CR2 ;JUMP IF 300 ANI BRS JNZ PCDRC LXI H,MSG28 ;PRINT '110' JMP PCDRD PCDRC: LXI H,MSG29 ;PRINT '300' PCDRD: CALL WASC LXI H,KWTAB+9*10 ;PRINT 'CAPS ' CALL W8CC LDA CAPS ;PRINT STATE CALL ONOFF MVI B,10 ;SPACE OVER 10 CALL WSPC LXI H,KWTAB+10*10 ;PRINT 'ESCAPE ' CALL W8CC LDA ESCAPE ;PRINT HEX VALUE CALL WHBC MVI A,'H' CALL WACC CALL WEOLC LXI H,KWTAB+13*10 ;PRINT 'DEBUG ' CALL W8CC LDA DEBUG ;PRINT STATE CALL ONOFF MVI B,10 ;SPACE OVER 10 CALL WSPC LXI H,KWTAB+14*10 ;PRINT 'ERROR ' CALL W8CC LDA ERROR ;PRINT HEX VALUE CALL WHBC MVI A,'H' CALL WACC CALL WEOLC LXI H,KWTAB+16*10 ;PRINT 'GARBAGE ' CALL W8CC LDA GARBAGE ;PRINT VALUE CALL WHBC MVI A,'H' CALL WACC MVI B,10 ;SPACE OVER 10 CALL WSPC LXI H,KWTAB+18*10 ;PRINT 'EXPAND ' CALL W8CC LDA EXPAND ;PRINT STATE CALL ONOFF CALL WEOLC LXI H,KWTAB+21*10 ;PRINT 'BREAK ' CALL W8CC LDA BREAK CALL WHBC MVI A,'H' CALL WACC MVI B,10 ;SPACE OVER 10 Š CALL WSPC LXI H,KWTAB+25*10 ;PRINT 'REMESC ' CALL W8CC LDA REMESC CALL WHBC ;PRINT REMOTE ESCAPE CODE MVI A,'H' CALL WACC CALL WEOLC LXI H,KWTAB+29*10 ;PRINT 'BLOCK ' CALL W8CC LDA BLKSZ ;PRINT BLOCK SIZE IN HEX CALL WHBC MVI A,'H' CALL WACC CALL WEOLC JMP PCDX2 ;NORMAL EXIT ; PCDS - PROCESS 'EXPAND' DIRECTIVE PCDS: CALL SNB ;SCAN TO PARAMETER RC CPI 'O' ;ERROR IF 1ST CHAR NOT 'O' JNZ PCDX1 CALL GNC ;GET 2ND CHAR RC CPI 'N' ;JUMP IF NOT 'ON' JNZ PCDS1 MVI A,1 ;TURN ON EXPAND FLAG STA EXPAND JMP PCDX2 ;EXIT PCDS1: CPI 'F' ;ERROR IF NOT 'OFF' JNZ PCDX1 XRA A ;TURN OFF EXPAND FLAG STA EXPAND JMP PCDX2 ;EXIT W8CC: MVI B,8 W8CC1: MOV A,M INX H CALL WACC DCR B JNZ W8CC1 RET ONOFF: ORA A ;JUMP IF OFF JZ ONOFF1 LXI H,MSG30 ;PRINT 'ON' JMP ONOFF2 ONOFF1: LXI H,MSG31 ;PRINT 'OFF' ONOFF2: CALL WASC RET ; PCDT - PROCESS 'CAPTURE' DIRECTIVE PCDT: MVI A,1 ;SET CAPTURE FLAG Š STA CAPTURE LXI H,MBUF ;RESET BUFFER POINTER SHLD MBUFP JMP PCDX2 ;EXIT ; PCDU - PROCESS 'WRITE' DIRECTIVE PCDU: XRA A ;TURN OFF CAPTURE FLAG STA CAPTURE LHLD MBUFP ;HL = POINTER TO LAST DATA + 1 LXI D,MBUF ;DE = POINTER TO FIRST DATA MOV A,L ;HL = HL - DE = DATA LENGTH SUB E MOV L,A MOV A,H SBB D MOV H,A SHLD SIZE ORA L ;JUMP IF HL>0 JNZ PCDU1 LXI H,MSG16 ;PRINT 'MEMORY BUFFER EMPTY' CALL WASC JMP PCDX2 ;EXIT PCDU1: CALL GFN ;GET USER'S FILE NAME RC XRA A STA TFCB+EX LXI D,TFCB ;CREATE FILE CALL DELETE CALL MAKE CPI 255 ;JUMP IF OK JNZ PCDU2 LXI H,MSG17 ;PRINT 'DISK FULL' CALL WASC JMP PCDX2 ;EXIT PCDU2: XRA A ;REWIND FILE STA TFCB+NR STA DOBUFC LXI H,DOBUF SHLD DOBUFP LHLD SIZE ;DE = NUMBER OF BYTES TO SAVE XCHG LXI H,MBUF ;HL = FWA OF DATA PCDU3: MOV A,M ;FETCH NEXT CHAR FROM MBUF INX H CALL WACD ;WRITE ASCII CHAR TO DISK JNC PCDU4 ;JUMP IF OK LXI H,MSG18 ;PRINT 'WRITE ERROR' CALL WASC JMP PCDX2 ;EXIT PCDU4: DCX D ;DECREMENT SIZE MOV A,D ;LOOP UNTIL ZERO ORA E JNZ PCDU3 CALL FLUSH ;FLUSH LAST OUTPUT BUFFER Š CALL WEOLC ;RETURN CARRIAGE MVI A,BEL ;RING BELL CALL WACC JMP PCDX2 ;EXIT ; PCDV - PROCESS 'BREAK' DIRECTIVE PCDV: CALL SNB ;SCAN TO PARAMETER RC CALL DHD ;DECODE 1ST HEX DIGIT RC ADD A ;LEFT SHIFT 4 ADD A ADD A ADD A MOV B,A ;SAVE IT CALL GNC ;GET 2ND DIGIT RC CALL DHD ;DECODE IT RC ADD B ;BUILD COMPLETE BYTE STA BREAK ;SAVE AS NEW BREAK TRIGGER JMP PCDX2 ; PCDW - PROCESS 'SAVE' DIRECTIVE PCDW: CALL GFN ;GET FILE NAME RC XRA A STA TFCB+EX LXI D,TFCB ;CREATE FILE CALL DELETE CALL MAKE CPI 255 ;JUMP IF OK JNZ PCDW2 LXI H,MSG17 ;PRINT 'DISK FULL' CALL WASC JMP PCDX2 PCDW2: XRA A ;REWIND FILE STA TFCB+NR STA DOBUFC LXI H,DOBUF SHLD DOBUFP MVI A,2 ;REDIRECT CONSOLE OUTPUT TO DISK STA COF CALL PCDR ;WRITE CONFIG FILE CALL FLUSH ;FLUSH BUFFER, CLOSE FILE XRA A ;REDIRECT CONSOLE OUTPUT TO CONSOLE STA COF JMP PCDX2 ;EXIT ; PCDX - PROCESS 'RESET' DIRECTIVE PCDX: LXI H,0 SHLD PERR Š SHLD OERR SHLD FERR JMP PCDX2 ; PCDY - PROCESS 'HELP' DIRECTIVE PCDY: CALL SNB ;SCAN TO PARAMETER JNC PCDY1 ;JUMP IF FOUND LXI H,HMSG0 ;ELSE PRINT HELP MESSAGE 0 CALL WASC JMP PCDX2 PCDY1: CPI '1' ;JUMP IF NOT '1' JNZ PCDY2 LXI H,HMSG1 ;ELSE PRINT HELP MESSAGE 1 CALL WASC JMP PCDX2 PCDY2: CPI '2' ;JUMP IF NOT '2' JNZ PCDY3 LXI H,HMSG2 ;ELSE PRINT HELP MESSAGE 2 CALL WASC JMP PCDX2 PCDY3: CPI '3' ;JUMP IF NOT '3' JNZ PCDY4 LXI H,HMSG3 ;ELSE PRINT HELP MESSAGE 3 CALL WASC JMP PCDX2 PCDY4: JMP PCDX1 ;FOR NOW, FLAG ERROR ; PCDZ - PROCESS 'REMESC' DIRECTIVE PCDZ: CALL SNB ;SCAN TO PARAMETER RC CALL DHD ;DECLARE 1ST HEX DIGIT RC ADD A ;LEFT SHIFT 4 BITS ADD A ADD A ADD A MOV B,A CALL GNC ;GET 2ND DIGIT RC CALL DHD ;DECODE IT RC ADD B ;ACCUMULATE BYTE STA REMESC ;SAVE AS NEW REMOTE ESCAPE CODE JMP PCDX2 ;EXIT ; PCEA - PROCESS 'DIR' DIRECTIVE PCEA: CALL GFN ;GET FILE NAME RC LXI H,TFCB+FN ;JUMP IF ANY NON-BLANK CHARS MVI B,11 PCEA0: MOV A,M CPI ' ' Š JNZ PCEA6 INX H DCR B JNZ PCEA0 LXI H,TFCB+FN MVI B,11 ;ESLE FILL FN ANF FT WITH ? PCEA5: MVI M,'?' INX H DCR B JNZ PCEA5 PCEA6: XRA A ;CLEAR COLUMN COUNT STA COL STA TFCB+EX ;RESET TO EXTENT #0 LXI D,TFCB CALL SRCHF ;SEARCH FOR 1ST OCCURANCE CPI 255 JZ PCEAX PCEA1: ANI 3 ;MASK OFF LOW 2 BITS ADD A ;MULTIPLY BY 32 ADD A ADD A ADD A ADD A LXI H,0080H ;ADD TO 80H ADD L MOV L,A INX H ;SKIP 1ST BYTE MVI B,11 ;NUMBER OF BYTES PCEA2: MOV A,M ;FETCH NEXT BYTE INX H CALL WACC ;WRITE TO CONSOLE DCR B JNZ PCEA2 LXI H,COL ;INCREMENT COLUMN COUNT INR M MOV A,M ANI 3 ;JUMP IF DIVISIBLE BY 4 JZ PCEA3 LXI H,MSG20 ;PRINT VERTICAL LINE CALL WASC JMP PCEA4 ;LOOP PCEA3: CALL WEOLC ;ISSUE END OF LINE PCEA4: LXI D,TFCB CALL SRCHN ;SEARCH FOR NEXT OCCURANCE CPI 255 ;LOOP IF FOUND JNZ PCEA1 CALL WEOLC ;ISSUE END OF LINE JMP PCDX2 ;EXIT PCEAX: LXI H,MSG1 ;PRINT 'FILE NOT FOUND' CALL WASC JMP PCDX2 ; PCEB - PROCESS 'SEND' DIRECTIVE PCEB: MVI B,LS2+LS1 ;FORCE 8 DATA BITS Š CALL CR1ON CALL GFN ;GET FILE NAME INTO TFCB RC XRA A STA TFCB+EX LXI D,TFCB ;TRY TO OPEN FILE CALL OPEN CPI 255 JNZ PCEB1 LXI H,MSG1 ;PRINT 'FILE NOT FOUND' CALL WASC JMP PCDX2 ;EXIT PCEB1: XRA A STA TFCB+NR ;REWIND FILE STA EOF ;CLEAR END-OF-FILE FLAG PCEB2: LDA EOF ;JUMP IF END-OF-FILE FLAG SET ORA A JNZ PCEB7 CALL CONST ;JUMP IF NO CONSOLE ACTIVITY ORA A JZ PCEB2A LXI H,MSG38 ;PRINT 'SEND ABORTED' CALL WASC JMP PCEB7 ;GO SEND EOT PCEB2A: LXI B,0 ;COUNT = 0 LXI D,MBUF ;INITIAL MBUF POINTER PCEB3: CALL RDREC2 ;READ NEXT RECORD INTO MBUF CPI 1 ;JUMP ON EOF JZ PCEB3A MOV A,E ;INCREMENT MBUF POINTER ADI 128 MOV E,A JNC $+4 INR D MOV A,C ;INCREMENT COUNT ADI 128 MOV C,A JNC $+4 INR B MOV A,B LXI H,BLKSZ CMP M JC PCEB3 JMP PCEB3B ;GO SEND DATA MESSAGE PCEB3A: MVI A,1 ;SET END-OF-FILE FLAG STA EOF MOV A,B ;GO SEND EOT IF COUNT = 0 ORA C JZ PCEB7 PCEB3B: MOV H,B ;SAVE COUNT MOV L,C SHLD OCNT PCEB4: MVI A,NULL ;SEND DATA MESSAGE STA OCODE CALL SEND ŠPCEB5: CALL RECV JNC PCEB5A ;JUMP IF OK LXI H,MSG36 ;PRINT 'INVALID CRC' CALL WASC JMP PCEB6 PCEB5A: LHLD TOC MOV A,H ORA L JNZ PCEB5B LXI H,MSG35 ;PRINT 'TIMEOUT' CALL WASC JMP PCEB4 PCEB5B: LDA ICODE ;FETCH INPUT MESSAGE TYPE CPI EOT ;JUMP IF ECHOED EOT JZ PCEB8 CPI ACK ;CONTINUE TO NEXT MSG IF ACK JZ PCEB2 CPI NAK ;RETRANSMIT IF NAK JNZ PCEB5C LXI H,MSG34 ;PRINT 'RETRANSMITTING' CALL WASC LDA OCODE ;JUMP IF LAST MSG WAS EOT CPI EOT JZ PCEB7 JMP PCEB4 ;ELSE RETRANS. DATA MESSAGE PCEB5C: LXI H,MSG37 ;PRINT 'UNKNOWN MESSAGE' CALL WASC PCEB6: MVI A,NAK ;SEND NAK STA OCODE CALL SEND JMP PCEB5 PCEB7: MVI A,EOT ;SEND EOT STA OCODE CALL SEND JMP PCEB5 ;AWAIT EOT ECHO PCEB8: LXI D,TFCB ;CLOSE FILE CALL CLOSE LXI H,MSG32 ;PRINT 'FILE SENT' CALL WASC JMP PCDX2 ;NORMAL EXIT ; PCEC - PROCESS 'RECV' DIRECTIVE PCEC: MVI B,LS2+LS1 ;FORCE 8 DATA BITS CALL CR1ON CALL GFN ;GET FILE NAME RC XRA A STA TFCB+EX LXI D,TFCB CALL DELETE ;DELETE EXISTING FILE, IF ANY CALL MAKE ;MAKE NEW ONE CPI 255 ;JUMP IF OK JNZ PCEC1 LXI H,MSG17 ;PRINT 'DISK FULL' Š CALL WASC JMP PCDX2 PCEC1: XRA A STA TFCB+NR MVI A,0FFH ;'AWAITING FIRST MSG' CODE STA OCODE PCEC2: CALL RECV ;RECEIVE MESSAGE JNC PCEC2A ;JUMP IF OK LXI H,MSG36 ;PRINT 'INVALID CRC' CALL WASC JMP PCEC3 PCEC2A: LHLD TOC ;BRANCH IF NO TIMEOUT MOV A,H ORA L JNZ PCEC2B LDA OCODE ;LOOP IF AWAITING FIRST MSG INR A JZ PCEC2 LXI H,MSG35 ;PRINT 'TIMEOUT' AND SEND NAK CALL WASC JMP PCEC3 PCEC2B: LDA ICODE ;FETCH MESSAGE CODE CPI NAK ;JUMP IF NAK JNZ PCEC2C LXI H,MSG34 ;PRINT 'RETRANSMITTING' CALL WASC JMP PCEC6 PCEC2C: CPI EOT ;JUMP IF EOT JZ PCEC9 CPI NULL ;JUMP IF DATA MESSAGE JZ PCEC7 LXI H,MSG37 ;PRINT 'UNKNOWN MESSAGE' CALL WASC PCEC3: MVI A,NAK ;SEND NAK JMP PCEC5 PCEC4: MVI A,ACK ;SEND ACK PCEC5: STA OCODE PCEC6: CALL SEND ;SEND MESSAGE JMP PCEC2 ;GO READ RESPONSE PCEC7: LXI D,MBUF2 ;FWA OF INPUT BUFFER LHLD ICNT ;HL = # OF BYTES READ PCEC8: CALL WRREC2 ;WRITE NEXT RECORD FROM MBUF MOV A,E ;ADD 128 TO POINTER ADI 128 MOV E,A JNC $+4 INR D MOV A,L ;SUBTRACT 128 FROM COUNT SUI 128 MOV L,A JNC $+4 DCR H MOV A,H ;LOOP UNTIL COUNT = 0 ORA L JNZ PCEC8 Š JMP PCEC4 ;GO SEND ACK, LOOP UNTIL EOF PCEC9: MVI A,EOT STA OCODE CALL SEND LXI D,TFCB CALL CLOSE LXI H,MSG33 ;PRINT 'FILE RECEIVED' CALL WASC JMP PCDX2 ; PCED - PROCESS 'BLOCK' DIRECTIVE PCED: CALL SNB RC CALL DHD RC STA BLKSZ ADD A ADD A ADD A ADD A MOV B,A CALL GNC JC PCDX2 CALL DHD RC ADD B STA BLKSZ JMP PCDX2 ;; SEND - SEND MESSAGE USING PROTOCOL ; ; ENTRY CONDITIONS ; ; OCODE MESSAGE TYPE (ACK,NAK,EOT,NUL) ; ; OCNT MESSAGE LENGTH (IF OCODE=NUL) ; ; MBUF MESSAGE (IF OCODE=NUL) SEND: MVI A,SOH ;SEND START OF HEADER CALL WACM LXI H,0 ;CLEAR CRC SHLD CRC LDA OCODE ;SEND MESSAGE TYPE CALL WACMC CPI NULL ;JUMP IF NOT DATA MESSAGE JNZ SEND2 LHLD OCNT ;FETCH MESSAGE LENGTH MOV A,H ;SEND HIGH BYTE CALL WACMC MOV A,L ;SEND LOW BYTE CALL WACMC MVI A,STX ;SEND START OF TEXT CALL WACMC Š MOV B,H ;BC=COUNT MOV C,L LXI H,MBUF ;HL = FWA OF MESSAGE SEND1: MOV A,M ;FETCH NEXT BYTE OF MESSAGE INX H CALL WACMC ;SEND NEXT DATA BYTE DCX B ;DECREMENT COUNT MOV A,B ;LOOP UNTIL ZERO ORA C JNZ SEND1 MVI A,ETX ;SEND END OF TEXT CALL WACMC SEND2: LDA CRC+1 ;SEND HIGH BYTE OF CRC CALL WACM LDA CRC ;SEND LOW BYTE OF CRC CALL WACM RET ;EXIT ;; RECV - RECEIVE MESSAGE USING PROTOCOL ; ; ENTRY CONDITIONS ; ; TIME TIMEOUT COUNT (IN MILLISECONDS) ; ; EXIT CONDITIONS ; ; TOC REMAINING TIME (ZERO IF TIMED OUT) ; ; C-FLAG SET IF ERROR DETECTED ; ; ICODE INPUT MESSAGE TYPE (ACK/NAK/EOT/NUL) ; ; ICNT INPUT MESSAGE COUNT (IF ICODE=NUL) ; ; MBUF2 INPUT MESSAGE (IF ICODE=NUL) RECV: LXI H,1000 ;SETUP FOR 1 SECOND TIMEOUT SHLD TIME MVI B,10 ;TRY 10 TIMES FOR SOH RECV0: CALL RACM ;READ CHARACTER CPI SOH ;JUMP IF SOH JZ RECV1 DCR B ;NON-SOH OR TIMEOUT, JNZ RECV0 ;TRY AGAIN LXI H,0 ;FAKE TIMEOUT SHLD TOC JMP RECVX ;AND EXIT RECV1: LXI H,0 ;CLEAR CRC SHLD CRC LXI H,500 ;SETUP FOR HALF-SECOND TIMEOUT SHLD TIME CALL RACMC ;READ MESSAGE TYPE JC RECVX STA ICODE CPI NULL ;JUMP IF NOT DATA MESSAGE Š JNZ RECV4 CALL RACMC ;READ HIGH BYTE OF COUNT JC RECVX MOV H,A CALL RACMC ;READ LOW BYTE OF COUNT JC RECVX MOV L,A SHLD ICNT ;SAVE COUNT MOV B,H ;BC = COUNT MOV C,L RECV2: CALL RACMC ;LOOP UNTIL STX READ JC RECVX CPI STX JNZ RECV2 LXI H,MBUF2 ;FWA OF INPUT BUFFER RECV3: CALL RACMC ;READ DATA BYTE JC RECVX MOV M,A ;STORE IN BUFFER INX H DCX B ;DECREMENT COUNT MOV A,B ;LOOP UNTIL ZERO ORA C JNZ RECV3 CALL RACMC ;ERROR IF NEXT BYTE NOT ETX JC RECVX CPI ETX JNZ RECVE RECV4: CALL RACM ;READ TRANSMITTED CRC INTO DE JC RECVX MOV D,A CALL RACM JC RECVX MOV E,A LHLD CRC ;FETCH COMPUTED CRC INTO HL MOV A,E ;ERROR IF NOT SAME CMP L JNZ RECVE MOV A,D CMP H JNZ RECVE RECVX: LXI H,0FFFFH ;RETURN TO INF. TIMEOUT SHLD TIME STC CMC RET RECVE: LXI H,0FFFFH ;RETURN TO INF. TIMEOUT SHLD TIME STC ;ERROR EXIT RET ;; WACMC - WRITE ASCII CHARACTER TO MODEM (WITH CRC) ; WACMC: CALL WACM ;WRITE CHAR TO MODEM CALL UCRC ;UPDATE CRC Š CMA ;DISPLAY ON LIGHTS OUT 0FFH CMA RET ;; RACMC - READ ASCII CHARACTER FROM MODEM (WITH CRC) ; RACMC: CALL RACM ;READ CHARACTER FROM MODEM PUSH PSW CALL UCRC ;UPDATE CRC CMA ;DISPLAY ON LIGHTS OUT 0FFH POP PSW RET ;; UCRC - UPDATE CRC ; UCRC: PUSH PSW ;SAVE REGS PUSH B PUSH H MOV B,A ;SAVE DATA BYTE MVI C,8 ;# BITS PER BYTE UCRC1: ANI 80H ;GET MOST SIG. BIT LHLD CRC ;HL = CRC XRA H ;XOR M.S.B. INTO CRC MOV H,A DAD H ;LEFT SHIFT CRC 1 BIT JNC UCRC2 ;JUMP IF M.S.B. ZERO MOV A,H ;HL = HL XOR CRC POLYNOMIAL XRI CRCPOL SHR 8 MOV H,A MOV A,L XRI CRCPOL AND 0FFH MOV L,A UCRC2: SHLD CRC ;REPLACE CRC DCR C ;EXIT WHEN DONE JZ UCRC3 MOV A,B ;SHIFT DATA BYTE LEFT 1 BIT ADD A MOV B,A JMP UCRC1 ;LOOP UCRC3: POP H ;RESTORE REGS, RETURN POP B POP PSW RET ;; SNB - SCAN TO NON-BLANK (AND NON-TAB) ; SNB: CALL GNC ;GET NEXT CHAR RC ;RETURN IF END OF LINE CPI ' ' ;LOOP IF BLANK JZ SNB Š CPI TAB ;LOOP IF TAB JZ SNB STC ;NORMAL EXIT CMC RET ;; DHD - DECODE HEX DIGIT ; DHD: CPI 'A' ;JUMP IF F JC DHD1 CPI 'F'+1 JNC DHD1 SUI 'A'-10 ;DECODE A THRU F JMP DHD2 ;EXIT DHD1: CPI '0' ;ERROR IF <0 OR >9 RC CPI '9'+1 CMC RC SUI '0' ;DECODE 0 THRU 9 DHD2: STC ;EXIT CMC RET ;; EASC - ECHO ASCII STRING TO CONSOLE ; EASC: LDA IBUF+1 ;FETCH STRING LENGTH ORA A ;RETURN IF EMPTY RZ MOV B,A ;B = LENGTH LXI H,IBUF+2 ;HL = FWA OF STRING MVI C,0 ;C = COLUMN COUNT EASC1: MOV A,M ;FETCH NEXT CHAR FROM IBUF INX H CPI TAB ;JUMP IF NOT TAB JNZ EASC3 EASC2: MVI A,' ' ;EXPAND TAB CALL WACC INR C MOV A,C ANI 07H JNZ EASC2 JMP EASC4 ;CONTINUE EASC3: CALL WACC ;WRITE CHAR INR C ;INCREMENT COLUMN COUNT EASC4: DCR B ;DECREMENT COUNT JNZ EASC1 ;LOOP THRU ENTIRE BUFFER CALL WEOLC ;WRITE END OF LINE TO CONSOLE RET ;EXIT ;; GFN - GET FILE NAME INTO TFCB ; ŠGFN: LXI H,TFCB ;AREA TO STORE NAME MVI M,0 ;DEFAULT TO CURRENT DRIVE INX H MVI B,11 ;BLANK FILL FN AND FT GFN1: MVI M,' ' INX H DCR B JNZ GFN1 CALL SNB ;SCAN TO FILE NAME JC GFNX MVI B,8 ;MAX CHARS IN NAME LXI H,TFCB+FN ;START SCANNING FN JMP GFN2A GFN1A: LXI H,TFCB+FN ;OOPS - THAT WAS A DRIVE NAME MOV A,M SUI 'A'-1 STA TFCB+0 MVI M,' ' MVI B,8 GFN2: CALL GNC ;GET NEXT CHAR JC GFNX GFN2A: CPI '*' ;JUMP IF ASTERISK JZ GFN2B CPI '.' ;JUMP IF END OF FN JZ GFN3 CPI ' ' JZ GFNX CPI ':' ;THIS IS NO FN, ITS A DRIVE ID! JZ GFN1A CALL CLC ;CONVERT LOWER CASE MOV M,A ;SAVE IN FN INX H DCR B ;DECREMENT COUNT JP GFN2 ;LOOP IF STILL ROOM JMP GFNE ;ELSE ERROR GFN2B: DCR B ;FILL REST OF FN WITH '?' GFN2C: MVI M,'?' INX H DCR B JNZ GFN2C CALL GNC ;GET NEXT CHAR JC GFNX ;EXIT IF END OF NAME CPI '.' ;ERROR IF NOT PERIOD JNZ GFNE GFN3: LXI H,TFCB+FT ;SCAN OFF FT FIELD GFN4: MVI B,3 ;MAX CHARS IN FT GFN5: CALL GNC ;GET CHAR JC GFNX ;EXIT IF END OF NAME CPI '*' ;JUMP IF ASTERISK JZ GFN5B CPI ' ' ;EXIT IF END OF NAME JZ GFNX CALL CLC ;CONVERT LOWER CASE MOV M,A ;SAVE IN FT INX H Š DCR B ;DECREMENT COUNT JP GFN5 ;LOOP IF STILL ROOM JMP GFNE ;ELSE ERROR GFN5B: DCR B ;FILL REST OF FT WITH '?' GFN5C: MVI M,'?' INX H DCR B JP GFN5C CALL GNC ;EXIT IF END OF NAME JC GFNX CPI ' ' JNZ GFNE ;ELSE ERROR GFNX: STC ;NORMAL EXIT CMC RET GFNE: STC ;ERROR EXIT RET ;; OPEN - OPEN SPECIFIED FILE ; ; ENTRY CONDITIONS: ; ; DE FWA OF FCB OF FILE ; ; EXIT CONDITIONS: ; ; A 255 IF FILE NOT FOUND OPEN: PUSH H PUSH D PUSH B MVI C,OFFC CALL ENTRY POP B POP D POP H RET ;; CLOSE - CLOSE SPECIFIED FILE ; ; ENTRY CONDITIONS: ; ; DE FWA OF FCB OF FILE ; ; EXIT CONDITIONS ; ; A 255 IF UNABLE TO CLOSE CLOSE: PUSH H PUSH D PUSH B MVI C,CFFC CALL ENTRY POP B POP D Š POP H RET ;; SRCHF - SEARCH FOR FIRST OCCURANCE (OF AFN IN DIRECTORY) ; SRCHF: PUSH H PUSH D PUSH B MVI C,SFFC CALL ENTRY POP B POP D POP H RET ;; SRCHN - SEARCH FOR NEXT OCCURANCE (OF AFN IN DIRECTORY) ; SRCHN: PUSH H PUSH D PUSH B MVI C,SNFC CALL ENTRY POP B POP D POP H RET ;; RASS - READ ASCII STRING FROM SOURCE FILE ; ; EXIT CONDITIONS ; ; IBUFC NUMBER OF CHARS READ ; ; IBUFP POINTER TO 1ST CHAR ; ; C-FLAG SET IF EOF READ RASS: PUSH H PUSH B LXI H,IBUF MOV B,M ;B = MAX CHAR COUNT INX H MVI M,0 INX H SHLD IBUFP ;SET IBUF POINTER RASS1: CALL RACS ;READ NEXT CHAR FROM SOURCE JC RASS3 ;JUMP ON PHYSICAL EOF CPI 'Z'-40H ;JUMP ON LOGICAL EOF JZ RASS3 CPI LF ;IGNORE LINE FEEDS JZ RASS1 CPI CR ;JUMP ON END-OF-LINE JZ RASS2 Š INR B ;LOOP IF NO ROOM IN IBUF DCR B JZ RASS1 MOV M,A ;STORE IN IBUF INX H LDA IBUFC ;INCREMENT IBUF COUNT INR A STA IBUFC DCR B ;DECREMENT MAX COUNT JMP RASS1 ;LOOP RASS2: STC ;NORMAL EXIT CMC JMP RASS4 RASS3: STC ;EOF EXIT RASS4: POP B POP H RET ;; RACS - READ ASCII CHARACTER FROM SOURCE ; ; EXIT CONDITIONS ; ; A CHARACTER READ ; ; C-FLAG SET IF PHYSICAL EOF RACS: PUSH H LDA DIBUFC ;JUMP IF DISK INPUT BUFFER NOT EMPTY ORA A JNZ RACS1 CALL RDREC ;READ NEXT RECORD INTO DIBUF CPI 1 ;BRANCH ON PHYSICAL EOF JZ RACS2 LXI H,DIBUF ;RESET DIBUF POINTER SHLD DIBUFP MVI A,80H ;RESET DIBUF COUNT RACS1: DCR A ;DECREMENT COUNT STA DIBUFC LHLD DIBUFP ;FETCH CHAR AT POINTER MOV A,M INX H ;INCREMENT POINTER SHLD DIBUFP POP H ;NORMAL EXIT STC CMC RET RACS2: POP H ;EOF EXIT STC RET ;; RDREC - READ RECORD FROM SOURCE FILE ; RDREC2: PUSH H PUSH D Š PUSH B JMP RDREC1 RDREC: PUSH H PUSH D PUSH B LXI D,DIBUF RDREC1: MVI C,SAFC CALL ENTRY LXI D,TFCB MVI C,RRFC CALL ENTRY PUSH PSW LXI D,80H MVI C,SAFC CALL ENTRY POP PSW POP B POP D POP H RET ;; DELETE - DELETE EXISTING FILE ; DELETE: PUSH H PUSH D PUSH B MVI C,DFFC CALL ENTRY POP B POP D POP H RET ;; MAKE - MAKE NEW FILE ; ; ENTRY CONDITIONS ; ; DE FWA OF FILE CONTROL BLOCK MAKE: PUSH H PUSH D PUSH B MVI C,MFFC CALL ENTRY POP B POP D POP H RET ;; WACD - WRITE ASCII CHARACTER TO DEST. FILE ; ; ENTRY CONDITIONS ; ; A CHARACTER TO WRITE Š WACD: PUSH H PUSH PSW LDA DOBUFC ;JUMP IF BUFFER NOT YET FULL CPI 128 JC WACD1 CALL WRREC ;WRITE BUFFER TO FILE LXI H,DOBUF ;RESET BUFFER POINTER SHLD DOBUFP XRA A ;RESET BUFFER COUNT WACD1: INR A ;INCREMENT BUFFER COUNT STA DOBUFC POP PSW ;GET CHAR BACK LHLD DOBUFP ;STORE CHAR AT POINTER MOV M,A INX H ;INCREMENT POINTER SHLD DOBUFP POP H RET ;; FLUSH - FLUSH BUFFER TO DEST. FILE ; FLUSH: PUSH H PUSH D MVI A,1AH ;INSURE AT LEAST ONE EOF CHAR CALL WACD LHLD DOBUFP ;FETCH POINTER LDA DOBUFC ;FETCH COUNT FLUSH1: CPI 128 ;JUMP IF BUFFER FILL JZ FLUSH2 MVI M,1AH ;INSERT ANOTHER EOF CHAR INX H ;BUMP POINTER INR A ;INCREMENT COUNT JMP FLUSH1 ;LOOP FLUSH2: CALL WRREC ;WRITE BUFFER TO FILE LXI D,TFCB ;CLOSE FILE CALL CLOSE POP D ;EXIT POP H RET ;; WRREC - WRITE NEXT RECORD TO DEST. FILE ; WRREC2: PUSH H PUSH D PUSH B JMP WRREC1 WRREC: PUSH H PUSH D PUSH B LXI D,DOBUF WRREC1: MVI C,SAFC CALL ENTRY Š LXI D,TFCB MVI C,WRFC CALL ENTRY PUSH PSW LXI D,80H MVI C,SAFC CALL ENTRY POP PSW POP B POP D POP H RET ;; RASM - READ ASCII STRING FROM MODEM ; RASM: PUSH H PUSH D PUSH B LDA IBUF MOV B,A MVI C,0 ;CLEAR CURRENT STRING LENGTH LXI H,IBUF+2 RASM1: CALL RACM ;READ ASCII CHAR FROM MODEM CALL WACM ANI 7FH CALL XWACC CALL CLC CPI CR ;JUMP IF CR JZ RASM4 CPI 'H'-40H ;JUMP IF NOT BACKSPACE JNZ RASM2 INR C ;IGNORE IF AT START OF LINE DCR C JZ RASM1 DCR C ;DECREMENT COUNT DCX H ;DECREMENT POINTER CALL WACM ;ECHO BS TO MODEM CALL XWACC JMP RASM1 ;LOOP UNTIL CR RASM2: CPI 'U'-40H ;JUMP IF NOT CTRL-U JNZ RASM3 MVI A,CR ;WRITE END OF LINE TO MODEM CALL WACM CALL XWACC MVI A,LF CALL WACM CALL XWACC LXI H,IBUF+2 ;RESET INPUT BUFFER MVI C,0 JMP RASM1 RASM3: MOV M,A ;STORE CHAR IN BUFFER INX H ;INCREMENT POINTER INR C ;INCREMENT COUNT MOV A,C Š CMP B ;LOOP IF STILL ROOM JC RASM1 RASM4: MOV A,C ;SAVE BUFFER COUNT STA IBUF+1 LXI H,IBUF+2 ;RESET INPUT BUFFER POINTER SHLD IBUFP POP B POP D POP H RET ;; RASC - READ ASCII STRING FROM CONSOLE ; RASC: PUSH H PUSH D PUSH B LXI D,IBUF MVI C,RSFC CALL ENTRY LXI H,IBUF+2 ;RESET INPUT BUFFER POINTER SHLD IBUFP POP B POP D POP H RET ;; GNC - GET NEXT CHARACTER FROM IBUF ; ; ENTRY CONDITIONS ; ; IBUFP POINTS TO NEXT CHAR IN IBUF ; ; IBUFC CONTAINS # OF CHARS LEFT ; ; EXIT CONDITIONS ; ; IBUFP INCREMENTED BY ONE ; ; IBUFC DECREMENTED BY ONE ; ; A RETURNED CHARACTER ; ; C-FLAG SET IF END OF LINE GNC: LDA IBUFC ;JUMP IF IBUFC > 0 ORA A JNZ GNC1 STC ;ELSE SET EOL FLAG, EXIT RET GNC1: DCR A ;DECREMENT IBUFC STA IBUFC PUSH H LHLD IBUFP ;FETCH POINTER MOV A,M ;GET CHAR AT POINTER Š INX H ;INCREMENT POINTER SHLD IBUFP POP H STC ;CLEAR EOL FLAG, EXIT CMC RET ;; CCA - CHECK FOR CONSOLE ACTIVITY ; ; EXIT CONDITIONS ; ; A CHARACTER READ, IF ANY ; ; C-FLAG SET IF CHARACTER FOUND CCA: PUSH H PUSH D PUSH B CALL CONST RRC JNC CCAX CALL CONIN STC CCAX: POP B POP D POP H RET ;; WDWC - WRITE DECIMAL WORD TO CONSOLE ; ; ENTRY CONDITIONS ; ; HL VALUE TO WRITE IN DECIMAL WDWC: PUSH H PUSH D PUSH B MVI C,0 ;CLEAR 'DIGIT PRINTED' FLAG LXI D,10000 ;WRITE TEN THOUSANDS DIGIT CALL WNDC LXI D,1000 ;WRITE THOUSANDS DIGIT CALL WNDC LXI D,100 ;WRITE HUNDREDS DIGIT CALL WNDC LXI D,10 ;WRITE TENS DIGIT CALL WNDC LXI D,1 ;WRITE UNITS DIGIT MVI C,1 ;FORCE UNITS DIGIT TO PRINT CALL WNDC POP B POP D POP H RET ;; WNDC - WRITE NEXT DIGIT TO CONSOLE Š; ; ENTRY CONDITIONS ; ; HL VALUE TO PRINT NEXT DIGIT OF ; ; DE DECIMAL ORDER OF MAGNITUDE ; ; C ZERO MEAN LEADING DIGIT NOT YET PRINTED ; ; EXIT CONDITIONS ; ; HL OLD.HL - (OLD.HL / DE) * DE ; ; C SET IF DIGIT PRINTED WNDC: MVI B,0 ;CLEAR COUNT WNDC1: MOV A,L ;HL = HL - DE SUB E MOV L,A MOV A,H SBB D MOV H,A JC WNDC2 ;BRANCH IF HL < 0 INR B ;ELSE INCREMENT COUNT JMP WNDC1 ;AND LOOP WNDC2: DAD D ;ADD DE BACK IN ONCE MOV A,B ;GET COUNT ORA A JNZ WNDC3 ;JUMP IF NON-ZERO INR C ;JUMP IF DIGIT PRINTED ALREADY DCR C JNZ WNDC3 MVI A,' ' ;PRINT A BLANK AND EXIT JMP WACC WNDC3: MVI C,1 ;SET 'DIGIT PRINTED' FLAG ADI '0' ;WRITE DIGIT IN ASCII JMP WACC ;; WHBC - WRITE HEX BYTE TO CONSOLE ; ; ENTRY CONDITIONS ; ; A BYTE TO WRITE IN HEX WHBC: PUSH PSW RRC RRC RRC RRC CALL WHDC POP PSW WHDC: PUSH PSW ANI 0FH CPI 10 JC $+5 Š ADI 7 ADI '0' CALL WACC POP PSW RET ;; WASC - WRITE ASCII STRING TO CONSOLE ; ; ENTRY CONDITIONS ; ; HL FWA OF STRING, TERM. BY ZERO BYTE WASC: MVI C,0 WASC1: MOV A,M ORA A RZ INX H CPI TAB JNZ WASC3 WASC2: MVI A,' ' CALL WACC INR C MOV A,C ANI 7 JNZ WASC2 JMP WASC1 WASC3: CALL WACC INR C CPI LF JNZ WASC1 MVI C,0 JMP WASC1 ;; WEOLC - WRITE END OF LINE TO CONSOLE ; WEOLC: MVI A,CR CALL WACC MVI A,LF JMP WACC ;; WSPC - WRITE SPACES TO CONSOLE ; WSPC: MVI A,' ' ;BLANK WSPCS: CALL WACC DCR B JNZ WSPCS RET ;; WACC - WRITE ASCII CHARACTER TO CONSOLE ; ; ENTRY CONDITIONS ; ; A CHARACTER TO WRITE Š WACC: PUSH H PUSH D PUSH B PUSH PSW MOV B,A LDA COF ORA A JNZ WACC1 MOV C,B CALL CONOUT JMP WACC3 WACC1: DCR A JNZ WACC2 MOV A,B CALL WACM MOV C,B CALL CONOUT JMP WACC3 WACC2: DCR A JNZ WACC3 MOV A,B CALL WACD WACC3: POP PSW POP B POP D POP H RET ;; XWACC - GO DIRECTLY TO CONSOLE ; XWACC: PUSH H PUSH D PUSH B PUSH PSW MOV C,A CALL CONOUT POP PSW POP B POP D POP H RET ;; RACM - READ ASCII CHAR FROM MODEM (WITH OPTIONAL TIMEOUT) ; ; ENTRY CONDITIONS ; ; TIME MILLISECONDS BEFORE TIMEOUT (FFFF=INF.) ; ; EXIT CONDITIONS ; ; A CHARACTER READ (ALL 8 BITS) ; ; C-FLAG SET IF TIMEOUT Š; ; TOC NUMBER OF MILLISECONDS REMAINING RACM: PUSH H LHLD TIME ;RESET TIMEOUT COUNT SHLD TOC RACM1: IN MSTAT ;JUMP IF DATA AVAILABLE ANI RRF JNZ RACM2 LHLD TOC ;LOOP IF INF. TIMEOUT INX H MOV A,H ORA L JZ RACM1 DCX H CALL WAIT1 ;WAIT ANOTHER MILLISECOND DCX H ;DECREMENT COUNT SHLD TOC MOV A,H ;LOOP IF STILL NON-ZERO ORA L JNZ RACM1 POP H XRA A ;RETURN NULL CHAR STC ;SET TIMEOUT FLAG RET RACM2: IN MDATA ;READ DATA FROM MODEM POP H STC ;CLEAR TIMEOUT FLAG CMC RET ;; WACM - WRITE ASCII CHAR TO MODEM ; ; ENTRY CONDITIONS ; ; A CHARACTER TO WRITE (ALL 8 BITS) WACM: PUSH PSW WACM1: IN MSTAT ANI TRE JZ WACM1 POP PSW OUT MDATA RET ;; CJV - CREATE (BIOS) JUMP VECTOR ; CJV: LHLD 0001H ;HL = FWA OF REAL VECTOR DCX H DCX H DCX H LXI D,BOOT ;FWA OF LOCAL VECTOR LXI B,13*3 ;NUMBER OF BYTES TO MOVE JMP MOVE ;COPY REAL VECTOR INTO LOCAL ONE Š ;; MOVE - MOVE BLOCK OF MEMORY ; ; ENTRY CONDITIONS ; ; HL FWA OF SOURCE BLOCK ; ; DE FWA OF DESTINATION AREA ; ; BC NUMBER OF BYTES TO MOVE MOVE: MOV A,B ORA C RZ MOV A,M INX H STAX D INX D DCX B JMP MOVE ;; WAIT50 - WAIT 50 MS ; WAIT50: PUSH PSW PUSH H LXI H,2776 WAIT51: DCX H MOV A,H ORA L JNZ WAIT51 POP H POP PSW RET ;; WAIT1 - WAIT 1 MS ; WAIT1: PUSH PSW PUSH H LXI H,55 WAIT11: DCX H MOV A,H ORA L JNZ WAIT11 POP H POP PSW RET ;; CR1ON - TURN ON BIT(S) ON MODEM CONTROL REG. ONE ; ; ENTRY CONDITIONS ; ; B ONES IN POSITIONS TO TURN ON ŠCR1ON: PUSH PSW LDA CR1 ORA B STA CR1 OUT MSTAT POP PSW RET ;; CR1OFF - TURN BIT(S) OFF ON MODEM CONTROL REG. ONE ; ; ENTRY CONDITIONS ; ; B ONES IN POSITIONS TO TURN OFF CR1OFF: PUSH PSW MOV A,B CMA MOV B,A LDA CR1 ANA B STA CR1 OUT MSTAT POP PSW RET ;; CR2ON - TURN ON BIT(S) ON MODEM CONTROL REG. TWO ; ; ENTRY CONDITIONS ; ; B ONES IN POSITIONS TO TURN ON CR2ON: PUSH PSW LDA CR2 ORA B STA CR2 OUT MCTRL POP PSW RET ;; CR2OFF - TURN BIT(S) OFF ON MODEM CONTROL REG. TWO ; ; ENTRY CONDITIONS ; ; B ONES IN POSITIONS TO TURN OFF CR2OFF: PUSH PSW MOV A,B CMA MOV B,A LDA CR2 ANA B STA CR2 OUT MCTRL POP PSW RET Š ;; CLC - CONVERT LOWER CASE (TO UPPER CASE) ; ; ENTRY CONDITIONS ; ; A CHARACTER TO CONVERT CLC: CPI 'A'+20H RC CPI 'Z'+20H+1 RNC SUI 20H RET MSG0: DB 'CLINK V3.0',CR,LF,0 MSG1: DB 'FILE NOT FOUND',CR,LF,0 MSG2: DB 'DIRECTIVE ERROR',CR,LF,0 MSG3: DB 'NO CARRIER DETECTED',CR,LF,0 MSG4: DB 'CARRIER LOST',CR,LF,0 MSG5: DB 'NOW DIALING ',0 MSG7: DB 'LINK TERMINATED',CR,LF,0 MSG8: DB 'LINK INTERRUPTED, CARRIER STILL PRESENT',CR,LF,0 MSG9: DB 'CARRIER ALREADY PRESENT, LINK RESUMED',CR,LF,0 MSG10: DB CR,LF,'COMMAND>',0 MSG11: DB ' PARITY ERRORS',CR,LF,0 MSG12: DB ' OVERRUN ERRORS',CR,LF,0 MSG13: DB ' FRAME ERRORS',CR,LF,0 MSG14: DB 'ENTER DIRECTIVES - END WITH EMPTY LINE',CR,LF,0 MSG15: DB ' TRANSMISSION ERRORS',CR,LF,0 MSG16: DB 'MEMORY BUFFER EMPTY',CR,LF,0 MSG17: DB 'DISK FULL',CR,LF,0 MSG18: DB 'WRITE ERROR',CR,LF,0 MSG19: DB BEL,BEL,BEL,CR,LF,'*** MEMORY OVERFLOW ***',CR,LF,0 MSG20: DB ' | ',0 MSG21: DB 'NONE',CR,LF,0 MSG22: DB 'EVEN',CR,LF,0 MSG23: DB 'ODD ',CR,LF,0 MSG24: DB 'ORIGINATE',CR,LF,0 MSG25: DB 'ANSWER',CR,LF,0 MSG26: DB 'FULL',0 MSG27: DB 'HALF',0 MSG28: DB '110',CR,LF,0 MSG29: DB '300',CR,LF,0 MSG30: DB 'ON ',0 MSG31: DB 'OFF',0 MSG32: DB 'FILE TRANSMITTED',CR,LF,0 MSG33: DB 'FILE RECEIVED',CR,LF,0 MSG34: DB 'RETRANSMITTING',CR,LF,0 MSG35: DB 'TIMEOUT OCCURED',CR,LF,0 MSG36: DB 'INVALID CRC',CR,LF,0 MSG37: DB 'UNKNOWN MESSAGE TYPE',CR,LF,0 MSG38: DB 'SEND ABORTED',CR,LF,0 HMSG0: DB 'HELP FOR CLINK IS AVAILABLE UNDER 3 HEADINGS,',CR,LF DB 'AND MAY BE ACCESSED BY THE COMMAND HELP N ',CR,LF Š DB 'WHERE N IS AN INTEGER FROM 1 TO 3 AS FOLLOWS:',CR,LF DB CR,LF DB ' 1 - TERMINAL CONFIGURATION DIRECTIVES',CR,LF DB ' 2 - LOCAL COMMANDS',CR,LF DB ' 3 - ASR FILE TRANSMISSION/RECEPTION',CR,LF DB 0 HMSG1: DB 'SITE NAME OF REMOTE SITE',CR,LF DB 'PHONE NUMBER OF REMOTE SITE',CR,LF DB 'BAUD 300,110 SET BAUD RATE',CR,LF DB 'PARITY EVEN,ODD,NONE SET PARITY',CR,LF DB 'DBITS 7,8 SET # OF DATA BITS',CR,LF DB 'SBITS 1,2 SET NUMBER OF STOP BITS',CR,LF DB 'MODE ORIG,ANS SET CARRIER FREQS, ETC.',CR,LF DB 'DUPLEX FULL,HALF REMOTE/LOCAL ECHO',CR,LF DB 'AUTOLF OFF,ON AUTO LF AFTER RCVD CR',CR,LF DB 'CAPS OFF,ON AUTO LC TO UC TRANSLATION',CR,LF DB 'ESCAPE (HEX VALUE) SET LOCAL ESCAPE CODE',CR,LF DB 'REMESC (HEX VALUE) SET REMOTE ESCAPE CODE',CR,LF DB 'ERROR (HEX VALUE) SET ERROR SUBST. CODE',CR,LF DB 'BREAK (HEX VALUE) SET BREAK TRIGGER CODE',CR,LF DB 0 HMSG2: DB 'RETURN RETURN TO CP/M',CR,LF DB 'ABORT DISCONNECT, RETURN TO CP/M',CR,LF DB 'ERROR SUMMARY REQUEST ERROR SUMMARY',CR,LF DB 'RESET CLEAR ERROR COUNTS',CR,LF DB 'DEBUG OFF,ON HEX DISPLAY OF RCVD DATA',CR,LF DB 'LIST LIST CURRENT CONFIGURATION',CR,LF DB 'SAVE D:FN.FT SAVE CONFIGURATION ON FILE',CR,LF DB 'DIR AFN SAME AS CP/M DIR COMMAND',CR,LF DB 0 HMSG3: DB 'CAPTURE START CAPTURING RCVD DATA',CR,LF DB 'WRITE D:FN.FT WRITE CAPTURED DATA TO FILE',CR,LF DB 'READ D:FN.FT READ FILE, SEND TO MODEM',CR,LF DB 'GARBAGE (HEX VALUE) IGNORE N CHARS AFTER LF',CR,LF DB 'EXPAND OFF,ON EXPAND TABS DURING READ',CR,LF DB 'SEND D:FN.FT TRANSMIT FILE WITH PROTOCOL',CR,LF DB 'RECV D:FN.FT RECEIVE FILE WITH PROTOCOL',CR,LF DB 'BLOCK N SET MESSAGE SIZE IN PAGES',CR,LF DB 0 ; LOCAL BIOS JUMP VECTOR BOOT: DS 3 WBOOT: DS 3 CONST: DS 3 CONIN: DS 3 CONOUT: DS 3 LIST: DS 3 PUNCH: DS 3 READER: DS 3 HOME: DS 3 SELDSK: DS 3 ŠSETTRK: DS 3 READ: DS 3 WRITE: DS 3 ; SCRATCH RAM AREA OLDSP: DS 2 ;ENTRY STACK POINTER STACK: DS 128 ;LOCAL STACK SIZE: DS 2 ;SCRATCH LOCATION CCPF: DS 1 ;CCP OVERWRITE FLAG COF: DS 1 ;CONSOLE OUTPUT FLAG (FOR WACC) CR1: DS 1 ;CONTROL REGISTER ONE (BUFFER) CR2: DS 1 ;CONTROL REGISTER TWO (BUFFER) CCHAR: DS 1 ;CONSOLE CHARACTER BUFFER MCHAR: DS 1 ;MODEM CHARACTER BUFFER DIBUFC: DS 1 ;DISK INPUT BUFFER COUNT DIBUFP: DS 2 ;DISK INPUT BUFFER POINTER DIBUF: DS 128 ;DISK INPUT BUFFER DOBUFC: DS 1 ;DISK OUTPUT BUFFER COUNT DOBUFP: DS 2 ;DISK OUTPUT BUFFER POINTER DOBUF: DS 128 ;DISK OUTPUT BUFFER SITEL: DS 1 ;LENGTH OF 'SITE' STRING SITE: DS 80 ;SITE STRING PHONEL: DS 1 ;LENGTH OF PHONE STRING PHONE: DS 20 ;PHONE STRING MODE: DS 1 ;MODE - 'A'=ANSWER 'O'=ORIGINATE ECHO: DS 1 ;FULL/HALF DUPLEX FLAG AUTOLF: DS 1 ;AUTO LINE-FEED FLAG CAPS: DS 1 ;CAPS LOCK FLAG ESCAPE: DS 1 ;ESCAPE CODE REMESC: DS 1 ;REMOTE ESCAPE CODE DEBUG: DS 1 ;DEBUG FLAG DEBUGC: DS 1 ;DEBUG COUNT ERROR: DS 1 ;ERROR CODE GARBAGE: DS 1 ;NUMBER OF GARBAGE CHARS TO IGNORE EXPAND: DS 1 ;TAB EXPANSION FLAG CAPTURE: DS 1 ;CAPTURE FLAG BREAK: DS 1 ;BREAK TRIGGER COL: DS 1 ;COLUMN COUNTER FOR TAB EXPANSION PERR: DS 2 ;PARITY ERROR COUNT OERR: DS 2 ;OVERRUN ERROR COUNT FERR: DS 2 ;FRAME ERROR COUNT TERR: DS 2 ;TRANSMISSION ERROR COUNT IBUFL EQU 150 ;INPUT BUFFER LENGTH IBUFP: DS 2 ;INPUT BUFFER POINTER IBUF: DS IBUFL+2 ;INPUT BUFFER ŠIBUFC: EQU IBUF+1 ;INPUT BUFFER COUNT KWBUF: DS 10 ;KEYWORD BUFFER MBUFP: DS 2 ;MEMORY BUFFER POINTER MAXADR: DS 2 ;MAX MEMORY BUFFER ADDRESS CCPADR: DS 2 ;FIRST WORD ADDRESS OF CCP EOF: DS 1 ;END OF FILE FLAG OCNT: DS 2 ;OUTPUT MESSAGE COUNT OCODE: DS 1 ;OUTPUT MESSAGE TYPE ICNT: DS 2 ;INPUT MESSAGE COUNT ICODE: DS 1 ;INPUT MESSAGE TYPE CRC: DS 2 ;CYCLIC REDUNDANY CHECK BLKSZ: DS 1 ;BLOCK SIZE FOR SEND TOC: DS 2 ;TIMEOUT COUNTER TIME: DS 2 ;TIMEOUT INITIAL VALUE ORG ($+127)/128*128 MBUF EQU $ ;START OF MEMORY BUFFER MBUF2 EQU MBUF+1024 ;START OF SECOND BUFFER DW 00H END CLINK