;
; FTYPE		Type a file to a COM Port
;

COM equ 1

ifdef ??version
	masm51
	quirks
endif

_code	segment byte
  if COM
	org	0100H
  endif
	assume	cs:_code
_go:
	jmp _start

PortNum	dw 0		; Assumes port 0
ChgBaud	dw -1		; -1 means don't change
Share	dw 0		; FOSSIL is shared
IsInit	dw 0		; FOSSIL is initialised
Carrier	dw 0		; Don't check carrier if non-zero
Handle	dw 0		; DOS file handle
DoEcho	dw 0		; Echo to screen as well

RateTbl	dw 0043H	; 300 baud
	dw 0063H	; 600 baud
	dw 0083H	; 1200 baud
	dw 00a3H	; 2400 baud
	dw 00c3H	; 4800 baud
	dw 00e3H	; 9600 baud
	dw 0003H	; 19200 baud
	dw 0023H	; 38400 baud

BaudTbl	dw 300
	dw 600
	dw 1200
	dw 2400
	dw 4800
	dw 9600
	dw 19200
	dw 38400

_bmark	equ $

UseText	db 'FTYPE v1.10   Type a file to a port via FOSSIL',13,10
	db '              Copyright (C) 1989  David Nugent & Unique Computing Ptd Ltd',13,10,10
	db 'Usage: ftype [/Pn] [/Bnnn] [/S] [/N] <filename>',13,10,10
	db '   Where:  /Pn    Optional port number: 0=COM1 1=COM2 ... (default is 0, COM1)',13,10
	db '           /Bnnnn Optional baud rate (default is current baud rate)',13,10
	db '           /S     Leaves FOSSIL driver active on exit',13,10
	db '           /N     Proceed even if carrier is not present',13,10
	db '           /E     Type output to screen (as well)',13,10
	db 10

_utend	equ $

NoFoss	db 13,10,'ftype: No FOSSIL loaded!',13,10
_nfend	equ $
NoPort	db 13,10,'ftype: FOSSIL init error (port not available)?',13,10
_nport	equ $
NoCarr	db 13,10,'ftype: No carrier - lost caller?',13,10
_ncarr	equ $
SndErr	db 13,10,'ftype: Error sending string!',13,10
_serr	equ $
TimErr	db 13,10,'ftype: Timeout waiting for output to clear!',13,10
_terr	equ $
InBaud	db 13,10,'ftype: Invalid baud rate specified',31,10
_vbaud	equ $
NoFile	db 13,10,'ftype: Unable to open file',13,10
_nfile	equ $
RdErr	db 13,10,'ftype: Error reading file',13,10
_rerr	equ $

_start:

; Scan the command line for switches

  if COM
	assume ds:_code, es:_code
  else
	mov ax,cs
	mov ds,ax
	assume ds:_code,es:nothing
  endif
	mov SI,080H
	mov AL,ES:[SI]
	inc SI
	mov DI,SI
	mov CL,AL
	xor CH,CH
	cmp CX,1
	jg @S
	jmp Usage
@S:
	mov AL,byte ptr ES:[SI]
	cmp AL,020H
	je @F
	cmp AL,009H
	jne @N
@@:
	inc SI
	loop @S
	jmp Usage
@N:
	cmp AL,'/'
	jne _ChkFile
	inc SI
	dec CX
	mov AL,byte ptr ES:[SI]
	inc SI
	dec CX
	cmp CX,1
	jg @F
	jmp Usage
@@:
	cmp AL,'a'
	jb @F
	cmp AL,'z'
	ja @F
	sub AL,32
@@:
	cmp AL,'P'
	jne @F
	jmp @Port
@@:
	cmp AL,'B'
	jne @F
	jmp @Baud
@@:
	cmp AL,'S'
	je @Share
	cmp AL,'E'
	je @Echo
	cmp AL,'N'
	je @F
	jmp Usage
@@:
	inc Carrier
	jmp @S
@Echo:
	inc DoEcho
	jmp @S
@Share:
	inc Share
	jmp @S

;
; Check tha file exists and can be opened
;
_ChkFile:
	mov BX,offset BufferStart
	add BX,800FH				; Add buffer and round
	mov AX,CS
	sub BX,AX
	shr BX,1
	shr BX,1
	shr BX,1
	shr BX,1
	mov AH,04aH				; Chop off memory for DOS 4.x->
	int 021H

	mov DX,SI				; Find end of string
@@:
	lodsb
	cmp AL,0dH
	je @F
	cmp AL,020H
	je @F
	cmp AL,09H
	je @F
	loop @B
	inc SI
@@:
	dec SI					; ASCIZ string
	mov byte ptr [SI],0
	xor AL,AL				; Open read_only
	mov AH,03DH
	int 021H
	jnc @F
	mov DX,offset NoFile
	mov CX,_nfile - NoFile
	jmp Error
@@:
	mov Handle,AX				; Save handle
	xor CX,CX				; No bytes currently in buffer
;
; Check that a FOSSIL exists
;
	push ES
	mov AX,03514H				; Check INT 14H vector
	int 021H
	cmp ES:[BX+6],01954H
	pop ES
	je @F
	mov DX,offset NoFoss
	mov CX,_nfend - NoFoss
	jmp Error
