; *************************************************************************** ; copyright : (C) 2023 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. * ; *************************************************************************** ; The state byte contains the state for two reed contacts (one in each nibble). ; ; bit meaning ; ------------------------------ ; 0 last measurement ; 1 measurement before last ; 2 change occurred ; 3 current stable state ; *************************************************************************** ; defs .equ REED_STATE_MASK_CURRENT = 0x8 .equ REED_STATE_MASK_CHANGED = 0x4 .equ REED_STATE_MASK_BEFORELAST = 0x2 .equ REED_STATE_MASK_LAST = 0x1 .equ REED_STATE_MASK_LASTVALUES = 0x3 ; bits 0 and 1 .equ REED_STATE_BIT_CURRENT = 3 .equ REED_STATE_BIT_CHANGED = 2 .equ REED_CONFIG_MASK_SET = 0x80 .equ REED_CONFIG_MASK_MULTI = 0x40 .equ REED_CONFIG_MASK_NO = 0x20 ; if set: normally open (e.g. disconnected when magnet near) .equ REED_INITIAL_CONFIG = REED_CONFIG_MASK_SET ; *************************************************************************** ; data .dseg reedDataBegin: reedConfigFromEeprom: .byte 1 reedState: .byte 1 reedDataEnd: ; *************************************************************************** ; code .cseg ; --------------------------------------------------------------------------- ; @routine REED_Init ; ; Init module. ; ; @return CFLAG set if okay, cleared on error ; @clobbers r16, r17, X REED_Init: ; preset SRAM data area ldi xh, HIGH(reedDataBegin) ldi xl, LOW(reedDataBegin) clr r16 ldi r17, (reedDataEnd-reedDataBegin) rcall Utils_FillSram ; (r17, x) cbi REEDOUT_PORT, REEDOUT_PINNUM ; set common reed port to low sbi REEDOUT_DDR, REEDOUT_PINNUM ; set common reed output port as output cbi REED1_PORT, REED1_PINNUM ; disable internal pullup for DATA cbi REED1_DDR, REED1_PINNUM ; set reed1 port as input cbi REED2_PORT, REED2_PINNUM ; disable internal pullup for DATA cbi REED2_DDR, REED2_PINNUM ; set reed2 port as input rcall reedSetupConfig ; initial setup from EEPROM, if possible ret REED_Fini: sec ret REED_Run: ret ; debug push r15 in r15, SREG cli rcall reedHandleChanges out SREG, r15 pop r15 ret REED_Every100ms: push r15 in r15, SREG cli rcall reedUpdateState ; (r16, r17, r18, r19) out SREG, r15 pop r15 ret REED_Timer: push r15 in r15, SREG cli rcall reedHandleChanges out SREG, r15 pop r15 ret ; --------------------------------------------------------------------------- ; @routine reedSetupConfig ; ; Read initial config from EEPROM or setup from new and write to EEPROM ; ; @clobbers r16, X reedSetupConfig: ldi xh, HIGH(EEPROM_OFFS_REED_CONF) ; read initial config from EEPROM ldi xl, LOW(EEPROM_OFFS_REED_CONF) ; rcall Utils_ReadEepromIncr ; (r16) sbiw xh:xl, 1 ; called routine increments X, undo tst r16 breq reedSetupConfig_noConfig cpi r16, 0xff brne reedSetupConfig_haveConfig reedSetupConfig_noConfig: ldi r16, REED_INITIAL_CONFIG rcall Utils_WriteEepromIncr reedSetupConfig_haveConfig: sts reedConfigFromEeprom, r16 reedSetupConfig_end: ret ; --------------------------------------------------------------------------- ; @routine reedHandleChanges ; ; @clobbers all reedHandleChanges: lds r19, reedState ; reed 1 mov r16, r19 ldi r17, VALUE_ID_REED1 push r19 rcall reedSendValueIfChanged pop r19 andi r16, 0x0f andi r19, 0xf0 or r19, r16 ; reed 2 mov r16, r19 swap r16 ldi r17, VALUE_ID_REED2 push r19 rcall reedSendValueIfChanged pop r19 andi r16, 0x0f swap r16 andi r19, 0x0f or r19, r16 sts reedState, r19 ret ; @end ; --------------------------------------------------------------------------- ; @routine reedSendValueIfChanged ; ; @return r16 updated state ; @param r16: current state nibble ; @param r17: value id ; @clobbers r16, r19 (all others) reedSendValueIfChanged: push r16 mov r18, r16 andi r16, REED_STATE_MASK_CHANGED breq reedSendValueIfChanged_l1 ; jmp if not changed ; value changed clr r16 sbrc r18, REED_STATE_BIT_CURRENT dec r16 ; if stable state=0 (meaning: closed) rcall reedSendChange brcc reedSendValueIfChanged_l1 pop r16 andi r16, ~REED_STATE_MASK_CHANGED ; clear change bit ret reedSendValueIfChanged_l1: pop r16 ret ; @end ; --------------------------------------------------------------------------- ; @routine reedSendChange ; ; @param r16 value ; @param r17 value id ; @clobbers r16, r18, r19, r20, r21, r22, X (R3, R4, R6, R7, R8, R9, R10, R11, R12, R15, R16, R17, R18, R19, R20, R21, R22, X, Y) reedSendChange: mov r18, r16 ; value to send in r19:r18 clr r19 ldi r16, 0xff ; dest addr: send to all ldi r20, 1 ; denominator in r21:r20 clr r21 ldi r22, AQHOME_VALUETYPE_DOOR ldi xl, LOW(com2SendBuffer) ldi xh, HIGH(com2SendBuffer) rcall CPRO_WriteValue ; (R3, R4, R6, R7, R8, R9, R10, R11, R12, R15, R16, R17, R18, R19, R20, R21, X, Y) rjmp COM2_SendPacket ; (r18, r19, r22, X) ; @end ; --------------------------------------------------------------------------- ; @routine reedUpdateState ; ; Updates SDRAM variable reedState according to current pin states. ; ; @clobbers r16, r17, r18, r19 reedUpdateState: lds r19, reedState ; current reed state ; handle reed 1 (low nibble state) rcall reedReadValue1 ; (r16) mov r17, r16 mov r16, r19 rcall reedUpdateStateNibble ; (r18) ; replace lower state nibble with new value andi r16, 0x0f ; only keep low nibble andi r19, 0xf0 ; clear out low nibble before or'ing new value in or r19, r16 ; handle reed2 (high nibble state) rcall reedReadValue2 ; (r16) mov r17, r16 mov r16, r19 swap r16 rcall reedUpdateStateNibble ; (r18) swap r16 ; replace higher state nibble with new value andi r16, 0xf0 andi r19, 0x0f or r19, r16 ; write back reed state sts reedState, r19 ret ; @end ; --------------------------------------------------------------------------- ; @routine reedUpdateStateNibble ; ; @return r16 updated current state nibble ; @param r16 current state nibble ; @param r17 current pin status (o if clear, 1 if set) ; @clobbers r18 reedUpdateStateNibble: mov r18, r16 andi r18, REED_STATE_MASK_LAST ; clear everything but last measurement lsl r18 ; shift previous measurement to left andi r17, 1 or r18, r17 ; or current measurement into value ; store new value in state nibble andi r16, ~REED_STATE_MASK_LASTVALUES ; clear pin states or r16, r18 ; put updated measurements back into state nibble ; check for new stable state tst r18 ; last measurements all zero? breq reedUpdateStateNibble_stable0 cpi r18, 0x03 ; last measurements all one? breq reedUpdateStateNibble_stable1 ; not a stable state right now ret reedUpdateStateNibble_stable0: sbrs r16, REED_STATE_BIT_CURRENT ; new stable is 0, changed? ret ; ret if no change ori r16, REED_STATE_MASK_CHANGED ; flag change andi r16, ~REED_STATE_MASK_CURRENT ; set new stable value to 0 ret reedUpdateStateNibble_stable1: sbrc r16, REED_STATE_BIT_CURRENT ; new stable is 1, changed? ret ; ret if no change ori r16, (REED_STATE_MASK_CHANGED | REED_STATE_MASK_CURRENT) ; flag change, set new stable value to 1 ret ; @end ; --------------------------------------------------------------------------- ; @routine reedReadValue1 ; ; @return r16 current pin state reedReadValue1: clr r16 clc sbic REED1_PIN, REED1_PINNUM sec adc r16, r16 ret ; @end ; --------------------------------------------------------------------------- ; @routine reedReadValue2 ; ; @return r16 current pin state reedReadValue2: clr r16 clc sbic REED2_PIN, REED2_PINNUM sec adc r16, r16 ret ; @end