/*
	HDC2080.cpp
	HDC2010.cpp originally created by: Brandon Fisher, August 1st 2017

	This code is release AS-IS into the public domain, no guarantee or warranty is given.

	Description: This library facilitates communication with, and configuration of,
	the HDC2080 Temperature and Humidity Sensor. It makes extensive use of the
	Wire.H library, and should be useable with both Arduino and Energia.
*/

#include <stdio.h>
#include <stdint.h>
#include <zephyr/drivers/i2c.h>
#include "jfet_files/jfet_common.h"
#include "jfet_files/HDC2080.h"

float readTemp(void)
{
	uint8_t byte[2];
	int err;
	uint16_t temp;
	float f;

	err = readReg(TEMP_LOW, byte, 2);
	temp = (byte[1] << 8) | byte[0];
	f = ((temp * 165.0f) / 65536.0f) - 40.0f;
	return f;
}

uint8_t readTempOffsetAdjust(void)
{
	uint8_t byte[2];

	readReg(TEMP_OFFSET_ADJUST, byte, 1);
	return byte[0];
}

// Página 22 do datasheet
uint8_t setTempOffsetAdjust(uint8_t value)
{
	uint8_t byte[2];

	byte[0] = value;
	writeReg(TEMP_OFFSET_ADJUST, byte, 1);
	return readTempOffsetAdjust();
}

float readHumidity(void)
{
	uint8_t byte[2];
	int err;
	uint16_t humidity;
	float f;

	err = readReg(HUMID_LOW, byte, 2);
	humidity = (byte[1] << 8) | byte[0];
	f = (humidity / 65536.0f) * 100.0f;
	return f;
}

uint8_t readHumidityOffsetAdjust(void)
{
	uint8_t byte[2];

	readReg(HUM_OFFSET_ADJUST, byte, 1);
	return byte[0];
}

// Página 23 do datasheet
uint8_t setHumidityOffsetAdjust(uint8_t value)
{
	uint8_t byte[2];

	byte[0] = value;
	writeReg(HUM_OFFSET_ADJUST, byte, 1);
	return readHumidityOffsetAdjust();
}

void enableHeater(void)
{
	int err;
	uint8_t configContents; // Stores current contents of config register

	err = readReg(HDC_CONFIG, &configContents, 1);

	// set bit 3 to 1 to enable heater
	configContents = (configContents | 0x08);

	writeReg(HDC_CONFIG, &configContents, 1);
}

void disableHeater(void)
{
	int err;
	uint8_t configContents; // Stores current contents of config register

	err = readReg(HDC_CONFIG, &configContents, 1);

	// set bit 3 to 0 to disable heater (all other bits 1)
	configContents = (configContents & 0xF7);
	writeReg(HDC_CONFIG, &configContents, 1);
}

uint8_t readReg(uint8_t reg, uint8_t *data, uint8_t count)
{
	uint8_t dataOut[2];

	dataOut[0] = reg;
	if (i2c_write(i2c_dev, dataOut, 1, HDC_ADDRESS))
	{
		myPrintkE("Fail to write to I2C\n");
		return FALSE;
	}
	if (i2c_read(i2c_dev, data, count, HDC_ADDRESS))
	{
		myPrintkE("Fail to read to I2C\n");
		return FALSE;
	}
	return TRUE;
}

uint8_t writeReg(uint8_t reg, uint8_t *data, uint8_t count)
{
	uint8_t datas[10];
	int i;

	/* load array with register and data */
	datas[0] = reg;
	for (i = 0; i < count; i++)
		datas[i + 1] = data[i];

	/* write data to HDC2080 */
	if (i2c_write(i2c_dev, datas, count + 1, HDC_ADDRESS))
	{
		myPrintkE("Fail to write to I2C\n");
		return FALSE;
	}
	return TRUE;
}

void setLowTemp(float temp)
{
	uint8_t temp_thresh_low;

	// Verify user is not trying to set value outside bounds
	if (temp < -40.0f)
	{
		temp = -40.0f;
	}
	else if (temp > 125.0f)
	{
		temp = 125.0f;
	}

	// Calculate value to load into register
	temp_thresh_low = (uint8_t)(256.0f * (temp + 40.0f) / 165.0f);

	writeReg(TEMP_THR_L, &temp_thresh_low, 1);
}

void setHighTemp(float temp)
{
	uint8_t temp_thresh_high;

	// Verify user is not trying to set value outside bounds
	if (temp < -40.0f)
	{
		temp = -40.0f;
	}
	else if (temp > 125.0f)
	{
		temp = 125.0f;
	}

	// Calculate value to load into register
	temp_thresh_high = (uint8_t)(256.0f * (temp + 40.0f) / 165.0f);

	writeReg(TEMP_THR_H, &temp_thresh_high, 1);
}

