$mod51
$nosymbols
$nolist
$include(i51ctrl.inc)
$include(c:\cet\inc\mymon.inc)
$list
$include(i51init.inc)

flags	data	21h
ctrl	bit	21h.0
parity	bit	21h.1

Mrk	data	24h
Len	data	25h
Seq	data	26h
Typ	data	27h
Chk	data	28h
fph	data	2eh
fpl	data	2fh

cksum	data	10h
EOL	data	11h
CTL	DATA	12H
T	data	13h
N	data	14h
try	data	15h
I	data	16h
T7	data	17h
Ptr	data	18h

	org	codeaddr
start:	jmp	main


main:	mov	N,#0		; initialize sequence number
	clr	parity		; no parity bit
	setb	runlite
;=========================================
L2000:	call	L5000
	mov	a,TYP
	cjne	a,#'S',L2035
	sjmp	L2040
L2035:	mov	flags,#0ffh
	mov	dptr,#D	
	mov	a,TYP
	movx	@dptr,a
	inc	dptr
	clr	a
	movx	@dptr,a
	call	strcat
	db	' Packet in S State',0
	jmp	L9500
;
; here on correct packet type
L2040:	mov	dptr,#pktdat
	call	strlen
	push	acc		; save packet length
;
; if pktlen > 4 then EOL=asc(mid$(pktdat,5,1) else EOL=13
	cjne	a,#4,L2042
L2042:	jc	L2044		; > 4
	mov	dpl,#4
	movx	a,@dptr
	call	unchar
	mov	EOL,a
	sjmp	L2050
L2044:	mov	EOL,#13		; <= 4
L2050:	pop	acc		; get packet length
; if pktlen > 5 then CTL=asc(mid$(pktdat,5,1) else CTL="#"
	cjne	a,#5,L2052
L2052:	jc	L2054
	mov	dpl,#5
	movx	a,@dptr
	mov	CTL,a
	sjmp	L2070
L2054:	mov	CTL,#'#'
L2070:	mov	dptr,#D
	clr	a
	movx	@dptr,a		; D = ""
	call	strcat
;
; MAXL =  80 bytes
; TIME =  10 seconds
; NPAD =  none
; PADC =  NUL
; EOL  =  13
; QCTL =  #
; QBIN =  No 8th bit prefix
; CHKT =  normal 6 bit checksum

	db	'p* @-#N1',0	; parameter string
	call	L8020		; send local parameters
;=========================================
; get a File Header packet. If a B packet comes, we're all done
L3000:	call	L5000
	mov	a,TYP
	cjne	a,#'B',L3030
	call	L8000
	jmp	L9900
L3030:	cjne	a,#'F',L3035
	sjmp	L3040
L3035:	mov	dptr,#D	
	mov	a,TYP
	movx	@dptr,a
	inc	dptr
	clr	a
	movx	@dptr,a
	call	strcat
	db	' Packet in F State',0
	jmp	L9500
L3040:	call	fopen		; open the file
L3060:	call	L8000
;=========================================
; get data packets. If a Z packet comes, the file is complete.
L4000:	call	L5000
L4020:	mov	a,TYP
	cjne	a,#'Z',L4030
	call	fclose		; close the file
	call	L8000
	jmp	L3000
L4030:	cjne	a,#'D',L4035
	sjmp	L4040		; we have data !
L4035:	mov	dptr,#D	
	mov	a,TYP
	movx	@dptr,a
	inc	dptr
	clr	a
	movx	@dptr,a
	call	strcat
	db	' Packet in D State',0
	jmp	L9500
L4040:	call	fwrite		; write to file
L4060:	call	L8000		; acknowledge
L4070:	jmp	L4000
;=========================================

; try to get a valid packet with the desired sequence number
L5000:	call	L7000
	mov	try,#1
nxttry:	mov	a,Seq
	cjne	a,N,L5040
	mov	a,Typ
	cjne	a,#'Q',L5090
L5040:	mov	dptr,#sndbuf
	call	print
	call	L7000
	inc	try
	mov	a,try
	cjne	a,#5,nxttry
	mov	TYP,#'T'
L5090:	ret
;
;=========================================
; Send a packet with data D$ of length L, type TYP, sequence #N.
L6000:	mov	dptr,#D
	push	dpl
	push	dph
	mov	a,TYP
	push	acc
	mov	a,N
	push	acc
	mov	a,Len
	push	acc
	call	spack
	ret
;
;=========================================

; routine to read and decode a packet
L7000:	call	rpack
	ret
;
;=========================================
; routine to send an ACK and increment the packet number
L8000:	mov	dptr,#D
	clr	a
	movx	@dptr,a		; d$ = ""
L8020:	mov	TYP,#'Y'
	mov	dptr,#D
	call	strlen
	mov	Len,a		; L = len(D$)
	call	L6000		; send packet
	mov	a,N
	inc	a
	anl	a,#3fh		; 63
	mov	N,a		; n = (n + 1) and 63
	anl	a,#3
	jnz	L8050
	cpl	runlite
L8050:	ret
;
;=========================================
; Error handler
L9000:	

;=========================================
; Error packet sender
L9500:	mov	dptr,#D
	call	strlen
	mov	TYP,#'E'
	call	L6000		; send packet
; Normal exit point
L9900:	call	fclose
	jmp	WARM
;
;=========================================
blkchk:	mov	b,a		; save check
	anl	a,#192
	swap	a
	rr	a
	rr	a		
	anl	a,#3		; a = a / 64
	add	a,b		; add check
	anl	a,#63
	ret
;
;=========================================
linput:	mov	dptr,#rcvbuf
linp1:	push	dpl
	push	dph
	call	getchr
	pop	dph
	pop	dpl
	movx	@dptr,a
	inc	dptr
	cjne	a,#cr,linp1
	clr	a
	movx	@dptr,a		; string terminator
	ret
;
;=========================================
; find char B in string DPTR return index A
instr:	mov	r2,#0
instr1:	movx	a,@dptr
	jz	instr3
	inc	r2
	cjne	a,b,instr2
	sjmp	instr4
instr2:	inc	dptr
	sjmp	instr1
instr3:	mov	r2,a
instr4:	mov	a,r2
	ret
;
tochar:	add	a,#32
	ret
;
unchar:	clr	c
	subb	a,#32
	ret
;
fopen:	mov	dptr,#fileaddr
	mov	fpl,dpl
	mov	fph,dph
	ret
;
; write Len bytes from PKTDAT to FPTR
fwrite:	mov	p2,#high pktdat
	mov	r0,#low pktdat
	mov	dpl,fpl
	mov	dph,fph
	mov	r2,Ptr		; pktdat length
fw1:	movx	a,@r0		; get byte from pktdat
	movx	@dptr,a		; put byte to fptr
	inc	r0
	inc	dptr
	djnz	r2,fw1
	mov	fpl,dpl
	mov	fph,dph
	ret
	
fclose:	ret
;
$include(i51scat.asm)
$include(i51slen.asm)
$include(i51spck.asm)
$include(i51rpck.asm)
$include(i51chkl.asm)
;
	dseg at	dataaddr
rcvbuf:	ds	128
sndbuf:	ds	1,'# N3',13,0
	ds	128 - ($-sndbuf)
pktdat:	ds	128
D:	ds	128

	end
