/*
	本文件主要是提供板相关的操作
*/

#include "stdio.h"
#include "esp_mac.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_timer.h"
#include "driver/ledc.h"
#include "driver/gpio.h"
#include "hal/gpio_types.h"

#include "deca_device_api.h"

#include "bsp.h"
#define TAG "BSP"

EUI64 g_EUI64; // EUI
uint8_t current_mac[6];

void bsp_init(void)
{
	button_init();

	//esp_read_mac(current_mac, ESP_MAC_BASE);
	esp_efuse_mac_get_default(current_mac);
	ESP_LOGI(TAG, "current_mac " MACSTR " <<<===============", MAC2STR(current_mac));

	g_EUI64 = current_mac[0];
	g_EUI64 += (uint64_t)(current_mac[1]) << 8;
	g_EUI64 += (uint64_t)(current_mac[2]) << 16;
	g_EUI64 += (uint64_t)(0xFF) << 24;
	g_EUI64 += (uint64_t)(0xFE) << 32;
	g_EUI64 += (uint64_t)(current_mac[3]) << 40;
	g_EUI64 += (uint64_t)(current_mac[4]) << 48;
	g_EUI64 += (uint64_t)(current_mac[5]) << 56;

}



uint8_t cfg_button_pressed = 0;
uint8_t cfg_button_long_pressed = 0;
uint8_t cfg_button_long_pressed_from_boot = 0;
uint8_t cfg_button_clicked = 0;

static void IRAM_ATTR cfg_button_gpio_isr_handler(void* arg)
{
	static int64_t last_pushed = -2;
	if (gpio_get_level(CONFIG_BUTTON_GPIO) == 0) {
		// 按下按钮
		last_pushed = esp_timer_get_time();
	}
	else {
		// 释放按钮
		uint64_t now = esp_timer_get_time();
		if (last_pushed == -2) {
			// 从来没有被按下过, 开机之前就被按下了
			cfg_button_long_pressed_from_boot = 1;
		}
		else if ((last_pushed >= 0) && (now - last_pushed > BUTTON_LONG_PUSH_US)) {
			// 长按
			cfg_button_long_pressed = 1;
		}
		else if ((!cfg_button_long_pressed) && (last_pushed >= 0) && (now - last_pushed <= BUTTON_LONG_PUSH_US)) {
			// 短按
			cfg_button_pressed = 1;
		}

		last_pushed = -1;
	}
}

void button_init(void)
{
	gpio_config_t button_gpio_config = {
		.intr_type = GPIO_INTR_ANYEDGE,
		.mode = GPIO_MODE_INPUT,
		.pin_bit_mask = (1ULL << CONFIG_BUTTON_GPIO),
		.pull_up_en = GPIO_PULLUP_ENABLE,
	};
	ESP_ERROR_CHECK(gpio_config(&button_gpio_config));
	gpio_install_isr_service(0);
	gpio_isr_handler_add(CONFIG_BUTTON_GPIO, cfg_button_gpio_isr_handler, NULL);
}

// uint8_t is_cfg_button_pressed(void)	// 返回值: 0=未按下, 1=按下
// {
// 	return (gpio_get_level(CONFIG_BUTTON_GPIO) == 0);
// }


void gpio_init_for_debug(void)
{
	gpio_config_t bk_gpio_config = {
		.mode = GPIO_MODE_OUTPUT,
		.pin_bit_mask = (1ULL << DBG_RX_GPIO) | (1ULL << DBG_TX_GPIO) | (1ULL << DBG_SLOT_GPIO)
	};
	ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));
}


void HardReset(void)
{
	esp_restart();
}

/**
 * 读取 Flash 的 64位/128位 唯一 ID
 */
// void get_flash_unique_id(void)
// {
// 	uint64_t flash_unique_id = 0;
// 	// 直接读取 64 位的唯一 ID
// 	esp_err_t ret = esp_flash_read_unique_chip_id(esp_flash_default_chip, &flash_unique_id);

// 	if (ret == ESP_OK) {
// 		ESP_LOGI(TAG, "Flash Unique ID: %016llX\n", flash_unique_id);
// 	}
// 	else {
// 		ESP_LOGE("FLASH", "读取失败: %s", esp_err_to_name(ret));
// 	}
// }

#define INDICATOR_LEDC_TIMER          LEDC_TIMER_1
#define INDICATOR_LEDC_MODE           LEDC_LOW_SPEED_MODE
#define INDICATOR_LEDC_GPIO           (5)
#define INDICATOR_LEDC_CHANNEL        LEDC_CHANNEL_3
#define INDICATOR_LEDC_DUTY_MAX       ((1u << LEDC_TIMER_13_BIT) - 1u)
/* output_invert=1: 停止 PWM 后保持与「占空比 100%」相同的电平，背光彻底熄灭 */
#define INDICATOR_BACKLIGHT_OFF_IDLE  1

