/**
 * @file app_config.h
 * @author LokLiang
 * @brief 用于应用控制程序的统一配置的数据结构
 * @version 0.1
 * @date 2023-11-24
 *
 * @copyright Copyright (c) 2023
 *
 * 本模块实现功能：
 * 1. 统一定义应用程序需要存储的所有数据；
 * 2. 依赖 nfs 模块，使当前数据与内部存储的数据实现同步；
 * 3. 依赖 sh_vset 模块，并提供其对应的所有设置实现函数；
 *
 * 对数据的读操作：
 * 上层应用：应用和模式管理模块和控制模块
 * 对外提数据结构为 g_cfg_app 指针，指内部的对应的内存，程序只读；
 *
 * 对数据的写操作：
 * 上层应用：
 * 为所有成员提供专门的写入接口，内部数据被立即更新。
 * 这些接口可用于 shell 的设置函数。
 *
 * 数据的默认值：
 * 当出现以下情况时，配置数据被恢复到默认值：
 * nvs 未初始化或操作失败；
 * 使用 app_cfg_factory_set() 恢复到默认值；
 * 结构体的长度 cfg_app_t 发生改变；
 * APP_CONFIG_DATA_VER 定义的值发生改变（在 app_config.c 内部定义）；
 *
 */

#pragma once

#include "sys_types.h"

/* 数据结构 ------------------------------------------------------------------------------------ */

#define MAX_WIFI_STA_NUM 12 /* cfg_app_t::wifi_setting.wifi_max_connection_num 的范围最大合法值 */
#define MIN_WIFI_STA_NUM 1  /* cfg_app_t::wifi_setting.wifi_max_connection_num 的范围最小合法值 */

typedef enum // 当前的无线数据模式，由按键控制更改
{
    DATA_BRIDGE_RF_MODE_OFF,      // 设置数据桥接模式：关闭所有数据接口
    DATA_BRIDGE_RF_MODE_BLE,      // 设置数据桥接模式：仅使用 UART <==> BLE
    DATA_BRIDGE_RF_MODE_WIFI_AP,  // 设置数据桥接模式：仅使用 UART <==> WIFI(AP)
    DATA_BRIDGE_RF_MODE_WIFI_STA, // 设置数据桥接模式：仅使用 UART <==> WIFI(STA)

    DATA_BRIDGE_RF_MODE_MAX,
} data_bridge_rf_mode_t;

typedef struct __packed // 由 APP 通过命令设置， WIFI 部分的透传设置
{
    uint16_t ardupilot_passthrough_tcp_port;                // tcp 透传端口（本地端口）
    uint16_t ardupilot_passthrough_udp_port;                // udp 透传端口（本地端口）
    uint8_t ardupilot_passthrough_udp_transfer_in_raw_mode; // UDP 连接下, 0: 解析飞控数据帧转发, 1: 直接转发原文
    uint8_t wifi_max_connection_num;                        // WIFI 最多的连接数。范围 MIN_WIFI_STA_NUM..MAX_WIFI_STA_NUM
    uint32_t uartBaudRate;                                  // 串口透传波特率
} cfg_app_wifi_setting_t;

