#ifndef __DLT645_H__
#define __DLT645_H__
#include <stdint.h>
#include <time.h>
//
#define DL645_START_CODE 0x68
#define DL645_STOP_CODE 0x16

#define DL645_PREMBLE_ENABLE 0 // 前导码使能标记
#define DL645_PREMBLE 0xFE     // 前导码

#define DL645_ADDR_LEN 6    // 设备地址长度
#define DL645_CONTROL_POS 8 // 控制码位置
#define DL645_LEN_POS 9     // 长度位置
#define DL645_DATA_POS 10   // 数据位置
#define DL645_WR_LEN 50     // 写入数据命令的长度
#define DL645_RESP_LEN 60   // 读取数据命令的长度

typedef enum dlt645_ext_type
{
    DLT645_EXT_UNSIGNED,
    DLT645_EXT_SIGNED,
    DLT645_EXT_MAX
} dlt645_ext_t;
typedef struct dlt645_hd_t dlt645_hd_t;

/* Raw data callback function types */
typedef void (*dlt645_raw_send_cb_t)(dlt645_hd_t *ctx, const uint8_t *data, int data_length, void *channel);
typedef void (*dlt645_raw_receive_cb_t)(dlt645_hd_t *ctx, const uint8_t *data, int data_length, void *channel);
typedef struct dlt645_if
{
    int (*dlt645_connect)(dlt645_hd_t *hd);
    int (*dlt645_tx)(dlt645_hd_t *hd, void *buff, uint32_t len);
    int (*dlt645_rx)(dlt645_hd_t *hd, void *buff, uint32_t max_len);
    int (*dlt645_flush)(dlt645_hd_t *hd);
    int (*dlt645_dis_connect)(dlt645_hd_t *hd);
    int (*dlt645_free)(dlt645_hd_t *hd);
} dlt645_if_t;

typedef enum
{
    DLT645_2007 = 0,
    DLT645_1997
} dlt645_protocal_t;

struct dlt645_hd_t
{
    char name[32];
    int fd;
    int error_recovery;
    dlt645_protocal_t proto_ver;
    dlt645_if_t *if_funs;
    void *data;
    uint32_t read_time_out;
    uint32_t interval;
    int32_t frame_gap;
    uint64_t lastread;
    /* Raw data callback functions */
    dlt645_raw_send_cb_t raw_send_cb;
    void *raw_send_channel;
    dlt645_raw_receive_cb_t raw_receive_cb;
    void *raw_receive_channel;
};

typedef struct dlt645_com_head
{
    uint8_t start_code1;
    uint8_t addr[DL645_ADDR_LEN];
    uint8_t start_code2;
    uint8_t ctrl_code;
    uint8_t data_len;
    uint8_t data[0];
} __attribute__((aligned(1))) dlt645_com_head;

typedef struct dlt645_2007_head
{
    dlt645_com_head com;
    uint8_t di[4];
    uint8_t data[0];
} __attribute__((aligned(1))) dlt645_2007_head;

typedef struct dlt645_2007_ask
{
    dlt645_2007_head head;
    uint8_t sum;
    uint8_t end_code;
} __attribute__((aligned(1))) dlt645_2007_ask;

typedef struct dlt645_1997_head
{
    dlt645_com_head com;
    uint8_t di[2];
    uint8_t data[0];
} __attribute__((aligned(1))) dlt645_1997_head;

typedef struct dlt645_1997_ask
{
    dlt645_1997_head head;
    uint8_t sum;
    uint8_t end_code;
} __attribute__((aligned(1))) dlt645_1997_ask;

typedef struct dlt645_item
{
    uint32_t data_id;
    dlt645_ext_t type;
    int pos;
    uint8_t data_len;
} dlt645_item;

dlt645_hd_t new_dlt645(char *ip_or_dev, uint16_t port);

