; ***************************************************************************
; copyright   : (C) 2023 by Martin Preuss
; email       : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome".                              *
; * Please see toplevel file COPYING of that project for license details.   *
; ***************************************************************************




; ---------------------------------------------------------------------------
; COM_BufferAlloc
;
; Allocate a transfer buffer.
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear otherwise
; - X: pointer to allocated buffer in SRAM
; MODIFIED REGISTERS: r16, r17, r21


COM2_BufferAlloc:
  in r21, SREG                            ; save global interrupt enable bit from SREG
  cli
  lds r17, com2RecvBuffersUsed
  cpi r17, COM2_BUFFER_NUM
  brcc COM2_AllocBuffer_error             ; no buffer available
  inc r17                                 ; increment number of buffers used
  sts com2RecvBuffersUsed, r17            ; store new value
  lds r16, com2MaxBuffersUsed             ; calc max buffers used
  cp r16, r17
  brcc COM2_AllocBuffer_l0
  sts com2MaxBuffersUsed, r17
COM2_AllocBuffer_l0:
  lds r16, com2RecvBuffersWritePos        ; get current write pos
  mov r17, r16                            ; increment for next call
  inc r17
  cpi r17, COM2_BUFFER_NUM                ; CF set if COM_BUFFER_NUM > R17
  brcs COM2_AllocBuffer_l1
  clr r17                                 ; wraparound
COM2_AllocBuffer_l1:
  sts com2RecvBuffersWritePos, r17        ; store new writepos for next caller
  rcall COM2_BufferPosToX                 ; (R16, R17)
  out SREG, r21                           ; restore global interrupt enable bit in SREG
  sec
  ret
COM2_AllocBuffer_error:
  out SREG, r21
  clc
  ret



; ---------------------------------------------------------------------------
; COM2_BufferDeallocBack
;
; Release a transfer buffer at the end of the list by decreasing the write pos.
; This releases the last allocated buffer!
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGISTERS: r16, r17, r21

COM2_BufferDeallocBack:
  in r21, SREG                            ; save global interrupt enable bit from SREG
  cli
  lds r17, com2RecvBuffersUsed
  tst r17
  breq COM2_BufferDeallocBack_error       ; no buffer allocated, nothing to release
  dec r17
  sts com2RecvBuffersUsed, r17            ; store new value
  lds r17, com2RecvBuffersWritePos
  tst r17                                 ; 0?
  brne COM2_BufferDeallocBack_l1          ; nope go directly decrement r17
  ldi r17, COM2_BUFFER_NUM                ; wrap-around
COM2_BufferDeallocBack_l1:
  dec r17
  sts com2RecvBuffersWritePos, r17
  out SREG, r21
  sec
  ret
COM2_BufferDeallocBack_error:
  out SREG, r21
  clc
  ret



; ---------------------------------------------------------------------------
; COM2_BufferDeallocFront
;
; Release a transfer buffer by increasing the read pos.
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGISTERS: r16, r17, r21

COM2_BufferDeallocFront:
  in r21, SREG                           ; save global interrupt enable bit from SREG
  cli
  lds r17, com2RecvBuffersUsed
  tst r17
  breq COM2_BufferDeallocFront_error     ; no buffer allocated, nothing to release
  dec r17
  sts com2RecvBuffersUsed, r17            ; store new value
  lds r17, com2RecvBuffersReadPos
  inc r17
  cpi r17, COM2_BUFFER_NUM
  brcs COM2_BufferDeallocFront_l1
  clr r17                                ; wrap-around
COM2_BufferDeallocFront_l1:
  sts com2RecvBuffersReadPos, r17
  out SREG, r21
  sec
  ret
COM2_BufferDeallocFront_error:
  out SREG, r21
  clc
  ret



; ---------------------------------------------------------------------------
; COM2_BufferPosToX
;
; Get a pointer to the SRAM position of the given buffer.
; CAVE: Code must correspond to COM2_BUFFER_SIZE!!
; IN:
; - R16: buffer number (starting with 0)
; OUT:
; - X: pointer to buffer in SRAM
; MODIFIED REGISTERS: R16, R17

COM2_BufferPosToX:
  ; calculate offset
  clr r17
  mov xl, r16
  clr xh

  lsl xl
  rol xh ; *2

  add xl, r16
  adc xh, r17 ; *3

  lsl xl
  rol xh ; *6

  lsl xl
  rol xh ; *12

  lsl xl
  rol xh ; *24

  ; add base position of buffers
  ldi r16, LOW(com2RecvBuffers)
  ldi r17, HIGH(com2RecvBuffers)
  add xl, r16
  adc xh, r17
  ret



