; ***************************************************************************
; copyright   : (C) 2025 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.   *
; ***************************************************************************


; ***************************************************************************
; macros

; @param @0 register to use

.macro M_SPIHW_MASTER_SEND_BYTE
  outr SPDR, @0 ; masterSend Byte
  l1_%:
    inr @0, SPSR
    sbrs @0, SPIF
  rjmp l1_%
  inr @0, SPDR
.endm



; ***************************************************************************
; defines

.equ SPIHW_MODE_SPEED0_BIT      = 0   ; 00=CLK/4, 01=CLK/16
.equ SPIHW_MODE_SPEED1_BIT      = 1   ; 10=CLK/64, 11=CLK/128
.equ SPIHW_MODE_DOUBLESPEED_BIT = 2   ; 1=double speed from SPIHW_MODE_SPEED0/1_BIT
.equ SPIHW_MODE_DATAORDER_BIT   = 3   ; 1=LSB first, 0=MSB first
.equ SPIHW_MODE_CPOL_BIT        = 4   ; 0=leading edge rising/trailing edge falling
.equ SPIHW_MODE_CPHA_BIT        = 5   ; 0=sample on leading edge, setup on trailing edge



; ***************************************************************************
; data

.dseg



; ***************************************************************************
; code

.cseg



; ---------------------------------------------------------------------------
; @routine SPIHW_Init @global
;

SPIHW_Init:
  sbi SPIHW_SS0_DDR, SPIHW_SS0_PIN ; SS0= output
  sbi SPIHW_SS1_DDR, SPIHW_SS1_PIN ; SS1= output
  sbi SPIHW_SS2_DDR, SPIHW_SS2_PIN ; SS2= output
  sec
  ret
; @end



; ---------------------------------------------------------------------------
; @routine SPIHW_Fini @global
;

SPIHW_Fini:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine SPIHW_MasterStart @global
;
; Start SPI hardware master with the given mode (see @ref SPIHW_MODE_SPEED0_BIT
; and others).

; @param r16 mode
; @param r17 device num (0-7)
; @clobbers r17

SPIHW_MasterStart:
  ; setup pins
  sbi SPIHW_SS_DDR, SPIHW_SS_PIN      ; SS  : output
  sbi SPIHW_MOSI_DDR, SPIHW_MOSI_PIN  ; MOSI: output
  cbi SPIHW_MISO_DDR, SPIHW_MISO_PIN  ; MISO: input
  sbi SPIHW_SCK_DDR, SPIHW_SCK_PIN    ; SCK:  output

  ; select device
  sbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN   ; SS high
  rcall spiHwSelectDevice             ; (none)
;  cbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN   ; SS low

  ; setup SPCR
  clr r17
  sbrc r16, SPIHW_MODE_DATAORDER_BIT
    sbr r17, (1<<DORD)
  sbrc r16, SPIHW_MODE_CPOL_BIT
    sbr r17, (1<<CPOL)
  sbrc r16, SPIHW_MODE_CPHA_BIT
    sbr r17, (1<<CPHA)
  sbrc r16, SPIHW_MODE_SPEED0_BIT
    sbr r17, (1<<SPR0)
  sbrc r16, SPIHW_MODE_SPEED1_BIT
    sbr r17, (1<<SPR1)
  sbr r17, (1<<SPE) | (1<<MSTR)
  outr SPCR, r17
  
  ; setup SPSR
  clr r17
  sbrc r16, SPIHW_MODE_DOUBLESPEED_BIT
    sbr r17, (1<<SPI2X)
  outr SPSR, r17
  
  ret
; @end



; ---------------------------------------------------------------------------
; @routine SPIHW_MasterStop @global
;
; Stop SPI hardware master.

; @clobbers r16

SPIHW_MasterStop:
;  sbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN   ; SS high
  inr r16, SPCR
  cbr r16, (1<<SPE)
  outr SPCR, r16
  ret
; @end



; ---------------------------------------------------------------------------
; @routine spiHwSelectDevice
;
; Select given device via SS0-SS2 pins
;
; @param r17=device
; @clobbers none

spiHwSelectDevice:
  cbi SPIHW_SS0_OUTPUT, SPIHW_SS0_PIN
  sbrc r17, 0
    sbi SPIHW_SS0_OUTPUT, SPIHW_SS0_PIN
  cbi SPIHW_SS1_OUTPUT, SPIHW_SS1_PIN
  sbrc r17, 1
    sbi SPIHW_SS1_OUTPUT, SPIHW_SS1_PIN
  cbi SPIHW_SS2_OUTPUT, SPIHW_SS2_PIN
  sbrc r17, 2
    sbi SPIHW_SS2_OUTPUT, SPIHW_SS2_PIN
  ret
; @end



; ---------------------------------------------------------------------------
; @routine SPIHW_MasterTransfer @global
;
; Complete transfer sending ony byte and receiving another.
;
; @param r16 byte to send
; @param r16 byte received
; @clobbers none

SPIHW_MasterTransfer:
  rcall SPIHW_MasterSendByte           ; (none)
  rjmp SPIHW_WaitForTransferComplete   ; (none)
; @end



; ---------------------------------------------------------------------------
; @routine SPIHW_MasterSendByte @global
;
; Send a byte to the SPI interface. Does not wait for result, you need to
; call @ref SPIHW_WaitForTransferComplete to complete the request and to
; get the response.
; This allows for transfers in background so that the caller can do other stuff
; instead of idly waiting for the transfer to complete.
; However, before calling this routine again you MUST call SPIHW_WaitForTransferComplete!

; @param r16 byte to send
; @clobbers none

SPIHW_MasterSendByte:
  outr SPDR, r16
  ret
; @end



; ---------------------------------------------------------------------------
; @routine SPIHW_WaitForTransferComplete @global
;
; Wait for a transfer to complete and return the byte received.
;
; @return r16 byte received
; @clobbers none

SPIHW_WaitForTransferComplete:
    inr r16, SPSR
    sbrs r16, SPIF
  rjmp SPIHW_WaitForTransferComplete
  inr r16, SPDR
  ret
; @end



