; ***************************************************************************
; 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.   *
; ***************************************************************************

#ifndef AQH_AVR_GUI_SCREENSAVER_SIMPLE_ASM
#define AQH_AVR_GUI_SCREENSAVER_SIMPLE_ASM


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

.equ SIMPLESAVER_TIMER100ms              =  6000 ; 10mins
;.equ SIMPLESAVER_TIMER100ms              =  100 ; 10secs


; widget data
.equ SIMPLESAVER_OFFS_BEGIN     = MAINWINDOW_SIZE
.equ SIMPLESAVER_OFFS_TIMER_LO  = SIMPLESAVER_OFFS_BEGIN+0
.equ SIMPLESAVER_OFFS_TIMER_HI  = SIMPLESAVER_OFFS_BEGIN+1
.equ SIMPLESAVER_OFFS_RELOAD_LO = SIMPLESAVER_OFFS_BEGIN+2
.equ SIMPLESAVER_OFFS_RELOAD_HI = SIMPLESAVER_OFFS_BEGIN+3
.equ SIMPLESAVER_OFFS_NODEADDR1 = SIMPLESAVER_OFFS_BEGIN+4
.equ SIMPLESAVER_OFFS_VALUEID1  = SIMPLESAVER_OFFS_BEGIN+5
.equ SIMPLESAVER_OFFS_NODEADDR2 = SIMPLESAVER_OFFS_BEGIN+6
.equ SIMPLESAVER_OFFS_VALUEID2  = SIMPLESAVER_OFFS_BEGIN+7
.equ SIMPLESAVER_SIZE           = SIMPLESAVER_OFFS_BEGIN+8


; EEPROM data
.equ SIMPLESAVER_EE_OFFS_NODEADDR1       = 0
.equ SIMPLESAVER_EE_OFFS_VALUEID1        = 1
.equ SIMPLESAVER_EE_OFFS_NODEADDR2       = 2
.equ SIMPLESAVER_EE_OFFS_VALUEID2        = 3
.equ SIMPLESAVER_EE_SIZE                 = 4



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

.cseg



; ---------------------------------------------------------------------------
; @routine SimpleSaver_new @global
;
; @return CFLAG set of okay, cleared otherwise
; @return Y address of newly created object
; @param X parent widget
; @param r16 value for OBJECT_OFFS_OPTS
; @param r17 value for WIDGET_OFFS_PACK
; @clobbers any

SimpleSaver_new:
  ldi r24, LOW(SIMPLESAVER_SIZE)
  ldi r25, HIGH(SIMPLESAVER_SIZE)
  bigcall Object_Alloc              ; (!r16, !r17, !X)
  brcc SimpleSaver_new_ret
  rcall SimpleSaver_Init            ; (r16, r17, X)
  sec
SimpleSaver_new_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine SimpleSaver_Init @global
;
; @return CFLAG set of okay, cleared otherwise
; @return Y address of newly created object
; @param X parent widget
; @param r16 value for OBJECT_OFFS_OPTS
; @param r17 value for WIDGET_OFFS_PACK
; @clobbers any

SimpleSaver_Init:
  ; call base class
  bigcall MainWindow_Init

  ; set default signal map
  ldi r16, LOW(SimpleSaver_DefaultSignalmap*2)
  std Y+OBJECT_OFFS_SIGNALMAP_LO, r16
  ldi r16, HIGH(SimpleSaver_DefaultSignalmap*2)
  std Y+OBJECT_OFFS_SIGNALMAP_HI, r16

  ; set style which has no spacing and no borders
  ldi r16, LOW(SimpleSaver_DefaultStyle*2)
  std Y+WIDGET_OFFS_STYLE_LO, r16
  ldi r16, HIGH(SimpleSaver_DefaultStyle*2)
  std Y+WIDGET_OFFS_STYLE_HI, r16

  ; read config from eeprom
  rcall simpleSaverReadFromEeprom

  ; preset and start timer
  ldi r16, LOW(SIMPLESAVER_TIMER100ms)
  ldi r17, HIGH(SIMPLESAVER_TIMER100ms)
  std Y+SIMPLESAVER_OFFS_RELOAD_LO, r16
  std Y+SIMPLESAVER_OFFS_RELOAD_HI, r17
  std Y+SIMPLESAVER_OFFS_TIMER_LO, r16
  std Y+SIMPLESAVER_OFFS_TIMER_HI, r17

  ret
; @end




SimpleSaver_Enter:
  bigcall Widget_GetApp
  push yl
    push yh
      mov xl, yl
      mov xh, yh
      mov yl, r18
      mov yh, r19
      bigcall GuiApp_EnterWindow
    pop yh
  pop yl
  
  ret
; @end



