/*
===============================================================================
 Name        : main.c
 Author      : $(author)
 Version     :
 Copyright   : $(copyright)
 Description : main definition
===============================================================================
*/


#include "ms_dht11.h"


// Private methods
static float dht_readTemperature(void);
static float dht_readHumidity(void);
static uint8_t dht_read(void);
static void DHTIntHandler(void);


// Private data
uint8_t data_buffer[6];
uint32_t dht_timing;
bool quit_timing = false;



void dht_init() {

	SysCtlPeripheralEnable(DHT_PORT_PERIPH);
	SysCtlPeripheralEnable(DHT_TIM_PERIPH);

    TimerConfigure(DHT_TIM_BASE, TIMER_CFG_ONE_SHOT_UP);
    TimerLoadSet(DHT_TIM_BASE, DHT_TIM, DHT_TIMEOUT+1000);

    // set interrupt for counter
    GPIOIntEnable(DHT_PORT, DHT_PIN);
	GPIOIntTypeSet(DHT_PORT, DHT_PIN, GPIO_BOTH_EDGES); // config interrupt both edges
	GPIOIntRegister(DHT_PORT, DHTIntHandler);

	DON();
    DHT_DATA(DHT_PIN);

}


// RETURN:
// 1 = success reading from sensor;
// 0 = error on reading from sensor;
// also return T and H

uint8_t dht_readTH(DHT_TypeDef *values) {

    if (dht_read() == 1) {
        // temperature
        values->celsius_temp = dht_readTemperature();

        // humidity
        values->humidity = dht_readHumidity();

        return 1;
    }

    return 0;
}


float dht_readTemperature() {

    float t;

#ifdef DHT11
    t = data_buffer[2];
#else

    t = data_buffer[2] & 0x7F;
    t *= 256;
    t += data_buffer[3];
    t /= 10.0;

    if (data_buffer[2] & 0x80)
        t *= -1.0;

    if (t > 80.0) {
    	t = 80.0;
    }
    if (t < -40.0) {
    	t = -40.0;
    }


#endif

    return t;
}


float dht_readHumidity() {

    float h;

#ifdef DHT11
    h = data_buffer[0];
#else
    h = data_buffer[0];
    h *= 256;
    h += data_buffer[1];
    h /= 10.0;

    if (h > 100.0) {
    	h = 100.0;
    }
    if (h < 0.0) {
    	h = 0.0;
    }

#endif

    return h;
}



uint8_t dht_read(void) {
    uint8_t ii, byteIdx, bitCounter;


    // clear data
    for (ii=0; ii< 5; ii++)
        *(data_buffer + ii) = 0;


    // send start signal low and wait 1-18 ms
    DON();
    DHT_DATA(0x00);
    SysCtlDelay(DHT_WAIT_18ms);

    // send pull up signal high and wait 20-40 us
    DHT_DATA(DHT_PIN);
    // wait at least 20us
    SysCtlDelay(DHT_WAIT_20us);
    DIN();
    while(GPIOPinRead(DHT_PORT, DHT_PIN) == DHT_PIN);

    // acknowledge ~80us low
    while(GPIOPinRead(DHT_PORT, DHT_PIN) == 0x00);
    // acknowledge ~80us high
    while(GPIOPinRead(DHT_PORT, DHT_PIN) == DHT_PIN);

    // gets data 5 bytes, 40 bits
    // every bit start with low level for 50us then high level last
    // 0 = 26-28us
    // 1 = 70us
    byteIdx = 0;
    bitCounter = 7;
    for (ii=0; ii<40; ii++) {
    	quit_timing = false;

        // do elaboration
    	while(!quit_timing);

        // check bit (timing is 1us) 26-28 -> 0 - 70us -> 1
        if (dht_timing > DHT_TIME_BIT_1) {
            data_buffer[byteIdx] |= (1 << bitCounter);
        }

        if (bitCounter == 0) {
            bitCounter = 7;
            byteIdx++;
        } else
            bitCounter--;

    }

    // check we read 40 bits and that the checksum matches
    if ((byteIdx == 5) && (data_buffer[4] == ( (data_buffer[0] + data_buffer[1] + data_buffer[2] + data_buffer[3]) & 0xFF) ) ) {
        return 1;
    }


    return 0;

}


void DHTIntHandler()
{

	volatile int32_t start_timer;


	GPIOIntClear(DHT_PORT, DHT_PIN); // clear interrupt flag
	if (GPIOPinRead(DHT_PORT, DHT_PIN) == DHT_PIN) { // check low to high
		TimerEnable(DHT_TIM_BASE, DHT_TIM);
		start_timer = TimerValueGet(DHT_TIM_BASE, DHT_TIM);
		quit_timing = false;
	} else { // check high to low, finish
	    TimerDisable(DHT_TIM_BASE, DHT_TIM);
	    dht_timing = TimerValueGet(DHT_TIM_BASE, DHT_TIM);
	    dht_timing -= start_timer;
    	quit_timing = true;
    	HWREG(DHT_TIM_BASE + TIMER_O_TAV) = 0;
	}

}

