; ***************************************************************************
; 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_GUI2_SENSORWATCH_ASM
#define AQH_AVR_GUI2_SENSORWATCH_ASM


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

.equ SENSORWATCH_OFFS_BEGIN               = VLAYOUT_SIZE
.equ SENSORWATCH_OFFS_BASEVALUEID         = SENSORWATCH_OFFS_BEGIN+0
.equ SENSORWATCH_OFFS_EEPROMID            = SENSORWATCH_OFFS_BEGIN+1
.equ SENSORWATCH_OFFS_NODEADDR            = SENSORWATCH_OFFS_BEGIN+2
.equ SENSORWATCH_OFFS_VALUEID             = SENSORWATCH_OFFS_BEGIN+3
.equ SENSORWATCH_OFFS_UPPER_LIMIT_WARN_LO = SENSORWATCH_OFFS_BEGIN+4
.equ SENSORWATCH_OFFS_UPPER_LIMIT_WARN_HI = SENSORWATCH_OFFS_BEGIN+5
.equ SENSORWATCH_OFFS_LOWER_LIMIT_WARN_LO = SENSORWATCH_OFFS_BEGIN+6
.equ SENSORWATCH_OFFS_LOWER_LIMIT_WARN_HI = SENSORWATCH_OFFS_BEGIN+7
.equ SENSORWATCH_OFFS_UPPER_LIMIT_CRIT_LO = SENSORWATCH_OFFS_BEGIN+8
.equ SENSORWATCH_OFFS_UPPER_LIMIT_CRIT_HI = SENSORWATCH_OFFS_BEGIN+9
.equ SENSORWATCH_OFFS_LOWER_LIMIT_CRIT_LO = SENSORWATCH_OFFS_BEGIN+10
.equ SENSORWATCH_OFFS_LOWER_LIMIT_CRIT_HI = SENSORWATCH_OFFS_BEGIN+11
.equ SENSORWATCH_OFFS_VALUE_LO            = SENSORWATCH_OFFS_BEGIN+12
.equ SENSORWATCH_OFFS_VALUE_HI            = SENSORWATCH_OFFS_BEGIN+13
.equ SENSORWATCH_OFFS_TYPE                = SENSORWATCH_OFFS_BEGIN+14
.equ SENSORWATCH_SIZE                     = SENSORWATCH_OFFS_BEGIN+15

; sensor types
.equ SENSORWATCH_TYPE_CO2       = 1
.equ SENSORWATCH_TYPE_TEMP      = 2
.equ SENSORWATCH_TYPE_HUM       = 3
.equ SENSORWATCH_TYPE_NEXTFREE  = 4

; indices of child widgets
.equ SENSORWATCH_CHILDIDX_TITLE      = 0
.equ SENSORWATCH_CHILDIDX_IMAGEVIEW  = 1
.equ SENSORWATCH_CHILDIDX_VALUELABEL = 2

; descriptors
.equ SENSORWATCH_DESCR_OFFS_TITLERES        = 0
.equ SENSORWATCH_DESCR_OFFS_IMGRES          = 2
.equ SENSORWATCH_DESCR_OFFS_POSTKOMMADIGITS = 4

; EEPROM data for SensorWatch
.equ SENSORWATCH_EE_OFFS_NODEADDR            = 0
.equ SENSORWATCH_EE_OFFS_VALUEID             = 1
.equ SENSORWATCH_EE_OFFS_UPPER_LIMIT_WARN_LO = 2
.equ SENSORWATCH_EE_OFFS_UPPER_LIMIT_WARN_HI = 3
.equ SENSORWATCH_EE_OFFS_LOWER_LIMIT_WARN_LO = 4
.equ SENSORWATCH_EE_OFFS_LOWER_LIMIT_WARN_HI = 5
.equ SENSORWATCH_EE_OFFS_UPPER_LIMIT_CRIT_LO = 6
.equ SENSORWATCH_EE_OFFS_UPPER_LIMIT_CRIT_HI = 7
.equ SENSORWATCH_EE_OFFS_LOWER_LIMIT_CRIT_LO = 8
.equ SENSORWATCH_EE_OFFS_LOWER_LIMIT_CRIT_HI = 9
.equ SENSORWATCH_EE_SIZE                     = 10


