#include <stdio.h>
#include "esp_log.h"
#include "string.h"
static const char *TAG = "--MLX90640--";

#include "driver/gpio.h"

#include "driver/i2c_master.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "nvs_flash.h"
#include "nvs.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_netif_sntp.h"
#include <time.h>
#include "lwip/sockets.h"
#include "lwip/dns.h"
#include "esp_mac.h"
#include "../../wifi.lib.c"


static i2c_master_bus_config_t i2c_mst_config = {.clk_source = I2C_CLK_SRC_DEFAULT, .i2c_port = 0, .scl_io_num = 2, .sda_io_num = 3, .glitch_ignore_cnt = 7, .flags.enable_internal_pullup = true, };
i2c_master_bus_handle_t i2c_bus_handle;
static i2c_device_config_t i2cMLX = { .dev_addr_length = I2C_ADDR_BIT_LEN_7, .device_address = 0x33, .scl_speed_hz = 400000, };
i2c_master_dev_handle_t i2c_dev_handle;

static uint8_t statusRegister[2] = {0x80, 0x00};
static uint8_t controlRegister[4] = { 0x80, 0x0d, 0b00011001, 0b10000001 };
static uint8_t resetStatus[4] = {0x80, 0x00, 0x00, 0x00};
static uint8_t ramAddr[2] = {0x04, 0x00};
static uint8_t Ta_VbeAddr[2] = {0x07, 0x00};
static uint8_t Ta_PTATAddr[2] = {0x07, 0x20};

static int8_t calibArr[768] = { -80,-73,-75,-66,-68,-62,-70,-56,-61,-54,-63,-52,-58,-50,-60,-48,-61,-48,-61,-42,-60,-46,-60,-42,-64,-48,-65,-46,-62,-49,-73,-44,-72,-63,-60,-64,-59,-52,-53,-51,-54,-45,-46,-47,-48,-40,-43,-45,-53,-40,-44,-41,-49,-38,-43,-42,-55,-40,-48,-46,-53,-44,-56,-45,-76,-70,-71,-67,-64,-61,-65,-54,-60,-54,-60,-48,-55,-45,-54,-40,-55,-44,-56,-41,-53,-44,-57,-38,-60,-42,-61,-41,-61,-47,-70,-41,-68,-59,-56,-63,-56,-50,-47,-49,-52,-44,-43,-45,-48,-34,-37,-39,-46,-35,-39,-40,-45,-36,-40,-38,-51,-36,-44,-42,-51,-42,-53,-42,-77,-70,-70,-60,-66,-59,-62,-51,-58,-51,-55,-42,-54,-44,-53,-39,-50,-39,-52,-37,-51,-37,-56,-37,-60,-40,-59,-40,-57,-44,-67,-39,-67,-58,-53,-55,-56,-48,-44,-45,-50,-39,-39,-39,-44,-34,-36,-36,-42,-29,-35,-35,-42,-30,-37,-35,-49,-32,-42,-38,-48,-39,-51,-39,-69,-67,-64,-60,-58,-57,-58,-48,-52,-45,-52,-41,-45,-39,-50,-39,-49,-38,-49,-37,-48,-37,-54,-36,-56,-38,-58,-40,-58,-42,-68,-40,-61,-53,-47,-54,-46,-41,-39,-43,-40,-32,-33,-36,-34,-28,-33,-34,-38,-26,-32,-34,-37,-27,-36,-34,-48,-30,-38,-37,-47,-35,-50,-39,-69,-66,-66,-55,-57,-52,-56,-47,-49,-44,-48,-39,-43,-39,-46,-34,-47,-35,-48,-31,-47,-37,-52,-35,-56,-38,-58,-39,-56,-41,-66,-38,-58,-51,-47,-49,-46,-37,-39,-40,-38,-31,-29,-32,-31,-26,-27,-30,-37,-24,-29,-28,-34,-27,-33,-32,-44,-29,-39,-37,-45,-33,-48,-35,-66,-62,-62,-55,-59,-51,-52,-46,-51,-41,-49,-36,-45,-36,-44,-30,-46,-34,-45,-31,-47,-34,-52,-33,-51,-38,-53,-33,-53,-38,-63,-37,-57,-46,-41,-47,-45,-37,-34,-35,-39,-26,-30,-28,-32,-23,-25,-24,-34,-21,-25,-29,-36,-22,-32,-29,-40,-28,-36,-31,-42,-31,-44,-34,-62,-61,-59,-52,-51,-48,-52,-43,-46,-40,-48,-36,-42,-38,-46,-31,-45,-33,-48,-31,-45,-34,-48,-32,-52,-34,-53,-34,-55,-40,-64,-35,-48,-42,-38,-44,-38,-30,-32,-33,-33,-24,-24,-27,-30,-24,-25,-24,-30,-21,-27,-25,-32,-21,-27,-28,-39,-25,-33,-32,-44,-31,-45,-34,-60,-63,-60,-55,-52,-50,-52,-42,-45,-39,-47,-34,-42,-37,-44,-31,-41,-32,-46,-30,-44,-36,-48,-32,-53,-35,-54,-37,-58,-40,-65,-37,-46,-44,-36,-43,-37,-32,-31,-33,-29,-25,-23,-26,-29,-19,-23,-25,-28,-18,-25,-23,-30,-23,-26,-34,-40,-25,-33,-34,-45,-31,-45,-35,-67,-67,-61,-57,-55,-52,-49,-46,-47,-42,-46,-40,-47,-37,-43,-35,-48,-36,-46,-34,-45,-36,-49,-35,-55,-40,-55,-39,-57,-47,-66,-39,-51,-45,-36,-45,-41,-32,-26,-34,-32,-23,-22,-27,-30,-20,-21,-24,-32,-19,-22,-26,-31,-20,-26,-28,-41,-26,-37,-32,-44,-34,-47,-35,-62,-64,-65,-56,-52,-52,-53,-44,-50,-44,-47,-38,-45,-40,-45,-34,-45,-35,-45,-32,-50,-37,-53,-36,-54,-40,-60,-43,-56,-49,-67,-46,-44,-43,-39,-42,-35,-30,-27,-30,-34,-23,-22,-26,-28,-21,-19,-23,-28,-17,-21,-23,-34,-23,-28,-29,-40,-26,-37,-35,-42,-36,-45,-40,-63,-69,-62,-59,-55,-56,-54,-47,-49,-45,-49,-42,-45,-41,-48,-34,-47,-38,-51,-37,-49,-43,-55,-40,-57,-47,-61,-46,-62,-52,-68,-49,-45,-45,-35,-42,-36,-33,-27,-32,-31,-24,-22,-30,-27,-21,-21,-23,-27,-20,-25,-26,-31,-25,-27,-31,-41,-31,-37,-37,-48,-36,-46,-42,-68,-70,-63,-60,-55,-56,-54,-49,-49,-49,-49,-43,-47,-46,-47,-41,-54,-44,-51,-41,-52,-45,-56,-45,-58,-48,-62,-49,-61,-53,-69,-55,-37,-35,-24,-34,-26,-23,-16,-23,-22,-17,-14,-17,-19,-13,-12,-18,-25,-14,-16,-22,-24,-18,-19,-27,-33,-22,-29,-29,-36,-27,-38,-35};
//staticint8_t calibArr[768] = { 0 };

