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


; ***************************************************************************
; SensorWatch
;
; This widget has three subwidgets:
; - Title (Label)
; - Image (ImageView)
; - Value (Label)
;
; It watches received messages and reacts on those matching the stored
; combination of NodeAddr and ValueId by colouring the image according to
; the value received and also shows the value beloe the image.
;
; Please note that this widget needs to have the option bit
; "WIDGET_OPTSLO_MSGRECV_BIT" set in order to receive MsgReceived signals.
;
; ***************************************************************************




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

; SensorWatch in flash
.equ SENSORWATCH_OFFS_BEGIN            =  WIDGET_SIZE
.equ SENSORWATCH_OFFS_BASEVALUEID      =  SENSORWATCH_OFFS_BEGIN+0
.equ SENSORWATCH_OFFS_EEPROMID         =  SENSORWATCH_OFFS_BEGIN+1
.equ SENSORWATCH_SIZE                  =  SENSORWATCH_OFFS_BEGIN+2

; SDRAM data for SensorWatch
.equ SENSORWATCH_SD_OFFS_SENSORWATCH         = WIDGET_SD_SIZE
.equ SENSORWATCH_SD_OFFS_NODEADDR            = SENSORWATCH_SD_OFFS_SENSORWATCH+0
.equ SENSORWATCH_SD_OFFS_VALUEID             = SENSORWATCH_SD_OFFS_SENSORWATCH+1
.equ SENSORWATCH_SD_OFFS_UPPER_LIMIT_WARN_LO = SENSORWATCH_SD_OFFS_SENSORWATCH+2
.equ SENSORWATCH_SD_OFFS_UPPER_LIMIT_WARN_HI = SENSORWATCH_SD_OFFS_SENSORWATCH+3
.equ SENSORWATCH_SD_OFFS_LOWER_LIMIT_WARN_LO = SENSORWATCH_SD_OFFS_SENSORWATCH+4
.equ SENSORWATCH_SD_OFFS_LOWER_LIMIT_WARN_HI = SENSORWATCH_SD_OFFS_SENSORWATCH+5
.equ SENSORWATCH_SD_OFFS_UPPER_LIMIT_CRIT_LO = SENSORWATCH_SD_OFFS_SENSORWATCH+6
.equ SENSORWATCH_SD_OFFS_UPPER_LIMIT_CRIT_HI = SENSORWATCH_SD_OFFS_SENSORWATCH+7
.equ SENSORWATCH_SD_OFFS_LOWER_LIMIT_CRIT_LO = SENSORWATCH_SD_OFFS_SENSORWATCH+8
.equ SENSORWATCH_SD_OFFS_LOWER_LIMIT_CRIT_HI = SENSORWATCH_SD_OFFS_SENSORWATCH+9
.equ SENSORWATCH_SD_OFFS_VALUE_LO            = SENSORWATCH_SD_OFFS_SENSORWATCH+10
.equ SENSORWATCH_SD_OFFS_VALUE_HI            = SENSORWATCH_SD_OFFS_SENSORWATCH+11
.equ SENSORWATCH_SD_SIZE                     = SENSORWATCH_SD_OFFS_SENSORWATCH+12


; signals
.equ SENSORWATCH_SIGNAL_SETSOURCE       =  WIDGET_SIGNAL_NEXTFREE+0
.equ SENSORWATCH_SIGNAL_SETUPPERLIMWARN =  WIDGET_SIGNAL_NEXTFREE+1
.equ SENSORWATCH_SIGNAL_SETLOWERLIMWARN =  WIDGET_SIGNAL_NEXTFREE+2
.equ SENSORWATCH_SIGNAL_SETUPPERLIMCRIT =  WIDGET_SIGNAL_NEXTFREE+3
.equ SENSORWATCH_SIGNAL_SETLOWERLIMCRIT =  WIDGET_SIGNAL_NEXTFREE+4
.equ SENSORWATCH_SIGNAL_NEXTFREE        =  WIDGET_SIGNAL_NEXTFREE+5



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

.cseg



; ---------------------------------------------------------------------------
; @routine SensorWatch_OnCreate @global
;
; @param Z byte address of widget object (for LPM!)
; @param XL node addr
; @param XH value id
; @return CFLAG set if signal handled
; @clobbers any, !Z