; values
.equ SENSORWATCH_VALUE_UPPERLIMITWARN = WIDGET_VALUE_NEXTFREE+0
.equ SENSORWATCH_VALUE_LOWERLIMITWARN = WIDGET_VALUE_NEXTFREE+1
.equ SENSORWATCH_VALUE_UPPERLIMITCRIT = WIDGET_VALUE_NEXTFREE+2
.equ SENSORWATCH_VALUE_LOWERLIMITCRIT = WIDGET_VALUE_NEXTFREE+3
.equ SENSORWATCH_VALUE_NEXT           = WIDGET_VALUE_NEXTFREE+4


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

.cseg



; ---------------------------------------------------------------------------
; @routine SensorWatch_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
; @param r20     base value id
; @param r21     eeprom id
; @param r22     type (see @ref SENSORWATCH_TYPE_CO2)
; @clobbers any

SensorWatch_new:
  push r20
    push r21
      push r22
        ldi r24, LOW(SENSORWATCH_SIZE)
        ldi r25, HIGH(SENSORWATCH_SIZE)
        bigcall Object_Alloc           ; (!r16, !r17, !X)
      pop r22
    pop r21
  pop r20
  brcc SensorWatch_new_ret
  rcall SensorWatch_Init               ; (r16, r17, X)
  sec
SensorWatch_new_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine SensorWatch_Init @global
;
; @param Y address of widget
; @param X parent widget (if any)
; @param r16 value for OBJECT_OFFS_OPTS
; @param r17 value for WIDGET_OFFS_PACK
; @param r20 base value id
; @param r21 eeprom id
; @param r22 type (see @ref SENSORWATCH_TYPE_CO2)
; @clobbers r16, r17, X

SensorWatch_Init:
  push r20
    push r21
      push r22
        ; call base class
        ldi r20, VLAYOUT_MODE_EXPAND
        bigcall VLayout_Init
      pop r22
    pop r21
  pop r20

  ; setup sensorWatch data
  std Y+SENSORWATCH_OFFS_BASEVALUEID, r20
  std Y+SENSORWATCH_OFFS_EEPROMID, r21
  std Y+SENSORWATCH_OFFS_TYPE, r22
  
  ; set default signal map
  ldi r16, LOW(SensorWatch_DefaultSignalmap*2)
  std Y+OBJECT_OFFS_SIGNALMAP_LO, r16
  ldi r16, HIGH(SensorWatch_DefaultSignalmap*2)
  std Y+OBJECT_OFFS_SIGNALMAP_HI, r16

  ; create sub windows
  rcall sensorWatchCreateTitleLabel
  rcall sensorWatchCreateImageViewer
  rcall sensorWatchCreateValueLabel

  rcall SensorWatch_fromEeprom        ; (R16, R18, X)

  ret
; @end



; ---------------------------------------------------------------------------
; @routine sensorWatchGetTitleResId
;
; @param r16      sensor type (see @ref SENSORWATCH_TYPE_CO2)
; @return r21:r20 ressource for sensor title

sensorWatchGetTitleResId:
  rcall sensorWatchGetDescriptor   ; (r17, r18, r19)
  adiw zh:zl, SENSORWATCH_DESCR_OFFS_TITLERES
  lpm r20, Z+
  lpm r21, Z
  ret
; @end



; ---------------------------------------------------------------------------
; @routine sensorWatchGetImgResId
;
; @param r16      sensor type (see @ref SENSORWATCH_TYPE_CO2)
; @return r21:r20 ressource for sensor title

sensorWatchGetImgResId:
  rcall sensorWatchGetDescriptor   ; (r17, r18, r19)
  adiw zh:zl, SENSORWATCH_DESCR_OFFS_IMGRES
  lpm r20, Z+
  lpm r21, Z
  ret
; @end



; ---------------------------------------------------------------------------
; @routine sensorWatchGetPostKommaDigits
;
; @param r16      sensor type (see @ref SENSORWATCH_TYPE_CO2)
; @return r20 postkomma digits

