#include <stdio.h>
#include "esp_log.h"
#include "driver/i2c.h"
#include "gw_grayscale_sensor.h"

static const char *TAG = "gw gray i2c example";

#define I2C_MASTER_SCL_IO           22      /*!< I2C 时钟针脚号  */
#define I2C_MASTER_SDA_IO           21      /*!< I2C 数据针脚号  */
#define I2C_MASTER_NUM              0       /*!< I2C 通道       */
#define I2C_MASTER_FREQ_HZ          100000  /*!< I2C 主的时钟频率 */
#define I2C_MASTER_TX_BUF_DISABLE   0       /*!< I2C 不设输出缓冲 */
#define I2C_MASTER_RX_BUF_DISABLE   0       /*!< I2C 不设输入缓冲 */
#define I2C_MASTER_TIMEOUT_MS       0

uint8_t gw_gray_addr = 0;

static esp_err_t gw_gray_write_cmd(uint8_t cmd)
{
	esp_err_t err;
	err = i2c_master_write_to_device(I2C_MASTER_NUM, gw_gray_addr,
	                                 &cmd, 1, pdMS_TO_TICKS(I2C_MASTER_TIMEOUT_MS));
	return err;
}

static esp_err_t gw_gray_read_byte(uint8_t *byte_read)
{
	esp_err_t err;
	err = i2c_master_read_from_device(I2C_MASTER_NUM, gw_gray_addr,
	                                  byte_read, 1, pdMS_TO_TICKS(I2C_MASTER_TIMEOUT_MS));
	return err;
}

static esp_err_t gw_gray_read(uint8_t *read_arr, size_t read_size)
{
	esp_err_t err;
	err = i2c_master_read_from_device(I2C_MASTER_NUM, gw_gray_addr,
	                                  read_arr, read_size, pdMS_TO_TICKS(I2C_MASTER_TIMEOUT_MS));
	return err;
}

static esp_err_t gw_gray_write(const uint8_t *write_arr, size_t write_size)
{
	esp_err_t err;
	err = i2c_master_write_to_device(I2C_MASTER_NUM, gw_gray_addr,
	                                 write_arr, write_size, pdMS_TO_TICKS(I2C_MASTER_TIMEOUT_MS));
	return err;
}

static esp_err_t i2c_master_init(void)
{
	int i2c_master_port = I2C_MASTER_NUM;

	i2c_config_t conf = {
			.mode = I2C_MODE_MASTER,
			.sda_io_num = I2C_MASTER_SDA_IO,
			.scl_io_num = I2C_MASTER_SCL_IO,
			.sda_pullup_en = GPIO_PULLUP_ENABLE,
			.scl_pullup_en = GPIO_PULLUP_ENABLE,
			.master.clk_speed = I2C_MASTER_FREQ_HZ,
	};

	i2c_param_config(i2c_master_port, &conf);

	return i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
}

/**
 * @brief 扫描和打印有回复的 任何i2c设备
 */
static void i2c_scan_generic(void);

/**
 * @brief 扫描和打印有回复的 感为灰度传感器设备
 * @return 0: 无设备, 其他: 最后一个被扫描到的设备
 */
static uint8_t i2c_scan_gw_gray(void);


void app_main(void)
{
	uint8_t ping_rsp = 0;
	uint8_t send_buff[8];
	int err;
	ESP_ERROR_CHECK(i2c_master_init());
	ESP_LOGI(TAG, "I2C initialized successfully");
	vTaskDelay(pdMS_TO_TICKS(500));

	i2c_scan_generic();
	gw_gray_addr = i2c_scan_gw_gray();

	// 更换地址
	if (gw_gray_addr == 0) {
		ESP_LOGI(TAG, "没找到设备啊");
	} else if (gw_gray_addr != 0x18) {
		// 对指定i2c地址更改地址,以下命令会发送到地址为gw_gray_addr
		ESP_LOGI(TAG, "对%x更改地址,新地址应为%x", gw_gray_addr, 0x18);
		send_buff[0] = GW_GRAY_CHANGE_ADDR; // 更新地址命令
		send_buff[1] = 0x33; // 新地址, 实际地址为 0x18 = (0x33 & 0b111) >> 1, 详细请看文档8.6.1
		err = gw_gray_write(send_buff, 2);

		// 传感器设备需要把地址写入EEPROM,需要1ms左右
		vTaskDelay(pdMS_TO_TICKS(1));

		ESP_LOGI(TAG, "软件重启设备");
		gw_gray_write_cmd(GW_GRAY_REBOOT);

		// 再次扫描地址
		i2c_scan_generic();
		gw_gray_addr = i2c_scan_gw_gray();
	}

	if ((gw_gray_addr & 0xFC) != GW_GRAY_ADDR_DEF){
		ESP_LOGI(TAG, "i2c广播重置");
		gw_gray_addr = 0;
		gw_gray_write((const uint8_t *)GW_GRAY_BROADCAST_RESET, 8);

		ESP_LOGI(TAG, "等待设备重启2...");
		vTaskDelay(pdMS_TO_TICKS(10));

		// 再次扫描地址
		i2c_scan_generic();
		gw_gray_addr = i2c_scan_gw_gray();
	}

	while (1) {
		vTaskDelay(portMAX_DELAY);
	}
}


static void i2c_scan_generic(void)
{
	uint8_t device_count = 0;
	printf("i2c 扫描开始: \n");
	for (uint8_t i = 1; i < 127; i++)
	{
		int ret;
		i2c_cmd_handle_t cmd = i2c_cmd_link_create();
		i2c_master_start(cmd);
		i2c_master_write_byte(cmd, (i << 1) | I2C_MASTER_WRITE, 1);
		i2c_master_stop(cmd);
		ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, pdMS_TO_TICKS(I2C_MASTER_TIMEOUT_MS));
		i2c_cmd_link_delete(cmd);

		if (ret == ESP_OK) {
			device_count += 1;
			printf("找到i2c设备,地址为: 0x%2x\n", i);
		}
		vTaskDelay(pdMS_TO_TICKS(10));
	}
	if (device_count == 0) {
		printf("无i2c设备\n");
	}
}

static uint8_t i2c_scan_gw_gray(void)
{
	printf("感为灰度传感器i2c 扫描开始: \n");
	uint8_t i2c_cmd = GW_GRAY_PING;
	uint8_t ping_rsp;
	uint8_t gw_gray_device_addr = 0;
	for (uint8_t i = 1; i < 127; i++)
	{
		int ret;
		ping_rsp = 0;
		ret = i2c_master_write_read_device(I2C_MASTER_NUM, i, &i2c_cmd, 1,
		                                   &ping_rsp, 1, pdMS_TO_TICKS(I2C_MASTER_TIMEOUT_MS));
		if (ret != ESP_FAIL && ret != ESP_OK) {
			printf("%d, %s\n", i, esp_err_to_name(ret));
		}
		if (ping_rsp == 0x66) {
			printf("找到感为传感器设备,地址为: 0x%2x\n", i);
			gw_gray_device_addr = i;
		} else if (ping_rsp != 0) {
			printf("设备: 0x%2x 回复 :%x\n", i, ping_rsp);
		}
		vTaskDelay(pdMS_TO_TICKS(2));
	}

	return gw_gray_device_addr;
}