float frame[768];
char tcppckt[768*6];

static void initi2c()
{
    ESP_LOGI(TAG, "initi2c START");

    i2c_new_master_bus(&i2c_mst_config, &i2c_bus_handle);
    for (int addr = 1; addr < 127; addr++) {
        if (i2c_master_probe(i2c_bus_handle, addr, -1) == 0 ) {
            ESP_LOGI(TAG,"i2c @ %#04x", addr);
        }
    }

    ESP_ERROR_CHECK(i2c_master_bus_add_device(i2c_bus_handle, &i2cMLX, &i2c_dev_handle));
    
    ESP_LOGI(TAG, "initi2c DONE");
}

void app_main(void)
{

    /* Specifically for the AliExpress ESP32C3*/
    gpio_reset_pin(GPIO_NUM_8);
    gpio_set_direction(GPIO_NUM_8, GPIO_MODE_OUTPUT);
    gpio_set_pull_mode(GPIO_NUM_8, GPIO_FLOATING);
    gpio_set_level(GPIO_NUM_8, 0); // low for on "It seems, that the LED is soldered in the wrong direction"

    initi2c();

    nvs_flash_init();
    initWiFi();
    int32_t lastReconnect = -60;
    int32_t lastNTP = -60;
    
    uint8_t dataReady, h, w;
    uint8_t rawdata[832 * 2];
    uint16_t i, p, sp, Ta_Vbe, Ta_PTAT;
    float irData;
    float ave;
    char tmp[7];
    uint8_t inbuf[2];
    
    struct sockaddr_in dest_addr;
    dest_addr.sin_addr.s_addr = inet_addr("192.168.11.1"); 
    dest_addr.sin_family = AF_INET;
    dest_addr.sin_port = htons(5797);
    char rx_buffer[128];
    int Failed = 0;
        
    ESP_ERROR_CHECK(i2c_master_transmit(i2c_dev_handle, controlRegister, sizeof(controlRegister), -1));
    
    while ( 1 ) {

        gpio_set_level(GPIO_NUM_8, 1);    
        //ESP_ERROR_CHECK(ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0));  ESP_ERROR_CHECK(ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0));
        
        if ((!bWIFIConnected) && (time(NULL)-lastReconnect > 60)){
            lastReconnect = time(NULL);
            ESP_LOGI(TAG, "WifiConnected IS FALSE, attempt to re-connect");
            esp_wifi_stop();
            vTaskDelay(pdMS_TO_TICKS(5000));
            if (fillWiFiConfig() != false) {
              ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
              ESP_ERROR_CHECK(esp_wifi_start());
            }
        }

        ESP_ERROR_CHECK(i2c_master_transmit_receive(i2c_dev_handle, Ta_VbeAddr, sizeof(Ta_VbeAddr), inbuf, 2, -1));
        Ta_Vbe = (inbuf[0] << 8 | inbuf[1]);
        ESP_ERROR_CHECK(i2c_master_transmit_receive(i2c_dev_handle, Ta_PTATAddr, sizeof(Ta_PTATAddr), inbuf, 2, -1));
        Ta_PTAT = (inbuf[0] << 8 | inbuf[1]);
        ESP_LOGI(TAG, "Ta_Vbe = %i, Ta_PTAT = %i", Ta_Vbe, Ta_PTAT);
        
        // xxxxxxxxxxxx1xxx ie. 8 = new data is available in RAM
        dataReady = 0;
        while (dataReady != 0x08) {
            ESP_ERROR_CHECK(i2c_master_transmit_receive(i2c_dev_handle, statusRegister, sizeof(statusRegister), inbuf, 2, -1));
            dataReady = inbuf[1] & 0x08;
        }

        // 0x0400 is RAM  73f-400=33F (i.e. 831) from  10.7.2. RAM
        uint8_t rawdata[832 * 2];
        ESP_ERROR_CHECK(i2c_master_transmit_receive(i2c_dev_handle, ramAddr, sizeof(ramAddr), rawdata, sizeof(rawdata), -1));
        // once read, reset    
        ESP_ERROR_CHECK(i2c_master_transmit(i2c_dev_handle, resetStatus, sizeof(resetStatus), -1));

        ave=0;
        for (i = 0; i < 32*24*2; i=i+2) {
            p = i/2;
            irData = (rawdata[i] << 8 | rawdata[i+1]);
            if (irData > 32767) { irData = irData - 65536; }
            frame[p] = (calibArr[p] / 10.0); 		// /10.0 because we store int, but we want to operate at 0.1 level, so force float;
            frame[p] = frame[p] + (irData / 10.0 + 38);
            ave=ave+frame[p];
        }
        ave=ave/(32*24);
        ESP_LOGI(TAG, "Ave %fC", ave);
        
        if (calibArr[0] == 0 ) {			// output for when in calibration calibArr[768] = { 0 }
            for (i = 0; i < 32*24; i++) {
                frame[i] = ((Ta_Vbe/1000) - frame[i]) * 10;
            }
        }
               
        sprintf(tmp, "%05d|", Ta_Vbe);	for (i = 0; i < 6; i++) { tcppckt[i] = tmp[i]; }
        sprintf(tmp, "%05d|", Ta_PTAT);	for (i = 0; i < 6; i++) { tcppckt[i+6] = tmp[i]; }
        tcppckt[11]='#';
        sp = 12;
        for (h = 0; h<24 ;h++) {
            if (h == 0) { gpio_set_level(GPIO_NUM_8, 0); } else { gpio_set_level(GPIO_NUM_8, 1); }
            if ( calibArr[0] == 0 ) {  			// calibration
                for (w = 0; w<32 ;w++) {
                    p = h * 32 + (w);
                    sprintf(tmp, "%4.0f|", frame[p]);
                    for (i = 0; i < 5; i++) { tcppckt[sp+i] = tmp[i]; }
                    sp = sp + 5;
                }
            } else {
                for (w = 32; w>0 ;w--) {
                    p = h * 32 + (w-1);
                    sprintf(tmp, "%04.1f|", frame[p]);
                    for (i = 0; i < 5; i++) { tcppckt[sp+i] = tmp[i]; }
                    sp = sp + 5;
                }
            }
            tcppckt[sp-1]='#';
        }
        gpio_set_level(GPIO_NUM_8, 1);
        
        sp = sp - 1;

      if (bWIFIConnected) {
        int sock = socket(AF_INET, SOCK_STREAM, 0);
        int flags = fcntl(sock, F_GETFL);
        ESP_LOGI(TAG, "Socket created, connecting to %lu:%d", dest_addr.sin_addr.s_addr, dest_addr.sin_port);
        int err = connect(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
        ESP_LOGI(TAG, "err1=%i", err);
        if (err != 0) { Failed = 1; }
        if (err == 0 ) {
            ESP_LOGI(TAG, "Successfully connected");
            err = send(sock, tcppckt, sp, 0);
        }
        ESP_LOGI(TAG, "err2=%i", err);
        
        if (err != -1) {
            ESP_LOGI(TAG, "Shutting down socket and restarting...");
            shutdown(sock, 0);
            close(sock);
        } 
      }
    }
}