void setHighHumidity(float humid)
{
	uint8_t humid_thresh;

	// Verify user is not trying to set value outside bounds
	if (humid < 0.0f)
	{
		humid = 0.0f;
	}
	else if (humid > 100.0f)
	{
		humid = 100.0f;
	}

	// Calculate value to load into register
	humid_thresh = (uint8_t)(256.0f * humid / 100.0f);

	writeReg(HUMID_THR_H, &humid_thresh, 1);
}

void setLowHumidity(float humid)
{
	uint8_t humid_thresh;

	// Verify user is not trying to set value outside bounds
	if (humid < 0.0f)
	{
		humid = 0.0f;
	}
	else if (humid > 100.0f)
	{
		humid = 100.0f;
	}

	// Calculate value to load into register
	humid_thresh = (uint8_t)(256.0f * humid / 100.0f);

	writeReg(HUMID_THR_L, &humid_thresh, 1);
}

//  Return humidity from the low threshold register
float readLowHumidityThreshold(void)
{
	int err;
	uint8_t regContents;

	err = readReg(HUMID_THR_L, &regContents, 1);
	float f = regContents;
	f = f * 100.0f / 256.0f;
	return f;
}

//  Return humidity from the high threshold register
float readHighHumidityThreshold(void)
{
	int err;
	uint8_t regContents;

	err = readReg(HUMID_THR_H, &regContents, 1);
	float f = regContents;
	f = f * 100.0f / 256.0f;
	return f;
}

//  Return temperature from the low threshold register
float readLowTempThreshold(void)
{
	int err;
	uint8_t regContents;

	err = readReg(TEMP_THR_L, &regContents, 1);
	float f = regContents;
	f = (f * 165.0f / 256.0f) - 40.0f;
	return f;
}

//  Return temperature from the high threshold register
float readHighTempThreshold(void)
{
	int err;
	uint8_t regContents;

	err = readReg(TEMP_THR_H, &regContents, 1);
	float f = regContents;
	f = (f * 165.0f / 256.0f) - 40.0f;

	return f;
}

/* Upper two bits of the MEASUREMENT_CONFIG register controls
   the temperature resolution*/
void setTempRes(int resolution)
{
	int err;
	uint8_t configContents;

	err = readReg(MEASUREMENT_CONFIG, &configContents, 1);

	switch (resolution)
	{
	case FOURTEEN_BIT:
		configContents = (configContents & 0x3F);
		break;

	case ELEVEN_BIT:
		configContents = (configContents & 0x7F);
		configContents = (configContents | 0x40);
		break;

	case NINE_BIT:
		configContents = (configContents & 0xBF);
		configContents = (configContents | 0x80);
		break;

	default:
		configContents = (configContents & 0x3F);
	}

	writeReg(MEASUREMENT_CONFIG, &configContents, 1);
}

/*  Bits 5 and 6 of the MEASUREMENT_CONFIG register controls
	the humidity resolution*/
void setHumidRes(int resolution)
{
	int err;
	uint8_t configContents;

	err = readReg(MEASUREMENT_CONFIG, &configContents, 1);

	switch (resolution)
	{
	case FOURTEEN_BIT:
		configContents = (configContents & 0xCF);
		break;

	case ELEVEN_BIT:
		configContents = (configContents & 0xDF);
		configContents = (configContents | 0x10);
		break;

	case NINE_BIT:
		configContents = (configContents & 0xEF);
		configContents = (configContents | 0x20);
		break;

	default:
		configContents = (configContents & 0xCF);
	}

	writeReg(MEASUREMENT_CONFIG, &configContents, 1);
}

/*  Bits 2 and 1 of the MEASUREMENT_CONFIG register controls
	the measurement mode  */
void setMeasurementMode(int mode)
{
	int err;
	uint8_t configContents;

	err = readReg(MEASUREMENT_CONFIG, &configContents, 1);

	switch (mode)
	{
	case TEMP_AND_HUMID:
		configContents = (configContents & 0xF9);
		break;

	case TEMP_ONLY:
		configContents = (configContents & 0xFC);
		configContents = (configContents | 0x02);
		break;

	case HUMID_ONLY:
		configContents = (configContents & 0xFD);
		configContents = (configContents | 0x04);
		break;

	default:
		configContents = (configContents & 0xF9);
	}

	writeReg(MEASUREMENT_CONFIG, &configContents, 1);
}

