/*
    dht11.c - DHT11 temperature/humidity sensor
    Copyright (C) 2019 Ladislav Vaiz <ok1zia@nagano.cz>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    version 2 as published by the Free Software Foundation.

*/

#include <libziaint.h>

#include <zdht11.h>

#include <zfile.h>
#include <zgpio.h>
#include <ztime.h>

#ifdef Z_HAVE_UNISTD_H
#include <unistd.h>
#endif

// foreign keys
#define SYSFS_DIRECTION "/sys/class/gpio/gpio%d/direction"

static int zdht11_wait_for(struct zgpio *gpio, int max){
    int val, i, sec, usec;
    struct timeval start, stop;

    gettimeofday(&start, NULL);
    for (i = 0; i < max; i++){
        val = zgpio_read(gpio);
        if (val == 1) break;
    }
    if (i >= max) return -10;

    for (i = 0; i < max; i++){
        val = zgpio_read(gpio);
        if (val == 0) break;
    }
    if (i >= max) return -11;
    
    gettimeofday(&stop, NULL);

    usec = stop.tv_usec - start.tv_usec;
    sec = stop.tv_sec - start.tv_sec;
    if (usec < 0){
        usec += 1000000;
        sec --;
    } 
    return usec; // nemuze trvat sekundu
}

// only for sysgpio
int zdht11_read_once(struct zdht11 *dht, struct zgpio *gpio, int prot){
    char dirfile[64];
    int ret;
    
    sprintf(dirfile, SYSFS_DIRECTION, gpio->nr);
    ret = zfile_printfile(dirfile, "out");
    if (ret < 0) return -20;

    zgpio_write(gpio, 0);
    usleep(18000 + 2000);
    
    //zgpio_write(gpio, 1); OPI is too slow
//    usleep(40);


    ret = zfile_printfile(dirfile, "in");
    if (ret < 0) return -21;
        
    
    ret = zdht11_wait_for(gpio, 30);
    if (ret < 0) return -22;

    unsigned char data[5];
    int by, bi, i = 0;
    for (by = 0; by < 5; by++){
        data[by] = 0;
        for (bi = 7; bi >= 0; bi--){
            ret = zdht11_wait_for(gpio, 30);
            if (ret < 0) return -100 - i;

            if (ret > 100) data[by] |= (1 << bi);
            i++;
        }
    }

    unsigned char chk = data[0] + data[1] + data[2] + data[3];
    printf("dht%d data: ", prot);
    for (i = 0; i < 5; i++){
        printf("%02x ", data[i]);
    } 
    printf(" computed checksum=%02x \n", chk);

    if (data[4] != chk) return -24;


    if (prot == 22){
        dht->humidity = ((unsigned char)data[0] * 256 + (unsigned char)data[1] ) / (float)10;
        dht->temperature = (((unsigned char)data[2] & 0x7f) * 256 + (unsigned char)data[3]) / (float)10;
        if (data[2] & 0x80) dht->temperature *= -1;
    }else{
        dht->humidity = (signed char)data[0];
        dht->temperature = (signed char)data[2];
    }
   // printf("temp=%3.1f  hum=%3.1f\n", dht->temperature, dht->humidity);

    ret = zfile_printfile(dirfile, "out");
    if (ret < 0) return -25;

    //printf("return 0\n");
    return 0;
}


int zdht11_read(struct zdht11 *dht, struct zgpio *gpio, int prot){
    int i;
    for (i = 0; i < 5; i++){
        int ret = zdht11_read_once(dht, gpio, prot);
        //printf("read_once=%d\n", ret);
        if (ret >= 0) return ret; 
        usleep((i + 1) * 1*1000*1000);
    }
    return -1;
}