typedef struct // 设备配置统一数据结构
{
    uint32_t version; // 配置版本，修改 APP_CONFIG_DATA_VER 的值后， nvs 已同步的数据被恢复到默认值

    int sys_log_on; // 打开调试日志

    data_bridge_rf_mode_t rf_mode; // 由按键控制切换的，当前的无线接口

    char psPassword[12]; // 由 APP 通过命令设置，透传密码

    char device_name_ble[32]; // 由 APP 通过命令设置， BLE 设备名，必须包含结束符

    char drone_data[12]; // 由 APP 通过命令设置，表示记录配置

    cfg_app_wifi_setting_t wifi_setting; // 由 APP 通过命令设置， WIFI 部分的透传设置

    uint8_t wifi_ap_ipv4[4]; // WIFI AP 模式下的 IP 地址
    struct
    {
        char wifi_ap_ssid[33];      // WIFI AP 模式下的 SSID
        char wifi_ap_password[65];  // WIFI AP 模式下的 密码
        char wifi_sta_ssid[33];     // WIFI STA 模式下的 SSID
        char wifi_sta_password[33]; // WIFI STA 模式下的 密码
    } app_config_wifi_para;

    uint16_t udp_port_passthrough_broadcast; // udp 透传端口（广播端口）
    uint16_t udp_port_command;               // udp 命令端口（本地端口）
    uint16_t tcp_port_command;               // tcp 命令端口（本地端口）
    uint16_t tcp_port_telnet;                // tcp telnet 端口(默认23)
    uint16_t tcp_port_dfu;                   // tcp DFU 升级服务端口（本地端口）
    uint16_t tcp_port_msc;                   // tcp 黑匣子服务端口（本地端口）

    char dev_mac_str[14]; // 通过 esp_base_mac_addr_get() 获取的 MAC 地址的字符串形式

    uint32_t salt_random; // 32 位的随机值，生成唯一 ID 的附加值

    struct // 功能模块开关
    {
        bool pwrup_light : 1; // 短亮黄灯表示启动（方便观察是否有重启）
        bool ble : 1;         // 使用 BLE
        bool ap : 1;          // 使用 WIFI AP 模式
        bool sta : 1;         // 使用 WIFI STA 模式

        bool strip_pwrup : 1;         // 使用灯带上电效果
        bool strip_show_rf : 1;       // 在灯带中用一个灯来显示射频数据接口状态的灯效图层
        bool strip_link_fc : 1;       // 开启灯带联动飞控：用于飞控状态监控（MSP）
        char ws2812_bat_led_mode : 3; // 电量灯效, 0: 关闭, 1: 普通飞控, 2: 竞速飞控, 3: 固定翼飞控

        uint32_t reserve : 21; // 预留占位(原来是24个uint32)
    } capacity;

    struct
    {
        uint8_t protocol_type; // @ref fc_comm_protocol_type_t
    } fc;

    uint8_t led_strip_ctrl_sw; // 记录当前灯带的模拟开关状态，0: 表示切换到由飞控控制， 1: 表示切换到由本固件控制

    uint8_t armed2close_rf_sw; // 解锁后自动关闭射频功能的开关，0: 关, 1: 开

    uint8_t mac_index;     // 记录当前通过 WIFI 连接过的 APP 的 MAC 地址的序号
    uint8_t mac_tab[6][6]; // 记录当前通过 WIFI 连接过的 APP 的 MAC 地址, 6 个 MAC 地址，每个 MAC 地址 6 字节,判断是否 APP 设备连接,用于决定是否停止对飞控状态监测

    uint8_t product_id[6]; // 产品 ID

    uint8_t gyro_heat_value; // 陀螺仪加热值,单位温度,0为关闭,最大值为80℃

    struct
    {
        bool temp_log_on : 1;       // 温度日志开关
        uint8_t temp_log_index : 5; // 温度日志最新索引
    } temperature_log;

    bool ws2812_bat_led_direction; // 0: 正向，1: 反向(正反向是指灯珠的连接方式，正向是指从第一个灯珠开始，反向是指从最后一个灯珠开始)
    uint32_t ws2812_bat_led_color; // 电量灯颜色, RGB颜色值,如 0xFFFFFF 代表白色(默认)

    uint8_t ble_mac_index;     // 记录当前通过 BLE 连接过的 APP 的 MAC 地址的序号
    uint8_t ble_mac_tab[6][6]; // 记录当前通过 BLE 连接过的 APP 的 MAC 地址, 6 个 MAC 地址，每个 MAC 地址 6 字节,判断是否 APP 设备连接,用于决定是否停止对飞控状态监测

    uint32_t reserve[25]; // 预留占位,下次更改时保证参数总长度不变,如超过预留长度后则当作新数据处理,sizeof(cfg_app_t) = 484UL

    uint32_t crc32; // 校验数据（可放于任何位置）
} cfg_app_t;

/* nvs 接口 ------------------------------------------------------------------------------------ */

int app_cfg_init(void); // 初始化

int app_cfg_factory_set(void); // 使内存的数据恢复到默认设置，注意不会被立即保存到 nvs 中

int app_cfg_do_save(uint32_t delay_ms); // 保存配置数据 到 nvs 的动作

/* 读接口 -------------------------------------------------------------------------------------- */

extern const cfg_app_t *g_cfg_app; // 指向 cfg_app_t 内存，只读，在 app_cfg_init() 执行初始化后可用

extern const int *g_sys_log_on;

/* 写接口 -------------------------------------------------------------------------------------- */

void app_cfg_set_sys_log(bool on);

void app_cfg_set_rf_mode_change(void); // 设置 g_cfg_app->rf_mode 的下一个模式
int app_cfg_set_rf_mode(data_bridge_rf_mode_t rf_mode);

int app_cfg_set_psPassword(const void *psPassword, int size);
int app_cfg_set_device_name_ble(const void *device_name_ble, int size);
int app_cfg_set_drone_data(const void *drone_data, int size);

int app_cfg_set_wifi_setting_ardupilot_passthrough_tcp_port(uint16_t ardupilot_passthrough_tcp_port);                                // TCP 透传端口（本地端口）
int app_cfg_set_wifi_setting_ardupilot_passthrough_udp_port(uint16_t ardupilot_passthrough_udp_port);                                // UDP 透传端口（本地端口）
int app_cfg_set_wifi_setting_ardupilot_passthrough_udp_transfer_in_raw_mode(uint8_t ardupilot_passthrough_udp_transfer_in_raw_mode); // UDP 连接下，直接转发原文
int app_cfg_set_wifi_setting_wifi_max_connection_num(uint8_t wifi_max_connection_num);                                               // WIFI 最多的连接数。范围 MIN_WIFI_STA_NUM..MAX_WIFI_STA_NUM
int app_cfg_set_wifi_setting_uartBaudRate(uint32_t uartBaudRate);                                                                    // 串口透传波特率

int app_cfg_set_fc_protocol_type(uint8_t type);

int app_cfg_set_led_strip_sw(uint8_t sw);

int app_cfg_set_armed2close_rf_sw(bool sw);

int app_cfg_set_rf_parameters(const void *wifi_parameters, size_t size);
int app_cfg_set_wifi_ap_ssid(const void *ssid);
int app_cfg_set_wifi_ap_password(const void *password);
int app_cfg_set_wifi_sta_ssid(const void *ssid);
int app_cfg_set_wifi_sta_password(const void *password);

int app_cfg_set_mac_tab(uint8_t mac[6]);
int app_cfg_set_ble_mac_tab(uint8_t mac[6]);

int app_cfg_set_temp_log_on(bool sw);
int app_cfg_set_temp_log_index(uint8_t index);

int app_cfg_set_gyro_heat_value(uint8_t value);

int app_cfg_set_bat_led_color(uint32_t color);
