/**
 * @file spbelib_interface.h
 * @author LokLiang
 * @brief 无线调参功能接口
 * @version 0.1
 * @date 2025-03-14
 *
 * @copyright Copyright (c) 2025
 *
 */

#pragma once

#include "sys_types.h"

typedef enum
{
    SBLIB_INIT_WIRE_TUNE = 0, // 初始化为无线调参功能
    SBLIB_INIT_ADAPTER,       // 初始化为 静态库 功能
} sblib_init_t;

/**
 * @brief 初始化功能库。
 */
void sblib_init(sblib_init_t init_type);

/*************************************************************************************************/
/**** 事件操作部分 ********************************************************************************/
/*************************************************************************************************/

/**
 * @brief 注册事件回调函数。
 * 当有关于静态库功能的事件发生或接收到数据时，调用回调函数。
 * 由 lib_notify_event() 和 sblib_notify_datastream() 函数调用。
 */
typedef void (*lib_notify_cb)(void);

typedef enum __packed // 静态库功能控制命令
{
    LIB_CONTROL_FCPORT_OFF,  // 关闭飞控数据接口
    LIB_CONTROL_FCPORT_UART, // 使用 UART 连接飞控
    LIB_CONTROL_FCPORT_OTG,  // 使用 OTG 连接飞控

    LIB_CONTROL_RF_OFF, // 关闭射频连接
    LIB_CONTROL_RF_BLE, // 打开 BLE
    LIB_CONTROL_RF_AP,  // 打开 WIFI(AP)
    LIB_CONTROL_RF_STA, // 打开 WIFI(STA)
} lib_control_t;

typedef enum __packed // 通知的事件类型
{
    LIB_EVENT_NONE = 0,

    LIB_EVENT_FC_PORT_OFF,  // 飞控数据接口关闭。参数：无
    LIB_EVENT_FC_PORT_UART, // 飞控数据接口为串口。参数：无
    LIB_EVENT_FC_PORT_OTG,  // 飞控数据接口为 USBH。参数：无

    LIB_EVENT_USBH_NO_START,      // USBH 接口未启动。参数：无
    LIB_EVENT_USBH_CDC,           // USBH 接口已连接 CDC 设备。参数：无
    LIB_EVENT_USBH_DFU,           // USBH 接口已连接 DFU 设备。参数：无
    LIB_EVENT_USBH_MSC,           // USBH 接口已连接 MSC 设备。参数：无
    LIB_EVENT_USBH_UNKNOW_DEVICE, // USBH 接口已连接未知设备。参数：无

    LIB_EVENT_RF_OFF,           // 无线连接已关闭。参数：无
    LIB_EVENT_RF_CHANGE_MODE,   // 提示模式切换已就绪。参数：无
    LIB_EVENT_RF_BLE_IDLE,      // 蓝牙模式未连接。参数：无
    LIB_EVENT_RF_BLE_CONNECTED, // 蓝牙模式已连接。参数：无
    LIB_EVENT_RF_AP_IDLE,       // WIFI AP 模式未连接。参数：无
    LIB_EVENT_RF_AP_CONNECTED,  // WIFI AP 模式已连接。参数：无
    LIB_EVENT_RF_STA_IDLE,      // WIFI STA 模式未连接。参数：无
    LIB_EVENT_RF_STA_CONNECTED, // WIFI STA 模式已连接。参数：已连接设备的 MAC 地址

    LIB_EVENT_BLE_NAME_SET,        // BLE 名称已设置。参数：无
    LIB_EVENT_BLE_PASSWD_SET,      // BLE 密码已设置。参数：无
    LIB_EVENT_WIFI_AP_SSID_SET,    // WIFI AP SSID 已设置。参数：无
    LIB_EVENT_WIFI_AP_PASSWD_SET,  // WIFI AP 密码已设置。参数：无
    LIB_EVENT_WIFI_STA_SSID_SET,   // WIFI STA SSID 已设置。参数：无
    LIB_EVENT_WIFI_STA_PASSWD_SET, // WIFI STA 密码已设置。参数：无

    LIB_EVENT_MAX
} lib_event_type_t;

typedef struct // 静态库通知的事件数据
{
    lib_event_type_t type; // 事件类型
    uint8_t len;           // data[] 有效数据长度
    uint8_t data[6];       // 事件数据
} lib_event_t;

/**
 * @brief 执行对静态库功能的控制。
 *
 * @param control 控制命令
 * @retval 0 表示成功； -1 表示失败。
 */
int sblib_control(lib_control_t control);

/**
 * @brief 注册事件回调函数。
 * 当有关于静态库的新事件发生时，将调用指定的回调函数以通知上层应用。
 * 内部可缓存的记录数为 32 个。
 * 使用 sblib_get_event() 可读取这些记录，读取后会清除记录。
 *
 * @param cb 指定的回调函数。建议在回调函数中执行发送信号的操作。
 */
void sblib_regist_notify_event(lib_notify_cb cb);