dlt645_ext_t dlt645_get_ext_type_by_string(char *typeString);
dlt645_hd_t *new_dlt645_tcp(char *ip_or_dev, uint16_t port, dlt645_protocal_t dlt645_ver);
dlt645_hd_t *new_dlt645_udp(char *ip_or_dev, uint16_t port, dlt645_protocal_t dlt645_ver);
dlt645_hd_t *new_dlt645_uart(char *dev, int baud, uint8_t data_bit, uint8_t stop_bit, char parity, dlt645_protocal_t dlt645_ver);
int dlt645_connect(dlt645_hd_t *hd);
int dlt645_dis_connect(dlt645_hd_t *hd);
int dlt645_free(dlt645_hd_t *hd);
int dlt645_read_data(dlt645_hd_t *hd, uint8_t *bcd_addr, int (*get_raw_data)(char *data, int len, void *contex), void *contex, dlt645_item *it, void *buff, uint32_t max_len);
int dlt645_set_time(dlt645_hd_t *hd, uint32_t timeout_ms, uint32_t interval);
int dlt645_set_name(dlt645_hd_t *hd, char *new_name);
int dlt645_sync_date_time(dlt645_hd_t *hd, time_t time_stamp);
int dlt645_analysis(dlt645_item *it, void *ack_buf, int len, uint8_t *bcd_addr, void *dist_buff, unsigned int max_len);
/* Set raw data callback functions */
void dlt645_set_raw_send_callback(dlt645_hd_t *hd, void (*cb)(dlt645_hd_t *hd, const uint8_t *data, int data_length, void *channel), void *channel);
void dlt645_set_raw_receive_callback(dlt645_hd_t *hd, void (*cb)(dlt645_hd_t *hd, const uint8_t *data, int data_length, void *channel), void *channel);

#define DLT745_RX_BUFF_MAX 128

// 功能码
#define C_2007_CODE_BRC 0x08 // 广播校时
#define C_2007_CODE_RD 0X11  // 读数据
#define C_2007_CODE_RDM 0x12 // 读后续数据
#define C_2007_CODE_RDA 0x13 // 读通信地址
#define C_2007_CODE_WR 0x14  // 写数据
#define C_2007_CODE_WRA 0x15 // 写通信地址
#define C_2007_CODE_DJ 0x16  // 冻结
#define C_2007_CODE_BR 0x17  // 更改通信速率
#define C_2007_CODE_PD 0x18  // 修改密码
#define C_2007_CODE_XL 0x19  // 最大需量清零
#define C_2007_CODE_DB 0x1a  // 电表清零
#define C_2007_CODE_MSG 0x1b // 事件清零

#define C_1997_CODE_BRC 0x08 // 广播校时
#define C_1997_CODE_RD 0x01  // 读数据
#define C_1997_CODE_RDM 0x02 // 读后续数据
#define C_1997_CODE_WR 0x04  // 写数据
#define C_1997_CODE_WRA 0x0A // 写设备地址
#define C_1997_CODE_BR 0x0C  // 更改通信速率
#define C_1997_CODE_PD 0x0F  // 修改密码
#define C_1997_CODE_XL 0x10  // 最大需量清零
#define C_1997_CEODE_RR 0x03 // 重读数据

#define C_TD_MASK 0x80 // 主从标志位
#define C_TD_POS 7     // 主从标志位比特位
#define C_TD_MASTER 0  // 主站发出的命令帧
#define C_TD_SLAVE 1   // 从站发出的应答帧

#define C_ACK_MASK 0x40 // 从站是否正确应答标志位
#define C_ACK_POS 6     // 从站应答标志位比特位
#define C_ACK_OK 0      // 从站应答正确
#define C_ACK_ERR 1     // 从站应答错误

#define C_FU_MASK 0x20 // 是否有后续帧标志位
#define C_FU_POS 5     // 后续帧标志位比特位
#define C_FU_NONE 0    // 无后续帧
#define C_FU_EXT 1     // 有后续帧

#define C_CODE_MASK 0x1F // 功能码标志位

#endif
