/*
 * Copyright (c) 2021 Thomas Stranger
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#define DT_DRV_COMPAT sensirion_shtcx

#include <zephyr/device.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/sys/__assert.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/sys/crc.h>
#include <zephyr/logging/log.h>

#include "shtcx.h"

LOG_MODULE_REGISTER(SHTCX, CONFIG_SENSOR_LOG_LEVEL);

/* all cmds read temp first: cmd[MEASURE_MODE][Clock_stretching_enabled] */
static const uint16_t measure_cmd[2][2] = {
	{ 0x7866, 0x7CA2 },
	{ 0x609C, 0x6458 },
};

/* measure_wait_us[shtcx_chip][MEASURE_MODE] */
static const uint16_t measure_wait_us[2][2] = {
	/* shtc1: 14.4ms, 0.94ms */
	{ 14400, 940 }, /* shtc1 */
	/* shtc3: 12.1ms, 0.8ms */
	{ 12100, 800 }, /* shtc3 */
};

/*
 * CRC algorithm parameters were taken from the
 * "Checksum Calculation" section of the datasheet.
 */
static uint8_t shtcx_compute_crc(uint16_t value)
{
	uint8_t buf[2];

	sys_put_be16(value, buf);
	return crc8(buf, 2, 0x31, 0xFF, false);
}

/* val = -45 + 175 * sample / (2^16) */
static void shtcx_temperature_from_raw(uint16_t raw, struct sensor_value *val)
{
	int32_t tmp;

	tmp = (int32_t)raw * 175U - (45 << 16);
	val->val1 = tmp / 0x10000;
	/* x * 1.000.000 / 65.536 == x * 15625 / 2^10 */
	val->val2 = ((tmp % 0x10000) * 15625U) / 1024;
}

/* val = 100 * sample / (2^16) */
static void shtcx_humidity_from_raw(uint16_t raw, struct sensor_value *val)
{
	uint32_t tmp;

	tmp = (uint32_t)raw * 100U;
	val->val1 = tmp / 0x10000;
	/* x * 1.000.000 / 65.536 == x * 15625 / 1024 */
	val->val2 = (tmp % 0x10000) * 15625U / 1024;
}

static int shtcx_write_command(const struct device *dev, uint16_t cmd)
{
	uint8_t tx_buf[2];

	sys_put_be16(cmd, tx_buf);
	return i2c_write(shtcx_i2c_bus(dev), tx_buf, sizeof(tx_buf),
			 shtcx_i2c_address(dev));
}

static int shtcx_read_words(const struct device *dev, uint16_t cmd, uint16_t *data,
		     uint16_t num_words, uint16_t max_duration_us)
{
	const struct shtcx_config *cfg = dev->config;
	int status = 0;
	uint32_t raw_len = num_words * (SHTCX_WORD_LEN + SHTCX_CRC8_LEN);
	uint16_t temp16;
	uint8_t rx_buf[SHTCX_MAX_READ_LEN];
	int dst = 0;

	status = shtcx_write_command(dev, cmd);
	if (status != 0) {
		LOG_DBG("Failed to initiate read");
		return -EIO;
	}

	if (!cfg->clock_stretching) {
		k_sleep(K_USEC(max_duration_us));
	}

	status = i2c_read(shtcx_i2c_bus(dev), rx_buf, raw_len,
			  shtcx_i2c_address(dev));
	if (status != 0) {
		LOG_DBG("Failed to read data");
		return -EIO;
	}

	for (int i = 0; i < raw_len; i += (SHTCX_WORD_LEN + SHTCX_CRC8_LEN)) {
		temp16 = sys_get_be16(&rx_buf[i]);
		if (shtcx_compute_crc(temp16) != rx_buf[i+2]) {
			LOG_DBG("invalid received invalid crc");
			return -EIO;
		}

		data[dst++] = temp16;
	}

	return 0;
}

static int shtcx_sleep(const struct device *dev)
{
	if (shtcx_write_command(dev, SHTCX_CMD_SLEEP) < 0) {
		return -EIO;
	}

	return 0;
}

static int shtcx_wakeup(const struct device *dev)
{
	if (shtcx_write_command(dev, SHTCX_CMD_WAKEUP)) {
		return -EIO;
	}

	k_sleep(K_USEC(100));
	return 0;
}

