#ifndef __UNIFY_PROTOCOL_H__
#define __UNIFY_PROTOCOL_H__

/*
 * @brief      纸飞机统一协议接口（多窗口曲线绘图、多窗口文本日志、多窗口图像显示）
 * @author     inhowe (inhowe@qq.com)
 * @date       创建时间：2025-08-24
 * @date       最后修改：2025-08-24
 * @copyright  Copyright (c) 2025 inhowe. 保留所有权利.
 *
 * @使用说明   需要了解数据包定义。了解之后只需要重点学会 fill_pack_for_xx 系列的函数用法即可。
 *
 * @数据包定义 一个完整数据包 由 包头 + 数据段 组成。
 *             包头定义参考 packHead_s 结构体。
 *             数据段为你要发送的原始数据，可能是图像原始数据、字符串数据等。
 */

#include "modbus_crc.h"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>

// 包头固定 magic
#define HEADER_MAGIC            (0x55)
// 数据包最大长度
#define MAX_PACK_BUFFER_LEN     (1048576)
// 最大曲线数量
#define MAX_CURVE_NUM           (16)

// 数据类型定义
typedef enum __attribute__ ((packed)) {
    TEXT_LOG        = 0x00,     // 文本数据
    GRAPH_JPG       = 0x01,     // JPG图片
    GRAPH_RGB565    = 0x02,     // 16位RGB565图片
    GRAPH_RGB555    = 0x03,     // 15位RGB555图片
    GRAPH_GRAY8     = 0x04,     // 8位灰度图片
    CURVE_INT8      = 0x10,     // 8位有符号整数曲线
    CURVE_INT16     = 0x11,     // 16位有符号整数曲线
    CURVE_INT32     = 0x12,     // 32位有符号整数曲线
    CURVE_FLOAT     = 0x13,     // 32位浮点数曲线
    /* 工作区控制下发：windowID=workspace-XX 的 XX；dataSize=5；payload=[cmdId:1][value:4] LE */
    WORKSPACE_FLOAT_TO_DEVICE  = 0x20,     // value 为 float（滑条、实数框）
    WORKSPACE_INT32_TO_DEVICE  = 0x21,     // value 为 int32_t（按钮、开关等）
} dataType_e;

// 图像分辨率
typedef struct __attribute__ ((packed)) {
    uint16_t width;
    uint16_t height;
} resulotion_s;

// 数据段大小
typedef union __attribute__ ((packed)) {
    resulotion_s resulotion;    // 适用于dataType为RGB565、RGB555、GRAY8的图像数据，表示数据段为这些图像数据的分辨率信息
    uint32_t size;              // 适用于dataType为JPG、TEXTLOG、INT8、INT16、INT32、FLOAT的数据，表示数据的长度或大小
} dataSize_u;

// 窗口ID
typedef union __attribute__ ((packed)) {
    uint8_t graphID;   // 图像ID，表示不同的图像窗口，目前只支持单窗口图像，填0。
    uint8_t textID;    // 文本ID，表示不同的文本窗口，用于分类文本显示
    uint8_t curveID;   // 曲线ID，表示不同的曲线窗口，用于分类曲线绘图
    uint8_t workspaceID;   // 工作区ID，表示不同的工作区窗口，用于分类工作区数值
} windowID_u;

// 数据包头
typedef struct __attribute__ ((packed)) {
    uint8_t head;
    uint8_t dataType;       // 数据段类型，用于区分接下来的数据段如何解析。定义可参考 dataType_e 枚举
    uint8_t windowID;       // 窗口ID，定义可参考 windowID_u
    uint16_t seqNum;        // 递增序列号
    uint32_t dataSize;      // 数据段大小，定义参考 dataSize_u
    uint16_t dataCheck;     // 数据段校验结果
    uint16_t headCheck;     // 包头段校验结果，用于校验包头段的完整性（ 从 head 到 dataCheck ）
} packHead_s;

/*
 * @brief      为 GRAPH_RGB565, GRAPH_RGB555, GRAPH_GRAY8 类型图像填充符合要求的协议数据
 * @param      packBuffer  数据包缓冲区指针
 * @param      packBufferLen  数据包缓冲区长度
 * @param      dataBuffer  数据段缓冲区指针
 * @param      dataBufferLen  数据段长度
 * @param      dataType  数据类型，支持 GRAPH_RGB565, GRAPH_RGB555, GRAPH_GRAY8
 * @param      width  图像宽度
 * @param      height  图像高度
 * @return     <=0 失败 >0 填充的实际长度
 */
int32_t fill_pack_for_pixel_image(void* packBuffer, int32_t packBufferLen, void* dataBuffer, int32_t dataBufferLen, dataType_e dataType, int32_t width, int32_t height);

/*
 * @brief      为 GRAPH_JPG 类型图像填充符合要求的协议数据
 * @param      packBuffer  数据包缓冲区指针
 * @param      packBufferLen  数据包缓冲区长度
 * @param      dataBuffer  数据段缓冲区指针
 * @param      dataBufferLen  数据段长度
 * @param      dataType  数据类型，支持 GRAPH_JPG
 * @return     <=0 失败 >0 填充的实际长度
 */

int32_t fill_pack_for_jpg        (void* packBuffer, int32_t packBufferLen, void* dataBuffer, int32_t dataBufferLen, dataType_e dataType);

int32_t fill_pack_for_text_log(void* packBuffer, int32_t packBufferLen, int32_t windowID, const char *format, ...);

int32_t fill_pack_for_curve(void* packBuffer, int32_t packBufferLen, dataType_e dataType, int32_t windowID, int32_t curveNum, ...);

#endif