@@:
	mov AH,04H
	mov DX,PortNum
	int 014H				; Initialise FOSSIL driver
	cmp AX,01954H
	je @F
	mov DX,offset NoPort
	mov CX,_nport - NoPort
	jmp Error
@@:
	cmp ChgBaud,-1
	je @M
	mov AL,byte ptr ChgBaud			; Set baud rate
	xor AH,AH
	mov DX,PortNum
	int 014H
@M:
	push CS
	inc IsInit
@@:
	cmp CX,0				; How many bytes left?
	jne @F
	mov DX,offset BufferStart
	mov CX,8000				; 32K chunks
	mov BX,Handle
	mov AH,03fH				; Read next slab
	int 021H
	mov CX,AX				; Update counter
	mov SI,offset BufferStart		; And start of buffer
	jnc @F
	mov DX,offset RdErr			; File read error
	mov CX,_rerr - RdErr
	jmp SHORT Error
@@:
	jcxz _nomore				; End of file
	lodsb
	call @Send				; Send next one
	dec CX
	push CX
	xor CX,CX				; Large timeout value
@J:
	mov AH,03H
	mov DX,PortNum
	int 014H
	cmp Carrier,0
	jne @F
	test AL,080H				; Is carrier up?
@cl:
	mov DX,offset NoCarr
	mov CX,_ncarr - NoCarr
	jmp SHORT Error
@@:
	and AH,40H				; Is TX buffer empty yet?
	jnz @F
	loop @J
	jmp SHORT @to
@@:
	mov AH,0DH
	int 014H
	cmp AX,-1
	je @F
	mov AH,0EH
	int 014H
	cmp AL,27				; Was ESC hit?
	je @End
@@:
	pop CX
	jmp @M

_nomore:
	mov AL,13				; Send CR
	call @Send
	mov AL,10				; Send LF
	call @Send

	xor CX,CX				; Large timeout value
@H:
	mov AH,03H
	mov DX,PortNum
	int 014H
	cmp Carrier,0
	jne @F
	test AL,080H				; Is carrier up?
	jz @cl
@@:
	and AH,40H				; Is TX buffer empty yet?
	jnz @End
	loop @H
@to:
	mov DX,offset TimErr			; Transmitter timed out
	mov CX,_terr - TimErr
	jmp SHORT Error

@End:
	xor AL,AL
	jmp SHORT Exit

;---------

Usage:
	mov DX,offset UseText
	mov CX,_utend - UseText

;---------

Error:
	mov BX,2
	call Write
	mov BX,1
	cmp IsInit,0
	je Exit
	mov AL,1

; -------

Exit:
	cmp Share,0
	jne @F
	cmp IsInit,0
	je @F
	mov AH,05H
	mov DX,PortNum
	int 014H
@@:
	mov BX,Handle
	or BX,BX			; Close file
	je @F
	mov AH,03fH
	int 021H
@@:
	mov AH,04CH
	int 021H

; -------

Write:
	mov AH,040H
	int 021H
	ret

;
; Parse port number
;
@Port:
	mov AL,byte ptr ES:[DI]
	inc SI
	dec CX
	sub AL,'0'
	xor AH,AH
	mov PortNum,AX
	jmp @S
;
; Parse baud rate
;
@Baud:
	xor DX,DX
	xor AH,AH
@L:
	jcxz @F
	mov AL,byte ptr ES:[SI]
	cmp AL,'0'
	jb @F
	cmp AL,'9'
	ja @F
	inc SI
	dec CX
	sub AL,'0'
	mov BX,DX
	shl DX,1
	shl DX,1
	add DX,BX
	shl DX,1
	add DX,AX
	jmp @L
@@:
	push CX
	mov CX,(_bmark - BaudTbl)/2
	mov BX,offset BaudTbl
@@:
	cmp DX,[BX]
	je  @F
	add BX,2
	loop @B
	pop CX
	mov DX,offset InBaud
	mov CX,_vbaud - InBaud
	jmp Error

@@:
	sub BX,BaudTbl - RateTbl
	mov AX,[BX]
	mov ChgBaud,AX
	pop CX
	jmp @S

;
; Send a character to the port
;

@Send:
	push CX
	mov CX,512				; Attempt sending 512 times
@X:
	push AX
	mov AH,0BH				; TX chr no wait
	mov DX,PortNum
	int 014H
	or AL,AL				; Character sent?
	jne @F
	pop AX
	loop @X

	pop CX
	pop AX					; Pop return address
	mov DX,offset SndErr
	mov CX,_serr - SndErr
	jmp Error
@@:
	pop AX
	cmp AL,13				; Delay after CR or LF
	je @F
	cmp AL,10
	jne @K
@@:
	xor CX,CX
	mov AH,03H				; Wait until its sent
@@:
	push AX
	mov DX,PortNum
	int 014H
	and AH,040H
	pop AX
	jne @F
	loop @B
	jmp @to
@@:
	mov CX,3
	push ES
	mov BX,ES:[046cH]
@Q:
	sti
@@:
	cmp BX,ES:[046cH]
	jne @B
	loop @B
	pop ES
@K:
	cmp DoEcho,0
	je @F
	mov AH,13H
	int 014H
@@:
	pop CX					; Character sent
	ret


BufferStart label byte
_code	ends

end	_go
