;FLTIBM.ASM -- Phil Wheeler [71266,125] ; ;Version 1.7 -- 9/25/86 ; ; ;TRS-80 Model 100 <--> IBM-PC File Transfer Utility ; ;Transfers ASCII files to/from Model 100 at ;9600 baud. Use setting 88N1E and Save & Load on Model 100 ;Examples are: ; In TEXT: Save to:com:88n1e ; in BASIC: Save"com:88n1e" ; ;Requires RS-232 cable with "Null Modem Adapter" ;for computer interconnect. ; ;Based on FLTKP.100 written by Don Corbitt, Feb 1984 ;as modified to FLTKP.UPD by Phil Wheeler, July 1984 ; ;Adapted to IBM-PC and Compatibles, July 1985 ;No BIOS functions used; generic MS-DOS code, ;but comm port set-up is for IBM/Compatibles ; ;Change COM1 equate to select COM: port -- TRUE for COM1: ;and FALSE for COM2: ; ;Modified to prompt for ;overwrite of existing files pcw -- 7/22/85 ; ;Modified for WS stripping pcw -- 8/1/85 ; ;Minor menu changes pcw -- 8/4/85 ; ;Send hang-up fixed; M100 ;hardware issue pcw -- 8/6/85 ; ;Time-out count increased to ;let Basic programs be sent pcw -- 8/8/85 ; ;Further changes in time-out ;code pcw -- 5/26/86 ; ;Still more changes in timing. ;Change to two-stage counter ;to allow counts larger than ;FFFFh and user patch of ;timing using DEBUG. pcw -- 6/8/86 ; ;Version to do EOF on CHR$(206) ;embedded in transmitted file. ;See minor patch at 'rloop:' pcw -- 9/22/86 ; ; CODE SEGMENT ASSUME CS:CODE,DS:CODE ORG 100H M EQU Byte Ptr 0[BX] FALSE EQU 0 TRUE EQU NOT FALSE COM1 EQU TRUE ;TRUE = COM1:, FALSE = COM2: BDOS EQU 5 FCBL EQU 5ch dbuff EQU 80h ;disk i/o buffer conin EQU 1 ;get char from console - wait printf EQU 9 ;print buffer function (DE) until '$' inlinf EQU 10 ;read buffer from console openf EQU 15 ;open file, closef EQU 16 ;close file after write search EQU 17 ;look for file - ff if not found readf EQU 20 ;read block from file writef EQU 21 ;write block to file makef EQU 22 ;make a file entry bell EQU 7 cr EQU 13 lf EQU 10 nul EQU 0 eof EQU 1ah ;end of file signal xoff EQU 19 ;stop transmission xon EQU 17 ;start transmission SPACE EQU 20h ;space COUNT EQU 30000 ;send time-out count CNTSCL EQU 2 ;count loop multiplier ;Wordstar attributes optionally stripped SCR EQU 8Dh ;soft cr SLF EQU 8Ah ;soft lf SHYPHE EQU 1Fh ;eol soft hyphen SHYPHM EQU 1Eh ;mid-text soft hyphen NBSPC EQU 0Fh ;no-break space CTLB EQU 02h ;control-b CTLD EQU 04h ;control-d CTLS EQU 13h ;control-s CTLT EQU 14h ;control-t CTLV EQU 16h ;control-v ; ; ;Set up 8250 UART addresses for selected com port ; IF COM1 ;PORT IS COM1 ; UARTD EQU 3F8H ;DATA PORT UARTS EQU 3FDH ;STATUS PORT URTSNDR EQU 20H ;SEND-READY TEST URTRCVR EQU 01H ;RCV-READY TEST LCREG EQU 3FBH ;LINE CONTROL REG BDLSB EQU 3F8H ;BAUD DIVISOR LSB BDMSB EQU 3F9H ;BAUD DIVISOR MSB INTREG EQU 3F9H ;INTERRUPT ENABLE REG MDMREG EQU 3FCH ;MODEM CONTROL REG ; ELSE ;THEN IT'S COM2 ; UARTD EQU 2F8H ;DATA PORT UARTS EQU 2FDH ;STATUS PORT URTSNDR EQU 20H ;SEND-READY TEST URTRCVR EQU 01H ;RCV-READY TEST LCREG EQU 2FBH ;LINE CONTROL REG BDLSB EQU 2F8H ;BAUD DIVISOR LSB BDMSB EQU 2F9H ;BAUD DIVISOR MSB INTREG EQU 2F9H ;INTERRUPT ENABLE REG MDMREG EQU 2FCH ;MODEM CONTROL REG ; ENDIF START: JMP BEGIN WFLAG DB 0 ;WS flag fbuff DB 18 DB 18 DUP(?) fexmsg DB bell,cr,lf,'File exists! Overwrite? $' wrtmsg DB ' Will Do! $' recmsg DB cr,lf,'File to receive: $' sndmsg DB cr,lf,'File to send: $' nfmsg DB bell,cr,lf,'File does not exist!!',cr,lf,'$' TRYMSG DB bell,cr,lf,'Send loop lock-up. Check M100 set-up ' DB 'and try again! $' PGMMSG DB cr,lf,lf DB 'FLTIBM ASCII File Transfer (COM1:) -- Version 1.7' DB cr,lf,lf DB 'Use with COM:88N1E & Save or Load on Model 100' DB cr,lf,'Works with TEXT or BASIC',cr,lf,'$' MENMSG DB cr,lf,'Selections are:',cr,lf,lf DB ' [Q] Return to DOS',cr,lf DB ' [S] Send file to M100',cr,lf DB ' [W] Send stripped WS file to M100',cr,lf DB ' [R] Receive file from M100',cr,lf,lf DB 'Enter your selection: $' BEGIN: ; ;Initialize 8250 UART for 9600 baud, 8 bits, 1 stop bit, no parity ;Use the ports for set-up (vs. ROMBIOS INT 14H), so that it will ;work on compatibles -- like my Z-150. RTN1: MOV DX,LCREG ;LINE CONTROL REGISTER MOV AL,80H ; OUT DX,AL ;TO ADDRESS BAUD RAT DIVISOR RTN2: MOV DX,BDLSB ;ADRS OF RATE DIV LSB MOV AL,0CH ;9600 BAUD LSB OUT DX,AL ;SET BAUD RATE -- LSB DIVISOR RTN3: MOV DX,BDMSB ;MSB ADRS MOV AL,0 ;MSB FOR 9600 BAUD OUT DX,AL ;SET BAUD RATE -- MSB DIVISOR RTN4: MOV DX,LCREG ;LINE CONTROL REGISTER MOV AL,013H ;NO PARITY, 1 STOP BIT, 8 BITS OUT DX,AL ;SET PARAMS ABOVE RTN5: MOV DX,MDMREG ;ADRS OF MDM CONTROL REG MOV AL,03H ;SET FOR DTR AND RTS OUT DX,AL ;IT MAY NOT MATTER, BUT DO IT! RTN6: MOV DX,INTREG ;ADRS OF ENABLE INTERRUPT REG MOV AL,0 ; OUT DX,AL ;DISABLE 8250 INTERRUPTS INIT: MOV DX,OFFSET PGMMSG MOV AH,PRINTF INT 21H loop1: MOV DX,OFFSET MENMSG MOV AH,printf INT 21H MOV AH,conin INT 21H CALL touppr ;get upper case letters CMP AL,'Q' ;test for quit JNZ L_1 ;no INT 20H ;yes -- return to DOS L_1: CMP AL,'W' ;send stripped WS file to M100 JZ SETFL1 ;go set WS flag on (=1) CMP AL,'S' ;send normal file to M100 JZ SETFL0 ;go set WS flag off (=0) CMP AL,'R' ;receive file from M100 JNZ LOOP1 ;try again JMP receive SETFL0: MOV DI,OFFSET WFLAG ;flag address in ah MOV AH,0 ;off value MOV [DI],AH ;set WS flag JMP SHORT SEND SETFL1: MOV DI,OFFSET WFLAG ;flag address in ah MOV AH,1 ;on value MOV [DI],AH ;set WS flag JMP SHORT SEND send: MOV DX,(Offset sndmsg) ;'Enter file to send' MOV AH,printf INT 21H CALL gfspec ;get the file name, and see if it exists JNZ sendit ;it exists, so send it MOV DX,(Offset nfmsg) ;'File doesn't exist' MOV AH,printf INT 21H JMP loop1 ;try again sendit: MOV BX,(Offset stbuff) ;end of program - start of buffer PUSH BX MOV DX,fcbl MOV AH,openf ;open file and read contents INT 21H sloop: MOV AH,readf MOV DX,fcbl INT 21H POP DI ;PT TO CURRENT END OF DATA MOV SI,DBUFF ;PT TO DMS BUFFER MOV CX,80H ;BUFFER SIZE REP MOVSB ;MOVE BLOCK PUSH DI ;NEW END OF DATA AND AL,AL ;nz = EOF JNZ sendfil JMP SHORT sloop sendfil: MOV DX,FCBL MOV AH,CLOSEF ;CLOSE SEND FILE INT 21H POP BX ;arrange stack - discard this value MOV BX,(Offset stbuff) ;buffer ended with EOF, OK? sloop1: MOV CL,M ;get char MOV CH,WFLAG ;get WS flag CMP CH,0 ;test the flag JZ WSEND ;not WS -- bypass stripping SOFTCR: CMP CL,SCR ;is it a soft CR? JNZ SOFTLF ;if not, bypass MOV CL,NUL ;it is! replace with a null JMP WSEND ;send it! SOFTLF: CMP CL,SLF ;is it a soft lf? JNZ HIBIT ;if not, bypass MOV CL,NUL ;it is! replace with a null JMP WSEND ;send it! HIBIT: CMP CL,80H ;char > 80h? JNA HDLF ;no. leave it as-is SUB CL,80H ;yes. reduce it by 80h HDLF: CMP CL,LF ;is it a hard lf? JNZ HDSPC ;no..bypass MOV CL,NUL ;yes..replace by null JMP WSEND ;send it! HDSPC: CMP CL,NBSPC ;is it a non-break space? JNZ HYPH1 ;if not, bypass MOV CL,SPACE ;it is! replace with a space JMP WSEND ;send it! HYPH1: CMP CL,SHYPHE ;is it an eol soft hyphen? JNZ HYPH2 ;if not, bypass MOV CL,NUL ;it is! replace with a null JMP WSEND ;send it! HYPH2: CMP CL,SHYPHM ;is it a mid soft hyphen? JNZ CONTB ;if not, bypass MOV CL,NUL ;it is! replace with a null JMP WSEND ;send it! CONTB: CMP CL,CTLB ;is it a control-b JNZ CONTD ;if not, bypass MOV CL,NUL ;it is! replace with a null JMP WSEND ;send it! CONTD: CMP CL,CTLD ;is it a control-d JNZ CONTS ;if not, bypass MOV CL,NUL ;it is! replace with a null JMP WSEND ;send it! CONTS: CMP CL,CTLS ;is it a control-s JNZ CONTT ;if not, bypass MOV CL,NUL ;it is! replace with a null JMP WSEND ;send it! CONTT: CMP CL,CTLT ;is it a control-t JNZ CONTV ;if not, bypass MOV CL,NUL ;it is! replace with a null JMP WSEND ;send it! CONTV: CMP CL,CTLV ;is it a control-v JNZ WSEND ;if not, bypass MOV CL,NUL ;it is! replace with a null JMP WSEND ;send it! WSEND: LAHF INC BX SAHF CALL rsout ;send char CMP AL,eof JNZ NWCHAR JMP send ;end of file - send new file?? NWCHAR: CALL rsist ;char waiting?? JNZ SKSKIP JMP SLOOP1 SKSKIP: CALL RSINT ;get char CMP AL,xoff ;if xoff, then wait..... JZ SLOOP2 JMP sloop1 ;else ignore it sloop2: CALL RSINT CMP AL,xon JNZ sloop2 JMP sloop1 ;rs output status. Z if uart busy, NZ otherwise. A modified. rsost: PUSH DX MOV DX,uarts IN AL,DX AND AL,URTSNDR POP DX RET ;RS character out, character in C rsout: ;send byte in C to uart CALL rsost JZ rsout PUSH DX MOV DX,uartd MOV AL,CL OUT DX,AL POP DX RET ;rs input status. Z if no char waiting, NZ if char ready. rsist: PUSH DX MOV DX,uarts IN AL,DX AND AL,URTRCVR ;char waiting? POP DX RET ;get char from uart and return in A (TX loop) RSINT: PUSH BX MOV BX,COUNT ;set up a COUNT loop counter RSINX: CALL CNTOUT CALL RSIST ;char wait test JZ RSINX ;loop if none PUSH DX MOV DX,uartd IN AL,DX POP DX POP BX RET ;escape path if locked in Xoff due to M100 buffer full CNTOUT: DEC BX CMP BX,0 JZ TMOUT ;too long in loop! PUSH BX MOV BX,CNTSCL ;initialize scaling loop SCALE: DEC BX CMP BX,0 JNZ SCALE ;cycle CNTSCL times POP BX RET TMOUT: POP BX ;clean up MOV DX, OFFSET TRYMSG ;print message MOV AH,PRINTF INT 21H JMP SEND ;go to send loop ;get char from uart and return in A (RX loop) RSINR: CALL RSIST ;char wait test JZ RSINR ;loop if none PUSH DX MOV DX,uartd IN AL,DX POP DX RET RECEIVE: MOV DX,(Offset recmsg) MOV AH,printf INT 21H CALL gfspec JZ rcvit ;doesn't exist, so get it EXTMSG: MOV DX,(Offset fexmsg) ;say it exists MOV AH,printf ;and ask about overwrite INT 21H ;of the existing file MOV AH,CONIN ;get a character INT 21H CALL TOUPPR ;make it upper case CMP AL,'Y' ;overwrite is yes? JZ OVRMSG ;show a response! then do it CMP AL,'N' ;overwrite is no? JZ RECEIVE ;then get a new name JMP EXTMSG ;not yes or no; ask again! OVRMSG: MOV DX,OFFSET WRTMSG ;get the message MOV AH,PRINTF INT 21H ;show it -- then do it! RCVIT: MOV DX,fcbl MOV AH,makef INT 21H MOV BX,(Offset stbuff) rloop: CALL RSINR ;get a char CMP AL,206 ;see if it is a '206' JNZ NOREPL MOV AL,eof ;replace '206' by '26' NOREPL: MOV M,AL ;and put in buffer INC BX CMP AL,eof ;if not last JZ ENDLOOP JMP rloop ;then get another ENDLOOP: MOV BX,(Offset stbuff) secloop: MOV DX,dbuff MOV CH,80h byteloop: MOV AL,M MOV SI,DX MOV [SI],AL CMP AL,eof JZ lastone LAHF INC BX SAHF LAHF INC DX SAHF DEC CH JNZ byteloop CALL wsect JMP SHORT secloop JMP lastone lastloop: MOV SI,DX MOV [SI],AL lastone: LAHF INC DX SAHF DEC CH JNZ lastloop CALL wsect MOV DX,fcbl MOV AH,closef INT 21H JMP receive ;end of file - get another one?? wsect: PUSH BX ;save position in buffer MOV DX,fcbl MOV AH,writef INT 21H POP BX RET touppr: CMP AL,'a' JNB L_3 RET L_3: CMP AL,'z'+1 JNAE L_4 RET L_4: AND AL,5fh RET gfspec: MOV BX,fcbl MOV CH,33 ;33 bytes to erase XOR AL,AL erase: MOV M,AL INC BX ;next byte in fcbl DEC CH JNZ erase MOV BX,fcbl+1 MOV CH,11 ;file name block - default spaces MOV AL,32 ;space erase1: MOV M,AL INC BX DEC CH JNZ erase1 MOV DX,(Offset fbuff) ;buffer to hold file name PUSH DX ;save start of buffer MOV AH,inlinf ;read line from keyboard INT 21H ;get line POP BX ;start of buffer (max count) INC BX ;actual value returned MOV AL,M AND AL,AL ;no chars in queue?? MOV CH,AL ;count in b JNZ congsp ;if chars, continue get file spec POP BX ;remove one level of subroutines JMP loop1 ;start over with menu congsp: INC BX ;first char of fspec INC BX ;second char of fspec MOV AL,M ;get ':' if in fspec DEC BX ;first char of fspec CMP AL,':' MOV AL,0 ;zero (A) without affecting flags JNZ noprefix DEC CH DEC CH ;skipping first two chars of buffer MOV AL,M CALL touppr SBB AL,'@' ;get value from 1 to 17 (A to P) MOV SI,fcbl MOV [SI],AL INC BX ;point to ':' INC BX ;point to first char of name noprefix: MOV DX,fcbl+1 ;start of name section of fcbl nprloop: MOV AL,M CALL touppr CMP AL,'.' JZ stext ;start extension MOV SI,DX ;put in fcbl MOV [SI],AL LAHF INC BX SAHF LAHF INC DX SAHF DEC CH JNZ nprloop exist: MOV AH,search MOV DX,fcbl INT 21H INC AL RET stext: LAHF ;skip '.' INC BX SAHF MOV DX,fcbl+9 ;start of extension DEC CH JZ exist ;done extloop: MOV AL,M CALL touppr MOV SI,DX MOV [SI],AL LAHF INC BX SAHF LAHF INC DX SAHF DEC CH JNZ extloop JMP SHORT exist endbuff DW 0 stbuff LABEL WORD ;start of free space CODE ENDS END start