SensorWatch_OnCreate:
  bigcall OBJ_IsObject              ; (none)
  brcc SensorWatch_OnCreate_ret

  ; preset SDRAM
  bigcall Widget_GetSdramPtr      ; (none)
  clr r16
  ldi r17, SENSORWATCH_SD_SIZE
  push yl
    push yh
SensorWatch_OnCreate_loop:
        st Y+, r16
        dec r17
      brne SensorWatch_OnCreate_loop
    pop yh
  pop yl

  bigcall Widget_OnCreate

SensorWatch_OnCreate_ret:
  sec
  ret
; @end



; ---------------------------------------------------------------------------
; @routine SensorWatch_OnSetSource @global
;
; @param Z byte address of widget object (for LPM!)
; @param XL node addr
; @param XH value id
; @return CFLAG set if signal handled
; @clobbers any, !Z

SensorWatch_OnSetSource:
  bigcall OBJ_IsObject              ; (none)
  brcc SensorWatch_OnSetSource_ret
  push zl
    push zh
      bigcall Widget_GetSdramPtr      ; (none)
      std Y+SENSORWATCH_SD_OFFS_NODEADDR, xl
      std Y+SENSORWATCH_SD_OFFS_VALUEID, xh
    pop zh
  pop zl
SensorWatch_OnSetSource_ret:
  sec
  ret
; @end



; ---------------------------------------------------------------------------
; @routine SensorWatch_OnSetLowerLimitWarn @global
;
; @param Z byte address of widget object (for LPM!)
; @param X value
; @return CFLAG set if signal handled
; @clobbers any, !Z

SensorWatch_OnSetLowerLimitWarn:
  bigcall OBJ_IsObject                             ; (none)
  brcc SensorWatch_OnSetLowerLimitWarn_ret
  bigcall Widget_GetSdramPtr                   ; (none)
  std Y+SENSORWATCH_SD_OFFS_LOWER_LIMIT_WARN_LO, xl
  std Y+SENSORWATCH_SD_OFFS_LOWER_LIMIT_WARN_HI, xh
  rcall sensorWatchSetColor
SensorWatch_OnSetLowerLimitWarn_ret:
  sec
  ret
; @end



; ---------------------------------------------------------------------------
; @routine SensorWatch_OnSetUpperLimitWarn @global
;
; @param Z byte address of widget object (for LPM!)
; @param X value
; @return CFLAG set if signal handled
; @clobbers any, !Z

SensorWatch_OnSetUpperLimitWarn:
  bigcall OBJ_IsObject                             ; (none)
  brcc SensorWatch_OnSetUpperLimitWarn_ret
  bigcall Widget_GetSdramPtr                   ; (none)
  std Y+SENSORWATCH_SD_OFFS_UPPER_LIMIT_WARN_LO, xl
  std Y+SENSORWATCH_SD_OFFS_UPPER_LIMIT_WARN_HI, xh
  rcall sensorWatchSetColor
SensorWatch_OnSetUpperLimitWarn_ret:
  sec
  ret
; @end



; ---------------------------------------------------------------------------
; @routine SensorWatch_OnSetLimitCrit @global
;
; @param Z byte address of widget object (for LPM!)
; @param X value
; @return CFLAG set if signal handled
; @clobbers any, !Z

SensorWatch_OnSetLowerLimitCrit:
  bigcall OBJ_IsObject              ; (none)
  brcc SensorWatch_OnSetLowerLimitCrit_ret
  rcall Widget_GetSdramPtr      ; (none)
  std Y+SENSORWATCH_SD_OFFS_LOWER_LIMIT_CRIT_LO, xl
  std Y+SENSORWATCH_SD_OFFS_LOWER_LIMIT_CRIT_HI, xh
  rcall sensorWatchSetColor
SensorWatch_OnSetLowerLimitCrit_ret:
  sec
  ret
; @end



; ---------------------------------------------------------------------------
; @routine SensorWatch_OnSetUpperLimitCrit @global
;
; @param Z byte address of widget object (for LPM!)
; @param X value
; @return CFLAG set if signal handled
; @clobbers any, !Z