sensorWatchGetPostKommaDigits:
  rcall sensorWatchGetDescriptor   ; (r17, r18, r19)
  adiw zh:zl, SENSORWATCH_DESCR_OFFS_POSTKOMMADIGITS
  lpm r20, Z
  ret
; @end



; ---------------------------------------------------------------------------
; @routine sensorWatchGetDescriptor
;
; @param  r16  sensor type (see @ref SENSORWATCH_TYPE_CO2)
; @return Z    byte address of start of descriptor for sensor type (for LPM!)
; @clobbers r17, r18, r19

sensorWatchGetDescriptor:
  cpi r16, SENSORWATCH_TYPE_NEXTFREE
  brcs sensorWatchGetDescriptor_get
  clr r16                                  ; default to entry 0
sensorWatchGetDescriptor_get:
  ldi zl, LOW(SensorWatch_Descriptors*2)
  ldi zh, HIGH(SensorWatch_Descriptors*2)
  clr r17
  mov r18, r16
  mov r19, r17
  lsl r18      ; *2
  rol r19
  add r18, r16 ; *3
  adc r19, r17
  lsl r18      ; *6
  rol r19
  add zl, r18
  adc zh, r19
  ret
; @end




; ---------------------------------------------------------------------------
; @routine sensorWatchCreateTitleLabel
;
; @param Y address of main window widget
; @param r21:r20 ressource id for title
; @return CFLAG set of okay, cleared otherwise

sensorWatchCreateTitleLabel:
  push yl
    push yh
      ldd r16, Y+SENSORWATCH_OFFS_TYPE
      rcall sensorWatchGetTitleResId  ; r21:r20=ressource id for title
      mov xl, yl
      mov xh, yh
      ldi r16, 0
      ldi r17, (WIDGET_PACK_CENTER<<WIDGET_PACK_HSELF0_BIT)     | (WIDGET_PACK_BEGIN<<WIDGET_PACK_VSELF0_BIT) | \
               (WIDGET_PACK_CENTER<<WIDGET_PACK_HCONTENT0_BIT)  | (WIDGET_PACK_CENTER<<WIDGET_PACK_VCONTENT0_BIT)
      bigcall Label_new
    pop yh
  pop yl
  ret
; @end



; ---------------------------------------------------------------------------
; @routine sensorWatchCreateImageViewer
;
; @param Y address of main window widget
; @param r21:r20 ressource id for image
; @return CFLAG set of okay, cleared otherwise

sensorWatchCreateImageViewer:
  push yl
    push yh
      ldd r16, Y+SENSORWATCH_OFFS_TYPE
      rcall sensorWatchGetImgResId  ; r21:r20=ressource id for image
      mov xl, yl
      mov xh, yh
      ldi r16, 0
      ldi r17, (WIDGET_PACK_CENTER<<WIDGET_PACK_HSELF0_BIT)     | (WIDGET_PACK_BEGIN<<WIDGET_PACK_VSELF0_BIT) | \
               (WIDGET_PACK_CENTER <<WIDGET_PACK_HCONTENT0_BIT) | (WIDGET_PACK_CENTER<<WIDGET_PACK_VCONTENT0_BIT)
      bigcall ImageView_new
    pop yh
  pop yl
  ret
; @end



; ---------------------------------------------------------------------------
; @routine sensorWatchCreateValueLabel
;
; @param Y address of main window widget
; @return CFLAG set of okay, cleared otherwise

sensorWatchCreateValueLabel:
  push yl
    push yh
      ldd r16, Y+SENSORWATCH_OFFS_TYPE
      rcall sensorWatchGetPostKommaDigits  ; r20=postkomma digits
      clr r21                              ; variable size
      mov xl, yl
      mov xh, yh
      ldi r16, 0
      ldi r17, (WIDGET_PACK_FILLED<<WIDGET_PACK_HSELF0_BIT)     | (WIDGET_PACK_BEGIN<<WIDGET_PACK_VSELF0_BIT) | \
               (WIDGET_PACK_CENTER <<WIDGET_PACK_HCONTENT0_BIT) | (WIDGET_PACK_CENTER<<WIDGET_PACK_VCONTENT0_BIT)
      bigcall ValueLabel_new
    pop yh
  pop yl
  ret