SimpleSaver_Leave:
  ldd r16, Y+OBJECT_OFFS_FLAGS
  andi r16, (1<<WIDGET_FLAGS_VISIBLE_BIT)
  breq SimpleSaver_Leave_ret                ; jump if not active

  bigcall Widget_GetApp
  push yl
    push yh
      mov yl, r18
      mov yh, r19
      bigcall GuiApp_LeaveWindow
    pop yh
  pop yl
SimpleSaver_Leave_ret:
  ret
; @end



SimpleSaver_KeepAlive:
  ; restart timer
  ldd r16, Y+SIMPLESAVER_OFFS_RELOAD_LO
  ldd r17, Y+SIMPLESAVER_OFFS_RELOAD_HI
  std Y+SIMPLESAVER_OFFS_TIMER_LO, r16
  std Y+SIMPLESAVER_OFFS_TIMER_HI, r17
  ; screen saver active?
  ldd r16, Y+OBJECT_OFFS_FLAGS
  andi r16, (1<<WIDGET_FLAGS_VISIBLE_BIT)
  breq SimpleSaver_KeepAlive_ret           ; jump if not active
  rcall SimpleSaver_Leave
SimpleSaver_KeepAlive_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine simpleSaverWriteToEeprom
;
; @param Y      widget
; @return CFLAG set if data found and read, cleared on error
; @clobbers R16, R17, R18, R20, R21, X

simpleSaverWriteToEeprom:
  ldi r16, EEID_SCREENSAVER
  bigcall EepromTlv_FindFirst                    ; (R18)
  brcs simpleSaverWriteToEeprom_write
  ldi r16, EEID_SCREENSAVER
  ldi r17, SIMPLESAVER_EE_SIZE
  bigcall EepromTlv_AddTlv                       ; X=pointer to EEPROM data (R16, R18, R20, R21)
  brcc simpleSaverWriteToEeprom_ret
simpleSaverWriteToEeprom_write:
  push yl
    push yh
      adiw yh:yl, SIMPLESAVER_OFFS_NODEADDR1
      ldi r18, SIMPLESAVER_EE_SIZE
simpleSaverWriteToEeprom_loop:
        ld r16, Y+
        bigcall Eeprom_WriteByteIfChanged            ; (R17)
        brcc simpleSaverWriteToEeprom_ret
        adiw xh:xl, 1
        dec r18
      brne simpleSaverWriteToEeprom_loop
    pop yh
  pop yl  
  sec
simpleSaverWriteToEeprom_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine simpleSaverReadFromEeprom
;
; @param Y      widget
; @return CFLAG set if data found and read, cleared on error
; @clobbers R16, R18, X

simpleSaverReadFromEeprom:
  ldi r16, EEID_SCREENSAVER
  bigcall EepromTlv_FindFirst                    ; (R18)
  brcc simpleSaverReadFromEeprom_ret
  push yl
    push yh
      adiw yh:yl, SIMPLESAVER_OFFS_NODEADDR1
      ldi r18, SIMPLESAVER_EE_SIZE
simpleSaverReadFromEeprom_loop:
        bigcall Eeprom_ReadByte                      ; R16=byte (none)
        brcc simpleSaverReadFromEeprom_ret
        st Y+, r16
        adiw xh:xl, 1
        dec r18
      brne simpleSaverReadFromEeprom_loop
    pop yh
  pop yl  
  sec
simpleSaverReadFromEeprom_ret:
  ret
; @end




; ***************************************************************************
; signal handlers

SimpleSaver_OnTimer:
  ldd r16, Y+OBJECT_OFFS_FLAGS
  andi r16, (1<<WIDGET_FLAGS_VISIBLE_BIT)
  brne SimpleSaver_OnTimer_ret            ; jump if active
  ; check timer
  ldd r24, Y+SIMPLESAVER_OFFS_TIMER_LO
  ldd r25, Y+SIMPLESAVER_OFFS_TIMER_HI
  mov r16, r24
  or r16, r25
  breq SimpleSaver_OnTimer_ret
  sbiw r25:r24, 1
  std Y+SIMPLESAVER_OFFS_TIMER_LO, r24
  std Y+SIMPLESAVER_OFFS_TIMER_HI, r25
  brne SimpleSaver_OnTimer_ret
  ; timer elapsed, enter screensaver
  rcall SimpleSaver_Enter
SimpleSaver_OnTimer_ret:
  sec
  ret
; @end