static int shtcx_sample_fetch(const struct device *dev,
			       enum sensor_channel chan)
{
	struct shtcx_data *data = dev->data;
	const struct shtcx_config *cfg = dev->config;

	__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL);

	if (cfg->chip == SHTC3) {
		if (shtcx_wakeup(dev)) {
			return -EIO;
		}
	}

	if (shtcx_read_words(dev,
			     measure_cmd[cfg->measure_mode][cfg->clock_stretching],
			     (uint16_t *)&data->sample, 2,
			     measure_wait_us[cfg->chip][cfg->measure_mode]) < 0) {
		LOG_DBG("Failed read measurements!");
		return -EIO;
	}

	if (cfg->chip == SHTC3) {
		if (shtcx_sleep(dev)) {
			LOG_DBG("Failed to initiate sleep");
			return -EIO;
		}
	}

	return 0;
}

static int shtcx_channel_get(const struct device *dev,
			      enum sensor_channel chan,
			      struct sensor_value *val)
{
	const struct shtcx_data *data = dev->data;

	if (chan == SENSOR_CHAN_AMBIENT_TEMP) {
		shtcx_temperature_from_raw(data->sample.temp, val);
	} else if (chan == SENSOR_CHAN_HUMIDITY) {
		shtcx_humidity_from_raw(data->sample.humidity, val);
	} else {
		return -ENOTSUP;
	}

	return 0;
}

static const struct sensor_driver_api shtcx_driver_api = {
	.sample_fetch = shtcx_sample_fetch,
	.channel_get = shtcx_channel_get,
};

static int shtcx_init(const struct device *dev)
{
	const struct shtcx_config *cfg = dev->config;
	uint16_t product_id;

	if (device_is_ready(cfg->bus) ==  0) {
		LOG_DBG("i2c bus is not ready");
		return -ENODEV;
	}

	k_sleep(K_USEC(SHTCX_POWER_UP_TIME_US));
	if (cfg->chip == SHTC3) {
		if (shtcx_wakeup(dev)) {
			LOG_ERR("Wakeup failed");
			return -EIO;
		}
	}

	if (shtcx_write_command(dev, SHTCX_CMD_SOFT_RESET) < 0) {
		LOG_ERR("soft reset failed");
		return -EIO;
	}

	k_sleep(K_USEC(SHTCX_SOFT_RESET_TIME_US));
	if (shtcx_read_words(dev, SHTCX_CMD_READ_ID, &product_id, 1, 0) < 0) {
		LOG_ERR("Failed to read product id!");
		return -EIO;
	}

	if (cfg->chip == SHTC1) {
		if ((product_id & SHTC1_ID_MASK) != SHTC1_ID_VALUE) {
			LOG_ERR("Device is not a SHTC1");
			return -EINVAL;
		}
	}
	if (cfg->chip == SHTC3) {
		if ((product_id & SHTC3_ID_MASK) != SHTC3_ID_VALUE) {
			LOG_ERR("Device is not a SHTC3");
			return -EINVAL;
		}
		shtcx_sleep(dev);
	}

	LOG_DBG("Clock-stretching enabled: %d", cfg->clock_stretching);
	LOG_DBG("Measurement mode: %d", cfg->measure_mode);
	LOG_DBG("Init SHTCX");
	return 0;
}

#define SHTCX_CONFIG(inst)						       \
	{								       \
		.bus = DEVICE_DT_GET(DT_INST_BUS(inst)),		       \
		.base_address = DT_INST_REG_ADDR(inst),			       \
		.chip = DT_INST_ENUM_IDX(inst, chip),			       \
		.measure_mode = DT_INST_ENUM_IDX(inst, measure_mode),	       \
		.clock_stretching = DT_INST_PROP(inst, clock_stretching)       \
	}

#define SHTCX_DEFINE(inst)						\
	static struct shtcx_data shtcx_data_##inst;			\
	static struct shtcx_config shtcx_config_##inst =		\
		SHTCX_CONFIG(inst);					\
	DEVICE_DT_INST_DEFINE(inst,					\
			      shtcx_init,				\
			      NULL,					\
			      &shtcx_data_##inst,			\
			      &shtcx_config_##inst,			\
			      POST_KERNEL,				\
			      CONFIG_SENSOR_INIT_PRIORITY,		\
			      &shtcx_driver_api);

DT_INST_FOREACH_STATUS_OKAY(SHTCX_DEFINE)
