avr: add complex fan controller app with base classes to be used by other apps as well.

- add modules
  - holdtimer (keep actor running while triggered)
  - triggeraction (connect actor with holdtimer)
- add app fan_controller
  - uses the modules mentioned above to turn on/off fans in connection
    with e.g. motion sensor nodes
This commit is contained in:
Martin Preuss
2026-08-06 00:05:50 +02:00
parent d8498dceaf
commit 88a66f6822
15 changed files with 1309 additions and 5 deletions

View File

@@ -0,0 +1,3 @@
# use MOTION (7) value from node 18
aqhome-tool setdata -N nodes/a5502228/FANCTL_TRIGGER1_SOURCE -v 0:0:7:18

View File

@@ -0,0 +1,38 @@
; ***************************************************************************
; 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_APPS_FAN_CONTROL_DEFS_ASM
#define AQH_AVR_APPS_FAN_CONTROL_DEFS_ASM
.equ APP_FANCONTROL_STEPS = 5
.equ APP_FANCONTROL_FLASH_OFFS_BEGIN = TCA_FLASH_SIZE
.equ APP_FANCONTROL_FLASH_OFFS_STEPTABLE = APP_FANCONTROL_FLASH_OFFS_BEGIN+0
.equ APP_FANCONTROL_FLASH_SIZE = APP_FANCONTROL_FLASH_OFFS_STEPTABLE+(APP_FANCONTROL_STEPS*3)
.equ APP_FANCONTROL_RAM_OFFS_BEGIN = TCA_RAM_SIZE
.equ APP_FANCONTROL_RAM_OFFS_VALUE_LO = APP_FANCONTROL_RAM_OFFS_BEGIN+0
.equ APP_FANCONTROL_RAM_OFFS_VALUE_HI = APP_FANCONTROL_RAM_OFFS_BEGIN+1
.equ APP_FANCONTROL_RAM_SIZE = APP_FANCONTROL_RAM_OFFS_BEGIN+2
.equ APP_FANCONTROL_EE_OFFS_BEGIN = TCA_EE_SIZE
.equ APP_FANCONTROL_EE_OFFS_VALUE_LO = APP_FANCONTROL_EE_OFFS_BEGIN+0
.equ APP_FANCONTROL_EE_OFFS_VALUE_HI = APP_FANCONTROL_EE_OFFS_BEGIN+1
.equ APP_FANCONTROL_EE_SIZE = APP_FANCONTROL_EE_OFFS_BEGIN+2
.equ APP_FANCONTROL_FLAGBIT_UPDATED = 0 ; value updated (move to TCA!)
#endif

View File

