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



; ***************************************************************************
; defs

.equ DS18B20_ROMCMD_READROM        = 0x33
.equ DS18B20_ROMCMD_SKIPROM        = 0xcc
.equ DS18B20_FNCMD_CONVERT         = 0x44
.equ DS18B20_FNCMD_READSCRATCHPAD  = 0xbe

.equ DS18B20_FLAGS_CONV_STARTED    = 0x01
.equ DS18B20_FLAGS_CONV_UPDATED    = 0x02

.equ DS18B20_POLYNOMIAL            = 0x8c


.equ DS18B20_INTERVAL_SECS         = 30


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

.dseg

ds18b20DataBegin:
  ds18b20Flags:         .byte 1
  ds18b20Timer:         .byte 1
  ds18b20DataBuffer:    .byte 9
  ds18b20DataTemp:      .byte 2
ds18b20DataEnd:






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

.cseg

DS18B20_BEGIN:


; ---------------------------------------------------------------------------
; @routine Ds18b20_Init @global
;
; @return CFLAG set if okay, cleared on error
; @clobbers r16, r17, X

Ds18b20_Init:
  ; preset SRAM data area
  ldi xh, HIGH(ds18b20DataBegin)
  ldi xl, LOW(ds18b20DataBegin)
  clr r16
  ldi r17, (ds18b20DataEnd-ds18b20DataBegin)
  rcall Utils_FillSram                ; (r17, x)
  ret
; @end



; ---------------------------------------------------------------------------
; @routine Ds18b20_Fini @global

Ds18b20_Fini:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine Ds18b20_OnEverySecond @global

Ds18b20_OnEverySecond:
  lds r16, ds18b20Timer
  subi r16, 1
  brcc Ds18b20_OnEverySecond_store
  ldi r16, DS18B20_INTERVAL_SECS
Ds18b20_OnEverySecond_store:
  sts ds18b20Timer, r16
  cpi r16, 28
  breq Ds18b20_OnEverySecond_startConversion
  cpi r16, 2
  breq Ds18b20_OnEverySecond_readResult
  rjmp Ds18b20_OnEverySecond_end
Ds18b20_OnEverySecond_startConversion:
  push r15
    in r15, SREG
    cli
    ldi r16, DS18B20_FNCMD_CONVERT
    rcall ds18b20SendCommand
    rjmp Ds18b20_OnEverySecond_popr15ret
Ds18b20_OnEverySecond_readResult:
  push r15
    in r15, SREG
    cli
    ldi xl, LOW(ds18b20DataBuffer)
    ldi xh, HIGH(ds18b20DataBuffer)
    rcall ds18b20ReadScratchPad
    brcc Ds18b20_OnEverySecond_popr15ret
  
    ld r16, X+                               ; copy temp from scratchpad
    sts ds18b20DataTemp, r16
    ld r16, X+
    sts ds18b20DataTemp+1, r16

    lds r16, ds18b20Flags
    andi r16, ~DS18B20_FLAGS_CONV_STARTED
    ori r16, DS18B20_FLAGS_CONV_UPDATED
    sts ds18b20Flags, r16
    rjmp Ds18b20_OnEverySecond_popr15ret
Ds18b20_OnEverySecond_popr15ret:
    out SREG, r15
  pop r15
Ds18b20_OnEverySecond_end:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ds18b20SendCommand @global
;
; Reset bus, send SKIP ROM and send command.
; Cave: Needs interrupts to be disabled!
;
; @param r16 command to send
; @clobbers r18 (r21, r22)

ds18b20SendCommand:
  mov r18, r16
  
  rcall OwiMaster_Reset           ; (r21, r22)
  tst r16                         ; presence detected?
  breq ds18b20SendCommand_error   ; nope, jump

  ldi r16, DS18B20_ROMCMD_SKIPROM ; skip rom
  rcall OwiMaster_SendByte        ; (r21, r22)

  mov r16, r18                    ; command to send
  rcall OwiMaster_SendByte        ; (r21, r22)
  sec
  ret
ds18b20SendCommand_error:
  clc
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ds18b20ReadRom @global
;
; Send READ ROM and read result into buffer.
; Cave: Needs interrupts to be disabled!
;
; @return CFLAG set if okay, cleared on error
; @return X points directly behind the last byte received
; @param X pointer to SDRAM to receive 8 bytes
; @clobbers r16, r18, r19, r23, X (r17, r20, r21, r22)

ds18b20ReadRom:
  rcall OwiMaster_Reset           ; (r21, r22)
  tst r16                         ; presence detected?
  breq ds18b20ReadRom_error      ; nope, jump

  ldi r16, DS18B20_ROMCMD_READROM
  rcall OwiMaster_SendByte        ; (r21, r22)

  ldi r23, 8
ds18b20ReadRom_loop1:
    Utils_WaitNanoSecs 10000, 0, r22
    rcall OwiMaster_RecvByte      ; (r21, r22)
    st X+, r16
    dec r23
  brne ds18b20ReadRom_loop1
  sbiw xh:xl, 8
  ldi r18, 8
  ldi r19, DS18B20_POLYNOMIAL
  rcall crc8Calc                  ; (R16, R17, R18, R20, R21, X)
  tst r16
  brne ds18b20ReadRom_error
  sec
  ret
ds18b20ReadRom_error:
  clc
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ds18b20ReadScratchPad
;
; Send SKIP_ROM, READ_SCRATCHPAD and read 9 byte result into buffer.
;
; Cave: Needs interrupts to be disabled!
;
; @return CFLAG set if okay, cleared on error
; @return X unchanged if CFLAG set (otherwise clobbered)
; @param X pointer to SDRAM to receive 8 bytes
; @clobbers r16, r18, r19, r23, X (r17, r20, r21, r22)

ds18b20ReadScratchPad:
  ldi r16, DS18B20_FNCMD_READSCRATCHPAD
  rcall ds18b20SendCommand
  brcc ds18b20ReadScratchPad_error
  ldi r23, 9
ds18b20ReadScratchPad_loop1:
    Utils_WaitNanoSecs 10000, 0, r22
    rcall OwiMaster_RecvByte      ; (r21, r22)
    st X+, r16
    dec r23
  brne ds18b20ReadScratchPad_loop1
  sbiw xh:xl, 9
  ldi r18, 9
  ldi r19, DS18B20_POLYNOMIAL
  rcall crc8Calc                  ; (R16, R17, R18, R20, R21, X)
  tst r16
  brne ds18b20ReadScratchPad_error
  sbiw xh:xl, 9
  sec
  ret
ds18b20ReadScratchPad_error:
  clc
  ret
; @end



; ---------------------------------------------------------------------------
; @routine Ds18b20_GetValue @global
;
; @return  CFLAG   set if value available, cleared otherwise
; @return  R19:R18 value
; @return  R21:R20 denom (e.g. 100, meaning value must be divided by 100)
; @clobbers R16

Ds18b20_GetValue:
  lds r16, ds18b20Flags
  andi r16, DS18B20_FLAGS_CONV_UPDATED
  breq Ds18b20_GetValue_done
  lds r18, ds18b20DataTemp           ; value
  lds r19, ds18b20DataTemp+1
  ldi r20, 16                        ; denominator
  clr r21
  sec
Ds18b20_GetValue_done:
  ret
; @end



DS18B20_END:
.equ MODULE_SIZE_DS18B20 = DS18B20_END-DS18B20_BEGIN


