Files
aqhomecontrol/avr/modules/lcd2/gui2/base/guiapp.asm
2026-03-07 13:47:05 +01:00

566 lines
13 KiB
NASM

; ***************************************************************************
; 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_GUIAPP_ASM
#define AQH_AVR_GUI2_GUIAPP_ASM
; ***************************************************************************
; defines
; Widget in flash
.equ GUIAPP_OFFS_BEGIN = OBJECT_SIZE
.equ GUIAPP_OFFS_ROOTWINDOW_LO = GUIAPP_OFFS_BEGIN+0
.equ GUIAPP_OFFS_ROOTWINDOW_HI = GUIAPP_OFFS_BEGIN+1
.equ GUIAPP_OFFS_SCREENSAVER_LO = GUIAPP_OFFS_BEGIN+2
.equ GUIAPP_OFFS_SCREENSAVER_HI = GUIAPP_OFFS_BEGIN+3
.equ GUIAPP_OFFS_CURRENTWINDOW_LO = GUIAPP_OFFS_BEGIN+4
.equ GUIAPP_OFFS_CURRENTWINDOW_HI = GUIAPP_OFFS_BEGIN+5
.equ GUIAPP_OFFS_TOUCHWIDGET_LO = GUIAPP_OFFS_BEGIN+6
.equ GUIAPP_OFFS_TOUCHWIDGET_HI = GUIAPP_OFFS_BEGIN+7
.equ GUIAPP_OFFS_GUITIMER = GUIAPP_OFFS_BEGIN+8
.equ GUIAPP_SIZE = WIDGET_OFFS_BEGIN+9
.equ GUIAPP_GUITIMER = 2
; ***************************************************************************
; data
.dseg
guiapp_touch_event:
.byte WIDGET_TOUCH_SIZE
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; @routine GuiApp_new @global
;
; @return CFLAG set of okay, cleared otherwise
; @return Y address of newly created object
; @param r16 value for OBJECT_OFFS_OPTS_LO
; @param r17 value for OBJECT_OFFS_OPTS_HI
; @clobbers any
GuiApp_new:
ldi r24, LOW(GUIAPP_SIZE)
ldi r25, HIGH(GUIAPP_SIZE)
bigcall Object_Alloc ; (!r16, !r17)
brcc GuiApp_new_ret
rcall GuiApp_Init ; (r16, r17, X)
sec
GuiApp_new_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_Init @global
;
; @param Y address of object in SDRAM
; @param r16 value for OBJECT_OFFS_OPTS_LO
; @param r17 value for OBJECT_OFFS_OPTS_HI
; @clobbers r16, r17, X
GuiApp_Init:
; call base class
bigcall OBJ_Init ; (r16, r17, X)
; clear object-specific data
mov xl, yl
mov xh, yh
adiw xh:xl, GUIAPP_OFFS_BEGIN
clr r16
ldi r17, (GUIAPP_SIZE-GUIAPP_OFFS_BEGIN)
bigcall Utils_FillSram ; (r17, X)
; set default signal map
ldi r16, LOW(GuiApp_DefaultSignalmap*2)
std Y+OBJECT_OFFS_SIGNALMAP_LO, r16
ldi r16, HIGH(GuiApp_DefaultSignalmap*2)
std Y+OBJECT_OFFS_SIGNALMAP_HI, r16
; create root window
push yl
push yh
mov xl, yl
mov xh, yh
ldi r16, 0 ; opts_lo
ldi r17, 0 ; opts_hi
bigcall RootWindow_new
mov xl, yl
mov xh, yh
pop yh
pop yl
brcc GuiApp_Init_ret
std Y+GUIAPP_OFFS_ROOTWINDOW_LO, xl
std Y+GUIAPP_OFFS_ROOTWINDOW_HI, xh
ldi r16, GUIAPP_GUITIMER
std Y+GUIAPP_OFFS_GUITIMER, r16
GuiApp_Init_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_Every100ms @global
;
; @param Y address of object in SDRAM
GuiApp_Every100ms:
ldi r16, OBJECT_SIGNAL_TIMER
clr r17
bigcall OBJ_HandleSignal
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_MsgReceived @global
;
; @param Y address of object in SDRAM
GuiApp_MsgReceived:
ldi r16, OBJECT_SIGNAL_RECVMSG
clr r17
bigcall OBJ_HandleSignal
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_PreventScreenSaver @global
;
; @param Y address of object in SDRAM
; @clobbers any, !Y
GuiApp_PreventScreenSaver:
rcall GuiApp_GetScreenSaver
brcc GuiApp_PreventScreenSaver_ret
push yl
push yh
mov yl, r18
mov yh, r19
ldi r16, WIDGET_SIGNAL_KEEPALIVE
clr r17
bigcall OBJ_HandleSignal
pop yh
pop yl
GuiApp_PreventScreenSaver_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_GrabTouchEvents
;
; @param Y address of object in SDRAM
; @param X byte address of widget grabbing touch events
; @return CFLAG set if grabbed, cleared otherwise
; @clobbers R16, R17, Y
GuiApp_GrabTouchEvents:
ldd r16, Y+GUIAPP_OFFS_TOUCHWIDGET_LO
ldd r17, Y+GUIAPP_OFFS_TOUCHWIDGET_HI
or r16, r17
clc
brne GuiApp_GrabTouchEvents_ret ; only grab if not already grabbed!
std Y+GUIAPP_OFFS_TOUCHWIDGET_LO, xl
std Y+GUIAPP_OFFS_TOUCHWIDGET_HI, xh
sec
GuiApp_GrabTouchEvents_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_UngrabTouchEvents
;
; @param Y address of object in SDRAM
; @param X byte address of widget ungrabbing touch events
; @return CFLAG set if ungrabbed, cleared otherwise
; @clobbers R16, R17
GuiApp_UngrabTouchEvents:
ldd r16, Y+GUIAPP_OFFS_TOUCHWIDGET_LO
ldd r17, Y+GUIAPP_OFFS_TOUCHWIDGET_HI
eor r16, xl
eor r17, xh
or r16, r17
clc
brne GuiApp_UngrabTouchEvents_ret ; only ungrab same widget!
clr r16
std Y+GUIAPP_OFFS_TOUCHWIDGET_LO, r16
std Y+GUIAPP_OFFS_TOUCHWIDGET_HI, r16
sec
GuiApp_UngrabTouchEvents_ret:
ret
; @end
; ***************************************************************************
; getters and setters
; ---------------------------------------------------------------------------
; @routine GuiApp_GetRootWindow @global
;
; @param Y address of object in SDRAM
; @param CFLAG set if response is not a NULL pointer
GuiApp_GetRootWindow:
ldd r18, Y+GUIAPP_OFFS_ROOTWINDOW_LO
ldd r19, Y+GUIAPP_OFFS_ROOTWINDOW_HI
sec
tst r18
brne GuiApp_GetRootWindow_ret
tst r19
brne GuiApp_GetRootWindow_ret
clc
GuiApp_GetRootWindow_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_SetRootWindow @global
;
; @param Y address of object in SDRAM
; @param X address of new window
GuiApp_SetRootWindow:
std Y+GUIAPP_OFFS_ROOTWINDOW_LO, xl
std Y+GUIAPP_OFFS_ROOTWINDOW_HI, xh
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_GetCurrentWindow @global
;
; @param Y address of object in SDRAM
; @param CFLAG set if response is not a NULL pointer
GuiApp_GetCurrentWindow:
ldd r18, Y+GUIAPP_OFFS_CURRENTWINDOW_LO
ldd r19, Y+GUIAPP_OFFS_CURRENTWINDOW_HI
sec
tst r18
brne GuiApp_GetCurrentWindow_ret
tst r19
brne GuiApp_GetCurrentWindow_ret
clc
GuiApp_GetCurrentWindow_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_SetCurrentWindow @global
;
; @param Y address of object in SDRAM
; @param X address of new window
GuiApp_SetCurrentWindow:
std Y+GUIAPP_OFFS_CURRENTWINDOW_LO, xl
std Y+GUIAPP_OFFS_CURRENTWINDOW_HI, xh
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_GetScreenSaver @global
;
; @param Y address of object in SDRAM
; @param CFLAG set if response is not a NULL pointer
GuiApp_GetScreenSaver:
ldd r18, Y+GUIAPP_OFFS_SCREENSAVER_LO
ldd r19, Y+GUIAPP_OFFS_SCREENSAVER_HI
sec
tst r18
brne GuiApp_GetScreenSaver_ret
tst r19
brne GuiApp_GetScreenSaver_ret
clc
GuiApp_GetScreenSaver_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_SetScreenSaver @global
;
; @param Y address of object in SDRAM
; @param X address of new window
GuiApp_SetScreenSaver:
std Y+GUIAPP_OFFS_SCREENSAVER_LO, xl
std Y+GUIAPP_OFFS_SCREENSAVER_HI, xh
ret
; @end
; ***************************************************************************
; signal handlers
; ---------------------------------------------------------------------------
; @routine GuiApp_OnDestroy @global
;
; @param Y address of object in SDRAM
; @return CFLAG set if signal handled
; @clobbers any, !Y
GuiApp_OnDestroy:
; TODO (destroy rootWindow)
; Clear CFLAG so that destroy handlers of base classes are called
; after this routine returns. This way the last routine called will be
; OBJ_OnDestroy which then frees the whole SDRAM object on heap.
clc
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_OnTimer
;
; @param Y address of object in SDRAM
; @clobbers any, !Y
GuiApp_OnTimer:
rcall guiAppCheckTouch ; (any, !Y)
rcall guiAppSendTimerEvents ; (any, !Y)
rcall guiAppCheckSendGuiEvents ; (any, !Y)
sec
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_OnMsgReceived @global
;
; @param Y address of object in SDRAM
; @param X pointer to message received in SDRAM
GuiApp_OnMsgReceived:
ret
; @end
; ---------------------------------------------------------------------------
; @routine GuiApp_OnTouch
;
; @param Y address of object in SDRAM
; @clobbers any, !Y
GuiApp_OnTouch:
rcall guiAppSendTouchEvents
ret
; @end
; ---------------------------------------------------------------------------
; @routine guiAppSendTimerEvents
;
; @param Y ptr to GUIAPP
; @clobbers any, !Y
guiAppSendTimerEvents:
push yl
push yh
ldd r16, Y+GUIAPP_OFFS_ROOTWINDOW_LO
ldd yh, Y+GUIAPP_OFFS_ROOTWINDOW_HI
mov yl, r16
or yl, yh
breq guiAppSendTimerEvents_done
ldi r16, OBJECT_SIGNAL_TIMER
clr r17
ldi r20, OBJECT_OPTSLO_TIMER_BIT
mov r21, r20
bigcall OBJ_TreeHandleSignalIfMatchingOptsLo
guiAppSendTimerEvents_done:
pop yh
pop yl
ret
; @end
; ---------------------------------------------------------------------------
; @routine guiAppCheckSendGuiEvents
;
; Send GUI events to current window if timer elapsed.
;
; @param Y ptr to GUIAPP
; @clobbers any, !Y
guiAppCheckSendGuiEvents:
push yl
push yh
ldd r16, Y+GUIAPP_OFFS_CURRENTWINDOW_LO
ldd yh, Y+GUIAPP_OFFS_CURRENTWINDOW_HI
mov yl, r16
or yl, yh
breq guiAppCheckSendGuiEvents_done
ldd r16, Y+GUIAPP_OFFS_GUITIMER
tst r16
breq guiAppCheckSendGuiEvents_done
dec r16
std Y+GUIAPP_OFFS_GUITIMER, r16
brne guiAppCheckSendGuiEvents_done
; timer elapsed, send layout events, draw events
ldi r16, WIDGET_SIGNAL_LAYOUT
clr r17
ldi r20, (1<<WIDGET_FLAGS_VISIBLE_BIT) | (1<<WIDGET_FLAGS_LAYOUT_BIT)
bigcall OBJ_TreeHandleSignalIfFlagsSet ; (any, !Y)
ldi r16, WIDGET_SIGNAL_DRAW
clr r17
ldi r20, (1<<WIDGET_FLAGS_VISIBLE_BIT) | (1<<WIDGET_FLAGS_DIRTY_BIT)
bigcall OBJ_TreeHandleSignalIfFlagsSet ; (any, !Y)
ldi r16, GUIAPP_GUITIMER
std Y+GUIAPP_OFFS_GUITIMER, r16
guiAppCheckSendGuiEvents_done:
pop yh
pop yl
ret
; @end
; ---------------------------------------------------------------------------
; @routine guiAppSendTouchEvents
;
; Send touch events to current window or grabbing widget.
;
; @param Y ptr to GUIAPP
; @clobbers any, !Y
guiAppSendTouchEvents:
push yl
push yh
ldd r18, Y+GUIAPP_OFFS_TOUCHWIDGET_LO
ldd r19, Y+GUIAPP_OFFS_TOUCHWIDGET_HI
mov r16, r18
or r16, r19
breq GuiApp_OnTouch_sendToAll
mov yl, r18
mov yh, r19
ldi r16, WIDGET_SIGNAL_TOUCH
clr r17
bigcall OBJ_HandleSignal
rjmp GuiApp_OnTouch_done
GuiApp_OnTouch_sendToAll:
ldd r18, Y+GUIAPP_OFFS_CURRENTWINDOW_LO
ldd r19, Y+GUIAPP_OFFS_CURRENTWINDOW_HI
mov r16, r18
or r16, r19
breq GuiApp_OnTouch_done
; send touch signal
ldi r16, WIDGET_SIGNAL_TOUCH
clr r17
ldi r20, (1<<WIDGET_OPTSLO_INPUT_BIT)
ldi r21, (1<<WIDGET_OPTSLO_INPUT_BIT)
bigcall OBJ_TreeHandleSignalIfMatchingOptsLo
GuiApp_OnTouch_done:
pop yh
pop yl
; send keepAlive to screensaver
rcall GuiApp_PreventScreenSaver
sec
ret
; @end
; ---------------------------------------------------------------------------
; @routine guiAppCheckTouch
;
; @param Y ptr to GUIAPP
; @clobbers any, !Y
guiAppCheckTouch:
bigcall Display_InputGetState ; r16=flags, r5:r4=x, r7:r6=y
mov r17, r16
andi r17, (1<<DISPLAY_IFLAGS_CHGCOORD_BIT) | (1<<DISPLAY_IFLAGS_CHGPRESS_BIT)
breq guiAppCheckTouch_ret
ldi xl, LOW(guiapp_touch_event)
ldi xh, HIGH(guiapp_touch_event)
st X+, r4 ; X
st X+, r5
st X+, r6 ; Y
st X+, r7
st X, r16 ; flags
sbiw xh:xl, 4 ; (4 times incremented)
; send touch signal
ldi r16, WIDGET_SIGNAL_TOUCH
clr r17
bigcall OBJ_HandleSignal
guiAppCheckTouch_ret:
ret
; @end
; ***************************************************************************
; data in FLASH
GuiApp_DefaultSignalmap:
; header
.dw Object_DefaultSignalmap ; next table to use
; entries
.db 0, OBJECT_SIGNAL_DESTROY, LOW(GuiApp_OnDestroy), HIGH(GuiApp_OnDestroy)
.db 0, 0, 0, 0 ; end of table
#endif