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



; ***************************************************************************
; defs

.equ DS3231_FLAGS_PRESENT_BIT = 7
.equ DS3231_FLAGS_VALID_BIT   = 6





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

.dseg

ds3231DataBegin:
  ds3231Flags:      .byte 1
  ds3231RecvBuffer: .byte 7
ds3231DataEnd:




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

.cseg



; ---------------------------------------------------------------------------
; @routine Ds3231_Init @global
;
; @return CFLAG set if okay, cleared on error
; @clobbers

Ds3231_Init:
  ldi xh, HIGH(ds3231DataBegin)
  ldi xl, LOW(ds3231DataBegin)
  clr r16
  ldi r17, (ds3231DataEnd-ds3231DataBegin)
  rcall Utils_FillSram

  rcall ds3231CheckPresence
  brcc Ds3231_Init_ret
  ldi r16, (1<<DS3231_FLAGS_PRESENT_BIT)
  sts ds3231Flags, r16
  sec
Ds3231_Init_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine Ds3231_Fini @global
;
; @return CFLAG set if okay, cleared on error
; @clobbers none

Ds3231_Fini:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine Ds3231_Fini @global
;
; @return CFLAG set if okay, cleared on error
; @clobbers

Ds3231_OnEveryMinute:
  push r15
    in r15, SREG
    cli

    lds r16, ds3231Flags
    sbrs r16, DS3231_FLAGS_PRESENT_BIT
      rjmp Ds3231_OnEveryMinute_ret
    ; clear valid bit
    cbr r16, (1<<DS3231_FLAGS_VALID_BIT)
    sts ds3231Flags, r16
    ; read time from clock
    ldi xl, LOW(ds3231RecvBuffer)
    ldi xh, HIGH(ds3231RecvBuffer)
    clr r16
    ldi r17, 7
    rcall ds3231ReadData
    brcc Ds3231_OnEveryMinute_ret
    ; set valid bit
    lds r16, ds3231Flags
    sbr r16, (1<<DS3231_FLAGS_VALID_BIT)
    sts ds3231Flags, r16
#ifdef MODULES_NETWORK
;    rcall ds3231SendDebug
    rcall Ds3231_AnnounceTime
#endif  
Ds3231_OnEveryMinute_ret:
    out SREG, r15
  pop r15

  ret
; @end



; ---------------------------------------------------------------------------
; @routine ds3231CheckPresence
;
; Expects interrupts being disabled!
;
; @return CFLAG set if okay, clear on error
; @clobbers R16 (R17, R18, R22)

ds3231CheckPresence:
  ldi r16, (DS3231_ADDR*2)   ; write access
  rjmp twiCheckPresence      ; (R16, R17, R18, R22)
; @end



; ---------------------------------------------------------------------------
; @routine ds3231ReadData
;
; @param r16 start address
; @param r17 number of bytes to read
; @param X pointer to buffer to receive data
; @return CFLAG set if okay, cleared on error
; @return r16 number of bytes received if CFLAG set
; @clobbers r16, r17, r18, r19, r20, r22, X

ds3231ReadData:
  mov r20, r16
  mov r19, r17
  rcall twiStart                         ; (R22)
  ldi r16, (DS3231_ADDR*2)               ; write access
  rcall twiSendByteExpectAck             ; (R16, R17, R18, R22)
  brcc ds3231ReadData_error
  mov r16, r20
  rcall twiSendByteExpectAck
  brcc ds3231ReadData_error
  rcall twiRestart                       ; (R22)
  ldi r16, (DS3231_ADDR*2)+1             ; read access
  rcall twiSendByteExpectAck
  brcc ds3231ReadData_error

  clr r20
ds3231ReadData_loop1:
    cpi r19, 1
    breq ds3231ReadData_recvLast
    rcall twiReceiveByteSendAck            ; (R16, R17, R18, R22)
    rjmp ds3231ReadData_recvd
ds3231ReadData_recvLast:
    rcall twiReceiveByte                   ; don't send ACK (R16, R17, R18, R22)
ds3231ReadData_recvd:
    brcc ds3231ReadData_error
    st X+, r16
    inc r20
    dec r19
  brne ds3231ReadData_loop1
  rcall twiStop                          ; (R22)
  mov r16, r20
  sec
  ret
ds3231ReadData_error:
  rcall twiStop                          ; (R22)
  clc
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ds3231SendData
;
; @param r16 start address
; @param r17 number of bytes to read
; @param Z   pointer to buffer to send
; @return    CFLAG set if okay, cleared on error
; @return    r16 number of bytes received if CFLAG set
; @clobbers r16, r17, r18, r19, r20, r22, Z

ds3231SendData:
  mov r20, r16
  mov r19, r17
  rcall twiStart                         ; (R22)
  ldi r16, (DS3231_ADDR*2)               ; write access
  rcall twiSendByteExpectAck             ; (R16, R17, R18, R22)
  brcc ds3231SendData_error

  mov r16, r20                           ; address
  rcall twiSendByteExpectAck             ; (R16, R17, R18, R22)
  brcc ds3231SendData_error

  clr r20
ds3231SendData_loop1:
    ld r16, Z+
    rcall twiSendByteExpectAck             ; (R16, R17, R18, R22)
    brcc ds3231SendData_error
    inc r20
    dec r19
  brne ds3231SendData_loop1
  rcall twiStop                          ; (R22)
  mov r16, r20
  sec
  ret
ds3231SendData_error:
  rcall twiStop                          ; (R22)
  clc
  ret
; @end