; @end



; ---------------------------------------------------------------------------
; @routine SensorWatch_GetImageView @global
;
; @param Y pointer to widget
; @return CFLAG set if widget found, cleared otherwise
; @return R19:R18 byte address pointer to image view (for LPM!)
; @clobbers R16

SensorWatch_GetImageView:
  ldi r16, SENSORWATCH_CHILDIDX_IMAGEVIEW
  bigcall OBJ_GetChildAt
  ret
; @end



; ---------------------------------------------------------------------------
; @routine SensorWatch_GetValueLabel @global
;
; @param Y pointer to widget
; @return CFLAG set if widget found, cleared otherwise
; @return R19:R18 byte address pointer to image view (for LPM!)
; @clobbers R16

SensorWatch_GetValueLabel:
  ldi r16, SENSORWATCH_CHILDIDX_VALUELABEL
  bigcall OBJ_GetChildAt
  ret
; @end



SensorWatch_OnSetCurrentValue:
  std Y+SENSORWATCH_OFFS_VALUE_LO, xl
  std Y+SENSORWATCH_OFFS_VALUE_HI, xh
  rjmp sensorWatchUpdate
; @end



sensorWatchUpdate:
  ; setup background color
  push xl
    push xh
      rcall sensorWatchSetColor                       ; (any, !Y)
      rcall sensorWatchSetValueLabel                  ; (any, !Y)
    pop xh
  pop xl
  sec
  ret
; @end



; ---------------------------------------------------------------------------
; @routine sensorWatchSetValueLabel
;
; @param Z byte address of widget object (for LPM!)
; @param Y pointer to SDRAM data
; @clobbers any, !Y, !Z

sensorWatchSetValueLabel:
  rcall SensorWatch_GetValueLabel         ; (none)
  brcc sensorWatchSetValueLabel_ret
  push yl
    push yh
      ldd xl, Y+SENSORWATCH_OFFS_VALUE_LO
      ldd xh, Y+SENSORWATCH_OFFS_VALUE_HI
      mov yl, r18
      mov yh, r19
      bigcall Widget_SetCurrentValue                   ; (any, !Y)
    pop yh
  pop yl
sensorWatchSetValueLabel_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine sensorWatchSetColor
;
; @param Y pointer to widget
; @clobbers any, !Y

sensorWatchSetColor:
  ; default color is green
  ldi xl, LOW(DISPLAY_COLOR_DARKGREEN)
  ldi xh, HIGH(DISPLAY_COLOR_DARKGREEN)
  ldd r20, Y+SENSORWATCH_OFFS_VALUE_LO
  ldd r21, Y+SENSORWATCH_OFFS_VALUE_HI
  mov r16, r20
  or r16, r21
  breq sensorWatchSetColor_ret                   ; do nothing
    
 ; check against critical limits
  mov zl, yl
  mov zh, yh
  adiw zh:zl, SENSORWATCH_OFFS_UPPER_LIMIT_CRIT_LO
  rcall sensorWatchCheckAgainstLimit                   ; (r16, r17, r22, r23)
  brcs sensorWatchSetColor_setRed

  ; check against warning limits
  mov zl, yl
  mov zh, yh
  adiw zh:zl, SENSORWATCH_OFFS_UPPER_LIMIT_WARN_LO
  rcall sensorWatchCheckAgainstLimit                   ; (r16, r17, r22, r23)
  brcs sensorWatchSetColor_setYellow
    
  ; set green background
  rjmp sensorWatchSetColor_setColor

sensorWatchSetColor_setRed:
  ldi xl, LOW(DISPLAY_COLOR_RED)
  ldi xh, HIGH(DISPLAY_COLOR_RED)
  rjmp sensorWatchSetColor_setColor
  
sensorWatchSetColor_setYellow:
  ldi xl, LOW(DISPLAY_COLOR_YELLOW)
  ldi xh, HIGH(DISPLAY_COLOR_YELLOW)
  
