	processor 6502

	include "jmptab.inc"

#if target & pet4001
	include "include/petram34.lib"
	include "include/petrom4.lib"
#endif
#if target & pet3001
	include "include/petram34.lib"
	include "include/petrom3.lib"
#endif
#if target & (c64 | c128 | vic20)
	include "include/cbmrom.lib"
#endif

	seg code
	org prutils

cmd_dread	= 1 ; command for reading a disk
cmd_dwrite	= 2 ; command for writing a disk

entry:
	lda #0		; send ack
	jsr send_switch

loop:
	; copy a disk protocol:
	; C=		     PC or Amiga
	; ack (00) ->
	;		     <- function: 0=quit, 1=read disk, 2=write disk
	;		     <- device #
	; <status (0=ok)> ->
	;
	; read disk:
	; <floppy status (0=ok)><chksum>datablock (256 bytes) ->
	;		     <- ok (80) or again (81) or stop (82)
	; send same or next block, accordingly
	; last block will be notified with the error code 66
	; (illegal track or sector)
	;
	; write disk:
	;		     <- <flag><chksum>datablock (256 bytes)
	; ok (80) or again (81) or stop (82 followed by error code) ->
	; last block will be notified with a non-zero flag.

	jsr receive_switch	; get function
	tay
	bne noexit$	; check if it was an exit command
jmpxit$:
	jmp exit	; reinstall server and exit.
noexit$:
	cmp #cmd_dread	; is it a legal command?
	beq init
	cmp #cmd_dwrite
	bne jmpxit$

init:	pha
	jsr receive	; receive device number
	sta fa
	lda #15
	sta sa		; error channel number
	sta la
	lda #0
	sta fnlen	; use zero file name
	jsr open
	lda status	; check if it succeeded
	beq ok
abort_init:
	pla
abortst:
	jsr send_switch ; send a non-zero number
abort:	jsr clrchn
	lda #2
	jsr close	; close the files
	lda #15
	jsr close
	jmp loop

ok:	lda #2
	sta sa		; use channel 2 for buffer
	sta la
	lda #filenend-filename
	sta fnlen	; use the file name "#"
	lda #<filename
	sta fnadr
	lda #>filename
	sta fnadr + 1
	jsr open
	lda status
	bne abort_init
	jsr send_switch ; send status code 0 (ok)

	pla
	cmp #cmd_dwrite ; branch according to the function specified
	beq write

	lda #"1"        ; select read operation
	jsr seek1	; reset the track and sector pointers
		; loop to send blocks from the disk
nextblock$:
	jsr advance	; command to get next sector, error code is in A
	bne abortst	; break in case of error

	ldx #2
	jsr chkin
	ldx #0
	stx checksum	; clear checksum

read$:			; read 256 bytes from the disk
	jsr stop	; test stop key
	bne noabort$
	lda #2		; send error code 2 (user break)
	bne abortst
noabort$:
	jsr chrin
	sta filebuf,x
	clc		; add into checksum
	adc checksum
	sta checksum
	inx		; x ranges from 00 to FF
	bne read$

	txa
	jsr send_switch ; send the status code (0)
	jsr clrchn	; restore normal file I/O assignments
			; now go send the buffer
sameblock$:
	lda checksum
	jsr send_switch ; send checksum
	ldx #0
send$:	lda filebuf,x
	jsr send
	inx
	bne send$
			; wait for go on, repeat, or abort.
	jsr receive_switch
	cmp #$80
	beq nextblock$
	cmp #$81
	beq sameblock$
abortj: jmp abort	; $82 (or other values) abort

write:	lda #"1"        ; first select read operation and
	jsr seek1	; try to read track 1, sector 0
	jsr advance	; (the error is ignored, this is only a kludge
			; to make the b-p command work)
	lda #"2"        ; select write operation
	jsr seek1	; reset the track and sector pointers
		; loop to receive blocks for the disk

nextblock$:
	jsr receive_switch
	tax		; copy the return code to X
	bne abortj	; nonzero return value indicates end of transmission