SensorWatch_OnSetUpperLimitCrit:
  bigcall OBJ_IsObject              ; (none)
  brcc SensorWatch_OnSetUpperLimitCrit_ret
  rcall Widget_GetSdramPtr      ; (none)
  std Y+SENSORWATCH_SD_OFFS_UPPER_LIMIT_CRIT_LO, xl
  std Y+SENSORWATCH_SD_OFFS_UPPER_LIMIT_CRIT_HI, xh
  rcall sensorWatchSetColor
SensorWatch_OnSetUpperLimitCrit_ret:
  sec
  ret
; @end




; ---------------------------------------------------------------------------
; @routine SensorWatch_OnMsgReceived @global
;
; @param Z byte address of widget object (for LPM!)
; @param XL node addr
; @param XH value id
; @return CFLAG set if signal handled
; @clobbers any, !Z

SensorWatch_OnMsgReceived:
  adiw xh:xl, 2                                   ; command
  ld r16, X
  sbiw xh:xl, 2
  cpi r16, NETMSG_CMD_VALUE_REPORT
  breq SensorWatch_OnMsgReceived_report
  cpi r16, NETMSG_CMD_VALUE_SET
  breq SensorWatch_OnMsgReceived_set
  rjmp SensorWatch_OnMsgReceived_ret
SensorWatch_OnMsgReceived_report:
  bigcall Widget_GetSdramPtr                      ; (none)
  bigcall NETMSG_ValueRead                        ; R17=valueId, R22=nodeAddr R19:R18=value (none)
  ; check node addr
  ldd r16, Y+SENSORWATCH_SD_OFFS_NODEADDR
  cp r16, r22
  brne SensorWatch_OnMsgReceived_ret
  ; check value id
  ldd r16, Y+SENSORWATCH_SD_OFFS_VALUEID
  cp r16, r17
  brne SensorWatch_OnMsgReceived_ret
  ; store value
  std Y+SENSORWATCH_SD_OFFS_VALUE_LO, r18
  std Y+SENSORWATCH_SD_OFFS_VALUE_HI, r19
  ; setup background color
  rcall sensorWatchSetColor                       ; (any, !Y, !Z)
  rcall sensorWatchSetValueLabel                  ; (any, !Y, !Z)
  rjmp SensorWatch_OnMsgReceived_ret

SensorWatch_OnMsgReceived_set:
  bigcall Widget_GetSdramPtr                      ; (none)
  bigcall NETMSG_ValueRead                        ; R17=valueId, R22=nodeAddr R19:R18=value R21:R20=denom (none)
  ; TODO: check valueid, read and set value
SensorWatch_OnMsgReceived_ret:
  sec
  ret
; @end



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

SensorWatch_GetImageView:
  bigcall OBJ_IsObject                   ; (none)
  brcc SensorWatch_GetImageView_ret
  push zl
    push zh
      bigcall OBJ_GetFirstChild          ; (none)
      brcc SensorWatch_GetImageView_done
      mov zl, r18
      mov zh, r19
      bigcall OBJ_GetNext                ; 2nd child
SensorWatch_GetImageView_done:
    pop zh
  pop zl  
SensorWatch_GetImageView_ret:
  ret
; @end




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

SensorWatch_GetValueLabel:
  bigcall OBJ_IsObject                   ; (none)
  brcc SensorWatch_GetValueLabel_ret
  push zl
    push zh
      bigcall OBJ_GetFirstChild          ; (none)
      brcc SensorWatch_GetValueLabel_done
      mov zl, r18
      mov zh, r19
      bigcall OBJ_GetNext                ; 2nd child
      brcc SensorWatch_GetValueLabel_done
      mov zl, r18
      mov zh, r19
      bigcall OBJ_GetNext                ; 3nd child
SensorWatch_GetValueLabel_done:
    pop zh
  pop zl  
SensorWatch_GetValueLabel_ret:
  ret
; @end



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