SimpleSaver_OnTouch:
  ; read touch signal data from X
  adiw xh:xl, WIDGET_TOUCH_OFFS_STATE
  ld r22, X                                ; WIDGET_DATA_TOUCH_OFFS_STATE
  sbiw xh:xl, WIDGET_TOUCH_OFFS_STATE

  sbrs r22, DISPLAY_IFLAGS_PRESSED_BIT
    rjmp SimpleSaver_OnTouch_up
  ; down (active touch), switch display on
  ldi r16, 0xff
  bigcall Display_SetBacklight
  rjmp SimpleSaver_OnTouch_ret
SimpleSaver_OnTouch_up:
  rcall SimpleSaver_KeepAlive
SimpleSaver_OnTouch_ret:
  sec
  ret
; @end



SimpleSaver_OnMsgReceived:
  push zl
    push zh
      ldi zl, LOW(SimpleSaver_MsgTable*2)
      ldi zh, HIGH(SimpleSaver_MsgTable*2)
      bigcall Main_HandleValueMsg           ; (any)
    pop zh
  pop zl
  clc
  ret
; @end



SimpleSaver_OnShow:
  ldd r16, Y+OBJECT_OFFS_FLAGS
  sbrc r16, WIDGET_FLAGS_VISIBLE_BIT
    rjmp SimpleSaver_OnShow_ret

  bigcall MainWindow_CreateContentWidget    ; R19:R18=content window
  brcc SimpleSaver_OnShow_ret

  ; overwrite content window style (use black background)
  push yl
    push yh
      mov yl, r18
      mov yh, r19
      ldi r16, LOW(SimpleSaver_DefaultStyle*2)
      std Y+WIDGET_OFFS_STYLE_LO, r16
      ldi r16, HIGH(SimpleSaver_DefaultStyle*2)
      std Y+WIDGET_OFFS_STYLE_HI, r16
    pop yh
  pop yl
  
  ; stop timer
  clr r16
  std Y+SIMPLESAVER_OFFS_TIMER_LO, r16
  std Y+SIMPLESAVER_OFFS_TIMER_HI, r16

  ; force redraw (black background)
  ldd r16, Y+OBJECT_OFFS_FLAGS
  sbr r16, (1<<WIDGET_FLAGS_DIRTY_BIT) | (1<<WIDGET_FLAGS_VISIBLE_BIT)
  std Y+OBJECT_OFFS_FLAGS, r16

SimpleSaver_OnShow_ret:
  ; turn off backlight
  clr r16
  bigcall Display_SetBacklight
  sec
  ret
; @end



; ---------------------------------------------------------------------------
; @routine SimpleSaver_OnHide @global
;
; @param  Y       pointer to dialog
; @return CFLAG set of okay, cleared otherwise
; @clobbers any, !Y

SimpleSaver_OnHide:
  ldd r16, Y+OBJECT_OFFS_FLAGS
  sbrs r16, WIDGET_FLAGS_VISIBLE_BIT
    rjmp SimpleSaver_OnHide_ret

  bigcall Dialog_OnHide  ; destroys content window
  
  ; restart timer
  ldd r16, Y+SIMPLESAVER_OFFS_RELOAD_LO
  ldd r17, Y+SIMPLESAVER_OFFS_RELOAD_HI
  std Y+SIMPLESAVER_OFFS_TIMER_LO, r16
  std Y+SIMPLESAVER_OFFS_TIMER_HI, r17
SimpleSaver_OnHide_ret:
  ; turn backlight on
  ldi r16, 0xff
  bigcall Display_SetBacklight
  sec
  ret
; @end



SimpleSaver_OnKeepAlive:
  rcall SimpleSaver_KeepAlive
  sec
  ret
; @end



; ***************************************************************************
; message handlers


; ---------------------------------------------------------------------------
; @routine simpleSaverHandleSetSource1
;
; @param Y       widget
; @param R17     value id
; @param R19:R18 value
; @param R21:R20 denom (e.g. 100, meaning value must be divided by 100)
; @param R22     source address
; @param R23     command
; @param R25:R24 message id
; @return CFLAG  set if ACK/NACK requested
; @return R23    command value for ACK/NACK message
; @clobbers R16, R17, R18, R20, R21, X, Y, Z

simpleSaverHandleSetSource1:
  std Y+SIMPLESAVER_OFFS_NODEADDR1, r18
  std Y+SIMPLESAVER_OFFS_VALUEID1, r19
  rcall simpleSaverWriteToEeprom           ; (R16, R17, R18, R20, R21, X, Y)
  ldi r23, NETMSG_CMD_VALUE_SET_ACK
  sec
  ret
; @end



; ---------------------------------------------------------------------------
; @routine simpleSaverHandleSetSource2
;
; @param Y       widget
; @param R17     value id
; @param R19:R18 value
; @param R21:R20 denom (e.g. 100, meaning value must be divided by 100)
; @param R22     source address
; @param R23     command
; @param R25:R24 message id
; @return CFLAG  set if ACK/NACK requested
; @return R23    command value for ACK/NACK message
; @clobbers R16, R17, R18, R20, R21, X, Y, Z