@@ -0,0 +1,279 @@
; ***************************************************************************
; 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_APPS_FAN_CONTROL_MAIN_ASM
#define AQH_AVR_APPS_FAN_CONTROL_MAIN_ASM
.equ APP_FANCONTROL_TEMP_LIMIT = 2400
.cseg
; ---------------------------------------------------------------------------
; @routine AppFanControl_Init
AppFanControl_Init:
ldi zl, LOW(appFanControlObjectFlash*2)
ldi zh, HIGH(appFanControlObjectFlash*2)
; preset RAM
lpm xl, Z+
lpm xh, Z
sbiw zh:zl, 1
clr r16
ldi r17,TCA_RAM_SIZE
bigcall Utils_FillSram
; init base class
bigcall TCA_Init
; preset source limits (low=1, high=65535)
lpm yl, Z+
lpm yh, Z
sbiw zh:zl, 1
ldi r16, 1
std Y+(TCA_RAM_OFFS_TRIGGER_SOURCE1+TCA_SOURCE_OFFS_LOWLIM_LO), r16
std Y+(TCA_RAM_OFFS_TRIGGER_SOURCE2+TCA_SOURCE_OFFS_LOWLIM_LO), r16
ldi r16, 0xff
std Y+(TCA_RAM_OFFS_TRIGGER_SOURCE1+TCA_SOURCE_OFFS_HIGHLIM_LO), r16
std Y+(TCA_RAM_OFFS_TRIGGER_SOURCE1+TCA_SOURCE_OFFS_HIGHLIM_HI), r16
std Y+(TCA_RAM_OFFS_TRIGGER_SOURCE2+TCA_SOURCE_OFFS_HIGHLIM_LO), r16
std Y+(TCA_RAM_OFFS_TRIGGER_SOURCE2+TCA_SOURCE_OFFS_HIGHLIM_HI), r16
; preset guard limits (low=24.0 Grad, high=65535)
ldi r16, LOW(APP_FANCONTROL_TEMP_LIMIT)
ldi r17, HIGH(APP_FANCONTROL_TEMP_LIMIT)
std Y+(TCA_RAM_OFFS_GUARD_SOURCE+TCA_SOURCE_OFFS_LOWLIM_LO), r16
std Y+(TCA_RAM_OFFS_GUARD_SOURCE+TCA_SOURCE_OFFS_LOWLIM_HI), r17
ldi r16, 0xff
std Y+(TCA_RAM_OFFS_GUARD_SOURCE+TCA_SOURCE_OFFS_HIGHLIM_LO), r16
std Y+(TCA_RAM_OFFS_GUARD_SOURCE+TCA_SOURCE_OFFS_HIGHLIM_HI), r16
; ldi r16, 2
ldi r16, 1
std Y+HTIM_EE_OFFS_MODE, r16
; setup from eeprom
push yl
push yh
rcall appFanControlReadEeprom
pop yh
pop yl
; start in given mode
rcall appFanControlUpdate
ret
; @end
; ---------------------------------------------------------------------------
; @routine AppFanControl_OnEveryTick @global
AppFanControl_OnEveryTick:
ldi zl, LOW(appFanControlObjectFlash*2)
ldi zh, HIGH(appFanControlObjectFlash*2)
lpm yl, Z+
lpm yh, Z
sbiw zh:zl, 1
bigcall TCA_OnEveryTick
; check update flag
ldd r16, Y+HTIM_RAM_OFFS_FLAGS
sbrs r16, APP_FANCONTROL_FLAGBIT_UPDATED
rjmp AppFanControl_OnEveryTick_ret ; jump if clear (value unchanged)
; value updated
cbr r16, (1<<APP_FANCONTROL_FLAGBIT_UPDATED) ; clear update bit
std Y+HTIM_RAM_OFFS_FLAGS, r16
rcall appFanControlWriteEeprom
rcall appFanControlUpdate
AppFanControl_OnEveryTick_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine appFanControlUpdate
appFanControlUpdate:
ldd r16, Y+HTIM_RAM_OFFS_FLAGS
ldd r17, Y+HTIM_RAM_OFFS_MODE
cpi r17, 2 ; auto?
breq appFanControlUpdate_auto
; non-auto
cbr r16, (1<<HTIM_FLAGBIT_ACTIVE) | (1<<HTIM_FLAGBIT_ACTORENABLED) ; disable timer
std Y+HTIM_RAM_OFFS_FLAGS, r16
cpi r17, 1 ; on?
breq appFanControlUpdate_on
rcall appFanControlActorOff
rjmp appFanControlUpdate_ret
appFanControlUpdate_auto:
sbr r16, (1<<HTIM_FLAGBIT_ACTIVE) | (1<<HTIM_FLAGBIT_ACTORENABLED) ; enable timer
std Y+HTIM_RAM_OFFS_FLAGS, r16
sbrs r16, HTIM_FLAGBIT_STATE
rjmp appFanControlUpdate_ret ; jump if clear (actor is off)
rcall appFanControlActorOn
rjmp appFanControlUpdate_ret
appFanControlUpdate_on:
rcall appFanControlActorOn
appFanControlUpdate_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine appFanControlReadEeprom
;
; @param Y pointer to data in RAM
appFanControlReadEeprom:
ldi r16, APP_FANCONTROL_EEID
bigcall EepromTlv_FindFirst
brcc appFanControlReadEeprom_ret
; let base class read
bigcall TCA_ReadEepromAt ; (r16, r17, Y)
brcc appFanControlReadEeprom_ret
push yl
push yh
adiw yh:yl, APP_FANCONTROL_RAM_OFFS_BEGIN
ldi r17, (APP_FANCONTROL_EE_SIZE-APP_FANCONTROL_EE_OFFS_BEGIN)
bigcall Eeprom_ReadBytes ; (r16, r17, X, Y)
pop yh
pop yl
appFanControlReadEeprom_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine appFanControlWriteEeprom
;
; @param Y pointer to data in RAM
appFanControlWriteEeprom:
ldi r16, APP_FANCONTROL_EEID
bigcall EepromTlv_FindFirst
brcs appFanControlWriteEeprom_write
; create eeprom TLV
ldi r16, APP_FANCONTROL_EEID
ldi r17, APP_FANCONTROL_EE_SIZE
bigcall EepromTlv_AddTlv
brcc appFanControlWriteEeprom_ret
appFanControlWriteEeprom_write:
; let base class write
bigcall TCA_WriteEepromAt
brcc appFanControlWriteEeprom_ret
push yl
push yh
adiw yh:yl, APP_FANCONTROL_RAM_OFFS_BEGIN
ldi r17, (APP_FANCONTROL_EE_SIZE-APP_FANCONTROL_EE_OFFS_BEGIN)
bigcall Eeprom_WriteBytes ; (r16, r17, r18, X, Y)
pop yh
pop yl
appFanControlWriteEeprom_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine appFanControlActorOn
; @param Z pointer to timer data in FLASH (byte address for lpm!)
; @param Y pointer to data in RAM
appFanControlActorOn:
ldd r16, Y+APP_FANCONTROL_RAM_OFFS_VALUE_LO
rcall appFanControlSetFanDutyFromTable
ret
; @end
; ---------------------------------------------------------------------------
; @routine appFanControlActorOff
;
; @param Z pointer to timer data in FLASH (byte address for lpm!)
; @param Y pointer to data in RAM
appFanControlActorOff:
clr r16
rjmp appFanControlSetFanDutyFromTable
; @end
; ---------------------------------------------------------------------------
; @routine appFanControlSetFanDutyFromTable
; @param r16 step value
appFanControlSetFanDutyFromTable:
cpi r16, APP_FANCONTROL_STEPS
brcs appFanControlSetFanDutyFromTable_getValue
ldi r16, APP_FANCONTROL_STEPS-1
appFanControlSetFanDutyFromTable_getValue:
push yl
push yh
push zl
push zh
adiw zh:zl, APP_FANCONTROL_FLASH_OFFS_STEPTABLE
clr r17
add zl, r16 ; 3 entries per step
adc zh, r17
add zl, r16
adc zh, r17
add zl, r16
adc zh, r17
lpm r16, Z+
bigcall MultiFan_SetFan1Duty
lpm r16, Z+
bigcall MultiFan_SetFan2Duty
lpm r16, Z+
bigcall MultiFan_SetFan3Duty
pop zh
pop zl
pop yh
pop yl
ret
; @end
appFanControlObjectFlash:
.dw appFanControlObjectRam ; HTIM_FLASH_OFFS_RAMPTR
.dw appFanControlActorOn ; HTIM_FLASH_OFFS_ON_PTR
.dw appFanControlActorOff ; HTIM_FLASH_OFFS_OFF_PTR
.dw (5*60*10) ; HTIM_FLASH_OFFS_RELOADVAL
.db 0, 0, 0, 20, 20, 20, 40, 40, 40, 70, 70, 70, 100, 100, 100, 0 ; speed table for 5 steps
.dseg
appFanControlObjectRam:
.byte APP_FANCONTROL_RAM_SIZE
#endif

