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

;
; The base timer makes sure that "onSystemTimerTick" is called about every
; 100ms.
; The setup depends on hardware and clock.
;



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

.dseg

baseTimerModuleData:
baseTimerModuleReloadValue: .byte 1
baseTimerModuleTickCounter: .byte 1
baseTimerTicksSinceLastRun: .byte 2
baseTimerModuleData_end:




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

.cseg

BASETIMER_BEGIN:



; ---------------------------------------------------------------------------
; @routine BaseTimer_Init @global
;
; @clobbers r16, r17, x

BaseTimer_Init:            ; setup timer for IRQ every 100ms
  ; reset data in SDRAM
  ldi xh, HIGH(baseTimerModuleData)
  ldi xl, LOW(baseTimerModuleData)
  ldi r16, 0
  ldi r17, (baseTimerModuleData_end-baseTimerModuleData)
  rcall Utils_FillSram

  bigcall systemSetupTimer0
  sec
  ret
; @end



; ---------------------------------------------------------------------------
; @routine BaseTimer_Fini @global
;

BaseTimer_Fini:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine BaseTimer_Run @global
;
; @return CFLAG set if something done, cleared otherwise
; @clobbers all

BaseTimer_Run:
  push r15
    in r15, SREG
    cli
      lds r24, baseTimerTicksSinceLastRun
      lds r25, baseTimerTicksSinceLastRun+1
      clr r16                               ; replace with 0 for next IRQ
      sts baseTimerTicksSinceLastRun, r16
      sts baseTimerTicksSinceLastRun+1, r16
    out SREG, r15                           ; restore global IRQ flag
  pop r15
  sbiw r25:r24, 0
  clc                                     ; flag "nothing done"
  breq BaseTimer_Run_End

BaseTimer_Run_loop:                       ; for every timer tick
    push r24
      push r25
        bigcall onSystemTimerTick
      pop r25
    pop r24
    sbiw r25:r24, 1
  brne BaseTimer_Run_loop
  sec
BaseTimer_Run_End:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine baseTimerIrqOC0A @isr
;
; OC0A interrupt handler
;
; Decrements baseTimerModuleTickCounter, if it reaches 0 then baseTimerTicksSinceLastRun
; is incremented and the baseTimerModuleTickCounter reloaded.
; The rest is done outside ISR baseTimerTicksSinceLastRun in BaseTimer_Run.

baseTimerIrqOC0A:
  push r15
    in r15, SREG

    push r24
      push r25
        lds r24, baseTimerModuleTickCounter
        dec r24
        breq baseTimerIrqOC0A_timerElapsed
        sts baseTimerModuleTickCounter, r24
        rjmp baseTimerIrqOC0A_end
        
baseTimerIrqOC0A_timerElapsed:
        lds r24, baseTimerModuleReloadValue  ; reload counter
        sts baseTimerModuleTickCounter, r24
        
        lds r24, baseTimerTicksSinceLastRun
        lds r25, baseTimerTicksSinceLastRun+1
        adiw r25:r24, 1
        sts baseTimerTicksSinceLastRun, r24
        sts baseTimerTicksSinceLastRun+1, r25
        
baseTimerIrqOC0A_end:
      pop r25
    pop r24
    out SREG, r15
  pop r15
  reti
; @end



BASETIMER_END:
.equ MODULE_SIZE_BASETIMER = BASETIMER_END-BASETIMER_BEGIN



