/**
 * @file board_config.h
 * @author LokLiang
 * @brief 统一板载硬件描述数据结构
 * @version 0.1
 * @date 2023-11-24
 *
 * @copyright Copyright (c) 2023
 *
 * 目的与作用场景：
 * 使同类型的固件适应不同的硬件版本。
 * 例如同一类型产品，即使某些功能引脚改动，依然可以根据配置文件正确引导程序，而不需要新增特定的固件版本，旧的产品依然得到长期的支持。
 *
 * 数据设置：
 * 只能在工厂中配置，除此之外不允许任何手段尝试修改。
 * 数据地址固定为分区配置中
 *
 */

#pragma once

#define CONFIG_LICENSE_CODE_LENGTH 16 /* 在烧录器设置的保存滚码的字段长度(g_license_code 指向的数据的实际长度) */

#define CONFIG_CFG_BOARD_PARTITION_NAME "bcfg"  /* 对应自定义分区表 partitions.csv 中的 Name 字段 */
#define CONFIG_CFG_BOARD_PARTITION_TYPE 0x40    /* 对应自定义分区表 partitions.csv 中的 Type 字段 */
#define CONFIG_CFG_BOARD_PARTITION_SUBTYPE 0x00 /* 对应自定义分区表 partitions.csv 中的 SubType 字段 */

#include "drivers/chip/_hal.h"
#include "sdkconfig.h"
#include "hal/adc_types.h"
#include "driver/ledc.h"

#define GPIO_USED(pin) ((pin) < 255)

#if (CONFIG_IDF_TARGET_ESP32S3) /* 带 OTG 的平台 */
#define CAP_USBOTG 1
#else
#define CAP_USBOTG 0
#endif

typedef struct // 对应 GPIO 单个引脚的输入/输出配置的基础定义
{
    uint8_t pin;    // 引脚号 (0~254, 255 表示不使用)
    uint8_t en_lev; // 触发电平
} cfg_board_pin_io_t;

typedef struct // LED: WS2812
{
    hal_id_t spi_id;        // 模拟 PWM 用的 SPI
    uint8_t strip_pin[4];   // 用于驱动灯带的输出引脚。[0] 为默认脚，[1..3] 为附加的另外几路，非 255 表示有效，程序根据这些脚判断接多少根灯带
    uint8_t bat_led_pin[2]; // 用于指示电池电量的 RGB 灯，[0]为IO非 255 表示有效,[1]为电量灯珠数目
    uint8_t rf_status_pin;  // 板上用于指示状态的 RGB 灯珠，非 255 表示有效
} cfg_board_led_spi_t;

typedef struct
{
    ledc_channel_t pwm_output; // pwm 输出控制引脚，有效电平为打开热输出的电平
    uint32_t pwm_period;       // pwm 输出周期
} cfg_pwm_config_t;

typedef struct
{
    uint8_t adc_short;       // 设测温电阻短路（阻值为0时）将表现的电平：0 表示接地，1 表示接电源
    uint16_t adc_max;        // 元器件量程(采样最大值)
    uint16_t thermistor_b;   // 热敏电阻的材料常数(B值。一般2000~6000之间，单位为K)
    uint16_t thermistor_ohm; // 热敏电阻在25℃时的阻值(Ω)
    uint16_t load_res_ohm;   // 测温度负载分压电阻（Ω)
} cfg_thermistor_config_t;

typedef enum __packed // 用于与飞控通讯的数据接口
{
    CFG_BOARD_FC_PORT_UART = 0, // 使用串口与飞控通讯
    CFG_BOARD_FC_PORT_USBH,     // 使用 USB Host 与飞控通讯
} cfg_board_fc_port_t;

typedef struct // 数据结构一旦定下不可随意变更
{
    char firmware_str[7];
    char platform_str[13];
    char board_name[32];

    /* 硬件描述类 */
    hal_uart_hdl_t uart_console; // 控制台
    hal_uart_hdl_t uart_fc;      // 与飞控连接的串口
    cfg_board_led_spi_t led_spi; // LED

    cfg_board_fc_port_t fc_port_type; // 用于与飞控通讯的数据接口

    struct // ISP 控制脚
    {
        uint8_t nrst;  // 复位控制引脚
        uint8_t boot0; // boot0 控制引脚
    } io_isp;

    struct // USB OTG 引脚
    {
        uint8_t usb_dm;
        uint8_t usb_dp;
    } io_usb;

    cfg_board_pin_io_t detect_usb; // 输入检测：检测飞控 USB 插入，有效电平为插入电平

    cfg_board_pin_io_t key_reset;            // 按键检测：开机时长安 10 秒恢复出厂设置的按键，有效电平为按下电平
    cfg_board_pin_io_t key_led_strip_switch; // 按键检测：切换灯带效果，适用于灯带固件，有效电平为按下电平
    cfg_board_pin_io_t key_led_color_switch; // 按键检测：切换灯带效果，适用于竞速灯带切换颜色，有效电平为按下电平
    cfg_board_pin_io_t key_rf_switch;        // 按键检测：切换射频数据接口，适用于固定翼无线 USB 板，有效电平为按下电平
    cfg_board_pin_io_t key_9v_switch;        // 按键检测：9伏电源开关控制，适用 F7V4, 有效电平为按下电平

    cfg_board_pin_io_t sw_led_strip; // 灯带控制主机的切换控制引脚，有效电平为切换为本模块控制的电平
    cfg_board_pin_io_t sw_pwr_9v;    // 9V 电源输出控制引脚，有效电平为打开 9V 电源的电平
    cfg_board_pin_io_t sw_usb;       // USB 切换的模拟开关，有效电平为切换为本模块控制的电平

    cfg_board_pin_io_t led_rf_status; // 射频指示灯，单色 LED. 引脚号值为 0 时，射频连接状态通过灯带展示，值为非 0 时，射频连接状态通过这个引脚控制的 LED 展示，有效电平为点亮电平
    cfg_board_pin_io_t led_strip_on;  // 灯带控制主机切换的指示灯，有效电平为点亮电平
    cfg_board_pin_io_t led_bat[4];    // 电池电量指示灯，有效电平为点亮电平

    hal_adc_hdl_t heat_adc;                  // 用于 ADC 测量的配置
    cfg_pwm_config_t heat_pwm;               // 用于控制 PWM 输出的配置
    cfg_thermistor_config_t heat_thermistor; // 热敏电阻配置

    /* 产品功能描述类 */

} cfg_board_t;

extern const uint8_t *g_license_code; // 在烧录器设置的保存滚码的字段，其对应的长度为 CONFIG_LICENSE_CODE_LENGTH

extern const cfg_board_t *g_cfg_board; // 配置数据

int board_cfg_init(void); // 初始化，使 g_cfg_board 指向正确的

int board_license_fresh(const uint8_t license_code[CONFIG_LICENSE_CODE_LENGTH]); // 更新激活码
int board_cfg_fresh(const cfg_board_t *cfg);                                     // 更新设置

int board_cfg_dump(const cfg_board_t *cfg);
