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


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

.cseg

OWIMASTER_BEGIN:


; ---------------------------------------------------------------------------
; @routine OwiMaster_Init @global
;
; @return CFLAG  set if okay, clear on error

OwiMaster_Init:
  cbi OWI_DDR, OWI_PINNUM     ; set to input
  cbi OWI_PORTOUT, OWI_PINNUM ; disable internal pullup
  sec
  ret
; @end



; ---------------------------------------------------------------------------
; @routine OwiMaster_Reset @global
;
; Cave: Needs interrupts to be disabled!
;
; @return r16 0xff if slave presence signal received, 0x00 otherwise
; @clobbers r21, r22

OwiMaster_Reset:
  ; send RESET pulse (min. 480usec)
  sbi OWI_DDR, OWI_PINNUM         ; set to output
  cbi OWI_PORTOUT, OWI_PINNUM     ; set value to zero
  rcall Utils_WaitFor100MicroSecs ; wait for about 500 usecs
  rcall Utils_WaitFor100MicroSecs
  rcall Utils_WaitFor100MicroSecs
  rcall Utils_WaitFor100MicroSecs
  rcall Utils_WaitFor100MicroSecs
  cbi OWI_DDR, OWI_PINNUM         ; set to input
  ; after 16-60 uS slave pulls line low for 60-240 uS
  ; if present slave pulls line low for 60 usecs (we check after 30 usecs)
  ldi r21, 100
OwiMaster_Reset_LoopWaitForLow:          ; wait for line low
    Utils_WaitNanoSecs 5000, 0, r22
    sbis OWI_PORTIN, OWI_PINNUM
      rjmp OwiMaster_Reset_isLow
    dec r21
  brne OwiMaster_Reset_LoopWaitForLow
  clr r16                      ; not present
  rjmp OwiMaster_Reset_done
OwiMaster_Reset_isLow:
  ldi r21, 160
OwiMaster_Reset_LoopWaitForHigh:          ; wait for line high
    Utils_WaitNanoSecs 5000, 0, r22
    sbic OWI_PORTIN, OWI_PINNUM
      rjmp OwiMaster_Reset_isHigh
    dec r21
  brne OwiMaster_Reset_LoopWaitForHigh
  clr r16                      ; not present
  rjmp OwiMaster_Reset_done
OwiMaster_Reset_isHigh:
  ldi r16, 0xff                ; presence detected
OwiMaster_Reset_done:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine OwiMaster_SendByte @global

; Cave: Needs interrupts to be disabled!
;
; @param r16 byte to send
; @clobbers r16, r21, r22

OwiMaster_SendByte:
  cbi OWI_DDR, OWI_PINNUM            ; set to input
  cbi OWI_PORTOUT, OWI_PINNUM        ; set value to zero
  ldi r21, 8
OwiMaster_SendByte_loop:
    sbi OWI_DDR, OWI_PINNUM          ; set to output (pull line low)
    lsr r16                          ; +1 bit to send -> CARRY
    brcs OwiMaster_SendByte_setHigh  ; +1 / +2
OwiMaster_SendByte_setLow:
    Utils_WaitNanoSecs 60000, 0, r22 ; low for 60 usecs
    cbi OWI_DDR, OWI_PINNUM          ; set to input (pulls line high)
    Utils_WaitNanoSecs 5000, 0, r22  ; wait for 5 usecs
    rjmp OwiMaster_SendByte_loopEnd
OwiMaster_SendByte_setHigh:
    Utils_WaitNanoSecs 5000, 0, r22  ; keep low for 5 usecs
    cbi OWI_DDR, OWI_PINNUM          ; set to output
    Utils_WaitNanoSecs 60000, 0, r22 ; keep high for remainder of write slot
OwiMaster_SendByte_loopEnd:
    dec r21
  brne OwiMaster_SendByte_loop
  ret
; @end



; ---------------------------------------------------------------------------
; @routine OwiMaster_RecvByte @global
;
; Receive a byte (slot size about 70 usecs)
; Cave: Needs interrupts to be disabled!
;
; @return r16 byte received
; @return CFLAG set if okay, cleared on error
; @clobbers r17, r20, r21, r22

OwiMaster_RecvByte:
  cbi OWI_DDR, OWI_PINNUM            ; set to input
  cbi OWI_PORTOUT, OWI_PINNUM        ; set value to zero
  clr r17
  ldi r20, 8
OwiMaster_RecvByte_loop:
    sbi OWI_DDR, OWI_PINNUM          ; set to output
    Utils_WaitNanoSecs 5000, 0, r22  ; set to low for 5 usecs ("1")
    cbi OWI_DDR, OWI_PINNUM          ; set to input
    Utils_WaitNanoSecs 5000, 0, r22  ; wait for 5 usecs
    sec
    sbic OWI_PORTIN, OWI_PINNUM      ; sample line
      rjmp OwiMaster_RecvByte_recv1
    Utils_WaitNanoSecs 55000, 0, r22
    clc                              ; shift-in ZERO
    rjmp OwiMaster_RecvByte_shiftIn
OwiMaster_RecvByte_recv1:
    Utils_WaitNanoSecs 55000, 0, r22
    sec
OwiMaster_RecvByte_shiftIn:
    ror r17
    Utils_WaitNanoSecs 5000, 0, r22  ; time between bits
OwiMaster_RecvByte_loopEnd:
    dec r20
  brne OwiMaster_RecvByte_loop
  mov r16, r17
  sec
  ret
OwiMaster_RecvByte_error:
  clc
  ret
; @end



; ---------------------------------------------------------------------------
; @routine owiWaitForDataState1ms
;
; @return CFLAG set if state reached, cleared otherwise
; @param  r16 state to wait for (00 for low, 0xff for high)
; @clobbers r21, r22

owiWaitForDataState1ms:
  ldi r21, 10
owiWaitForDataState1ms_loop:
    in r22, OWI_PORTIN
    eor r22, r16
    andi r22, (1<<OWI_PINNUM)
    breq owiWaitForDataState1ms_stateReached
    nop
    nop
    nop
    dec r21
  brne owiWaitForDataState1ms_loop
  clc
  ret
owiWaitForDataState1ms_stateReached:
  sec
  ret
; @end



OWIMASTER_END:
.equ MODULE_SIZE_OWIMASTER = OWIMASTER_END-OWIMASTER_BEGIN