View File

@@ -0,0 +1,77 @@
; ***************************************************************************
; 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_APPS_FAN_CONTROL_RECV_ASM
#define AQH_AVR_APPS_FAN_CONTROL_RECV_ASM
.cseg
; ---------------------------------------------------------------------------
; @routine AppMotionLight_OnPacketReceived @global
;
; @clobbers any, -X
AppFanControl_OnPacketReceived:
ldi zl, LOW(appFanControlObjectFlash*2)
ldi zh, HIGH(appFanControlObjectFlash*2)
push zl
push zh
lpm yl, Z+
lpm yh, Z
ldi zl, LOW(appFanControlMsgTable*2)
ldi zh, HIGH(appFanControlMsgTable*2)
bigcall Main_HandleValueMsg
pop zh
pop zl
AppFanControl_OnPacketReceived_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine appFanControlSetValue
;
; @clobbers any, -X
appFanControlSetValue:
std Y+APP_FANCONTROL_RAM_OFFS_VALUE_LO, r18
std Y+APP_FANCONTROL_RAM_OFFS_VALUE_HI, r19
bigjmp TCA_SetValueACK
; @end
appFanControlMsgTable:
.db NETMSG_CMD_VALUE_REPORT, 0, LOW(TCA_HandleMsg), HIGH(TCA_HandleMsg)
.db NETMSG_CMD_VALUE_SET, VALUE_ID_FANCTRL_GUARDSRC, LOW(TCA_SetValue_GuardSrc), HIGH(TCA_SetValue_GuardSrc)
.db NETMSG_CMD_VALUE_SET, VALUE_ID_FANCTRL_GUARDLIM, LOW(TCA_SetValue_GuardLimits), HIGH(TCA_SetValue_GuardLimits)
.db NETMSG_CMD_VALUE_SET, VALUE_ID_FANCTRL_TRIGGER1SRC, LOW(TCA_SetValue_Trigger1Src), HIGH(TCA_SetValue_Trigger1Src)
.db NETMSG_CMD_VALUE_SET, VALUE_ID_FANCTRL_TRIGGER1LIM, LOW(TCA_SetValue_Trigger1Limits), HIGH(TCA_SetValue_Trigger1Limits)
.db NETMSG_CMD_VALUE_SET, VALUE_ID_FANCTRL_TRIGGER2SRC, LOW(TCA_SetValue_Trigger2Src), HIGH(TCA_SetValue_Trigger2Src)
.db NETMSG_CMD_VALUE_SET, VALUE_ID_FANCTRL_TRIGGER2LIM, LOW(TCA_SetValue_Trigger2Limits), HIGH(TCA_SetValue_Trigger2Limits)
.db NETMSG_CMD_VALUE_SET, VALUE_ID_FANCTRL_HOLDTIME, LOW(TCA_SetValue_HoldTime), HIGH(TCA_SetValue_HoldTime)
.db NETMSG_CMD_VALUE_SET, VALUE_ID_FANCTRL_MODE, LOW(TCA_SetValue_Mode), HIGH(TCA_SetValue_Mode)
.db NETMSG_CMD_VALUE_SET, VALUE_ID_FANCTRL_VALUE, LOW(appFanControlSetValue), HIGH(appFanControlSetValue)
.db 0, 0, 0, 0
#endif

View File

@@ -40,6 +40,10 @@ appsOnEvery100ms:
bigcall AppDoor_Every100ms bigcall AppDoor_Every100ms
#endif #endif
#ifdef APPS_FANCONTROL
bigcall AppFanControl_OnEveryTick
#endif
ret ret
; @end ; @end

View File

@@ -94,6 +94,18 @@ APP_END_NETWORK:
#endif #endif
#ifdef APPS_FANCONTROL
.include "modules/holdtimer/defs.asm"
.include "modules/holdtimer/main.asm"
.include "modules/triggeractor/defs.asm"
.include "modules/triggeractor/main.asm"
.include "modules/triggeractor/recv.asm"
.include "apps/fan_control/defs.asm"
.include "apps/fan_control/main.asm"
.include "apps/fan_control/recv.asm"
#endif
#endif #endif

View File

@@ -67,6 +67,10 @@ appsInit:
bigcall AppCo2Watch_Init bigcall AppCo2Watch_Init
#endif #endif
#ifdef APPS_FANCONTROL
bigcall AppFanControl_Init
#endif
; done ; done
ret ret
; @end ; @end

View File

@@ -27,14 +27,18 @@
appsOnPacketReceived: appsOnPacketReceived:
#ifdef APPS_NETWORK #ifdef APPS_NETWORK
; handle messages ; handle messages
ldi yl, LOW(netInterfaceData) ldi yl, LOW(netInterfaceData)
ldi yh, HIGH(netInterfaceData) ldi yh, HIGH(netInterfaceData)
bigcall AppNetwork_HandleMsg bigcall AppNetwork_HandleMsg
#endif #endif
#ifdef APPS_MA_LIGHT #ifdef APPS_MA_LIGHT
bigcall AppMotionLight_OnPacketReceived bigcall AppMotionLight_OnPacketReceived
#endif
#ifdef APPS_FANCONTROL
bigcall AppFanControl_OnPacketReceived
#endif #endif
; add more here ; add more here

View File