void indicator_backlight_init(void)
{
	ledc_timer_config_t ledc_timer = {
	.duty_resolution = LEDC_TIMER_13_BIT,
	.freq_hz = 4000,
	.speed_mode = INDICATOR_LEDC_MODE,
	.timer_num = INDICATOR_LEDC_TIMER,
	.clk_cfg = LEDC_AUTO_CLK,
	};
	ledc_timer_config(&ledc_timer);

	ledc_channel_config_t ledc_channel = {
			.channel = INDICATOR_LEDC_CHANNEL,
			.duty = INDICATOR_LEDC_DUTY_MAX,
			.gpio_num = INDICATOR_LEDC_GPIO,
			.speed_mode = INDICATOR_LEDC_MODE,
			.hpoint = 0,
			.timer_sel = INDICATOR_LEDC_TIMER,
			.flags.output_invert = 1
	};
	ledc_channel_config(&ledc_channel);

	indicator_backlight_set_brightness(0xFF);
}

void indicator_backlight_set_brightness(uint8_t brightness)
{
	/* output_invert=1: duty 越大 → GPIO 低电平占比越高 → 背光越暗
	 * brightness: 0=灭, 255=最亮；对 brightness 做 γ≈2 使人眼感觉均匀 */

	if (brightness == 0) {
		ledc_stop(INDICATOR_LEDC_MODE, INDICATOR_LEDC_CHANNEL, INDICATOR_BACKLIGHT_OFF_IDLE);
		return;
	}

	/* γ≈2: (brightness/255)^2 * 255，亮度 1..255 至少对应 1 级 PWM */
	uint32_t perceptual = (uint32_t)brightness * (uint32_t)brightness;
	perceptual = (perceptual + 254u) / 255u;
	if (perceptual > 255u) {
		perceptual = 255u;
	}

	uint32_t duty = (255u - perceptual) * INDICATOR_LEDC_DUTY_MAX / 255u;

	ledc_set_duty(INDICATOR_LEDC_MODE, INDICATOR_LEDC_CHANNEL, duty);
	ledc_update_duty(INDICATOR_LEDC_MODE, INDICATOR_LEDC_CHANNEL);
}


void alive_led_init(void)
{
	gpio_config_t alive_led_gpio_config = {
		.mode = GPIO_MODE_OUTPUT,
		.pin_bit_mask = (1ULL << ALIVE_LED_PIN),
	};
	ESP_ERROR_CHECK(gpio_config(&alive_led_gpio_config));
}

void alive_led_on(void)
{
	gpio_set_level(ALIVE_LED_PIN, 1);
}

void alive_led_off(void)
{
	gpio_set_level(ALIVE_LED_PIN, 0);
}


static uint8_t system_status = SYSTEM_STATUS_INITIALIZING;
static uint32_t alive_led_on_time = 0;
static uint32_t alive_led_off_time = 0;
void set_system_status(uint8_t status)
{
	system_status = status;
	switch (status) {
	case SYSTEM_STATUS_INITIALIZING:
		alive_led_on_time = SYSTEM_STATUS_INITIALIZING_ALIVE_LED_ON_TIME;
		alive_led_off_time = SYSTEM_STATUS_INITIALIZING_ALIVE_LED_OFF_TIME;
		break;
	case SYSTEM_STATUS_WORKING:
		alive_led_on_time = SYSTEM_STATUS_WORKING_ALIVE_LED_ON_TIME;
		alive_led_off_time = SYSTEM_STATUS_WORKING_ALIVE_LED_OFF_TIME;
		break;
	case SYSTEM_STATUS_WIFI_CONNECTING:
		alive_led_on_time = SYSTEM_STATUS_WIFI_CONNECTING_ALIVE_LED_ON_TIME;
		alive_led_off_time = SYSTEM_STATUS_WIFI_CONNECTING_ALIVE_LED_OFF_TIME;
		break;
	default:
		alive_led_on_time = SYSTEM_STATUS_INITIALIZING_ALIVE_LED_ON_TIME;
		alive_led_off_time = SYSTEM_STATUS_INITIALIZING_ALIVE_LED_OFF_TIME;
		break;
	}
}

void check_alive_led(void)
{
	static uint8_t alive_led_status = 1;
	/* esp_timer_get_time() 为 int64_t；uint32_t 截断约 71min 后会使间隔判断失真 */
	static int64_t alive_led_start_time = 0;
	if (alive_led_status == 1) {
		if (esp_timer_get_time() - alive_led_start_time > alive_led_on_time) {
			alive_led_status = 0;
			alive_led_off();
			alive_led_start_time = esp_timer_get_time();
		}
	}
	else {
		if (esp_timer_get_time() - alive_led_start_time > alive_led_off_time) {
			alive_led_status = 1;
			alive_led_on();
			alive_led_start_time = esp_timer_get_time();
		}
	}
}