simpleSaverHandleSetSource2:
  std Y+SIMPLESAVER_OFFS_NODEADDR1, r18
  std Y+SIMPLESAVER_OFFS_VALUEID1, r19
  rcall simpleSaverWriteToEeprom           ; (R16, R17, R18, R20, R21, X, Y)
  ldi r23, NETMSG_CMD_VALUE_SET_ACK
  sec
  ret
; @end



; ---------------------------------------------------------------------------
; @routine simpleSaverHandleReport
;
; @param Y       widget
; @param R17     value id
; @param R19:R18 value
; @param R21:R20 denom (e.g. 100, meaning value must be divided by 100)
; @param R22     source address
; @param R23     command
; @param R25:R24 message id
; @return CFLAG  cleared (no ACK/NACK requested)
; @clobbers any

simpleSaverHandleReport:
  mov r16, r18                             ; check for non-zero value
  or r16, r19
  breq simpleSaverHandleReport_end
  ldd r16, Y+SIMPLESAVER_OFFS_NODEADDR1
  cp r16, r22
  brne simpleSaverHandleReport_l1
  ldd r16, Y+SIMPLESAVER_OFFS_VALUEID1
  cp r16, r17
  breq simpleSaverHandleReport_matches

simpleSaverHandleReport_l1:
  ldd r16, Y+SIMPLESAVER_OFFS_NODEADDR2
  cp r16, r22
  brne simpleSaverHandleReport_end
  ldd r16, Y+SIMPLESAVER_OFFS_VALUEID2
  cp r16, r17
  brne simpleSaverHandleReport_end
simpleSaverHandleReport_matches:
  rcall SimpleSaver_KeepAlive
simpleSaverHandleReport_end:
  clc                                      ; no ACK needed
  ret
; @end





; ***************************************************************************
; data in FLASH

SimpleSaver_DefaultStyle:
  .dw DISPLAY_COLOR_LIGHTGREY  ; frontCol_norm
  .dw DISPLAY_COLOR_BLACK      ; backCol_norm
  .dw DISPLAY_COLOR_BLACK      ; borderCol_norm
  .dw DISPLAY_COLOR_WHITE      ; shadowCol_norm
  
  .dw DISPLAY_COLOR_WHITE      ; frontCol_activated
  .dw DISPLAY_COLOR_NAVY       ; backCol_activated
  .dw DISPLAY_COLOR_BLACK      ; borderCol_activated
  .dw DISPLAY_COLOR_WHITE      ; shadowCol_activated
  
  .db 0, 1                     ; outerBorderSize, innerBorderSize
  .dw ili9341Font12x16_1*2     ; font
  .db 12, 16                   ; charWidth, charHeight



SimpleSaver_MsgTable:
  .dw NETMSG_CMD_VALUE_SET | (VALUE_ID_SCREENSAVER_SETSOURCE1<<8), simpleSaverHandleSetSource1
  .dw NETMSG_CMD_VALUE_SET | (VALUE_ID_SCREENSAVER_SETSOURCE2<<8), simpleSaverHandleSetSource2
  .dw NETMSG_CMD_VALUE_REPORT,                                     simpleSaverHandleReport
  .dw 0, 0



SimpleSaver_DefaultSignalmap:
  ; header
  .dw MainWindow_DefaultSignalmap*2  ; next table to use
  ; entries
  .db 0, OBJECT_SIGNAL_TIMER,     LOW(SimpleSaver_OnTimer),       HIGH(SimpleSaver_OnTimer)
  .db 0, WIDGET_SIGNAL_KEEPALIVE, LOW(SimpleSaver_OnKeepAlive),   HIGH(SimpleSaver_OnKeepAlive)
  .db 0, WIDGET_SIGNAL_SHOW,      LOW(SimpleSaver_OnShow),        HIGH(SimpleSaver_OnShow)
  .db 0, WIDGET_SIGNAL_HIDE,      LOW(SimpleSaver_OnHide),        HIGH(SimpleSaver_OnHide)
  .db 0, WIDGET_SIGNAL_TOUCH,     LOW(SimpleSaver_OnTouch),       HIGH(SimpleSaver_OnTouch)
  .db 0, OBJECT_SIGNAL_RECVMSG,   LOW(SimpleSaver_OnMsgReceived), HIGH(SimpleSaver_OnMsgReceived)
  .db 0, WIDGET_SIGNAL_DRAW,      LOW(Widget_OnDraw),             HIGH(Widget_OnDraw)

  .db 0, 0, 0, 0  ; end of table




#endif