sameblock$:
	jsr receive_switch
	pha		; store checksum
	stx checksum	; clear checksum

receive$:		; receive 256 bytes for the disk
	jsr receive
	sta filebuf,x
	clc		; add to checksum
	adc checksum
	sta checksum
	inx		; x ranges from 00 to FF
	bne receive$

	pla
	cmp checksum	; compare the checksums
	beq received$
	lda #$81
	jsr send_switch ; request the block again in case of error
	jmp sameblock$	; get the block again

received$:		; send the data to the drive
	ldx #15
	jsr chkout	; first issue the B-P command
	ldx #bpend-bp-1
sendbp$:
	lda bp,x
	jsr chrout
	dex
	bpl sendbp$
	ldx #2
	jsr chkout	; then set the output channel
	ldx #0
send$:	lda filebuf,x	; send the data to the floppy
	jsr chrout
	inx
	bne send$
	jsr clrchn

	jsr stop	; test stop key
	beq error$	; abort the transfer when necessary
	jsr advance	; try to write the sector
	bne error$	; abort the transfer in case of error
	lda #$80
	jsr send_switch ; acknowledge the data block to the remote end
	jmp nextblock$	; get the next data block
stopped$:
	lda #0
error$: pha
	lda #$82
	jsr send_switch ; tell the remote end to abort the transfer
	pla
	jmp abortst	; and return the error code

seek1:	sta _cmd	; select operation ("1"=read, "2"=write)
	lda #"0"        ; reset the track and sector numbers
	ldx #2
0$:	sta track,x
	sta sector,x
	dex
	bpl 0$
	rts

advance:		; go to next sector (or track),
	ldx #2		; return error code in A, use Z as error flag
incsect$:		; increment the sector number
	lda #"9"
	inc sector,x
	cmp sector,x
	bcs advanced$
	lda #"0"
	sta sector,x
	dex
	bpl incsect$
	bcc adv_track$	; branch always (sector number overflow)

advanced$:		; try to read or write the sector
	ldx #15
	jsr chkout
	ldy #0
send$:	lda string,y	; send the command
	jsr chrout
	iny
	cpy #_strend-string
	bcc send$
	jsr clrchn

	jsr geterror	; get the error code from the drive
	beq return$	; no error

	cmp #66 	; was it an illegal track or sector?
	bne return$	; no, some other error => return

	lda #"0"        ; check the sector number (should be nonzero)
	ldx #2
check_sector$:
	cmp sector,x
	bne sector_ok$
	dex
	bpl check_sector$
	bmi return66$	; branch always

sector_ok$:
	ldx #2
zero_sector$:		; reset the sector number
	sta sector,x
	dex
	bpl zero_sector$

adv_track$:		; increase the track number
	ldx #2
inctrack$:
	lda #"9"
	inc track,x
	cmp track,x
	bcs advanced$
	lda #"0"
	sta track,x
	dex
	bpl inctrack$
			; fall through in case of track number overflow

return66$:
	lda #66 	; return with error code 66 (end of copy)
return$:
	rts

geterror:		; read the disk error channel
	ldx #15
	jsr chkin	; select the error channel
	jsr chrin	; read the first digit
	and #$0f
	tax		; and store it
	jsr chrin	; read the second digit
	clc
	and #$0f
0$:	dex		; combine the digits to one number
	bmi 1$
	adc #10
	bne 0$		; branch always
1$:	pha
2$:	jsr chrin
	lda status
	beq 2$
	jsr clrchn	; clear the channel
	pla
	rts		; return (error code in accumulator)

filename: .byte "#"
filenend:
string: .byte "U"
_cmd:	.byte "1:2 0 "
track:	.byte "000 "
sector: .byte "000"
_strend:
bp:	.byte "0 2:P-B" ; string stored backwards
bpend:
endcode = .

	seg.u bss
	org endcode

checksum:
	ds.b 1		; save block length
filebuf:
	ds.b 256	; checksum followed by 255 bytes of file data

endbss = .