@@ -0,0 +1,47 @@
; ***************************************************************************
; 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_MODULES_HOLDTIMER_DEFS_ASM
#define AQH_AVR_MODULES_HOLDTIMER_DEFS_ASM
.equ HTIM_FLASH_OFFS_RAMPTR_LO = 0
.equ HTIM_FLASH_OFFS_RAMPTR_HI = 1
.equ HTIM_FLASH_OFFS_ON_PTR_LO = 2
.equ HTIM_FLASH_OFFS_ON_PTR_HI = 3
.equ HTIM_FLASH_OFFS_OFF_PTR_LO = 4
.equ HTIM_FLASH_OFFS_OFF_PTR_HI = 5
.equ HTIM_FLASH_OFFS_RELOADVAL_LO = 6
.equ HTIM_FLASH_OFFS_RELOADVAL_HI = 7
.equ HTIM_FLASH_SIZE = 8
.equ HTIM_RAM_OFFS_FLAGS = 0
.equ HTIM_RAM_OFFS_CURRVAL_LO = 1
.equ HTIM_RAM_OFFS_CURRVAL_HI = 2
.equ HTIM_RAM_OFFS_RELOAD_LO = 3
.equ HTIM_RAM_OFFS_RELOAD_HI = 4
.equ HTIM_RAM_OFFS_MODE = 5
.equ HTIM_RAM_SIZE = 6
.equ HTIM_EE_OFFS_RELOAD_LO = 0
.equ HTIM_EE_OFFS_RELOAD_HI = 1
.equ HTIM_EE_OFFS_MODE = 2
.equ HTIM_EE_SIZE = 3
.equ HTIM_FLAGBIT_ACTIVE = 7
.equ HTIM_FLAGBIT_ACTORENABLED = 6
.equ HTIM_FLAGBIT_STATE = 5
#endif

View File

@@ -0,0 +1,283 @@
; ***************************************************************************
; 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_MODULES_HOLDTIMER_MAIN_ASM
#define AQH_AVR_MODULES_HOLDTIMER_MAIN_ASM
; ---------------------------------------------------------------------------
; @routine HTIM_Init @global
;
; @param Z pointer to timer data in FLASH (byte address for lpm!)
; @return Y pointer to data in RAM
; @clobbers r16, r18, r19
HTIM_Init:
; get RAM ptr
lpm yl, Z+
lpm yh, Z
sbiw zh:zl, 1
; read default reload value
adiw zh:zl, HTIM_FLASH_OFFS_RELOADVAL_LO
lpm r18, Z+
lpm r19, Z
sbiw zh:zl, (HTIM_FLASH_OFFS_RELOADVAL_LO+1)
; setup RAM data
clr r16
std Y+HTIM_RAM_OFFS_FLAGS, r16
std Y+HTIM_RAM_OFFS_CURRVAL_LO, r16
std Y+HTIM_RAM_OFFS_CURRVAL_HI, r16
std Y+HTIM_RAM_OFFS_RELOAD_LO, r18
std Y+HTIM_RAM_OFFS_RELOAD_HI, r19
ret
; @end
; ---------------------------------------------------------------------------
; @routine HTIM_EnableActor @global
;
; @param Z pointer to timer data in FLASH (byte address for lpm!)
; @param Y pointer to data in RAM
; @clobbers R16 (any)
HTIM_EnableActor:
ldd r16, Y+HTIM_RAM_OFFS_FLAGS
sbr r16, (1<<HTIM_FLAGBIT_ACTORENABLED)
std Y+HTIM_RAM_OFFS_FLAGS, r16
sbrs r16, HTIM_FLAGBIT_ACTIVE
rjmp HTIM_EnableActor_ret
sbrc r16, HTIM_FLAGBIT_STATE
rcall htimCallActorOn ; turn on actor if state is ON
HTIM_EnableActor_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine HTIM_DisableActor @global
;
; @param Z pointer to timer data in FLASH (byte address for lpm!)
; @param Y pointer to data in RAM
; @clobbers R16
HTIM_DisableActor:
ldd r16, Y+HTIM_RAM_OFFS_FLAGS
cbr r16, (1<<HTIM_FLAGBIT_ACTORENABLED)
std Y+HTIM_RAM_OFFS_FLAGS, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine HTIM_Start @global
;
; @param Z pointer to timer data in FLASH (byte address for lpm!)
; @param Y pointer to data in RAM
; @clobbers R16
HTIM_Start:
ldd r16, Y+HTIM_RAM_OFFS_FLAGS
sbr r16, (1<<HTIM_FLAGBIT_ACTIVE)
std Y+HTIM_RAM_OFFS_FLAGS, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine HTIM_Stop @global
;
; @param Z pointer to timer data in FLASH (byte address for lpm!)
; @param Y pointer to data in RAM
; @clobbers R16
HTIM_Stop:
ldd r16, Y+HTIM_RAM_OFFS_FLAGS
cbr r16, (1<<HTIM_FLAGBIT_ACTIVE)
std Y+HTIM_RAM_OFFS_FLAGS, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine HTIM_Trigger @global
;
; @param Z pointer to timer data in FLASH (byte address for lpm!)
; @param Y pointer to data in RAM
; @clobbers Y
HTIM_Trigger:
rjmp htimReloadTimer
; @end
; ---------------------------------------------------------------------------
; @routine HTIM_OnEveryTick @global
;
; @param Z pointer to timer data in FLASH (byte address for lpm!)
; @param Y pointer to data in RAM
; @clobbers r16, r16, r24, r25 (any)
HTIM_OnEveryTick:
ldd r17, Y+HTIM_RAM_OFFS_FLAGS
sbrs r17, HTIM_FLAGBIT_ACTIVE
rjmp HTIM_OnEveryTick_ret
; active
ldd r24, Y+HTIM_RAM_OFFS_CURRVAL_LO
ldd r25, Y+HTIM_RAM_OFFS_CURRVAL_HI
mov r16, r24 ; value 0?
or r16, r25
breq HTIM_OnEveryTick_ret ; yes, nothing to do
sbiw r25:r24, 1
std Y+HTIM_RAM_OFFS_CURRVAL_LO, r24 ; store new value
std Y+HTIM_RAM_OFFS_CURRVAL_HI, r25
brne HTIM_OnEveryTick_ret ; jmp if not 0
; just became zero, turn actor off
sbrc r17, HTIM_FLAGBIT_STATE
rcall htimCallActorOff ; only call if ON
HTIM_OnEveryTick_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine HTIM_ReadEepromAt
;
; @param Z pointer to data in FLASH (byte address for lpm!)
; @param Y pointer to data in RAM
; @param X EEPROM address
; @return X EEPROM address after the data handled by this routine
; @clobbers r16, r17, Y
HTIM_ReadEepromAt:
push yl
push yh
adiw yh:yl, HTIM_RAM_OFFS_RELOAD_LO ; start at reload value
ldi r17, HTIM_EE_SIZE
bigcall Eeprom_ReadBytes ; (r16, r17, X, Y)
pop yh
pop yl
ret
; @end
; ---------------------------------------------------------------------------
; @routine HTIM_WriteEepromAt
;
; @param Z pointer to data in FLASH (byte address for lpm!)
; @param Y pointer to data in RAM
; @param X EEPROM address
; @return X EEPROM address after the data handled by this routine
; @clobbers r16, r17, r18, Y
HTIM_WriteEepromAt:
push yl
push yh
adiw yh:yl, HTIM_RAM_OFFS_RELOAD_LO ; start at reload value
ldi r17, HTIM_EE_SIZE
bigcall Eeprom_WriteBytes ; (r16, r17, r18, X, Y)
pop yh
pop yl
ret
; @end
; ---------------------------------------------------------------------------
; @routine htimCallActorOn
;
; @param Z pointer to timer data in FLASH (byte address for lpm!)
; @param Y pointer to data in RAM
; @clobbers any (!Y, !Z)
htimCallActorOn:
ldd r17, Y+HTIM_RAM_OFFS_FLAGS
sbr r17, (1<<HTIM_FLAGBIT_STATE)
std Y+HTIM_RAM_OFFS_FLAGS, r17
adiw zh:zl, HTIM_FLASH_OFFS_ON_PTR_LO
lpm r18, Z+
lpm r19, Z
sbiw zh:zl,(HTIM_FLASH_OFFS_ON_PTR_LO+1)
mov r16, r18
or r16, r19
breq htimCallActorOn_ret
push r18 ; jmp via stack
push r19
htimCallActorOn_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine htimCallActorOff
;
; @param Z pointer to timer data in FLASH (byte address for lpm!)
; @param Y pointer to data in RAM
; @clobbers any (!Y, !Z)
htimCallActorOff:
ldd r17, Y+HTIM_RAM_OFFS_FLAGS
cbr r17, (1<<HTIM_FLAGBIT_STATE)
std Y+HTIM_RAM_OFFS_FLAGS, r17
adiw zh:zl, HTIM_FLASH_OFFS_OFF_PTR_LO
lpm r18, Z+
lpm r19, Z
sbiw zh:zl,(HTIM_FLASH_OFFS_OFF_PTR_LO+1)
mov r16, r18
or r16, r19
breq htimCallActorOff_ret
push r18 ; jmp via stack
push r19
htimCallActorOff_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine htimReloadTimer
;
; @param Z pointer to timer data in FLASH (byte address for lpm!)
; @param Y pointer to data in RAM
; @clobbers none
htimReloadTimer:
ldd r17, Y+HTIM_RAM_OFFS_FLAGS
sbrs r17, HTIM_FLAGBIT_ACTIVE
rjmp htimReloadTimer_ret ; jmp if not active
; really reload timer
ldd r16, Y+HTIM_RAM_OFFS_RELOAD_LO
std Y+HTIM_RAM_OFFS_CURRVAL_LO, r16
ldd r16, Y+HTIM_RAM_OFFS_RELOAD_HI
std Y+HTIM_RAM_OFFS_CURRVAL_HI, r16
; switch fans ON
sbrc r17, HTIM_FLAGBIT_ACTORENABLED
rcall htimCallActorOn ; turn on actor
htimReloadTimer_ret:
ret
; @end
#endif

