/*
 * 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)
{
	const struct shtcx_config *cfg = dev->config;
	uint8_t tx_buf[2];

	sys_put_be16(cmd, tx_buf);
	return i2c_write_dt(&cfg->i2c, tx_buf, sizeof(tx_buf));
}

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_dt(&cfg->i2c, rx_buf, raw_len);
	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->i2c.bus)) {
		LOG_ERR("Bus device 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)						       \
	{								       \
		.i2c = I2C_DT_SPEC_INST_GET(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)