sensorWatchSetColor:
  ; default color is green
  ldi xl, LOW(DISPLAY_COLOR_DARKGREEN)
  ldi xh, HIGH(DISPLAY_COLOR_DARKGREEN)
  ldd r20, Y+SENSORWATCH_SD_OFFS_VALUE_LO
  ldd r21, Y+SENSORWATCH_SD_OFFS_VALUE_HI
  mov r16, r20
  or r16, r21
  breq sensorWatchSetColor_ret                   ; do nothing

  ; check against critical limits
  adiw yh:yl, SENSORWATCH_SD_OFFS_UPPER_LIMIT_CRIT_LO
  rcall sensorWatchCheckAgainstLimit                   ; (r16, r17, r22, r23)
  sbiw yh:yl, SENSORWATCH_SD_OFFS_UPPER_LIMIT_CRIT_LO
  brcs sensorWatchSetColor_setRed

  ; check against warning limits
  adiw yh:yl, SENSORWATCH_SD_OFFS_UPPER_LIMIT_WARN_LO
  rcall sensorWatchCheckAgainstLimit                   ; (r16, r17, r22, r23)
  sbiw yh:yl, SENSORWATCH_SD_OFFS_UPPER_LIMIT_WARN_LO
  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                  ; (none)
  brcc sensorWatchSetColor_ret
  push zl
    push zh
      mov zl, r18
      mov zh, r19
      ldi r16, IMGVIEW_SIGNAL_SETBGCOL
      clr r17
      bigcall OBJ_HandleSignal                    ; (any, !X, !Y, !Z)
    pop zh
  pop zl
sensorWatchSetColor_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine sensorWatchCheckAgainstLimit
;
; @param R21:R20 value to check against limit
; @param Y 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)
  ldd r22, Y+0
  ldd r23, Y+1
  mov r16, r22
  or r16, r23                              ; zero?
  clc
  breq sensorWatchCheckAgainstLimit_ret    ; yes, jmp
  cp r20, r22
  cpc r21, r23
  brcc sensorWatchCheckAgainstLimit_secRet

  ; check against lower limit (if any)
  ldd r22, Y+2
  ldd r23, Y+3
  mov r16, r22
  or r16, r23                              ; zero?
  clc
  breq sensorWatchCheckAgainstLimit_ret    ; yes, jmp

  cp r22, r20
  cpc r23, r21
  brcc sensorWatchCheckAgainstLimit_secRet
  clc 
  rjmp sensorWatchCheckAgainstLimit_ret
sensorWatchCheckAgainstLimit_secRet:
  sec
sensorWatchCheckAgainstLimit_ret:
  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 zl
    push zh
      mov zl, r18
      mov zh, r19
      ldd xl, Y+SENSORWATCH_SD_OFFS_VALUE_LO
      ldd xh, Y+SENSORWATCH_SD_OFFS_VALUE_HI
      ldi r16, VLABEL_SIGNAL_SETVALUE
      clr r17
      bigcall OBJ_HandleSignal                    ; (any, !X, !Y, !Z)
    pop zh
  pop zl
sensorWatchSetValueLabel_ret:
  ret
; @end





SensorWatch_DefaultSignalmap:
  .db 0, OBJECT_SIGNAL_CREATE,               LOW(SensorWatch_OnCreate),            HIGH(SensorWatch_OnCreate)
  .db 0, WIDGET_SIGNAL_DRAW,                 LOW(Widget_OnDraw),                   HIGH(Widget_OnDraw)
  .db 0, OBJECT_SIGNAL_RECVMSG,              LOW(SensorWatch_OnMsgReceived),       HIGH(SensorWatch_OnMsgReceived)
  .db 0, SENSORWATCH_SIGNAL_SETSOURCE,       LOW(SensorWatch_OnSetSource),         HIGH(SensorWatch_OnSetSource)
  .db 0, SENSORWATCH_SIGNAL_SETUPPERLIMWARN, LOW(SensorWatch_OnSetUpperLimitWarn), HIGH(SensorWatch_OnSetUpperLimitWarn)
  .db 0, SENSORWATCH_SIGNAL_SETLOWERLIMWARN, LOW(SensorWatch_OnSetLowerLimitWarn), HIGH(SensorWatch_OnSetLowerLimitWarn)
  .db 0, SENSORWATCH_SIGNAL_SETUPPERLIMCRIT, LOW(SensorWatch_OnSetUpperLimitCrit), HIGH(SensorWatch_OnSetUpperLimitCrit)
  .db 0, SENSORWATCH_SIGNAL_SETLOWERLIMCRIT, LOW(SensorWatch_OnSetLowerLimitCrit), HIGH(SensorWatch_OnSetLowerLimitCrit)
  .db 0, 0, 0, 0  ; end of table





#endif