View File

@@ -0,0 +1,14 @@
<?xml?>
<gwbuild>
<extradist>
defs.asm
main.asm
recv.asm
</extradist>
</gwbuild>

View File

@@ -0,0 +1,85 @@
This module extends the hold timer to keep an actor ON as long as
positive messages are received from either of two TRIGGER sources
(e.g. from motion sensors).
Matching messages from GUARD sources can prohibit actors from being
switched on.
Example: Motion activated light
- trigger
- source: motion sensors
- matching values: >0
- guard:
- source: light sensor
- matching values: 0-XX (XX being the value below which light
is to be switched on)
FLASH:
- HTIM_FLASH_OFFS_RAMPTR_LO 0
- HTIM_FLASH_OFFS_RAMPTR_HI 1
- HTIM_FLASH_OFFS_ON_PTR_LO 2
- HTIM_FLASH_OFFS_ON_PTR_HI 3
- HTIM_FLASH_OFFS_OFF_PTR_LO 4
- HTIM_FLASH_OFFS_OFF_PTR_HI 5
- HTIM_FLASH_OFFS_RELOADVAL_LO 6
- HTIM_FLASH_OFFS_RELOADVAL_HI 7
RAM:
- HTIM_RAM_OFFS_FLAGS 0
- HTIM_RAM_OFFS_CURRVAL_LO 1
- HTIM_RAM_OFFS_CURRVAL_HI 2
- HTIM_RAM_OFFS_RELOAD_LO 3
- HTIM_RAM_OFFS_RELOAD_HI 4
- TCA_RAM_OFFS_GUARD_SOURCE
- ADDR 5
- VALUEID 6
- LOWER LIMIT lo 7
- LOWER LIMIT hi 8
- UPPER LIMIT lo 9
- UPPER LIMIT hi 10
- TCA_RAM_OFFS_TRIGGER_SOURCE1
- ADDR 11
- VALUEID 12
- LOWER LIMIT lo 13
- LOWER LIMIT hi 14
- UPPER LIMIT lo 15
- UPPER LIMIT hi 16
- TCA_RAM_OFFS_TRIGGER_SOURCE2
- ADDR 17
- VALUEID 18
- LOWER LIMIT lo 10
- LOWER LIMIT hi 20
- UPPER LIMIT lo 21
- UPPER LIMIT hi 22
EEPROM:
- HTIM_RAM_OFFS_RELOAD_LO 0
- HTIM_RAM_OFFS_RELOAD_HI 1
- TCA_RAM_OFFS_GUARD_SOURCE
- ADDR 2
- VALUEID 3
- LOWER LIMIT lo 4
- LOWER LIMIT hi 5
- UPPER LIMIT lo 6
- UPPER LIMIT hi 7
- TCA_RAM_OFFS_TRIGGER_SOURCE1
- ADDR 8
- VALUEID 9
- LOWER LIMIT lo 10
- LOWER LIMIT hi 11
- UPPER LIMIT lo 12
- UPPER LIMIT hi 13
- TCA_RAM_OFFS_TRIGGER_SOURCE2
- ADDR 14
- VALUEID 15
- LOWER LIMIT lo 16
- LOWER LIMIT hi 17
- UPPER LIMIT lo 18
- UPPER LIMIT hi 19