/**
 * @brief 获取静态库的事件。线程和中断可用。
 *
 * @return lib_event_t
 */
lib_event_t sblib_get_event(void);

/**
 * @brief 发送通知。
 * 通知信息保存到内部队列中，长度为 32。
 * 每次发送通知时，由 sblib_regist_notify_event() 注册的回调函数会被调用。
 * @param type  事件类型
 * @param len   事件数据长度。范围 0..6。如果取值大于最大值时，事件数据被截断。
 * @param data  事件数据
 */
void sblib_send_event(lib_event_type_t type, uint8_t len, const uint8_t data[]);

/*************************************************************************************************/
/**** 通过无线接口与 APP 通讯部分 ******************************************************************/
/*************************************************************************************************/

/**
 * @brief 当无线接口接收到 APP 数据时的回调函数。
 * @param port      收到的端口号，这个号码与注册时的 port 一致。
 * @param cmd       收到的命令代号，这个号码与注册时的 cmd 一致。
 * @param payload   收到的数据指针，指向数据的内存地址。
 * @param size      收到的数据长度。
 */
typedef void (*cmd_func_cb)(uint8_t port, uint8_t cmd, const void *payload, uint16_t size);

typedef enum
{
    SBLIB_CMD_PORT_DEBUG = 0, // 保留的端口，用于 debug 等
    SBLIB_CMD_PORT_ADAPTER,   // 无线调参扩展命令集
    SBLIB_CMD_PORT_FINDTAG,   // 寻机命令集
    SBLIB_CMD_PORT_JOYSTICK,  // 遥控器命令集
    SBLIB_CMD_PORT_ELRS,      // 接收机命令集
} sblib_cmd_port_t;

typedef struct // 注册命令的结构体
{
    uint8_t cmd;    // 命令代号
    cmd_func_cb cb; // 命令处理函数
} sblib_cmd_t;

typedef enum // 返回的发送状态
{
    SBLIB_SEND_STATUS_OK = 0,     // 当前等发送数据已缓存到待发送区中，数据将会被发送
    SBLIB_SEND_STATUS_NO_SPACE,   // 当前没有缓存空间，数据不会被处理
    SBLIB_SEND_STATUS_NO_CONNECT, // 当前没有连接，数据不会被处理
} sblib_cmd_send_status_t;

/**
 * @brief 注册一个通过无线接口接收 APP 数据的外部命令集。
 * 当收到 APP 发出的命令和数据时，会调 cmd_struct 中对应的 port 和 cmd 的函数。
 * 回调过程中允许调用 sblib_send_event() 向 APP 发送数据。
 * 注意：回调函数附带的参数不会被缓存，并且必须尽快处理，如果需要缓存需要自行处理。
 *
 * @param port          端口号。一个端口号对应一个应用的命令集合标识，具体序号由收发双方的应用层协商，一旦确定后，不能更改。收发双向都使用同一个端口号。
 * @param cmd_struct    指向一个命令集合的结构体数组。这个命令集合与参数 port 绑定。当收到 APP 发出的命令时，会调 cmd_struct 中对应的 port 和 cmd 的函数。
 * @param struct_size   命令集结构体大小。使用 sizeof() 计算。
 * @retval 0 成功
 * @retval -1 失败：内置预设的命令集已满，无法注册新的命令集。
 */
int sblib_register_cmd(sblib_cmd_port_t port, const sblib_cmd_t *cmd_struct, uint32_t struct_size);

/**
 * @brief 通过无线接口发送数据到 APP。
 * 发送的数据会被缓存到待发送区中，当收到 APP 的回应时缓存会被自动清除，通过 sblib_get_cmd_sned_buf() 函数可以获取当前未被成功发送的数据包的数量。
 *
 * @param port      端口号。一个端口号对应一个应用的命令集合标识，具体序号由收发双方的应用层协商，一旦确定后，不能更改。收发双向都使用同一个端口号。
 * @param cmd       命令代号。命令代号由收发双方的应用层协商，一旦确定后，不能更改。
 * @param data      数据指针。指向要发送的数据的内存地址。指向的内存地址的数据会被复制到缓存区中，发送结束后会被自动释放。
 * @param length    数据长度。长度任意，建议最大为 1460 字节
 * @return
 *  SBLIB_SEND_STATUS_OK 当前等发送数据已缓存到待发送区中，数据将会被发送
 *  SBLIB_SEND_STATUS_NO_SPACE 当前没有缓存空间，数据不会被处理
 *  SBLIB_SEND_STATUS_NO_CONNECT 当前没有连接，数据不会被处理
 */
sblib_cmd_send_status_t sblib_cmd_send(sblib_cmd_port_t port, uint8_t cmd, const void *data, uint16_t length);

/**
 * @brief 获取当前已缓存但未发送成功的数据包的数量。
 *
 * @return uint32_t 未发送完成的数据包的数量
 */
uint32_t sblib_get_cmd_sned_buf(void);
