; ***************************************************************************
; copyright   : (C) 2024 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.   *
; ***************************************************************************


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

.equ MOTIONLIGHT_DEFAULT_ONTIME      = 3000 ; 5min (in 1/10 secs)

.equ MOTIONLIGHT_SOURCE_NUM          = 2

.equ MOTIONLIGHT_SOURCE_OFFS_ADDR    = 0
.equ MOTIONLIGHT_SOURCE_OFFS_VALUEID = 1
.equ MOTIONLIGHT_SOURCE_SIZE         = 2



; ***************************************************************************
; data

.dseg



motionLightDataBegin:
motionLightTimer:   .byte 2
motionLightOnTime:  .byte 2
motionLightColor:   .byte 4
motionLightSources: .byte MOTIONLIGHT_SOURCE_NUM*MOTIONLIGHT_SOURCE_SIZE
motionLightDataEnd:



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

.cseg

MOTIONLIGHT_BEGIN:


; ---------------------------------------------------------------------------
; @routine MotionLight_Init @global
;

MotionLight_Init:
  ; preset SRAM data area
  ldi xh, HIGH(motionLightDataBegin)
  ldi xl, LOW(motionLightDataBegin)
  clr r16
  ldi r17, (motionLightDataEnd-motionLightDataBegin)
  rcall Utils_FillSram
  
  ldi xh, HIGH(motionLightColor)
  ldi xl, LOW(motionLightColor)
  clr r16
  ldi r17, 0x80
  st X+, r16    ; R
  st X+, r16    ; G
  st X+, r17    ; B
  st X+, r16    ; WW
  ldi r16, LOW(MOTIONLIGHT_DEFAULT_ONTIME)
  sts motionLightOnTime, r16
  ldi r16, HIGH(MOTIONLIGHT_DEFAULT_ONTIME)
  sts motionLightOnTime+1, r16

  rcall motionLightReadConfFromEeprom
 
  ret
; @end



; ---------------------------------------------------------------------------
; @routine MotionLight_Fini @global
;

MotionLight_Fini:
  clr r16
  sts motionLightTimer, r16   ; clear timer
  sts motionLightTimer+1, r16
  rjmp motionLightTurnOff
; @end



; ---------------------------------------------------------------------------
; @routine MotionLight_Every100ms @global
;
; @clobbers r16, r24, r26, (r17, r18, r19, r20, r21, r23)

MotionLight_Every100ms:
  lds r24, motionLightTimer
  lds r25, motionLightTimer+1
  sbiw r25:r24, 1
  brcs MotionLight_Every100ms_ret
  sts motionLightTimer, r24
  sts motionLightTimer+1, r25
  breq MotionLight_Every100ms_off
MotionLight_Every100ms_ret:
  ret
MotionLight_Every100ms_off:
  rjmp motionLightTurnOff   ; (r16, r17, r18, r19, r20, r21, r23)
; @end



; ---------------------------------------------------------------------------
; @routine MotionLight_OnPacketReceived @global
;
; @clobbers any, -X

MotionLight_OnPacketReceived:
  adiw xh:xl, 2                                ; command
  ld r16, X
  sbiw xh:xl, 2
  cpi r16, CPRO_CMD_VALUE_REPORT
  breq MotionLight_OnPacketReceived_report
  cpi r16, CPRO_CMD_VALUE_SET
  breq MotionLight_OnPacketReceived_set
MotionLight_OnPacketReceived_clcRet:
  clc                                          ; unexpected msg
  ret
MotionLight_OnPacketReceived_report:
  rcall CPRO_ReadValue                         ; (none)
  mov r16, r18
  or r16, r19
  breq MotionLight_OnPacketReceived_clcRet     ; zero value, ignore
  rcall motionLightHasSource                   ; (r16, r24, Y)
  brcs MotionLight_OnPacketReceived_turnOn
  ret