View File

@@ -0,0 +1,47 @@
; ***************************************************************************
; 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_MODULES_TRIGGERACTOR_DEFS_ASM
#define AQH_AVR_MODULES_TRIGGERACTOR_DEFS_ASM
.equ TCA_SOURCE_OFFS_ADDR = 0
.equ TCA_SOURCE_OFFS_VALUEID = 1
.equ TCA_SOURCE_OFFS_LOWLIM_LO = 2
.equ TCA_SOURCE_OFFS_LOWLIM_HI = 3
.equ TCA_SOURCE_OFFS_HIGHLIM_LO = 4
.equ TCA_SOURCE_OFFS_HIGHLIM_HI = 5
.equ TCA_SOURCE_SIZE = 6
.equ TCA_FLASH_OFFS_BEGIN = HTIM_FLASH_SIZE
.equ TCA_FLASH_SIZE = TCA_FLASH_OFFS_BEGIN+0
.equ TCA_RAM_OFFS_BEGIN = HTIM_RAM_SIZE
.equ TCA_RAM_OFFS_GUARD_SOURCE = TCA_RAM_OFFS_BEGIN+0
.equ TCA_RAM_OFFS_TRIGGER_SOURCE1 = TCA_RAM_OFFS_BEGIN+TCA_SOURCE_SIZE
.equ TCA_RAM_OFFS_TRIGGER_SOURCE2 = TCA_RAM_OFFS_TRIGGER_SOURCE1+TCA_SOURCE_SIZE
.equ TCA_RAM_SIZE = TCA_RAM_OFFS_TRIGGER_SOURCE2+TCA_SOURCE_SIZE
.equ TCA_EE_OFFS_BEGIN = HTIM_EE_SIZE
.equ TCA_EE_OFFS_GUARD_SOURCE = TCA_EE_OFFS_BEGIN
.equ TCA_EE_OFFS_TRIGGER_SOURCE1 = TCA_EE_OFFS_BEGIN+TCA_SOURCE_SIZE
.equ TCA_EE_OFFS_TRIGGER_SOURCE2 = TCA_EE_OFFS_TRIGGER_SOURCE1+TCA_SOURCE_SIZE
.equ TCA_EE_SIZE = TCA_EE_OFFS_TRIGGER_SOURCE2+TCA_SOURCE_SIZE
.equ TCA_FLAGBITS_NEED_TRIGGER = 1
.equ TCA_FLAGBITS_NEED_DISABLE = 2
.equ TCA_FLAGBITS_NEED_ENABLE = 3
#endif

View File

@@ -0,0 +1,115 @@
; ***************************************************************************
; 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_MODULES_TRIGGERACTOR_MAIN_ASM
#define AQH_AVR_MODULES_TRIGGERACTOR_MAIN_ASM
; ---------------------------------------------------------------------------
; @routine TCA_Init @global
;
; @param Z pointer to data in FLASH (byte address for lpm!)
TCA_Init:
; let base class init
bigcall HTIM_Init ; (any, !Z)
bigcall HTIM_Start
bigcall HTIM_EnableActor
ret
; @end
; ---------------------------------------------------------------------------
; @routine TCA_OnEveryTick
;
; @param Z pointer to data in FLASH (byte address for lpm!)
; @param Y pointer to data in RAM
TCA_OnEveryTick:
ldd r17, Y+HTIM_RAM_OFFS_FLAGS
mov r16, r17
cbr r17, (1<<TCA_FLAGBITS_NEED_TRIGGER) | (1<<TCA_FLAGBITS_NEED_DISABLE) | (1<<TCA_FLAGBITS_NEED_ENABLE)
std Y+HTIM_RAM_OFFS_FLAGS, r17
push r16
sbrc r16, TCA_FLAGBITS_NEED_ENABLE
bigcall HTIM_EnableActor
pop r16
push r16
sbrc r16, TCA_FLAGBITS_NEED_DISABLE
bigcall HTIM_DisableActor
pop r16
push r16
sbrc r16, TCA_FLAGBITS_NEED_TRIGGER
bigcall HTIM_Trigger
pop r16
bigcall HTIM_OnEveryTick
ret
; @end
; ---------------------------------------------------------------------------
; @routine TCA_ReadEepromAt
;
; @param Z pointer to data in FLASH (byte address for lpm!)
; @param Y pointer to data in RAM
; @param X EEPROM address
; @return X EEPROM address after the data handled by this routine
; @clobbers r16, r17
TCA_ReadEepromAt:
bigcall HTIM_ReadEepromAt ; (r16, r17)
push yl
push yh
adiw yh:yl, TCA_RAM_OFFS_BEGIN
ldi r17, (TCA_EE_SIZE-TCA_EE_OFFS_BEGIN)
bigcall Eeprom_ReadBytes ; (r16, r17, X, Y)
pop yh
pop yl
ret
; @end
; ---------------------------------------------------------------------------
; @routine TCA_WriteEepromAt
;
; @param Z pointer to data in FLASH (byte address for lpm!)
; @param Y pointer to data in RAM
; @param X EEPROM address
; @return X EEPROM address after the data handled by this routine
; @clobbers r16, r17, r18
TCA_WriteEepromAt:
bigcall HTIM_WriteEepromAt ; (r16, r17, r18)
push yl
push yh
adiw yh:yl, TCA_RAM_OFFS_BEGIN
ldi r17, (TCA_EE_SIZE-TCA_EE_OFFS_BEGIN)
bigcall Eeprom_WriteBytes ; (r16, r17, r18, X, Y)
pop yh
pop yl
ret
; @end
#endif

