; RTTY.ASM Version 2.0 By G.F.Reding 02/13/86 ; ; -------------------------------------------------------------- ; ; Ascii to Baudot to Ascii program with buffer to disk and disk ; to buffer routines (taken frop 'PLINK.ASM' by L.E.Hughs ; Randy Suess 12/20/78 ; ; -------------------------------------------------------------- ; ; 02/13/86 Program and version upgrade ; v 3.1 by G.F.Reding [72436,45] ; ; Capture to memory may be toggled on or off as desired. ; ; Transmit text file and write to disk options prompt for the ; drive in addition to the filename. ; ; Baudot or ascii receive/transmit modes may be selected, with ; the program initially starting in baudot mode. Upon change of ; mode, the bits/parity are changed, speed is set to the lowest ; rate for the appropriate mode, and a flag is appropriately set ; which determines if ascii/baudot or ascii/baudot conversion is ; to be performed and it's also used in the speed display/change ; routines. ; ; The speed may be viewed and/or changed. If change is desired, ; the speed is stepped up to the next higher rate available for ; the (ascii or baudot) mode. Once the highest rate is reached, ; the next rate will be the lowest rate for the current mode. ; ; The program has been cleaned up and improved. It is comparable ; to version 6.7 of PLINK from which a lot of the routines came. ; Messages are given at most times, making the program fairly ; user-friendly. ; ; Note: Console and serial port i/o is shown for a Zilog SIO. ; ; G.F.Reding [72436,45] ; 02/13/86 ; ; Future upgrades could include a buffered send routine, possibly ; split screen mode of operation for send/receive, 25th line for ; status of the program and/or command options, AMTOR mode, etc. ; Any helpers out there? ; ; -------------------------------------------------------------- ; ; System and program equates ; BASE EQU 0 ; Standard = 0, Alternate 4200H BDOS EQU BASE+5 DBUF EQU BASE+80H ; Default disk buffer address FCB EQU BASE+5CH ; File control block FN EQU 1 ; File name field (rel) FT EQU 9 ; File type field (rel) NR EQU 32 ; Next record field (rel) ; RESDSK EQU 13 ; Reset disk OFFC EQU 15 ; Open file CFFC EQU 16 ; Close file DFFC EQU 19 ; Delete file RRFC EQU 20 ; Read record WRFC EQU 21 ; Write record MFFC EQU 22 ; Make file ; BEL EQU 07H ; Bell LF EQU 0AH ; Line feed CR EQU 0DH ; Carriage return DEL EQU 7FH ; Delete ; ; I/O Port addresses and masks ; COND EQU 60H ; Console data port CONS EQU 61H ; Console status port CRBF EQU 01H ; Receive buffer full (ready) CTBE EQU 04H ; Transmit buffer empty (ready) ; MODD EQU 62H ; Modem data port MODS EQU 63H ; Modem status port MRBF EQU 01H ; Receive buffer full (ready) MTBE EQU 04H ; Transmit buffer empty (ready) ; BRPORT EQU 053H BAUDS EQU 051H MODEW EQU 07EH ; Value for BRPORT ; EV1: EQU 046H ; Reg 4 - even parity, 1 stop NO1: EQU 044H ; Reg 4 - no parity, 1 stop NO5: EQU 048H ; Reg 4 - no parity, 1.5 stop RX5: EQU 001H ; Reg 3 - 5 bit, rx enable RX7: EQU 041H ; Reg 3 - 7 bit, rx enable RX8: EQU 0C1H ; Reg 3 - 8 bit, rx enable TX5: EQU 08AH ; Reg 5 - dtr, rts, tx on, 5 bit TX7: EQU 0AAH ; Reg 5 - dtr, rts, tx on, 7 bit TX8: EQU 0EAH ; Reg 5 - dtr, rts, tx on, 8 bit ; ; ; Command control characters ; KYEXIT EQU 'E'-40H ; Exit program to CPM KYMODE EQU 'A'-40H ; Mode (baudot/ascii) toggle KYABRT EQU 'C'-40H ; Abort file transmit KYSPED EQU 'R'-40H ; Speed display/change (steps) KYTRAN EQU 'T'-40H ; Transmit text file from disk KYCAPT EQU 'Y'-40H ; Ascii capture (yank) toggle KYWRIT EQU 'W'-40H ; Write to disk (disables capture) ; ; ; EQUATES FOR THE BAUDOT SEND/RECEIVE ROUTINES ; ALTM: EQU 7DH ; Alternate mode key ; FIGS: EQU 1BH ; Baudot 'figs' LTRS: EQU 1FH ; Baudot 'ltrs' SPACE: EQU 04H ; Baudot 'space' ; CNTA: EQU 01H ; Control a CNTB: EQU 02H ; Control b CNTC: EQU 03H ; Control c CNTE: EQU 05H ; Control e CNTH: EQU 08H ; Control h CNTI: EQU 09H ; Control i CNTO: EQU 0FH ; Control o CNTV: EQU 16H ; Control v CNTX: EQU 18H ; Control x CNTZ: EQU 1AH ; Control z ; ASPC: EQU 20H ; Ascii space APOS: EQU 27H ; Apostrophe ATSN: EQU 40H ; "at" SIGN EQL: EQU 3DH ; Equals sign ESCP: EQU 1BH ; Escape key GRTH: EQU 3EH ; Greater-than sign LARW: EQU 5FH ; Left arrow LBKT: EQU 5BH ; Left bracket LETH: EQU 3CH ; Less-than sign PCT: EQU 25H ; Percent sign PLUS: EQU 2BH ; Plus sign RBKT: EQU 5DH ; Right bracket RESL: EQU 5CH ; Reverse slant STAR: EQU 2AH ; Asterisk UARW: EQU 5EH ; Up-arrow ; CRX: EQU 48H LFX: EQU 42H ; ; ; MAIN PROGRAM ; ORG BASE+100H ; LINK: LXI H,0 ; Save old stack ptr DAD SP SHLD OLDSP LXI SP,STACK+64 ; Create local stack ; LINK2: LXI H,TBUF ; Set ptr to tbuf SHLD PTR LXI H,0 ; Size = 0 SHLD SIZE LXI H,LINK1M ; Signon and help message CALL WCS ; Print it CALL MDIN5N ; 5 bit no parity 1.5 stop CALL MDSTB1 ; Set low baudot rate LXI H,MODEBM ; Baudot mode message CALL WCS ; Print it ; ; ; MAIN LOOP ; LINK3: IN CONS ; Get console status ANI CRBF JZ LINK4 ; Jump if no data IN COND ; Else read console data OUT COND ; Echo to terminal ANI 7FH ; Call pcc if control char CPI 20H CC PCC1 JC LINK4 ; Jump if pcc handled char ORI 80H ; Else set valid data bit STA INCH ; Store in input char buffer ; LINK4: LDA OUTCH ; Get data for console ORA A JP LINK5 ; Jump if no data for console ANI 7FH ; Else discard valid data bit OUT COND ; And output char to console XRA A ; Then clear output char buffer STA OUTCH ; LINK5: IN MODS ; Get status ANI MRBF JZ LINK6 ; Jump if no data from rtty CALL RMC ; Call rtty read routine CALL SAVE ; Save char in text buffer if flag on ORI 80H ; Set data valid bit STA OUTCH ; Store in output char buffer ; LINK6: IN MODS ; Get status ANI MTBE JZ LINK3 ; Jump if rtty xmit buffer busy LDA INCH ; Jump if no data for rtty ORA A JP LINK3 ANI 7FH ; Else discard valid data bit ; CPI CR ; For each cr to send JNZ LINK7 MVI A,CR ; Added code CALL WMC ; To send two cr CALL WMC MVI A,LF ; And one lf OUT COND ; Echo lf to console ; LINK7: CALL WMC XRA A ; Then clear input char buffer STA INCH JMP LINK3 ; End of main loop ; ; ; PCC - PROCESS CONTROL CHARACTER ; PCC1: CPI KYEXIT ; Exit program? JNZ PCC2 ; No, check more PUSH H LXI H,EXIT1M ; Exit confirm message CALL WCS ; Print it POP H CALL RCC ; Get answer CALL WCC ; Echo it ANI 5FH ; Make upper case CPI 'Y' ; If yes JZ PCC1A ; Then continue exit CALL WCCR ; Else cr/lf LXI H,EXITNM ; No exit message CALL WCS ; Print it STC ; Ignore the char RET ; PCC1A: PUSH H LHLD SIZE ; Get capture buffer size MOV A,L ; Check ORA H ; If anything there JZ PCC1B ; No, exit simply LXI H,EXIT2M ; Save buffer message CALL WCS ; Print it POP H CALL RCC ; Get save answer CALL WCC ; Echo it ANI 5FH ; Make upper case CPI 'Y' ; If yes CZ WTB ; Then save the buffer JMP PCC1C ; And exit ; PCC1B: POP H PCC1C: LXI H,EXITYM ; Exit to cp/m message CALL WCS ; Print it CALL MDIN8N ; Reset to 8 bit no parity 1 stop CALL MDSTA6 ; 1200 baud LHLD OLDSP ; Clean up act, exit to cp/m SPHL RET ; PCC2: CPI KYTRAN ; Transmit a file? JNZ PCC3 CALL STF ; Send ascii file to rtty STC ; Ignore the char RET ; PCC3: CPI KYMODE ; Change mode? JNZ PCC4 ; No, check more LDA FLAGM DCR A ; Was the flag zero JNZ PCC3A ; Yes, so go set to 1 STA FLAGM ; No, was 1, now zero CALL MDIN5N ; 5 bit no parity 1.5 stop CALL MDSTB1 ; Set low baudot rate LXI H,MODEBM ; Baudot mode message JMP PCC3B ; PCC3A: MVI A,1 ; Turn on capture flag STA FLAGM CALL MDIN7E ; 7 bit even parity 1 stop CALL MDSTA1 ; Set low ascii rate LXI H,MODEAM ; Ascii mode message PCC3B: CALL WCS ; Print it STC ; Ignore the char RET ; PCC4: CPI KYCAPT ; Yank (capture)? JNZ PCC5 ; No, check more LDA FLAGC DCR A ; Was the flag zero JNZ PCC4A ; Yes, so go set to 1 STA FLAGC ; No, was 1, now zero LXI H,CAPTNM ; Capture off message JMP PCC4B ; PCC4A: MVI A,1 ; Turn on capture flag STA FLAGC LXI H,CAPTYM ; Capture on message PCC4B: CALL WCS ; Print it STC ; Ignore the char RET ; PCC5: CPI KYWRIT ; Write buffer? JNZ PCC6 ; No, check more XRA A ; Turn off capture flag STA FLAGC CALL WTB ; Write text buffer to disk STC ; Ignore the char RET ; PCC6: CPI KYSPED ; Speed change? JNZ PCC7 ; No, invalid command CALL MDTELL ; Display and/or change speed STC ; Ignore the char RET ; PCC7: STC ; Link handle all other ctrl chars CMC RET ; ; STF - SEND TEXT FILE (TO RTTY) ; STF: CALL GFN ; Get file name to send JC STF6 ; Jump if file name error CALL OPEN ; Try to open specified file CPI 255 ; Jump if file not found JZ STF7 XRA A ; Else rewind file and continue STA FCB+NR ; STF1: CALL READ ; Read next record into dbuf CPI 1 ; Jump if end-of-file JZ STF5 LXI H,DBUF ; Point to disk buffer MVI C,128 ; STF2: MOV A,M ; Fetch next char from dbuf INX H CPI 'Z'-40H ; Jump if end-of-file char JZ STF5 CALL WMC ; Write char to rtty CALL WCC ; Write char to console IN CONS ; Get console status ANI CRBF ; Anything there JZ STF4 ; No, skip over IN COND ; Else get the char ANI 7FH ; Strip parity CPI KYABRT ; Check for ctrl c abort JZ STF8 ; STF4: DCR C ; Loop thru rest of dbuf JNZ STF2 JMP STF1 ; Go get next record from disk ; STF5: CALL CLOSE ; Clean up act LXI H,STFS1M ; Transfer complete message CALL WCS ; Print it RET ; STF6: LXI H,STFS2M ; File name error message CALL WCS ; Print it RET ; STF7: LXI H,STFS3M ; File not found message CALL WCS ; Print it RET ; STF8: CALL CLOSE ; Clean up act LXI H,STFS4M ; Transfer aborted message CALL WCS ; Print it RET ; ; ; SAVE - SAVE CHAR IN TEXT BUFFER IF FLAG ON ; ; ENTRY: A - CHARACTER TO SAVE ; SAVE: PUSH PSW LDA FLAGC ORA A JNZ SAVE1 POP PSW RET ; SAVE1: POP PSW ANI 7FH ; Discard parity bit RZ ; Return if char is a null ; SAVE2: PUSH H LHLD SIZE ; Get the size INX H ; Increment it SHLD SIZE ; Size = size + 1 LHLD PTR ; Get capture buffer ptr MOV M,A ; Put char into buffer INX H ; Point to next addr SHLD PTR ; Store it PUSH PSW LDA BASE+7 ; Get system size SUI 1 ; So we don't crash cp/m CMP H ; Are we out of room? JZ SAVE3 ; Yes, abort SUI 4 ; Leave some room (1k) CMP H ; Are we low on memory LXI H,SAVE1M ; Memory low message CC WCS ; Print it POP PSW POP H RET ; SAVE3: LXI SP,STACK+64 ; Reinitialize the stack LXI H,SAVE2M ; Aborted - no memory message CALL WCS ; Print it LXI H,LINK ; Set up return address PUSH H ; Leave it on stack ; ; ; WTB - WRITE TEXT BUFFER TO DISK ; WTB: LHLD SIZE ; Jump if text buffer empty MOV A,L ORA H JZ WTB5 CALL GFN ; Get file name JC WTB6 ; Jump if file name error MVI C,RESDSK ; Reset disk in case r/o CALL BDOS ; Or error recovery CALL DELT ; Delete old file, if any CALL MAKE ; Make new file XRA A ; Rewind file STA FCB+NR LHLD SIZE ; De = tbuf size XCHG LXI H,DBUF ; Top of stack points to dbuf PUSH H LXI H,TBUF ; Hl points to tbuf ; WTB1: MVI C,128 ; Disk buffer size ; WTB2: MOV A,M ; Fetch next byte of tbuf INX H XTHL MOV M,A ; Store in dbuf INX H XTHL DCX D ; Size = size - 1 MOV A,D ; Exit loop if size = 0 ORA E JZ WTB3 DCR C ; Loop until dbuf full JNZ WTB2 CALL WRITE ; Write full dbuf to disk CPI 0 ; Did we have an error? JNZ WTB4B ; If so, bail out XTHL ; Top of stack points to dbuf LXI H,DBUF XTHL JMP WTB1 ; Loop until end of tbuf ; WTB3: POP H ; Hl points to current place in dbuf ; WTB4: MVI M,'Z'-40H ; Store eof code INX H DCR C ; Loop thru rest of dbuf JNZ WTB4 CALL WRITE ; Write last sector to disk CPI 0 ; Error? JNZ WTB4B ; If so handle it CALL CLOSE ; Else clean up act LXI H,TBUF ; Clear text buffer SHLD PTR LXI H,0 ; Set the size to zero SHLD SIZE LXI H,WTBS1M ; Saved, capture off message CALL WCS ; Print it RET ; WTB4B: LXI H,WTBS2M ; Error writing - disk full msg CALL WCS ; Print it JMP WTB ; And try again ; WTB5: LXI H,WTBS3M ; Buffer empty message CALL WCS ; Print it RET ; WTB6: LXI H,WTBS4M ; File name error message CALL WCS ; Print it RET ; ; ; WCS - WRITE CONSOLE STRING ; ; ENTRY: HL - POINTS TO NUL TERMINATED STRING ; WCS: MOV A,M INX H ORA A RZ CALL WCC JMP WCS ; ; WCCR - WRITE CONSOLE CARRIAGE RETURN (AND LINE FEED) ; WCCR: MVI A,CR CALL WCC MVI A,LF ; ; ; WCC - WRITE CONSOLE CHARACTER ; ; ENTRY: A - CHARACTER TO WRITE ; WCC: PUSH PSW WCC1: IN CONS ANI CTBE JZ WCC1 POP PSW OUT COND RET ; ; ; RCS - READ CONSOLE STRING (WITH ECHO) ; ; EXIT: B - NUMBER OF CHARS READ (<255) ; HL - POINTS TO LAST CHAR STORED (CR) ; RCS: LXI H,IBUF MVI B,0 ; RCS1: CALL RCC ; Read next char from console CPI DEL ; Jump if not del JNZ RCS2 INR B ; Ignore del if ibuf already empty DCR B JZ RCS1 DCX H ; Else discard last char MOV A,M CALL WCC ; Echo it DCR B ; Decrement count JMP RCS1 ; And loop ; RCS2: CPI 'U'-40H ; Jump if not control-u JNZ RCS3 CALL WCCR ; Else abort current line JMP RCS ; And start over ; RCS3: CALL WCC ; Echo it MOV M,A ; Store char in ibuf INR B ; Increment count CPI CR ; Jump if carriage return JZ RCS4 INX H ; Else advance ptr JMP RCS1 ; And loop ; RCS4: MVI A,LF ; Issue line feed CALL WCC ; Echo it RET ; ; ; RCC - READ CONSOLE CHARACTER ; ; EXIT: A - CHARACTER READ ; RCC: IN CONS ANI CRBF JZ RCC IN COND ANI 7FH RET ; ; ; WMC - WRITE RTTY CHARACTER ; ; ENTRY: A - CHARACTER TO WRITE ; WMC: PUSH B ; Save registers PUSH H PUSH PSW LDA FLAGM ; Get mode flag CPI 1 ; Is it 1 JZ WMC1 ; Yes, ascii mode JMP STTY1 ; No, baudot mode ; WMC1: IN MODS ; Get status ANI MTBE ; Transmit buffer empty? JZ WMC1 ; If not, loop and wait POP PSW ; Get char PUSH PSW ; Resave ANI 7FH OUT MODD ; Send the char POP PSW ; Restore registers POP H POP B RET ; ; ASCXMT(4) REV. 2 BY KEITH PETERSEN, W8SDZ. 10/29/78. ; ; This program is for transmitting ascii through a baudot medium ; use a special format of figures blank (X) - where (X) is a ; special baudot character used to convey the ascii equivalent ; character to the receiving end where it is then converted back ; to ascii again. Lower case alpha characters are transmitted ; via a 4th case, ltrs blank (X). ; ; Call with ascii character in accumulator. ; STTY1: POP PSW ; Get char PUSH PSW ; Resave ; MVI C,0 ; Set up counter ANI 7FH ; Strip parity bit CPI ALTM ; Alternate mode key? JNZ STTY2 ; No, ignore next routine MVI A,09H ; Baudot '$' JMP STTY3 ; STTY2: CPI 7BH ; Above l.c. 'z' ? JNC STTY7 ; If so, ignore it LXI H,BTABLE ; Point to table start ADD L ; Add char value MOV L,A ; L points to baudot char. MOV A,H ; Get h for correction ACI 0 ; Correct if necessary MOV H,A ; H is now correct MOV A,M ; Get baudot char ORA A ; Is it a non-printing char? JZ STTY7 ; If so ignore it CPI CRX ; Is it a carriage return? JZ STTY5 ; Yes, handle without case test CPI LFX ; Is it a line feed? JNZ STTY3 ; No, ignore next routine MVI A,LTRS PUSH PSW ; Save it on stack MVI A,LFX LXI H,SCASE ; Point to present case reg. MVI M,40H ; Set it to lower case JMP STTY4 ; Send lf and ltrs ; STTY3: PUSH PSW ; Save char ANI 0C0H ; Strip all but case bits LXI H,SCASE ; Point to present case reg. CMP M ; Same case as previous char? JZ STTY6 ; Yes no change necessary MOV M,A ; Update case register ORA A JZ STTYTC CPI 80H JZ STTYUC CPI 0C0H JNZ STTYLC ; STTYFC: XRA A ; Get a baudot 'blank' PUSH PSW ; Save it on the stack INR C ; Increment char count ; STTYLC: MVI A,LTRS JMP STTY4 ; STTYTC: XRA A ; Get a baudot 'blank' PUSH PSW ; Save it on the stack INR C ; Increment char count ; STTYUC: MVI A,FIGS STTY4: INR C ; Increment char count STTY5: PUSH PSW ; Save it on the stack ; STTY6: IN MODS ; Baudot uart status ANI MTBE ; Trans. buffer empty? JZ STTY6 ; If not, loop and wait POP PSW ; Get char ; ORI 0E0H ; Make upper 3 bits marking OUT MODD ; Send to baudot port DCR C ; More to send? JP STTY6 ; Yes, continue sending ; STTY7: POP PSW ; Restore registers POP H POP B RET ; ; ; RMC - READ RTTY CHARACTER ; ; EXIT: A - CHARACTER READ ; RMC: PUSH H ; Save hl LDA FLAGM ; Get mode flag CPI 1 ; Is it 1 JZ RMC1 ; Yes, ascii mode JMP RTTY1 ; No, baudot mode ; RMC1: IN MODD ; Get char ANI 7FH POP H ; Restore hl RET ; ; ASCRCV(4), VER. 2 BY KEITH PETERSEN, W8SDZ. 10/30/78. ; ; This is a program to change ascii-coded-baudot to ascii. ; The routine returns with a 0FFH in the 'A' register if ; character it to be ignored. Otherwise it returns with ; the ascii character in the 'A' register. It is assumed ; that a status test has been done before calling this ; routine to determine that a baudot character is available. ; RTTY1: LHLD CASAVE ; Get present case ; IN MODD ; Get baudot char ANI 1FH ; Baudot chars only CPI FIGS JZ RTTYUC CPI LTRS JZ RTTYLC ORA A ; Baudot 'blank' ? JZ RTTYTC CPI SPACE JNZ RTTY2 LXI H,LTABLE ; Space gives lower case ; RTTY2: SHLD CASAVE ; Save present case ADD L ; Add char. to table adrs. MOV L,A ; L points to ascii char. MOV A,H ; Get h for correction ACI 0 ; See if correction needed MOV H,A ; H is correct now XRA A ; Put zero in a reg. STA FLAGR ; Clear ltrs-figs last flag MOV A,M ; Get ascii equivalent POP H ; Restore hl registers ORA A ; Is it printable? RNZ ; Yes, valid char. return CMA ; Make 0ffh 'ignore flag' RET ; Return to calling program ; RTTYLC: LXI H,LTABLE ; Lower case table address JMP SETFLG ; Set ltrs last flag, exit ; RTTYUC: LXI H,UTABLE ; Upper case table address JMP SETFLG ; Set figs last flag, exit ; RTTYTC: LDA FLAGR ; Get shift reminder flag CPI FIGS JNZ RTTYFC LXI H,TTABLE ; Third case table address JMP CLRFLG ; RTTYFC: CPI LTRS ; Check for ltrs last JNZ CLRFLG LXI H,FTABLE ; Fourth case table address ; CLRFLG: XRA A ; Ready to clear flag ; SETFLG: STA FLAGR ; Ltrs-figs last flag SHLD CASAVE ; Save present case MVI A,0FFH ; 'ignore flag' POP H ; Restore hl regs. RET ; Return to program ; ; ; Get drive and filename ; GFN: XRA A ; Initialize the fcb STA FCB LXI H,FCB+12 ; Zero the fcb to its end MVI C,21 CALL ZEROM ; LXI H,GFNS1M ; Which drive message CALL WCS ; Print it CALL RCC ; Get answer from console CALL WCC ; Echo it ANI 5FH ; Make upper case CPI 'C'-40H ; Control c abort JZ GFN6 SUI 'A'-1 JC GFN ; Require alphabetic JZ GFN CPI 6 ; Allow 5 drives (cp/m 2.x max 16) JNC GFN STA FCB ; Store it ; LXI H,GFNS2M ; Filename message CALL WCS ; Print it CALL RCS ; Read response into ibuf LXI H,FCB+FN ; Blank fill fn and ft fields MVI C,11 ; GFN1: MVI M,' ' INX H DCR C JNZ GFN1 LXI H,IBUF ; Point to input buffer LXI D,FCB+FN ; Scan off fn field MVI C,9 ; GFN2: MOV A,M ; Fetch next char from ibuf INX H CPI 61H ; If lc, convert to uc JC GFN2A SUI 20H ; GFN2A: CPI CR ; Jump if end of line JZ GFN5 CPI '.' ; Jump if end of name JZ GFN3 STAX D ; Else store char in fn field INX D DCR C ; Loop if 8 or less chars so far JNZ GFN2 JMP GFN6 ; Else take error exit ; GFN3: LXI D,FCB+FT ; Scan off ft field MVI C,4 ; GFN4: MOV A,M ; Fetch next char from ibuf INX H CPI 61H ; If lc, convert to uc JC GFN4A SUI 20H ; GFN4A: CPI CR ; Jump if end of line JZ GFN5 STAX D ; Else store char in ft field INX D DCR C ; Loop if 3 or less chars so far JNZ GFN4 JMP GFN6 ; Else take error exit ; GFN5: STC ; Clear error flag and return CMC RET ; GFN6: STC ; Set error flag and return RET ; ; ZEROM: MVI M,0 ; Zero memory, length in c INX H DCR C JNZ ZEROM RET ; ; OPEN - OPEN DISK FILE ; OPEN: PUSH H PUSH D PUSH B LXI D,FCB MVI C,OFFC CALL BDOS POP B POP D POP H RET ; ; READ - READ RECORD FROM DISK FILE ; READ: PUSH H PUSH D PUSH B LXI D,FCB MVI C,RRFC CALL BDOS POP B POP D POP H RET ; ; CLOSE - CLOSE DISK FILE ; CLOSE: PUSH H PUSH D PUSH B LXI D,FCB MVI C,CFFC CALL BDOS POP B POP D POP H RET ; ; DELT - DELETE DISK FILE ; DELT: PUSH H PUSH D PUSH B LXI D,FCB MVI C,DFFC CALL BDOS POP B POP D POP H RET ; ; WRITE - WRITE RECORD TO DISK ; WRITE: PUSH H PUSH D PUSH B LXI D,FCB MVI C,WRFC CALL BDOS POP B POP D POP H RET ; ; MAKE - MAKE NEW DISK FILE ; MAKE: PUSH H PUSH D PUSH B LXI D,FCB MVI C,MFFC CALL BDOS POP B POP D POP H RET ; ; ; Show the modem speed, prompt for change ; MDTELL: LDA FLAGM ; Get mode flag CPI 1 ; Is it 1 JZ MDTLA1 ; Yes, ascii mode JMP MDTLB1 ; No, baudot mode ; ; Check and tell the ascii rate ; MDTLA1: LDA MDRATE ; Get the rate flag CPI 1 ; Is it 1 JNZ MDTLA2 ; No, check others LXI H,MDTA1M ; 1st speed message JMP MDTELC ; MDTLA2: CPI 2 ; Is it 2 JNZ MDTLA3 ; No, check others LXI H,MDTA2M ; 2nd speed message JMP MDTELC ; MDTLA3: CPI 3 ; Is it 3 JNZ MDTLA4 ; No, check others LXI H,MDTA3M ; 3rd speed message JMP MDTELC ; MDTLA4: CPI 4 ; Is it 4 JNZ MDTLA5 ; No, check others LXI H,MDTA4M ; 4th speed message JMP MDTELC ; MDTLA5: CPI 5 ; Is it 5 JNZ MDTLA6 ; No, must be 6 LXI H,MDTA5M ; 5th speed message JMP MDTELC ; MDTLA6: LXI H,MDTA6M ; 6th speed message JMP MDTELC ; ; Check and tell the baudot rate ; MDTLB1: LDA MDRATE ; Get the rate flag CPI 1 ; Is it 1 JNZ MDTLB2 ; No, check others LXI H,MDTB1M ; 1st speed message JMP MDTELC ; MDTLB2: CPI 2 ; Is it 2 JNZ MDTLB3 ; No, check others LXI H,MDTB2M ; 2nd speed message JMP MDTELC ; MDTLB3: CPI 3 ; Is it 3 JNZ MDTLB4 ; No, check others LXI H,MDTB3M ; 3rd speed message JMP MDTELC ; MDTLB4: CPI 4 ; Is it 4 JNZ MDTLB5 ; No, must be 5 LXI H,MDTB4M ; 4th speed message JMP MDTELC ; MDTLB5: LXI H,MDTB5M ; 5th speed message JMP MDTELC ; ; MDTELC: CALL WCS ; Print it LXI H,MDCH1M ; Change it (Y) message CALL WCS ; Print it CALL RCC ; Get answer CALL WCC ; Echo it ANI 5FH ; Make upper case CPI 'Y' JNZ MDTELD CALL MDSET0 JMP MDTELL ; Loop, another change? ; MDTELD: CALL WCCR ; Print cr/lf RET ; ; ; MDSET0: LDA FLAGM ; Get mode flag CPI 1 ; Is it 1 JZ MDSETA ; Yes, ascii mode JMP MDSETB ; No, baudot mode ; ; For ascii, check existing rate and step to next ; MDSETA: LDA MDRATE ; Get the rate flag CPI 1 ; Is it 1 JZ MDSTA2 ; If yes, set to next rate CPI 2 ; Else is it 2 JZ MDSTA3 ; If yes, set to next rate CPI 3 ; Else is it 3 JZ MDSTA4 ; Yes, set to next rate CPI 4 ; Else is it 4 JZ MDSTA5 ; Yes, set to next rate CPI 5 ; Else is it 5 JZ MDSTA6 ; Yes, set to next rate JMP MDSTA1 ; No, must be 6, so set low rate ; ; For baudot, check existing rate and step to next ; MDSETB: LDA MDRATE ; Get the rate flag CPI 1 ; Is it 1 JZ MDSTB2 ; If yes, set to next rate CPI 2 ; Else is it 2 JZ MDSTB3 ; If yes, set to next rate CPI 3 ; Else is it 3 JZ MDSTB4 ; If yes, set to next rate CPI 4 ; Else is it 4 JZ MDSTB5 ; If yes, set to next rate JMP MDSTB1 ; No, must be 5, so set low rate ; ; Baud rate for ascii mode ; MDSTA1: XRA A ; Set flag to zero STA MDRATE ; As set bumps it LXI H,BD110 ; 110 baud JMP MDSETX ; MDSTA2: LXI H,BD300 ; 300 baud JMP MDSETX ; MDSTA3: LXI H,BD450 ; 450 baud JMP MDSETX ; MDSTA4: LXI H,BD600 ; 600 baud JMP MDSETX ; MDSTA5: LXI H,BD710 ; 710 baud JMP MDSETX ; MDSTA6: LXI H,BD1200 ; 1200 baud JMP MDSETX ; ; Baud rates for baudot mode ; MDSTB1: XRA A ; Set flag to zero STA MDRATE ; As set bumps it LXI H,BD045 ; 60 wpm = 45.45 baud JMP MDSETX ; MDSTB2: LXI H,BD050 ; 66 wpm = 50 baud JMP MDSETX ; MDSTB3: LXI H,BD057 ; 75 wpm = 57 baud JMP MDSETX ; MDSTB4: LXI H,BD074 ; 100 wpm = 74 baud JMP MDSETX ; MDSTB5: LXI H,BD100 ; 132 wpm = 100 baud JMP MDSETX ; ; Modem speed setup ; MDSETX: MVI A,MODEW OUT BRPORT MOV A,M OUT BAUDS INX H MOV A,M OUT BAUDS ; LDA MDRATE ; Get rate INR A ; And bump it to next higher STA MDRATE ; Store the new value RET ; ; MDIN5N: MVI A,NO5 ; No parity 1.5 stop STA MDINI1 ; Store for reg 4 MVI A,RX5 ; 5 bits, rx enable STA MDINI3 ; Store for reg 3 MVI A,TX5 ; Dtr, rts, tx on, 5 bits STA MDINI4 ; Store for reg 5 JMP MDINI0 ; Do the setup ; MDIN7E: MVI A,EV1 ; Even parity 1 stop STA MDINI1 ; Store for reg 4 MVI A,RX7 ; 7 bits, rx enable STA MDINI3 ; Store for reg 3 MVI A,TX7 ; Dtr, rts, tx on, 7 bits STA MDINI4 ; Store for reg 5 JMP MDINI0 ; Do the setup ; MDIN8N: MVI A,NO1 ; No parity 1 stop STA MDINI1 ; Store for reg 4 MVI A,RX8 ; 8 bits, rx enable STA MDINI3 ; Store for reg 3 MVI A,TX8 ; Dtr, rts, tx on, 8 bits STA MDINI4 ; Store for reg 5 ; ; Main initialization routine used by those above ; MDINI0: MVI A,4 ; Write reg 4 OUT MODS MVI A,NO5 ; No parity, 1.5 stop, 16x MDINI1: EQU $-1 OUT MODS MVI A,1 ; Write reg 1 OUT MODS MVI A,0 OUT MODS MVI A,5 ; Write reg 5 OUT MODS MVI A,0 ; DTR, RTS both off OUT MODS PUSH B ; Save in case used elsewhere MVI B,5 ; 1/2 second delay (10 = 1 sec) MDINI2: CALL DELAY ; 1/10 second delay DCR B JNZ MDINI2 ; Keep looping until finished POP B ; Restore bc MVI A,3 ; Write reg 3 OUT MODS MVI A,RX5 ; 5 bits, enable receive MDINI3: EQU $-1 OUT MODS MVI A,5 ; Write reg 5 OUT MODS MVI A,TX5 ; DTR, RTS, TX on, 5 bits MDINI4: EQU $-1 OUT MODS RET ; Return ; ; 1/10 second delay routine ; DELAY: PUSH B LXI B,4167*4 ; 4167 * system clock mhz DELAY1: DCX B MOV A,B ORA C JNZ DELAY1 POP B RET ; ; ; MESSAGES ; CAPTNM: DB CR,LF,'[Capture OFF]',CR,LF,0 CAPTYM: DB CR,LF,'[Capture ON]',CR,LF,0 ; EXIT1M: DB CR,LF,'Exit to CP/M -- Confirm (Y/N)? ',0 EXIT2M: DB CR,LF,'Save buffer before exit? ',BEL,0 EXITNM: DB CR,LF,'[Exit aborted]',CR,LF,0 EXITYM: DB CR,LF,LF,'[Exit to CP/M]',CR,LF,0 ; LINK1M: DB CR,LF,'RTTY v 3.1' LINK2M: DB CR,LF DB '^',KYTRAN+40H DB ' Transmit ' DB '^',KYWRIT+40H DB ' Write ' DB '^',KYCAPT+40H DB ' Capture ' DB '^',KYSPED+40H DB ' Speed' DB CR,LF DB '^',KYMODE+40H DB ' Mode ' DB '^',KYABRT+40H DB ' Cancel ' DB '^',KYEXIT+40H DB ' Exit' DB CR,LF,LF,0 ; GFNS1M: DB CR,LF,'Which drive? ',0 GFNS2M: DB CR,LF,'Filename? ',0 ; STFS1M: DB CR,LF,'[Transfer complete]',BEL,CR,LF,0 STFS2M: DB CR,LF,'[File name error]',CR,LF,0 STFS3M: DB CR,LF,'[File not found]',CR,LF,0 STFS4M: DB CR,LF,'[Transfer aborted]',CR,LF,0 ; WTBS1M: DB CR,LF,'[Buffer saved - Capture OFF]',CR,LF,0 WTBS2M: DB CR,LF,'[Write error - Disk may be full]' DB CR,LF,'[Change disks - Use other drive]',BEL,CR,LF,0 WTBS3M: DB CR,LF,'[Buffer empty]',CR,LF,0 WTBS4M: DB CR,LF,'[File name error]',CR,LF,0 ; SAVE1M: DB CR,LF,'[Memory LOW]',BEL,CR,LF,0 SAVE2M: DB CR,LF,'[Aborted - NO memory]',BEL,CR,LF,0 ; MODEAM: DB CR,LF,'[Ascii Mode]',CR,LF,0 MODEBM: DB CR,LF,'[Baudot Mode]',CR,LF,0 ; MDTA1M: DB CR,LF,'[ 110 baud]',0 MDTA2M: DB CR,LF,'[ 300 baud]',0 MDTA3M: DB CR,LF,'[ 450 baud]',0 MDTA4M: DB CR,LF,'[ 600 baud]',0 MDTA5M: DB CR,LF,'[ 710 baud]',0 MDTA6M: DB CR,LF,'[1200 baud]',0 ; MDTB1M: DB CR,LF,'[ 60 wpm]',0 MDTB2M: DB CR,LF,'[ 66 wpm]',0 MDTB3M: DB CR,LF,'[ 75 wpm]',0 MDTB4M: DB CR,LF,'[100 wpm]',0 MDTB5M: DB CR,LF,'[132 wpm]',0 MDCH1M: DB ' Change it? ',0 ; ; ; LOWER-CASE TABLE FOR RECEIVE ; LTABLE: DB 0,'E',LF,'A SIU',CR,'DRJNFCK' DB 'TZLWHYPQOBG',FIGS,'MXV' ; ; UPPER-CASE TABLE FOR RECEIVE ; UTABLE: DB 0,'3',LF,'- ',BEL,'87',CR,'$4' DB APOS,',!:(5")2#6019?&',FIGS,'./;' ; ; THIRD-CASE TABLE FOR RECEIVE. USED FOR SPECIAL CHARACTERS. ; THE FIRST COLUMN IN THE TABLE THE ASCII CHARACTER EQUIVALENT. ; THE SECOND COLUMN IS THE SPECIAL CASE BAUDOT CHARACTER ; FROM WHICH THE CONVERSION IS MADE. ; TTABLE: DB 0,CNTC,LF ; BL 3 LF DB LARW,ASPC,ATSN ; - SP BEL DB CNTV,CNTO,CR ; 8 7 CR DB ALTM,CNTE,PCT ; $ 4 ' DB DEL,EQL,ESCP ; , ! : DB LETH,CNTH,LBKT ; ( 5 " DB GRTH,CNTB,STAR ; ) 2 # DB CNTI,CNTZ,CNTA ; 6 0 1 DB CNTX,UARW,PLUS ; 9 ? & DB 0,RBKT,RESL ; FIG . / DB 0 ; ; ; ; FOURTH-CASE TABLE FOR RECEIVE. FOR LOWER-CASE ALPHA CHARS. ; FTABLE: DB 0,65H,LF,61H,ASPC,73H DB 69H,75H,CR,64H,72H,6AH DB 6EH,66H,63H,6BH,74H,7AH DB 6CH,77H,68H,79H,70H,71H DB 6FH,62H,67H,FIGS,6DH,78H DB 76H ; ; ; TABLE FOR SENDING ; BTABLE: DB 5FH,17H,13H ; NUL SOH STX DB 1,0,0AH ; ETX EOT ENQ DB 0,85H,10H ; ACK BEL BS DB 15H,42H,0C2H ; HT LF VT DB 2,48H,0 ; FF CR SO DB 7,0,0 ; SI DLE DC1 DB 0,0,0 ; DC2 DC3 DC4 DB 0,6,0 ; NAK SYN ETB DB 18H,0,16H ; CAN EM SUB DB 0EH,0,0 ; ESC FS GS DB 0,0,44H ; RS US SPACE DB 8DH,91H,94H ; ! " # DB 89H,0BH,9AH ; $ PCT & DB 8BH,8FH,92H ; ' ( ) DB 14H,1AH,8CH ; AS PL , DB 83H,9CH,9DH ; - . / DB 96H,97H,93H ; 0 1 2 DB 81H,8AH,90H ; 3 4 5 DB 95H,87H,86H ; 6 7 8 DB 98H,8EH,9EH ; 9 : ; DB 0FH,0DH,12H ; LT EQ GT DB 99H,5,43H ; ? AT A DB 59H,4EH,49H ; B C D DB 41H,4DH,5AH ; E F G DB 54H,46H,4BH ; H I J DB 4FH,52H,5CH ; K L M DB 4CH,58H,56H ; N O P DB 57H,4AH,45H ; Q R S DB 50H,47H,5EH ; T U V DB 53H,5DH,55H ; W X Y DB 51H,11H,1DH ; Z LB LS DB 1CH,19H,3 ; RB UA LA ; ; THESE ARE THE LOWER CASE ALPHA CHARACTERS ; DB 0,0C3H,0D9H ; ' a b DB 0CEH,0C9H,0C1H ; c d e DB 0CDH,0DAH,0D4H ; f g h DB 0C6H,0CBH,0CFH ; i j k DB 0D2H,0DCH,0CCH ; l m n DB 0D8H,0D6H,0D7H ; o p q DB 0CAH,0C5H,0D0H ; r s t DB 0C7H,0DEH,0D3H ; u v w DB 0DDH,0D5H,0D1H ; x y z ; ; ; Following are baud rates values -- (19200 x 13)/ baud = divisor ; BD045: DW 5492 ; 60 wpm = 45.45 baud BD050: DW 4992 ; 66 wpm = 50.00 baud BD057: DW 4385 ; 75 wpm = 56.92 baud BD074: DW 3364 ; 100 wpm = 74.20 baud BD100: DW 2496 ; 132 wpm = 100.00 baud ; BD110: DW 2272 ; 08E0H BD300: DW 832 ; 0342H BD450: DW 554 ; 022AH BD600: DW 416 ; 01A0H BD710: DW 351 ; 015FH BD1200: DW 208 ; 00D0H BD2400: DW 104 ; 0068H BD4800: DW 52 ; 0034H BD9600: DW 26 ; 001AH BD1920: DW 0 ; 19200 baud ; ; ; TEMPORARY STORAGE AREAS ; CASAVE: DW LTABLE ; Recv present case reminder FLAGR: DB 0 ; Recv figs/ltrs last flag SCASE: DB 40H ; Send present case reg FLAGM: DB 0 ; Mode flag, initial 0=baudot (1=ascii) MDRATE: DS 1 ; Modem baud rate flag ; ; DATA AREA ; MCB: DS 1 ; Rtty control byte INCH: DB 0 ; Input char buffer, initial 0 OUTCH: DB 0 ; Output char buffer, initial 0 ; OLDSP: DS 2 ; Old stack pointer STACK: DS 128 ; Local stack ; IBUF: DS 256 ; ; TEXT BUFFER ; FLAGC: DB 0 ; Text capture flag, initial 0=off PTR: DS 2 ; Text buffer pointer SIZE: DS 2 ; Text buffer size TBUF EQU $ ; Start of text buffer ; END