MotionLight_OnPacketReceived_turnOn:
  lds r16, motionLightTimer
  lds r17, motionLightTimer+1
  or r16, r17
  brne MotionLight_OnPacketReceived_startTimer
  rcall motionLightTurnOn                      ; (r16, r17, r18, r19, r20, r21, r23)
MotionLight_OnPacketReceived_startTimer:
  rcall motionLightStartTimer
  ret
MotionLight_OnPacketReceived_set:
  rcall CPRO_ReadValue                         ; (none)
  cpi r17, VALUE_ID_MAL_RGBW_VALUE
  breq MotionLight_OnPacketReceived_setRGBW
  cpi r17, VALUE_ID_MAL_ONTIME
  breq MotionLight_OnPacketReceived_setOnTime
  cpi r17, VALUE_ID_MAL_SOURCE1
  breq MotionLight_OnPacketReceived_setSource1
  cpi r17, VALUE_ID_MAL_SOURCE2
  breq MotionLight_OnPacketReceived_setSource2
  clc                                          ; unexpected message
  ret
MotionLight_OnPacketReceived_setRGBW:
  sts motionLightColor, r18
  sts motionLightColor+1, r19
  sts motionLightColor+2, r20
  sts motionLightColor+3, r21
  rcall motionLightStartTimer                  ; immediately ON with new color
  rcall motionLightTurnOn                      
  rjmp MotionLight_OnPacketReceived_sendAck
MotionLight_OnPacketReceived_setOnTime:
  sts motionLightOnTime, r18
  sts motionLightOnTime+1, r19
  rjmp MotionLight_OnPacketReceived_sendAck
MotionLight_OnPacketReceived_setSource1:
  sts motionLightSources, r18                           ; peerAddr
  sts motionLightSources+1, r19                         ; valueId
  rjmp MotionLight_OnPacketReceived_sendAck
MotionLight_OnPacketReceived_setSource2:
  sts motionLightSources+MOTIONLIGHT_SOURCE_SIZE, r18   ; peerAddr
  sts motionLightSources+MOTIONLIGHT_SOURCE_SIZE+1, r19 ; valueId
MotionLight_OnPacketReceived_sendAck:
  ldi r16, CPRO_CMD_VALUE_SET_ACK
  rcall CPRO_SendSetValueResponse
  push xl
    push xh
      rcall motionLightWriteConfToEeprom
    pop xh
  pop xl
  sec
  ret
; @end



; ---------------------------------------------------------------------------
; @routine motionLightHasSource
;
; @return CFLAGS set if we have a matching source entry, cleared otherwise
; @param r17 value id
; @param r22 source address
; @clobbers r16, r24, Y

motionLightHasSource:
  ldi yl, LOW(motionLightSources)
  ldi yh, HIGH(motionLightSources)
  ldi r24, MOTIONLIGHT_SOURCE_NUM
motionLightHasSource_loop:
    ldd r16, Y+MOTIONLIGHT_SOURCE_OFFS_ADDR
    cp r16, r22
    brne motionLightHasSource_next
    ldd r16, Y+MOTIONLIGHT_SOURCE_OFFS_VALUEID
    cp r16, r17
    brne motionLightHasSource_next
    sec
    ret
motionLightHasSource_next:
    adiw yh:yl, MOTIONLIGHT_SOURCE_SIZE
    dec r24
  brne motionLightHasSource_loop
  clc
  ret
; @end



; ---------------------------------------------------------------------------
; @routine motionLightStartTimer
;
; @clobbers r16

motionLightStartTimer:
  lds r16, motionLightOnTime
  sts motionLightTimer, r16
  lds r16, motionLightOnTime+1
  sts motionLightTimer+1, r16
  ret
; @end



; ---------------------------------------------------------------------------
; @routine motionLightTurnOn
;
; @clobbers r18, r19, r20, r21 (r16, t17, r23)

