;
; Christian Groessler, Dec-2001
;
; RS232 routines using the R: device (currently tested with an 850 only)
;
; unsigned char __fastcall__ rs232_init (char hacked);
; unsigned char __fastcall__ rs232_params (unsigned char params, unsigned char parity);
; unsigned char __fastcall__ rs232_done (void);
; unsigned char __fastcall__ rs232_get (char* B);
; unsigned char __fastcall__ rs232_put (char B);
; unsigned char __fastcall__ rs232_pause (void); [TODO]
; unsigned char __fastcall__ rs232_unpause (void); [TODO]
; unsigned char __fastcall__ rs232_status (unsigned char* status,
;					   unsigned char* errors); [TODO]
;

	.import		findfreeiocb
	.import		__do_oserror
	.import		fddecusage
	.import		fdtoiocb
	.import		__inviocb
	.import		clriocb
	.import		newfd
	.import		_close, pushax, popax, popa
	.importzp	ptr1, tmp2, tmp3

	.export	       	_rs232_init, _rs232_params, _rs232_done, _rs232_get
	.export	      	_rs232_put, _rs232_pause, _rs232_unpause, _rs232_status

	.include	"atari.inc"
	.include	"errno.inc"
        .include        "rs232.inc"

	.rodata

rdev:	.byte	"R:", ATEOL, 0

	.bss

; receive buffer
RECVBUF_SZ = 256
recv_buf: .res	RECVBUF_SZ

cm_run:	.res	1	; concurrent mode running?

	.data

rshand:	.word	$ffff

	.code

;----------------------------------------------------------------------------
;
; unsigned char __fastcall__ rs232_init (char hacked);
; /* Initialize the serial port. The parameter is ignored in the Atari version.
;  * return 0/-1 for OK/Error
;  */
;

.proc	_rs232_init

	jsr	findfreeiocb
	bne	init_err
	txa
	tay			; move iocb # into Y
	lda	#3
	sta	tmp3		; name length + 1
	lda	#<rdev
	ldx	#>rdev
	jsr	newfd
	tya
	bcs	doopen		; C set: open needed / device not already open

	pha
	jsr	_rs232_done	;** shut down if started  @@@TODO check this out!!
	pla

doopen:	tax
	pha
	jsr	clriocb
	pla
	tax
	lda	#<rdev
	sta	ICBAL,x
	lda	#>rdev
	sta	ICBAH,x
	lda	#OPEN
	sta	ICCOM,x

 	lda	#$0D		; mode in+out+concurrent
	sta	ICAX1,x
	lda	#0
	sta	ICAX2,x
	sta	ICBLL,x		; zap buf len
	sta	ICBLH,x
	jsr	CIOV
	bmi	cioerr1

	lda	tmp2		; get fd
	sta	rshand
	ldx	#0
	stx	rshand+1
	txa
	rts

cioerr1:jsr	fddecusage	; decrement usage counter of fd as open failed

init_err:
	ldx	#0
	lda	#RS_ERR_INIT_FAILED
	rts

.endproc	; _rs232_init


;----------------------------------------------------------------------------
;
; unsigned char __fastcall__ rs232_params (unsigned char params, unsigned char parity);
;
; Set communication parameters.
;
; params contains baud rate, stop bits and word size
; parity contains parity
;
; 850 manual documents restrictions on the baud rate (not > 300), when not
; using 8 bit word size. So only 8 bit is currently tested.
;

.proc	_rs232_params

	sta	tmp2
	lda	rshand
	cmp	#$ff
	bne	work		; work only if initialized
	lda	#RS_ERR_NOT_INITIALIZED
	bne	done
work:	lda	rshand
	ldx	#0
	jsr	fdtoiocb	; get iocb index into X
	bmi	inverr		; shouldn't happen
	tax

	; set handshake lines

	lda	#34		; xio 34, set cts, dtr etc
	sta	ICCOM,x
	lda	#192+48+3	; DTR on, RTS on, XMT on
	sta	ICAX1,x
	lda	#0
	sta	ICBLL,x
	sta	ICBLH,x
	sta	ICBAL,x
	sta	ICBAH,x
	sta	ICAX2,x
	jsr	CIOV
	bmi	cioerr

	; set baud rate, word size, stop bits and ready monitoring

	lda	#36		; xio 36, baud rate
	sta	ICCOM,x
	jsr	popa		; get parameter
	sta	ICAX1,x
	;ICAX2 = 0, monitor nothing
	jsr	CIOV
	bmi	cioerr

	; set translation and parity

	lda	#38		; xio 38, translation and parity
	sta	ICCOM,x
	lda	tmp2
	ora	#32		; no translation
	sta	ICAX1,x
	jsr	CIOV
	bmi	cioerr

	lda	#0
done:	ldx	#0
	rts

inverr:	jmp	__inviocb

.endproc	;_rs232_params

cioerr:	jmp	__do_oserror


