//----------------------------------------------------------------------------------
// <copyright file="User_Humidity.c" company="LiquidRobotics">
//	Copyright (c) Liquid Robotics Corporation.  All rights reserved.
// </copyright>
//
// <summary>
// 	Module that manages communication with the humidity sensor
// </summary>
//
// <owner>Jim Kirklin</owner>
//---------------------------------------------------------------------------------

#include "includes.h"
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/power.h>
#include "user_app_init.h"
#include "uart.h"
#include "pib.h"
#include "timer.h"
#include "lrstat.h"
#include "spidebug.h"
#include "wdtrig.h"
#include "int_math.h"

#include "User_Health.h"


static uint16_t humid_send_byte(uint8_t b, uint8_t ack); 

int16_t humidity;
int16_t hs_temp;
static uint16_t so_rh;

#define SCL_HIGH PORTE |=  _BV(7)
#define SCL_LOW  PORTE &= ~_BV(7)
#define SDA_HIGH DDRE &= ~_BV(6)
#define SDA_LOW  DDRE |=  _BV(6)
#define HBIT0 SDA_LOW; SCL_HIGH; SCL_LOW
#define HBIT1 SDA_HIGH; SCL_HIGH; SCL_LOW

void init_humid(void) 
{

    // the humidity sensor uses SCLK (PE6) and SDAT (PE7)
    // PE7 is a bidirectional pin so enable the onboard pullup
    // and set to "0" by making it an output, and set to "1" by
    // making it an input
    DDRE  |= _BV(7);        // SCLK output
//    EICRB |= _BV(ISC61);    // falling edge triggered

}

static void humid_start(uint8_t rst) 
{
    if (rst) 
	{
    // give 9 clock cycles to reset the interface
        SCL_HIGH;
        SCL_LOW;
        SCL_HIGH;
        SCL_LOW;
        SCL_HIGH;
        SCL_LOW;
        SCL_HIGH;
        SCL_LOW;
        SCL_HIGH;
        SCL_LOW;
        SCL_HIGH;
        SCL_LOW;
        SCL_HIGH;
        SCL_LOW;
        SCL_HIGH;
        SCL_LOW;
        SCL_HIGH;
        SCL_LOW;
    }

    // the start sequence is indicated by dropping SDA while
    // SCL is high
    SCL_HIGH;
    SDA_LOW;
    SCL_LOW;
    SCL_HIGH;
    SDA_HIGH;
    SCL_LOW;
}


static uint16_t humid_send_byte(uint8_t b, uint8_t ack) 
{
    uint8_t tmp;

    b = ~b;
    ack = ~ack;
    tmp = DDRE;

#define X(n, reg)                                               \
    asm volatile("bst %0, " #n "\n" : : "r" (reg));             \
    asm volatile("bld %0, 6\n" : "=r" (tmp) : "0" (tmp));       \
    DDRE = tmp;                                                 \
    BSET(PORTE, _BV(7));                                        \
    asm volatile("clt");                                        \
    asm volatile("sbic %0, 6" : : "I" (_SFR_IO_ADDR(PINE)));    \
    asm volatile("set");                                        \
    asm volatile("bld %0, " #n "\n" : "=r" (reg) : "0" (reg));  \
    BCLR(PORTE, _BV(7))                                         \


    X(7, b);
    X(6, b);
    X(5, b);
    X(4, b);
    X(3, b);
    X(2, b);
    X(1, b);
    X(0, b);
    X(0, ack);
    BCLR(DDRE, _BV(6)); // leave it in high-z state

#undef X

    return b;
}

int8_t measure_humid_start(void) 
{
    uint16_t result;
    int16_t tmp;

    humid_start(1);

    // read humidity command
    result = humid_send_byte(5, 1);
    if (result > 256)
	{
        return 0;
	}
    else 
	{
		OSTimeDlyHMSM(0,0,0,400);

        so_rh = humid_send_byte(0xFF, 0) << 8; 
        so_rh |= 0xFF & humid_send_byte(0xFF, 1);

	    humidity = (umult16x16(umult16x16(14464 - so_rh, so_rh) >> 10, 37581) >> 17) - 400;

        // measure temperature
        humid_start(0);
        humid_send_byte(3, 1);

		OSTimeDlyHMSM(0,0,0,400);

        hs_temp = humid_send_byte(0xFF, 0) << 8; 
        hs_temp |= 0xFF & humid_send_byte(0xFF, 1);

        // temp is in units of 0.01°C
        hs_temp -= 3966;

        // temperature correct the humidity...
        tmp = (int16_t)(smult16x16(hs_temp - 2500, 1250 + so_rh) >> 10);
        humidity += (int16_t)(smult16x16(tmp, 17180) >> 21);

        // force the humidity to lie between 0 and 100%
        if (humidity < 0) humidity = 0;
        if (humidity > 100*100) humidity = 100*100;

		humidity = humidity / 100;
		hs_temp = hs_temp / 100;
		
        return -1;
    }

	return 0;
}



void get_temp_humid(int16_t * t, int16_t * h)
{
    *t = hs_temp;
    *h = humidity;
}

/*









*/
