#ifndef __DLT698_H__
#define __DLT698_H__

#include <stdint.h>
#include <time.h>

#define DLT698_START_CODE 0x68
#define DLT698_STOP_CODE  0x16
#define DLT698_PREAMBLE   0xFE
#define DLT698_PREAMBLE_CNT 4
/* 1: send FE x4 before each request (ADL400 manual); 0: send frame from 0x68 only */
#ifndef DLT698_PREAMBLE_ENABLE
#define DLT698_PREAMBLE_ENABLE 1
#endif

#define DLT698_ADDR_LEN 16
#define DLT698_WR_LEN   128
#define DLT698_RESP_LEN 512
#define DLT698_RX_BUFF_MAX 512

#define DLT698_CTRL_CLIENT_REQ 0x43
#define DLT698_CTRL_SERVER_RSP 0xC3

#define DLT698_PIID_MAX 63
#define DLT698_CA_IGNORE  0x00

typedef enum dlt698_ext_type
{
    DLT698_EXT_UNSIGNED,
    DLT698_EXT_SIGNED,
    DLT698_EXT_MAX
} dlt698_ext_t;

typedef struct dlt698_hd_t dlt698_hd_t;

typedef void (*dlt698_raw_send_cb_t)(dlt698_hd_t *ctx, const uint8_t *data, int data_length, void *channel);
typedef void (*dlt698_raw_receive_cb_t)(dlt698_hd_t *ctx, const uint8_t *data, int data_length, void *channel);

struct dlt698_hd_t
{
    char name[32];
    int fd;
    int error_recovery;
    void *data;
    uint32_t read_time_out;
    uint32_t interval;
    int32_t frame_gap;
    uint64_t lastread;
    uint8_t piid;
    dlt698_raw_send_cb_t raw_send_cb;
    void *raw_send_channel;
    dlt698_raw_receive_cb_t raw_receive_cb;
    void *raw_receive_channel;
};

typedef struct dlt698_oad
{
    uint16_t oi;
    uint8_t  attr;
    uint8_t  index;
} dlt698_oad_t;

typedef struct dlt698_item
{
    dlt698_oad_t oad;
    dlt698_ext_t type;
    int pos;
    uint8_t data_len;
} dlt698_item;

typedef struct dlt698_addr
{
    uint8_t bytes[DLT698_ADDR_LEN];
    uint8_t len;
    uint8_t ca;
} dlt698_addr_t;

dlt698_ext_t dlt698_get_ext_type_by_string(char *typeString);

int dlt698_parse_addr_string(const char *addr_str, dlt698_addr_t *addr);
int dlt698_parse_oad_string(const char *oad_str, dlt698_oad_t *oad);
int dlt698_oad_equal(const dlt698_oad_t *a, const dlt698_oad_t *b);

dlt698_hd_t *new_dlt698_uart(char *dev, int baud, uint8_t data_bit, uint8_t stop_bit, char parity);
int dlt698_connect(dlt698_hd_t *hd);
int dlt698_dis_connect(dlt698_hd_t *hd);
int dlt698_free(dlt698_hd_t *hd);
int dlt698_set_time(dlt698_hd_t *hd, uint32_t timeout_ms, uint32_t interval);
int dlt698_set_name(dlt698_hd_t *hd, char *new_name);
int dlt698_set_piid(dlt698_hd_t *hd, uint8_t piid);

int dlt698_pack_get_request(const dlt698_addr_t *addr, uint8_t piid, const dlt698_oad_t *oad,
                            void *buff, int max_len);
int dlt698_read_data(dlt698_hd_t *hd, const dlt698_addr_t *addr,
                     int (*get_raw_data)(char *data, int len, void *contex), void *contex,
                     dlt698_item *it, void *buff, uint32_t max_len);
int dlt698_analysis(dlt698_item *it, void *ack_buf, int len, const dlt698_addr_t *addr,
                    void *dist_buff, unsigned int max_len);

void dlt698_set_raw_send_callback(dlt698_hd_t *hd, dlt698_raw_send_cb_t cb, void *channel);
void dlt698_set_raw_receive_callback(dlt698_hd_t *hd, dlt698_raw_receive_cb_t cb, void *channel);

uint16_t dlt698_crc16(const uint8_t *data, uint16_t len);
int dlt698_frame_check(const uint8_t *frame, int len, const dlt698_addr_t *addr);

#endif /* __DLT698_H__ */