/*  Bit 0 of the MEASUREMENT_CONFIG register can be used
	to trigger measurements  */
void triggerMeasurement(void)
{
	int err;
	uint8_t configContents;

	err = readReg(MEASUREMENT_CONFIG, &configContents, 1);

	configContents = (configContents | 0x01);
	writeReg(MEASUREMENT_CONFIG, &configContents, 1);
}

/*  Bit 7 of the CONFIG register can be used to trigger a
	soft reset  */
void reset(void)
{
	int err;
	uint8_t configContents;

	err = readReg(HDC_CONFIG, &configContents, 1);

	configContents = (configContents | 0x80);
	writeReg(HDC_CONFIG, &configContents, 1);
	k_sleep(K_MSEC(50));
}

/*  Bit 2 of the CONFIG register can be used to enable/disable
	the interrupt pin  */
void enableInterrupt(void)
{
	int err;
	uint8_t configContents;

	err = readReg(HDC_CONFIG, &configContents, 1);

	configContents = (configContents | 0x04);
	writeReg(HDC_CONFIG, &configContents, 1);
}

/*  Bit 2 of the CONFIG register can be used to enable/disable
	the interrupt pin  */
void disableInterrupt(void)
{
	int err;
	uint8_t configContents;

	err = readReg(HDC_CONFIG, &configContents, 1);

	configContents = (configContents & 0xFB);
	writeReg(HDC_CONFIG, &configContents, 1);
}

/*  Bits 6-4  of the CONFIG register controls the measurement
	rate  */
void setRate(int rate)
{
	int err;
	uint8_t configContents;

	err = readReg(HDC_CONFIG, &configContents, 1);

	switch (rate)
	{
	case MANUAL:
		configContents = (configContents & 0x8F);
		break;

	case TWO_MINS:
		configContents = (configContents & 0x9F);
		configContents = (configContents | 0x10);
		break;

	case ONE_MINS:
		configContents = (configContents & 0xAF);
		configContents = (configContents | 0x20);
		break;

	case TEN_SECONDS:
		configContents = (configContents & 0xBF);
		configContents = (configContents | 0x30);
		break;

	case FIVE_SECONDS:
		configContents = (configContents & 0xCF);
		configContents = (configContents | 0x40);
		break;

	case ONE_HZ:
		configContents = (configContents & 0xDF);
		configContents = (configContents | 0x50);
		break;

	case TWO_HZ:
		configContents = (configContents & 0xEF);
		configContents = (configContents | 0x60);
		break;

	case FIVE_HZ:
		configContents = (configContents | 0x70);
		break;

	default:
		configContents = (configContents & 0x8F);
	}

	writeReg(HDC_CONFIG, &configContents, 1);
}

/*  Bit 1 of the CONFIG register can be used to control the
	the interrupt pins polarity */
void setInterruptPolarity(int polarity)
{
	int err;
	uint8_t configContents;

	err = readReg(HDC_CONFIG, &configContents, 1);

	switch (polarity)
	{
	case ACTIVE_LOW:
		configContents = (configContents & 0xFD);
		break;

	case ACTIVE_HIGH:
		configContents = (configContents | 0x02);
		break;

	default:
		configContents = (configContents & 0xFD);
	}

	writeReg(HDC_CONFIG, &configContents, 1);
}

/*  Bit 0 of the CONFIG register can be used to control the
	the interrupt pin's mode */
void setInterruptMode(int mode)
{
	int err;
	uint8_t configContents;

	err = readReg(HDC_CONFIG, &configContents, 1);

	switch (mode)
	{
	case LEVEL_MODE:
		configContents = (configContents & 0xFE);
		break;

	case COMPARATOR_MODE:
		configContents = (configContents | 0x01);
		break;

	default:
		configContents = (configContents & 0xFE);
	}

	writeReg(HDC_CONFIG, &configContents, 1);
}

uint8_t readInterruptStatus(void)
{
	int err;
	uint8_t regContents;

	err = readReg(INTERRUPT_DRDY, &regContents, 1);
	return regContents;
}

//  Clears the maximum temperature register
void clearMaxTemp(void)
{
	uint8_t value = 0;

	writeReg(TEMP_MAX, &value, 1);
}

//  Clears the maximum humidity register
void clearMaxHumidity(void)
{
	uint8_t value = 0;

	writeReg(HUMID_MAX, &value, 1);
}

//  Reads the maximum temperature register
float readMaxTemp(void)
{
	int err;
	uint8_t regContents;

	err = readReg(TEMP_MAX, &regContents, 1);
	float f = regContents;
	f = (f * 165.0f / 256.0f) - 40.0f;

	return f;
}