;----------------------------------------------------------------------------
;
; unsigned char __fastcall__ rs232_done (void);
; /* Close the port, deinstall the interrupt hander. You MUST call this function
;  * before terminating the program, otherwise the machine may crash later. If
;  * in doubt, install an exit handler using atexit(). The function will do
;  * nothing, if it was already called.
;  */
;

.proc	_rs232_done

	lda	rshand
	cmp	#$ff
	beq	done
work:	ldx	rshand+1
	jsr	pushax
	jsr	_close
	pha
	txa
	pha
	ldx	#$ff
	stx	rshand
	stx	rshand+1
	inx
	stx	cm_run
	pla
	tax
	pla
done:	rts

.endproc	;rs232_done


;----------------------------------------------------------------------------
;
; unsigned char __fastcall__ rs232_get (char* B);
; /* Get a character from the serial port. If no characters are available, the
;  * function will return RS_ERR_NO_DATA, so this is not a fatal error.
;  */
;

.proc	_rs232_get

	ldy	rshand
	cpy	#$ff
	bne	work		; work only if initialized
	lda	#RS_ERR_NOT_INITIALIZED
	bne	nierr

work: 	sta	ptr1
 	stx	ptr1+1		; store pointer to received char

	lda	rshand
	ldx	#0
	jsr	fdtoiocb
	tax
	lda	cm_run		; concurrent mode already running?
	bne	go
	jsr	ena_cm		; turn on concurrent mode

go:	; check whether there is any input available

	lda	#STATIS		; status request, returns bytes pending
	sta	ICCOM,x
	jsr	CIOV
	bmi	cioerr		; @@@ error handling

	lda	DVSTAT+1	; get byte count pending
	ora	DVSTAT+2
	beq	nix_da		; no input waiting...

	; input is available: get it!

	lda	#GETCHR		; get raw bytes
	sta	ICCOM,x		; in command code
	lda	#0
	sta	ICBLL,x
	sta	ICBLH,x
	sta	ICBAL,x
	sta	ICBAH,x
	jsr	CIOV		; go get it
	bmi	cioerr		; @@@ error handling

	ldx	#0
	sta	(ptr1,x)	; return received byte
	txa
	rts

nierr:	ldx	#0
	rts

nix_da:	lda	#RS_ERR_NO_DATA
   	ldx 	#0
   	rts

.endproc	;_rs232_get


;----------------------------------------------------------------------------
;
; unsigned char __fastcall__ rs232_put (char B);
; /* Send a character via the serial port. There is a transmit buffer, but
;  * transmitting is not done via interrupt. The function returns
;  * RS_ERR_OVERFLOW if there is no space left in the transmit buffer.
;  */
;

.proc	_rs232_put

	ldy	rshand
	cpy	#$ff
	bne	work		; work only if initialized
	lda	#RS_ERR_NOT_INITIALIZED
	bne	nierr

work:	pha
	lda	rshand
	ldx	#0
	jsr	fdtoiocb
	tax
	lda	cm_run		; concurrent mode already running?
	bne	go
	jsr	ena_cm		; turn on concurrent mode

	; @@@TODO:	 check output buffer overflow
go:	lda	#PUTCHR		; put raw bytes
	sta	ICCOM,x		; in command code
	lda	#0
	sta	ICBLL,x
	sta	ICBLH,x
	sta	ICBAL,x
	sta	ICBAH,x
	pla			; get the char back
	jsr	CIOV		; go do it
	rts

nierr:	ldx	#0
	rts

.endproc	;_rs232_put

;----------------------------------------------------------------------------
;
; unsigned char __fastcall__ rs232_pause (void);
; /* Assert flow control and disable interrupts. */
;

_rs232_pause:


;----------------------------------------------------------------------------
;
; unsigned char __fastcall__ rs232_unpause (void);
; /* Re-enable interrupts and release flow control */
;

_rs232_unpause:


;----------------------------------------------------------------------------
;
; unsigned char __fastcall__ rs232_status (unsigned char* status,
;					   unsigned char* errors);
; /* Return the serial port status. */
;

_rs232_status:

	lda	#255
	tax
	rts


; enable concurrent rs232 mode
; gets iocb index in X
; all registers destroyed

.proc	ena_cm

	lda	#40		; XIO 40, start concurrent IO
	sta	ICCOM,x
	sta	cm_run		; indicate concurrent mode is running
	lda	#0
	sta	ICAX1,x
	sta	ICAX2,x
	lda	#<recv_buf
	sta	ICBAL,x
	lda	#>recv_buf
	sta	ICBAH,x
	lda	#<RECVBUF_SZ
	sta	ICBLL,x
	lda	#>RECVBUF_SZ
	sta	ICBLH,x
	lda	#$0D		; value from 850 man, p62.  must be 0D?,
	sta	ICAX1,x		;  or any non-zero?
	jmp	CIOV

.endproc	;ena_cm

	.end