View File

@@ -0,0 +1,292 @@
; ***************************************************************************
; 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_MODULES_TRIGGERACTOR_RECV_ASM
#define AQH_AVR_MODULES_TRIGGERACTOR_RECV_ASM
; ---------------------------------------------------------------------------
; @routine TCA_HandleMsg @global
;
; @param X pointer to msg received
; @param Y pointer to data in RAM
; @param R17 value id
; @param R19:R18 value
; @param R22 src addr
; @clobbers any, !X, !Y, !Z
TCA_HandleMsg:
push xl
push xh
mov xl, yl
mov xh, yh
adiw xh:xl, TCA_RAM_OFFS_GUARD_SOURCE
; rcall tcaCheckGuardSource ; enable or disable actor, if matching msg
adiw xh:xl, TCA_SOURCE_SIZE
rcall tcaCheckTriggerSource ; trigger, if matching msg
adiw xh:xl, TCA_SOURCE_SIZE
; rcall tcaCheckTriggerSource ; trigger, if matching msg
pop xh
pop xl
TCA_HandleMsg_ret:
clc
ret
; @end
; ---------------------------------------------------------------------------
; @routine tcaCheckTriggerSource
;
; @param Z pointer to data in FLASH (byte address for lpm!)
; @param Y pointer to data in RAM
; @param X pointer to TCA_SOURCE object
; @param R17 value id
; @param R19:R18 value
; @param R22 src addr
; @clobbers R16, R24, R25, (any), !Z, !Y
tcaCheckTriggerSource:
rcall tcaCheckSourceAndValue ; (r16)
brcc tcaCheckTriggerSource_ret
; we have a value
rcall tcaCheckValue ; (r24, r25)
brcc tcaCheckTriggerSource_ret
ldd r16, Y+HTIM_RAM_OFFS_FLAGS
sbr r16, (1<<TCA_FLAGBITS_NEED_TRIGGER)
std Y+HTIM_RAM_OFFS_FLAGS, r16
tcaCheckTriggerSource_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine tcaCheckGuardSource
;
; @param X pointer to TCA_SOURCE object
; @param R17 value id
; @param R19:R18 value
; @param R22 src addr
; @clobbers R16, R24, R25, (any), !Z, !Y
tcaCheckGuardSource:
rcall tcaCheckSourceAndValue ; (r16)
brcc tcaCheckGuardSource_ret
; we have a value
rcall tcaCheckValue
ldd r16, Y+HTIM_RAM_OFFS_FLAGS
brcc tcaCheckGuardSource_noMatch
sbr r16, (1<<TCA_FLAGBITS_NEED_ENABLE) | (1<<APP_FANCONTROL_FLAGBIT_UPDATED)
rjmp tcaCheckGuardSource_done
tcaCheckGuardSource_noMatch:
sbr r16, (1<<TCA_FLAGBITS_NEED_DISABLE) | (1<<APP_FANCONTROL_FLAGBIT_UPDATED)
tcaCheckGuardSource_done:
std Y+HTIM_RAM_OFFS_FLAGS, r16
tcaCheckGuardSource_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine tcaCheckSourceAndValue
;
; @param X pointer to TCA_SOURCE object
; @param R17 value id
; @param R22 src addr
; @clobbers r16
tcaCheckSourceAndValue:
ld r16, X
cp r16, r22 ; compare src addr
brne tcaCheckSourceAndValue_clcRet
adiw xh:xl, TCA_SOURCE_OFFS_VALUEID
ld r16, X
sbiw xh:xl, TCA_SOURCE_OFFS_VALUEID
cp r16, r17 ; compare value id
brne tcaCheckSourceAndValue_clcRet
sec
rjmp tcaCheckSourceAndValue_ret ; matches
tcaCheckSourceAndValue_clcRet:
clc
tcaCheckSourceAndValue_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine tcaCheckValue
;
; @param Z pointer to data in FLASH (byte address for lpm!)
; @param Y pointer to TCA_SOURCE object
; @param R19:R18 value
; @clobbers r24, r25
tcaCheckValue:
adiw xh:xl, TCA_SOURCE_OFFS_LOWLIM_LO
ld r24, X+
ld r25, X
sbiw xh:xl, (TCA_SOURCE_OFFS_LOWLIM_LO+1)
cp r18, r24
cpc r19, r25
brcs tcaCheckValue_clcRet
adiw xh:xl, TCA_SOURCE_OFFS_HIGHLIM_LO
ld r24, X+
ld r25, X
sbiw xh:xl, (TCA_SOURCE_OFFS_HIGHLIM_LO+1)
cp r24, r18
cpc r25, r19
brcs tcaCheckValue_clcRet
sec
rjmp tcaCheckValue_ret
tcaCheckValue_clcRet:
clc
tcaCheckValue_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine TCA_SetValue_GuardSrc
; @param Y pointer to TCA data in RAM
TCA_SetValue_GuardSrc: ; value is in R18-R21 (R16, R17, X)
std Y+(TCA_RAM_OFFS_GUARD_SOURCE+TCA_SOURCE_OFFS_ADDR), r18
std Y+(TCA_RAM_OFFS_GUARD_SOURCE+TCA_SOURCE_OFFS_VALUEID), r19
rjmp TCA_SetValueACK
; @end
; ---------------------------------------------------------------------------
; @routine TCA_SetValue_GuardLimits
; @param Y pointer to TCA data in RAM
TCA_SetValue_GuardLimits: ; value is in R18-R21 (R16, R17, X)
std Y+(TCA_RAM_OFFS_GUARD_SOURCE+TCA_SOURCE_OFFS_LOWLIM_LO), r18
std Y+(TCA_RAM_OFFS_GUARD_SOURCE+TCA_SOURCE_OFFS_LOWLIM_HI), r19
std Y+(TCA_RAM_OFFS_GUARD_SOURCE+TCA_SOURCE_OFFS_HIGHLIM_LO), r20
std Y+(TCA_RAM_OFFS_GUARD_SOURCE+TCA_SOURCE_OFFS_HIGHLIM_HI), r21
rjmp TCA_SetValueACK
; @end
; ---------------------------------------------------------------------------
; @routine TCA_SetValue_Trigger1Src
; @param Y pointer to TCA data in RAM
TCA_SetValue_Trigger1Src: ; value is in R18-R21 (R16, R17, X)
std Y+(TCA_RAM_OFFS_TRIGGER_SOURCE1+TCA_SOURCE_OFFS_ADDR), r18
std Y+(TCA_RAM_OFFS_TRIGGER_SOURCE1+TCA_SOURCE_OFFS_VALUEID), r19
rjmp TCA_SetValueACK
; @end
; ---------------------------------------------------------------------------
; @routine TCA_SetValue_Trigger1Limits
; @param Y pointer to TCA data in RAM
TCA_SetValue_Trigger1Limits: ; value is in R18-R21 (R16, R17, X)
std Y+(TCA_RAM_OFFS_TRIGGER_SOURCE1+TCA_SOURCE_OFFS_LOWLIM_LO), r18
std Y+(TCA_RAM_OFFS_TRIGGER_SOURCE1+TCA_SOURCE_OFFS_LOWLIM_HI), r19
std Y+(TCA_RAM_OFFS_TRIGGER_SOURCE1+TCA_SOURCE_OFFS_HIGHLIM_LO), r20
std Y+(TCA_RAM_OFFS_TRIGGER_SOURCE1+TCA_SOURCE_OFFS_HIGHLIM_HI), r21
rjmp TCA_SetValueACK
; @end
; ---------------------------------------------------------------------------
; @routine TCA_SetValue_Trigger2Src
; @param Y pointer to TCA data in RAM
TCA_SetValue_Trigger2Src: ; value is in R18-R21 (R16, R17, X)
std Y+(TCA_RAM_OFFS_TRIGGER_SOURCE2+TCA_SOURCE_OFFS_ADDR), r18
std Y+(TCA_RAM_OFFS_TRIGGER_SOURCE2+TCA_SOURCE_OFFS_VALUEID), r19
rjmp TCA_SetValueACK
; @end
; ---------------------------------------------------------------------------
; @routine TCA_SetValue_Trigger2Limits
; @param Y pointer to TCA data in RAM
TCA_SetValue_Trigger2Limits: ; value is in R18-R21 (R16, R17, X)
std Y+(TCA_RAM_OFFS_TRIGGER_SOURCE2+TCA_SOURCE_OFFS_LOWLIM_LO), r18
std Y+(TCA_RAM_OFFS_TRIGGER_SOURCE2+TCA_SOURCE_OFFS_LOWLIM_HI), r19
std Y+(TCA_RAM_OFFS_TRIGGER_SOURCE2+TCA_SOURCE_OFFS_HIGHLIM_LO), r20
std Y+(TCA_RAM_OFFS_TRIGGER_SOURCE2+TCA_SOURCE_OFFS_HIGHLIM_HI), r21
rjmp TCA_SetValueACK
; @end
; ---------------------------------------------------------------------------
; @routine TCA_SetValue_HoldTime
; @param Y pointer to TCA data in RAM
TCA_SetValue_HoldTime:
std Y+HTIM_RAM_OFFS_RELOAD_LO, r18
std Y+HTIM_RAM_OFFS_RELOAD_HI, r19
rjmp TCA_SetValueACK
; @end
; ---------------------------------------------------------------------------
; @routine TCA_SetValue_Mode
; @param Y pointer to TCA data in RAM
TCA_SetValue_Mode:
std Y+HTIM_RAM_OFFS_MODE, r18
rjmp TCA_SetValueACK
; @end
; ---------------------------------------------------------------------------
; @routine TCA_SetValueACK
TCA_SetValueACK:
ldd r16, Y+HTIM_RAM_OFFS_FLAGS
sbr r16, (1<<APP_FANCONTROL_FLAGBIT_UPDATED)
std Y+HTIM_RAM_OFFS_FLAGS, r16
ldi r23, NETMSG_CMD_VALUE_SET_ACK
sec
ret
; @end
#endif