;;; usart driver, transmitting

;; bit definitions

.set pc_ = pc
.org UDREaddr
  jmp_ usart_udre_isr
.org pc_


.if WANT_RS485 == 1

.set pc_ = pc
; serial transfer complete interrupt clears R/W
.org UTXCaddr
  jmp_ usart_utx_isr
.org pc_

usart_utx_isr:
  cbi RS485_RW_PORT,RS485_RW_PIN
  reti

.endif

	
; sizes have to be powers of 2!
.equ usart_tx_size = $10
.equ usart_tx_mask = usart_tx_size - 1

.set usart_tx_in = here
.set here = here + 1

.set usart_tx_out = here
.set here = here + 1

.set usart_tx_data = here
.set here = here + usart_tx_size

usart_udre_isr:
  push xl
  in xl,SREG
  push xl
  push xh
  push zl
  push zh

  lds xl,usart_tx_in
  lds xh,usart_tx_out
  cp xh,xl
  brne usart_udre_next

usart_udre_last:
  lds xl, USART_B
  cbr xl,(1<<UDRIE)
  sts USART_B,xl

  rjmp usart_udre_done

usart_udre_next:
.if WANT_RS485 == 1
  sbi RS485_RW_PORT,RS485_RW_PIN
.endif

  inc xh
  andi xh,usart_tx_mask
  sts usart_tx_out,xh

  ldi zl,low(usart_tx_data)
  ldi zh,high(usart_tx_data)
  add zl,xh
  adc zh,zeroh
usart_udre_send:
  ld xl,z
  sts USART_DATA,xl

usart_udre_done:
  pop zh
  pop zl
  pop xh
  pop xl
  out SREG,xl
  pop xl
  reti

; ( -- ) Hardware Access
; R( --)
; initialize usart
;VE_USART_INIT_TX:
;  .dw $ff06
;  .db "+usart"
;  .dw VE_HEAD
;  .set VE_HEAD = VE_USART_INIT_TX
XT_USART_INIT_TX:
  .dw DO_COLON
PFA_USART_INIT_TX:          ; ( -- )
  .dw XT_ZERO
  .dw XT_DOLITERAL
  .dw usart_tx_in
  .dw XT_STORE
  .dw XT_EXIT