//  Reads the maximum humidity register
float readMaxHumidity(void)
{
	int err;
	uint8_t regContents;

	err = readReg(HUMID_MAX, &regContents, 1);
	float f = regContents;
	f = (f / 256.0f) * 100.0f;

	return f;
}

// Enables the interrupt pin for comfort zone operation
void enableThresholdInterrupt(void)
{
	int err;
	uint8_t regContents;

	err = readReg(INTERRUPT_CONFIG, &regContents, 1);

	regContents = (regContents | 0x78);

	writeReg(INTERRUPT_CONFIG, &regContents, 1);
}

// Disables the interrupt pin for comfort zone operation
void disableThresholdInterrupt(void)
{
	int err;
	uint8_t regContents;

	err = readReg(INTERRUPT_CONFIG, &regContents, 1);

	regContents = (regContents & 0x87);

	writeReg(INTERRUPT_CONFIG, &regContents, 1);
}

// enables the interrupt pin for DRDY operation
void enableDRDYInterrupt(void)
{
	int err;
	uint8_t regContents;

	err = readReg(INTERRUPT_CONFIG, &regContents, 1);

	regContents = (regContents | 0x80);

	writeReg(INTERRUPT_CONFIG, &regContents, 1);
}

// disables the interrupt pin for DRDY operation
void disableDRDYInterrupt(void)
{
	int err;
	uint8_t regContents;

	err = readReg(INTERRUPT_CONFIG, &regContents, 1);

	regContents = (regContents & 0x7F);

	writeReg(INTERRUPT_CONFIG, &regContents, 1);
}

int initHDC2080(void)
{
	unsigned char datas[6];
	char str[80];

	int ret;

	ret = readReg(MID_L, datas, 4);
	if (ret == FALSE)
		return FALSE;
	manfID = (datas[1] << 8) | datas[0];
	deviceID = (datas[3] << 8) | datas[2];
	if ((manfID != MAN_ID) || (deviceID != DEV_ID))
	{
		//sprintf(str, "Manf: %04X Device: %04X\r\n", manfID, deviceID);
		// myPrintkE(str);
		// myPrintkE("HDC2080 Temp/Humidty Sensor not found\r\n");
		return FALSE;
	}

	/* initialize HDC2080 */
	/* interrupt status 0x04 */
	readInterruptStatus(); /* read status to clear */

	/* TEMP_MAX 0x05 */
	clearMaxTemp();

	/* HUMIDITY_MAX 0x06 */
	clearMaxHumidity();

	/* Interrupt Enable 0x07 */
	//	disableThresholdInterrupt();	/* disable temp/humidity low/high threshold interrupts */
	enableThresholdInterrupt(); /* enable temp/humidity low/high threshold interrupts */
								//	disableDRDYInterrupt();
	enableDRDYInterrupt();

	/* TEMP_OFFSET adjust 0x08 */
	setTempOffsetAdjust(0);

	/* HUMIDITY_OFFSET adjust 0x09 */
	setHumidityOffsetAdjust(0);

	/* Temperature Threshold adjust Low 0x0A */
	setLowTemp(10.0);

	/* Temperature Threshold adjust High 0x0B */
	setHighTemp(30.0);

	/* Humidity Threshold adjust Low 0x0C */
	setLowHumidity(10.0);

	/* Humidity Threshold adjust High 0x0D */
	setHighHumidity(80.0);

	/* CONFIG 0x0E*/
	setInterruptMode(LEVEL_MODE);	  /* set interrupt mode */
	setInterruptPolarity(ACTIVE_LOW); /* set interrupt polarity */
	enableInterrupt();
	disableHeater();	  /* dusable heater */
	setRate(TEN_SECONDS); /* set auto conversion rate */

	/* MEASUREMENT_CONFIG 0x0F*/
	//	setMeasurementMode(TEMP_ONLY);		/* set measurement mode */
	//	setMeasurementMode(HUMID_ONLY);		/* set measurement mode */
	setMeasurementMode(TEMP_AND_HUMID); /* set measurement mode */
	setHumidRes(FOURTEEN_BIT);			/* set humidity resolution */
	setTempRes(FOURTEEN_BIT);			/* set temperature resolution */
	triggerMeasurement();				/* start measurement */

	/* HDC2080  found */
	sensorTypePresentAll |= (1 << SENSORTYPEHDC2080);
	myPrintkI("HDC2080 Temp/Humidty Sensor found\r\n");
	return TRUE;
}