sensorWatchSetColor_setColor:
  rcall SensorWatch_GetImageView                  ; (r16)
  brcc sensorWatchSetColor_ret
  push yl
    push yh
      mov yl, r18
      mov yh, r19
      ldi r17, IMAGEVIEW_VALUE_BGCOL
      bigcall Widget_SetValue                     ; (any, !Y)
    pop yh
  pop yl
sensorWatchSetColor_ret:
  ret
; @end





; ---------------------------------------------------------------------------
; @routine sensorWatchCheckAgainstLimit
;
; @param R21:R20 value to check against limit
; @param Z points to upper limit (lo/hi), followed by lower limit (lo/hi)
; @return CFLAG set if limit triggered, cleared if between upper and lower limit
; @clobbers r16, r17, r22, r23

sensorWatchCheckAgainstLimit:
  ; check against upper limit (if any)
  ld r22, Z+
  ld r23, Z+
  mov r16, r22
  or r16, r23                              ; zero?
  breq sensorWatchCheckAgainstLimit_checkLower
  ; r23:r22=upper limit
  cp r20, r22                                ; upper limit > value?
  cpc r21, r23
  brcc sensorWatchCheckAgainstLimit_secRet   ; no, upper limit breached

sensorWatchCheckAgainstLimit_checkLower:
  ; check against lower limit (if any)
  ld r22, Z+
  ld r23, Z+
  mov r16, r22
  or r16, r23                              ; zero?
  clc
  breq sensorWatchCheckAgainstLimit_ret    ; yes, jmp

  cp r20, r22                              ; value below lower limit?
  cpc r21, r23
  brcs sensorWatchCheckAgainstLimit_secRet ; yes -> lower limit breached
  
  clc                                      ; limit not breached
  rjmp sensorWatchCheckAgainstLimit_ret
sensorWatchCheckAgainstLimit_secRet:
  sec
sensorWatchCheckAgainstLimit_ret:
  ret
; @end




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

SensorWatch_fromEeprom:
  ldd r16, Y+SENSORWATCH_OFFS_EEPROMID
  bigcall EepromTlv_FindFirst                    ; (R18)
  brcc SensorWatch_fromEeprom_ret
  push yl
    push yh
      adiw yh:yl, SENSORWATCH_OFFS_NODEADDR
      ldi r18, SENSORWATCH_EE_SIZE
SensorWatch_fromEeprom_loop:
        bigcall Eeprom_ReadByte                      ; R16=byte (none)
        brcc SensorWatch_fromEeprom_loopEnd
        st Y+, r16
        adiw xh:xl, 1
        dec r18
      brne SensorWatch_fromEeprom_loop
      sec
SensorWatch_fromEeprom_loopEnd:
    pop yh
  pop yl  
SensorWatch_fromEeprom_ret:
  ret
; @end








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

SensorWatch_DefaultSignalmap:
  ; header
  .dw VLayout_DefaultSignalmap*2  ; next table to use
  ; entries
  .db 0,                                WIDGET_SIGNAL_DRAW,     LOW(Widget_OnDraw),                   HIGH(Widget_OnDraw)
  .db WIDGET_VALUE_CURRENTVALUE,        WIDGET_SIGNAL_SETVALUE, LOW(SensorWatch_OnSetCurrentValue),   HIGH(SensorWatch_OnSetCurrentValue)
  .db 0, 0, 0, 0  ; end of table



SensorWatch_Descriptors:
;     res for title             res for image              post-komma digits
  .dw RESSOURCE_TXT_UNKNOWN_S,  RESSOURCE_IMG_CLOUD96,     0                   ; unknown
  .dw RESSOURCE_TXT_CO2_S,      RESSOURCE_IMG_CLOUD96,     0                   ; co2
  .dw RESSOURCE_TXT_TEMP_S,     RESSOURCE_IMG_TEMP96,      2                   ; temp
  .dw RESSOURCE_TXT_HUM_S,      RESSOURCE_IMG_HUMIDITY96,  0                   ; hum




#endif

