/*
 * SGP40.c
 *
 *  Created on: Jan 9, 2022
 *      Author: david
 */

#include <sgp40.h>

int8_t sgp40_send_cmd(sgp40_cmd_t cmd)
{
	uint8_t buffer[32];
	int result;

	// start measurement
	buffer[0] = cmd >> 8;
	buffer[1] = cmd & 0x00ff;
	result = i2c_transmit(SGP40_I2C_ADDRESS<<1, buffer, 2);
	if (result == I2C_ERROR_TX_INCOMPLETE) {
		return SGP40_ERROR;
	}

	/* Sensirion sensors return NACK after last byte (so NACK at the end is ok) */
	return SGP40_OK;
}

int8_t sgp40_measure_raw_signal(uint16_t * voc_ticks)
{
	uint8_t buffer[32];
	int result;

	/* Start measurement */
	buffer[0] = 0x26;
	buffer[1] = 0x0F;
	buffer[2] = 0x80;
	buffer[3] = 0x00;
	buffer[4] = 0xA2;
	buffer[5] = 0x66;
	buffer[6] = 0x66;
	buffer[7] = 0x93;

	/* Returns NACK if CRC is wrong */
	result = i2c_transmit(SGP40_I2C_ADDRESS<<1, buffer, 8);
	if (result != I2C_OK) {
		return SGP40_ERROR;
	}

	LL_mDelay(SGP40_MAX_MEAS_DURATION_MS); // 30ms

	result = i2c_receive(SGP40_I2C_ADDRESS<<1, buffer, 3);
	if (result != I2C_OK)
	{
		return SGP40_ERROR;
	}

	*voc_ticks = (buffer[0] << 8) + buffer[1];
	uint8_t voc_ticks_crc = buffer[2];
	uint8_t crc_correct = crc8_calculate(buffer, 2) == voc_ticks_crc;
	if (!crc_correct) {
		return SGP40_CRC8_ERROR;
	}
	return SGP40_OK;

}

int8_t sgp40_measure_raw_signal_compensated(uint16_t * voc_ticks, uint16_t relative_humidity, int16_t temperature)
{
	uint8_t buffer[32];
	int result;

	uint16_t rh_ticks = (uint16_t)((uint32_t)relative_humidity * 65535 / 100);
	uint16_t t_ticks = (uint16_t)(((uint32_t)temperature/10 + 45) * 65535 / 175);

	buffer[0] = SGP40_MEASURE_RAW_SIGNAL >> 8;
	buffer[1] = SGP40_MEASURE_RAW_SIGNAL & 0x00ff;
	buffer[2] = (uint8_t)(rh_ticks >> 8);
	buffer[3] = (uint8_t)rh_ticks;
	buffer[4] = crc8_calculate(buffer+2, 2);
	buffer[5] = (uint8_t)(t_ticks >> 8);
	buffer[6] = (uint8_t)t_ticks;
	buffer[7] = crc8_calculate(buffer+5, 2);

	/* Returns NACK if CRC is wrong */
	result = i2c_transmit(SGP40_I2C_ADDRESS<<1, buffer, 8);
	if (result != I2C_OK) {
		return SGP40_ERROR;
	}

	LL_mDelay(SGP40_MAX_MEAS_DURATION_MS); // 30ms

	result = i2c_receive(SGP40_I2C_ADDRESS<<1, buffer, 3);
	if (result != I2C_OK)
	{
		return SGP40_ERROR;
	}

	*voc_ticks = (buffer[0] << 8) + buffer[1];
	uint8_t voc_ticks_crc = buffer[2];
	uint8_t crc_correct = crc8_calculate(buffer, 2) == voc_ticks_crc;
	if (!crc_correct) {
		return SGP40_CRC8_ERROR;
	}
	return SGP40_OK;
}

int8_t SGP40_execute_self_test ( uint8_t * test_result)
{
	uint8_t buffer[16];
	int8_t result;

	result = sgp40_send_cmd(SGP40_EXECUTE_SELF_TEST);
	if (result != I2C_OK) {
		return SGP40_ERROR;
	}

	LL_mDelay(350);

	result = i2c_receive(SGP40_I2C_ADDRESS << 1, buffer, 3);
	if (result != I2C_OK) {
		return SGP40_ERROR;
	}

	test_result = buffer[0];
	uint8_t test_result_crc = buffer[2];

	uint8_t crc_correct = crc8_calculate(buffer, 2) == test_result_crc;
	if (!crc_correct) {
		return SGP40_CRC8_ERROR;
	}
	return SGP40_OK;
}

int8_t SGP40_get_serial_number(uint8_t serial[6])
{
	uint8_t buffer[16];

	sgp40_send_cmd(SGP40_GET_SERIAL_NUMBER);

	LL_mDelay(5);

	i2c_receive(SGP40_I2C_ADDRESS << 1, buffer, 9);

	serial[0] = buffer[0];
	serial[1] = buffer[1];
	uint8_t crc_ser01 = buffer[3];
	serial[2] = buffer[4];
	serial[3] = buffer[5];
	uint8_t crc_ser23 = buffer[6];
	serial[4] = buffer[7];
	serial[5] = buffer[8];
	uint8_t crc_ser45 = buffer[9];

	uint8_t crc_correct = crc8_calculate(buffer, 2) == crc_ser01;
	crc_correct &= crc8_calculate(buffer + 3, 2) == crc_ser23;
	crc_correct &= crc8_calculate(buffer + 6, 2) == crc_ser45;
	if (!crc_correct) {
		return SGP40_CRC8_ERROR;
	}
	return SGP40_OK;
}

int8_t SGP40_turn_heater_off(void)
{
	return sgp40_send_cmd(SGP40_TURN_HEATER_OFF);
}
int8_t SGP40_soft_reset(void)
{
	return sgp40_send_cmd(SGP40_SOFT_RESET);
}
