; Functions for working with a DHT22 part.
;
; See: DHT22.pdf
;
; Note: the PIN is normally in a HIGH-Z state when inactive.
;   It is made an OUTPUT and pulled LOW to initiate a data
;   transfer, but it immediately returns to HIGH-Z. This means
;   than we can easily ignore/terminate any reading of the
;   device (electrically; we still have internal bits to reset).
;

        list p = 16f688
        include p16f688.inc
        include ../include/handy.inc

; Define this module's variables
.gpr0   udata

; We will accumulate 5 bytes of data from the DHT22. Two bytes
; for humidity, two for temperature, and one checksum byte.
ACCUM           res     5
#define HUMIDH  ACCUM+0
#define HUMIDL  ACCUM+1
#define TEMPH   ACCUM+2
#define TEMPL   ACCUM+3
#define CSUM    ACCUM+4


dht22:  code                    ; relocatable

dht22_start:
        ; ### adjust pin from HIGH-Z to OUTPUT. Pull LOW for N µS
        ; ### Step 2: release pin to HIGH-Z

        ; ### use TIMER0 for duration measurements
        ; ### T.cy is 0.5 µS
        ; ### use 1:16 prescalar for 8.0 µS ticks; rollover at 2.0 ms

        nop


dht22_rising_edge:
        ; ### signal that a new bit is approaching.
        ; ### rise after initiating data delivery, or rise at
        ; ### the end of a bit, signaling next-bit-arrival soon


dht22_falling_edge:
        ; ### do work on the falling edge

        ; ### checksum
        ; ### waiting periods
        ; ### 


; ENTRY: Assume Bank 0.
; EXIT: W contains humidity. Value is [0..250] representing scaled %RH.
dht22_get_humidity:
        ; NOTE: HUMIDH and HUMIDL are destroyed.

        ; HUMIDH/L is [0..1000]. Divide by 4, for [0..250]
        rotate10_2r HUMIDH, HUMIDL
        ; Result is now in W.

        return


; ENTRY: Assume Bank 0.
; EXIT: W contains temperature. Value is (T+20)*2.5 (Celsius-ish)
dht22_get_temp:
        ; NOTE: TEMPH and TEMPL are destroyed.

        ; Temperature is sampled as abs(T*10) (Celsius) with a
        ; range of -20C to +80C, with the sign in MSB. Thus, the
        ; maximum decimal value is 800 (bin: 0000 0011 0010 0000)
        ; and -200 (bin: 1000 0000 1100 1000).

        ; We divide by 4, to bring these values into a single byte.
        ; Thus: [0..200] (positive values) and [0..50] (negative).
        rotate10_2r TEMPH, TEMPL

        ; We rotated away 0.5 C of accuracy (cuz dividing by 8 without
        ; rounding, instead of div-by-10 with rounding). Offset the
        ; temperature-ish value by +50 (current value is T*10/4); this
        ; will shift positive values from [0..200] to [50..250]. The
        ; negative values will shift from [0..50] to [50..100].
        addlw   d'50'

        ; We shifted TEMPH one bit to the right, so the "negative"
        ; bit has moved. If it indicates negative, then we have more
        ; work. Otherwise, return.
        btfss   TEMPH, 6
        return

        ; W has a "negative" value from [50..100]. Convert to [50..0]
        ; Easy: just subtract it from 100, then return it.
        sublw   d'100'
        return


; stupid assemblers don't realize EOF means *end*
        end