motionLightTurnOn:
  lds r18, motionLightColor
  lds r19, motionLightColor+1
  lds r20, motionLightColor+2
  lds r21, motionLightColor+3
  rjmp SK6812_SetAllColor     ; (r16, r17, r23)
; @end
  


; ---------------------------------------------------------------------------
; @routine motionLightTurnOff
;
; @clobbers r18, r19, r20, r21 (r16, t17, r23)

motionLightTurnOff:
  clr r18
  clr r19
  clr r20
  clr r21
  rjmp SK6812_SetAllColor     ; (r16, r17, r23)
; @end



; ---------------------------------------------------------------------------
; @routine motionLightReadConfFromEeprom
;
; @clobbers 

motionLightReadConfFromEeprom:
  push r15
    in r15, SREG
    cli
    ldi xl, LOW(EEPROM_OFFS_MAL_CONF_ONTIME)
    ldi xh, HIGH(EEPROM_OFFS_MAL_CONF_ONTIME)
    rcall Utils_ReadEepromIncr ; (R16)
    mov r18, r16
    rcall Utils_ReadEepromIncr ; (R16)
    mov r19, r16
    and r16, r18
    cpi r16, 0xff
    breq motionLightReadConfFromEeprom_end
    sts motionLightOnTime, r18
    sts motionLightOnTime+1, r19
    
    ; read source 1
    rcall Utils_ReadEepromIncr ; (R16)
    mov r18, r16
    rcall Utils_ReadEepromIncr ; (R16)
    mov r19, r16
    sts motionLightSources+MOTIONLIGHT_SOURCE_OFFS_ADDR, r18
    sts motionLightSources+MOTIONLIGHT_SOURCE_OFFS_VALUEID, r19

    ; read source 2
    rcall Utils_ReadEepromIncr ; (R16)
    mov r18, r16
    rcall Utils_ReadEepromIncr ; (R16)
    mov r19, r16
    sts motionLightSources+MOTIONLIGHT_SOURCE_SIZE+MOTIONLIGHT_SOURCE_OFFS_ADDR, r18
    sts motionLightSources+MOTIONLIGHT_SOURCE_SIZE+MOTIONLIGHT_SOURCE_OFFS_VALUEID, r19
    
motionLightReadConfFromEeprom_end:
    out SREG, r15
  pop r15
  ret
; @end



; ---------------------------------------------------------------------------
; @routine motionLightWriteConfToEeprom
;
; @clobbers r15, r16, r17, X

motionLightWriteConfToEeprom:
  push r15
    in r15, SREG
    cli
    ldi xl, LOW(EEPROM_OFFS_MAL_CONF_ONTIME)
    ldi xh, HIGH(EEPROM_OFFS_MAL_CONF_ONTIME)
    
    lds r16, motionLightOnTime
    rcall Utils_WriteEepromIncr ; (R17)
    lds r16, motionLightOnTime+1
    rcall Utils_WriteEepromIncr ; (R17)

    ; write source 1
    lds r16, motionLightSources+MOTIONLIGHT_SOURCE_OFFS_ADDR
    rcall Utils_WriteEepromIncr ; (R16)
    lds r16, motionLightSources+MOTIONLIGHT_SOURCE_OFFS_VALUEID
    rcall Utils_WriteEepromIncr ; (R16)

    ; write source 2
    lds r16, motionLightSources+MOTIONLIGHT_SOURCE_SIZE+MOTIONLIGHT_SOURCE_OFFS_ADDR
    rcall Utils_WriteEepromIncr ; (R16)
    lds r16, motionLightSources+MOTIONLIGHT_SOURCE_SIZE+MOTIONLIGHT_SOURCE_OFFS_VALUEID
    rcall Utils_WriteEepromIncr ; (R16)

    out SREG, r15
  pop r15
  ret
; @end



MOTIONLIGHT_END:
.equ MODULE_SIZE_MOTIONLIGHT = MOTIONLIGHT_END-MOTIONLIGHT_BEGIN


