#ifndef __ADEMCO_H__
#define __ADEMCO_H__

#pragma once

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

#include "ademco_config.h"
#include "ademco_version.h"

#ifdef __cplusplus
extern "C" {
#endif

// Prototypes
typedef uint32_t ademco_id_t;
typedef uint8_t ademco_gg_t;
typedef uint16_t ademco_zone_t;

#define ADEMCO_OK 0
#define ADEMCO_ERR -1

#define ADEMCO_PACKET_ACCT_MIN_LEN 6                // #acct之acct最小长度
#define ADEMCO_PACKET_ACCT_MAX_LEN 18               // #acct之acct最大长度
#define ADEMCO_PACKET_ACCT_MAC_LEN 12               // WiFi主机账号使用MAC地址
#define ADEMCO_PACKET_PWD_MIN_LEN 6                 // 主机密码最小长度
#define ADEMCO_PACKET_PWD_MAX_LEN 8                 // 主机密码最大长度
#define ADEMCO_PACKET_DATA_SEGMENT_EMPTY_LEN 2      // 空data段[]长度
#define ADEMCO_PACKET_DATA_SEGMENT_FULL_LEN 21      // 非空data段长度,acct长度6
#define ADEMCO_PACKET_DATA_SEGMENT_FULL_LEN_MAX 64  // 非空data段长度,acct长度未知
#define ADEMCO_PACKET_MAX_LEN 512                   // 安定宝协议最大长度,包括前缀、后缀、data段、xdata段
#define CONGWIN_FE100_PACKET_LEN 31                 // 丛文FE100协议长度
#define ADEMCO_PACKET_TIMESTAMP_LEN 20              // 时间戳长度
#define ADEMCO_PACKET_XDATA_MAX_LEN 128             // xdata段最大长度

// 安定宝ID范围
#define ADEMCO_ID_INVALID 0
#define ADEMCO_ID_MIN 1
#define ADEMCO_ID_MAX 999999  // 兼容性考虑,最大安定宝 ID 为 0x0F423F
#define ADEMCO_ID_SENTINEL (ADEMCO_ID_MAX + 1)
#define ADEMCO_ID_MASK 0xFFFFFF
#define ademco_is_valid_ademco_id(ademco_id) \
    ((ADEMCO_ID_MIN <= (ademco_id)) && ((ademco_id) <= ADEMCO_ID_MAX))

// 防区号为0时表示主机自身
#define ADEMCO_ZONE_FOR_MACHINE_SELF 0
// 主机防区号范围
#define ADEMCO_ZONE_MIN 1
// 对任何主机类型,最大的防区号
#define ADEMCO_ZONE_MAX 999
#define ADEMCO_ZONE_SENTINEL (ADEMCO_ZONE_MAX + 1)
#define ADEMCO_ZONE_MASK 0xFFFF

// 对任何主机类型,防区号是否合法(可以包含0防区)
#define ademco_is_valid_zone(zone) \
    ((ADEMCO_ZONE_FOR_MACHINE_SELF <= (zone)) && ((zone) <= ADEMCO_ZONE_MAX))

// 对任何主机类型,防区号是否合法(不可以包含0防区)
#define ademco_is_valid_zone_strict(zone) \
    ((ADEMCO_ZONE_MIN <= (zone)) && ((zone) <= ADEMCO_ZONE_MAX))

#define ADEMCO_GG_MIN 0
#define ADEMCO_GG_MAX 99
#define ADEMCO_GG_SENTINEL 100
#define ADEMCO_GG_MASK 0xFF

// 信号强度范围 [0, 31]
#define ADEMCO_SIGNAL_STRENGTH_MIN 0
#define ADEMCO_SIGNAL_STRENGTH_MAX 31

// 主机或分机状态报告
#define ADEMCO_STATUS_EVENTS_MAP(XX) \
    XX(ARM, 3400, "布防")            \
    XX(DISARM, 1400, "撤防")         \
    XX(HALFARM, 3456, "半布防")      \
    XX(HALFARM_1456, 1456, "半布防") \
    XX(EMERGENCY, 1120, "紧急报警")

// 防区报警
#define ADEMCO_ALARM_EVENTS_MAP(XX)   \
    XX(BURGLAR, 1130, "盗警")         \
    XX(DOORRINGING, 1134, "门铃")     \
    XX(FIRE, 1110, "火警")            \
    XX(DURESS, 1121, "胁迫")          \
    XX(GAS, 1151, "煤气")             \
    XX(WATER, 1113, "水警")           \
    XX(TAMPER, 1137, "主机防拆")      \
    XX(ZONE_TAMPER, 1383, "防区防拆") \
    XX(BYPASS, 1570, "旁路")

// 防区异常
#define ADEMCO_EXEPTION_EVENTS_MAP(XX)      \
    XX(AC_BROKE, 1301, "主机AC掉电")        \
    XX(LOWBATTERY, 1302, "低电")            \
    XX(BADBATTERY, 1311, "坏电")            \
    XX(SOLARDISTURB, 1387, "光扰")          \
    XX(DISCONNECT, 1381, "失效")            \
    XX(LOST, 1393, "失联")                  \
    XX(BATTERY_EXCEPTION, 1384, "电源故障") \
    XX(OTHER_EXCEPTION, 1380, "其他故障")

// 防区异常恢复
#define ADEMCO_RESUME_EVENTS_MAP(XX)                    \
    XX(BYPASS_RESUME, 3570, "解除旁路")                 \
    XX(AC_RECOVER, 3301, "主机AC复电")                  \
    XX(BATTERY_RECOVER, 3302, "低电恢复")               \
    XX(BADBATTERY_RECOVER, 3311, "坏电恢复")            \
    XX(SOLARDISTURB_RECOVER, 3387, "光扰恢复")          \
    XX(RECONNECT, 3381, "失效恢复")                     \
    XX(LOST_RECOVER, 3393, "失联恢复")                  \
    XX(BATTERY_EXCEPTION_RECOVER, 3384, "电源故障恢复") \
    XX(OTHER_EXCEPTION_RECOVER, 3380, "其他故障恢复")   \
    XX(CLEAR_EXCPTION, 3100, "清除异常指示")

// 恒博自定义安定宝事件码
#define ADEMCO_HB_EVENTS_MAP(XX)                               \
    XX(SERIAL485DIS, 1485, "485断开")                          \
    XX(SERIAL485CONN, 3485, "485连接")                         \
    XX(CONN_HANGUP, 1700, "链路挂起")                          \
    XX(CONN_RESUME, 3700, "链路恢复")                          \
    XX(DISARM_PWD_ERR, 1701, "撤防密码错误")                   \
    XX(SUB_MACHINE_SENSOR_EXCEPTION, 1702, "分机探头异常")     \
    XX(SUB_MACHINE_SENSOR_RESUME, 3702, "分机探头恢复")        \
    XX(SUB_MACHINE_POWER_EXCEPTION, 1703, "分机电源异常")      \
    XX(SUB_MACHINE_POWER_RESUME, 3703, "分机电源恢复")         \
    XX(COM_PASSTHROUGH, 1704, "串口透传")                      \
    XX(ENTER_SET_MODE, 2704, "进入设置状态")                   \
    XX(EXIT_SET_MODE, 3704, "退出设置状态")                    \
    XX(QUERY_SUB_MACHINE, 1705, "查询分机信息")                \
    XX(WRITE_TO_MACHINE, 1706, "写入主机信息")                 \
    XX(I_AM_NET_MODULE, 1707, "主机类型--网络模块")            \
    XX(I_AM_GPRS, 1717, "主机类型--GPRS主机")                  \
    XX(I_AM_LCD_MACHINE, 1727, "主机类型--液晶主机")           \
    XX(I_AM_WIRE_MACHINE, 1737, "主机类型--网线主机")          \
    XX(I_AM_WIFI_MACHINE, 1747, "主机类型--WiFi主机(停用)")    \
    XX(I_AM_3_SECTION_MACHINE, 1757, "主机类型--三区段主机")   \
    XX(I_AM_IOT_MACHINE, 1767, "主机类型--物联卡主机")         \
    XX(I_AM_TRUE_COLOR, 1777, "主机类型--真彩主机")            \
    XX(I_AM_GPRS_IOT, 1787, "主机类型--物联卡主机")            \
    XX(I_AM_GPRS_PHONE, 1797, "主机类型--GRPS主机带电话功能")  \
    XX(I_AM_NB_MACHINE, 1807, "主机类型--NB报警接收主机")      \
    XX(I_AM_WIFI2_MACHINE, 1817, "主机类型--WiFi主机(新版)")   \
    XX(PHONE_USER_SOS, 1709, "手机用户SOS")                    \
    XX(PHONE_USER_CANCLE_ALARM, 1711, "手机用户消警")          \
    XX(ENTER_SETTING_MODE, 1712, "主机进入设置状态")           \
    XX(EXIT_SETTING_MODE, 3712, "主机退出设置状态")            \
    XX(RESTORE_FACTORY_SETTINGS_710, 1710, "主机恢复出厂设置") \
    XX(RESTORE_FACTORY_SETTINGS, 1713, "主机恢复出厂设置")     \
    XX(SIM_IS_IOT_CARD, 1756, "物联卡")                        \
    XX(SIM_IS_IOT_PLATFORM_CARD, 2756, "平台物联卡")           \
    XX(SIM_IS_NOT_IOT_CARD, 3756, "非物联卡")                  \
    XX(WHAT_IS_YOUR_TYPE, 1798, "索要主机类型")                \
    XX(SIGNAL_STRENGTH_CHANGED, 1799, "信号强度")              \
    XX(OFFLINE, 1944, "主机断线")                              \
    XX(ONLINE, 1946, "主机上线")

// Ademco events
typedef enum ademco_event_t {
    EVENT_INVALID_EVENT = 0,

#define XX(name, code, zh) EVENT_##name = code,

    // ----标准安定宝协议事件----
    // 主机状态
    ADEMCO_STATUS_EVENTS_MAP(XX)
    // 防区报警
    ADEMCO_ALARM_EVENTS_MAP(XX)
    // 防区异常
    ADEMCO_EXEPTION_EVENTS_MAP(XX)
    // 防区异常恢复
    ADEMCO_RESUME_EVENTS_MAP(XX)

    // ---私有事件---------
    ADEMCO_HB_EVENTS_MAP(XX)
#undef XX

#define ADEMCO_EVENT_SENTINEL 10000

} ademco_event_t;

// 安定宝事件级别
typedef enum ademco_event_level_t {
    EVENT_LEVEL_NULL,
    EVENT_LEVEL_STATUS,            // 主机状态
    EVENT_LEVEL_EXCEPTION_RESUME,  // 黄色报警
    EVENT_LEVEL_EXCEPTION,         // 橙色报警
    EVENT_LEVEL_ALARM,             // 红色报警
} ademco_event_level_t;

// 安定宝协议解析结果
typedef enum ademco_parse_result_t {
    ADEMCO_PARSE_RESULT_OK,          // 解析到正确、完整的一包
    ADEMCO_PARSE_RESULT_NOT_ENOUGH,  // 解析到正确、不完整的一包,需要缓存数据,下次继续处理
    ADEMCO_PARSE_RESULT_ERROR,       // 解析到错误的数据,应当丢弃该数据包,丢弃长度为 *ate
} ademco_parse_result_t;

// 安定宝协议解析错误信息
typedef struct ademco_parse_error_t {
    const char* file;  // user do not free
    int line;          // line number in ademco.c
    size_t offset;     // error offset
    const char* msg;   // user do not free
} ademco_parse_error_t;

// 安定宝协议data段
typedef struct ademco_data_t {
    ademco_char_t raw[ADEMCO_PACKET_DATA_SEGMENT_FULL_LEN_MAX];
    size_t raw_len;
    ademco_id_t ademco_id;
    ademco_event_t ademco_event;
    ademco_gg_t gg;
    ademco_zone_t zone;
} ademco_data_t;

typedef enum ademco_xdata_length_format_t {
    ADEMCO_XDATA_LENGTH_FMT_TWO_HEX,       // 两个hex字节表示长度
    ADEMCO_XDATA_LENGTH_FMT_FOUR_DECIMAL,  // 四个decimal char 表示长度
} ademco_xdata_length_format_t;

typedef enum ademco_xdata_transform_t {
    ADEMCO_XDATA_TRANSFORM_AS_IS,     // 原样打包
    ADEMCO_XDATA_TRANSFORM_TO_ASCII,  // 转为ascii打包,如 0xEB 0xBA 打包为 "EBBA"
} ademco_xdata_transform_t;

typedef struct ademco_xdata_t {
    ademco_xdata_length_format_t lenghFormat;
    ademco_char_t raw[ADEMCO_PACKET_XDATA_MAX_LEN];
    size_t raw_len;
} ademco_xdata_t;

#define ADEMCO_PACKET_ID_NULL "\"NULL\""
#define ADEMCO_PACKET_ID_ACK "\"ACK\""
#define ADEMCO_PACKET_ID_NAK "\"NAK\""
#define ADEMCO_PACKET_ID_DUH "\"DUH\""
#define ADEMCO_PACKET_ID_HB "\"HENG-BO\""
#define ADEMCO_PACKET_ID_ADM_CID "\"ADM-CID\""
#define ADEMCO_PACKET_ID_MOD_REG "\"MODULE_REG\""
#define ADEMCO_PACKET_ID_REG_RSP "\"REG-RSP\""

typedef enum ademco_packet_id_t {
    AID_NULL,
    AID_ACK,
    AID_NAK,
    AID_DUH,
    AID_HB,
    AID_ADM_CID,
    AID_MOD_REG,
    AID_REG_RSP,
    AID_COUNT,
    AID_INVALID = -1,
} ademco_packet_id_t;

#define ADEMCO_RRCVR_DEFAULT "R123ABC"
#define ADEMCO_LPREF_DEFAULT "L456DEF"

#define ADEMCO_PACKET_PREFIX '\n'
#define ADEMCO_PACKET_SUFIX '\r'

typedef struct ademco_packet_t {
    uint16_t crc;
    size_t len;
    ademco_packet_id_t id;
    uint16_t seq;
    // +1 for '\0'
    char acct[ADEMCO_PACKET_ACCT_MAX_LEN + 1];
    ademco_data_t data;
    ademco_xdata_t xdata;
    time_t timestamp;

    ademco_char_t raw[ADEMCO_PACKET_MAX_LEN];
    size_t raw_len;
} ademco_packet_t;

/* control source defs
 * 范围 0~255
 * 0: 主机
 * 1~50: 遥控器
 * 51~97: 智能家居
 * 98: 中转接警中心
 * 99: 直连接警中心
 * 100~199: 手机APP,末二位为手机尾号
 * 200: web用户,web端包括 网页,H5, 公众号,小程序等
 * 201~255: web分享用户
 * 特别注意:三区段主机,0 代表主机,1~255 都是遥控器
 */
#define ADEMCO_CONTROL_SOURCES_MAP(XX)                \
    XX(MACHINE, 0, "主机")                            \
    XX(REMOTE, 1, "遥控器")                           \
    XX(REMOTE_MAX, 50, "遥控器MAX")                   \
    XX(SMART_HOME_ALEXA, 51, "Amazon Alexa")          \
    XX(SMART_HOME_GOOGLE, 52, "Google Home")          \
    XX(SMART_HOME_APPLE, 54, "Apple Homekit")         \
    XX(SMART_HOME_SAMSUNG, 55, "Samsung Smartthings") \
    XX(SMART_HOME_ALI_GENIE, 56, "阿里天猫精灵")      \
    XX(SMART_HOME_MI_AI, 57, "小米小爱同学")          \
    XX(SMART_HOME_BAIDU, 58, "百度小度")              \
    XX(SMART_HOME_MAX, 97, "智能家居MAX")             \
    XX(CENTER_TRANSMIT, 98, "中转接警中心")           \
    XX(CENTER_DIRECT, 99, "直连接警中心")             \
    XX(PHONE_APP, 100, "手机APP")                     \
    XX(PHONE_APP_MAX, 199, "手机APP_MAX")             \
    XX(OWNER, 200, "web用户")                         \
    XX(SHAREE, 201, "web分享用户")                    \
    XX(SHAREE_MAX, 255, "web分享用户MAX")

typedef enum ademco_control_source_t {
#define XX(name, code, zh) ADEMCO_CONTROL_SOURCE_##name = code,
    ADEMCO_CONTROL_SOURCES_MAP(XX)
#undef XX
} ademco_control_source_t;

//////////////////////// Functions ////////////////////////

ADEMCO_EXPORT_SYMBOL
uint32_t ademco_version(void);

ADEMCO_EXPORT_SYMBOL
const char* ademco_version_string(void);

ADEMCO_EXPORT_SYMBOL
void ademco_print(const ademco_char_t* buff, size_t len);

ADEMCO_EXPORT_SYMBOL
uint8_t ademco_encode_signal_strength(uint8_t strength);

ADEMCO_EXPORT_SYMBOL
uint8_t ademco_decode_signal_strength(uint8_t code);

// 是否合法主机账号
ADEMCO_EXPORT_SYMBOL
int ademco_is_valid_account(const char* acct);

//////////////////////// ademco_event_t functions ////////////////////////

// 是否主机状态事件
ADEMCO_EXPORT_SYMBOL
int ademco_is_machine_status_event(ademco_event_t ademco_event);

// 是否主机类型事件
ADEMCO_EXPORT_SYMBOL
int ademco_is_machine_type_event(ademco_event_t ademco_event);

// 事件是否需要控制源
ADEMCO_EXPORT_SYMBOL
int ademco_is_event_need_control_source(ademco_event_t ademco_event);

// 获取安定宝事件级别
ADEMCO_EXPORT_SYMBOL
ademco_event_level_t ademco_get_event_level(ademco_event_t ademco_event);

// 获取异常恢复事件所对应的异常事件
ADEMCO_EXPORT_SYMBOL
ademco_event_t ademco_get_exception_event_by_resume_event(ademco_event_t resumeEvent);

ADEMCO_EXPORT_SYMBOL
const char* ademco_event_to_string(ademco_event_t ademco_event);

#if ADEMCO_ENABLE_CHINESE
ADEMCO_EXPORT_SYMBOL
const char* ademco_event_to_string_chinese(ademco_event_t ademco_event);
#endif

//////////////////////// ademco_data_t functions ////////////////////////

// make a `DATA` packet and store to `packet`, return length
ADEMCO_EXPORT_SYMBOL
size_t ademco_append_data(ademco_char_t* packet,
                          const char* acct,
                          ademco_id_t ademco_id,
                          ademco_event_t ademco_event,
                          ademco_gg_t gg,
                          ademco_zone_t zone);

// make a `DATA` packet and store to `ademco_data`, return length
ADEMCO_EXPORT_SYMBOL
size_t ademco_append_data2(ademco_data_t* ademco_data,
                           const char* acct,
                           ademco_id_t ademco_id,
                           ademco_event_t ademco_event,
                           ademco_gg_t gg,
                           ademco_zone_t zone);

// parse `DATA` packet, if ok, `ademco_data`'s members will be useful
// err can be NULL; caller should only check err on got ADEMCO_PARSE_RESULT_ERROR
ADEMCO_EXPORT_SYMBOL
ademco_parse_result_t ademco_parse_data(const ademco_char_t* packet,
                                        size_t packet_len,
                                        ademco_data_t* ademco_data,
                                        ademco_parse_error_t* err);

// return 0 for empty packet, CONGWIN_FE100_PACKET_LEN for success
ADEMCO_EXPORT_SYMBOL
size_t ademco_data_to_congwin_fe100(ademco_char_t* fe100,
                                    size_t fe100_len,
                                    const ademco_data_t* ademco_data);

//////////////////////// ademco_xdata_t functions ////////////////////////

// init a empty xdata
ADEMCO_EXPORT_SYMBOL
void ademco_xdata_init(ademco_xdata_t* xdata);

// return ADEMCO_OK for success, ADEMCO_ERR for failed
ADEMCO_EXPORT_SYMBOL
int ademco_xdata_convert(ademco_xdata_t* xdata, ademco_xdata_length_format_t xlf);

#ifndef SWIG
// get valid content address of xdata (except [len])
ADEMCO_EXPORT_SYMBOL
const char* ademco_xdata_get_valid_content_addr(const ademco_xdata_t* xdata);
#endif

// get valid content length of xdata (except [len])
ADEMCO_EXPORT_SYMBOL
size_t ademco_xdata_get_valid_content_len(const ademco_xdata_t* xdata);

// return 0 if xdata's valid content is exactly the same as [buf, buf+buf_len)
ADEMCO_EXPORT_SYMBOL
int ademco_xdata_memcmp(const ademco_xdata_t* xdata,
                        const void* buf,
                        size_t buf_len);

// copy xdata content from src to dst, return copied length = src.raw_len
ADEMCO_EXPORT_SYMBOL
size_t ademco_xdata_copy(ademco_xdata_t* dst,
                         const ademco_xdata_t* src);

// return ADEMCO_OK for success, return ADEMCO_ERR for len is too long
ADEMCO_EXPORT_SYMBOL
int ademco_make_xdata(ademco_xdata_t* xdata,
                      ademco_xdata_length_format_t xlf,
                      ademco_xdata_transform_t xtr,
                      const ademco_char_t* content,
                      size_t len);

//////////////////////// ademco_packet_id_t functions ////////////////////////

ADEMCO_EXPORT_SYMBOL
int ademco_is_valid_packet_id(const char* standard,
                              const char* id,
                              size_t len);

ADEMCO_EXPORT_SYMBOL
ademco_packet_id_t ademco_packet_id_from_string(const char* id,
                                                size_t len);

ADEMCO_EXPORT_SYMBOL
const char* ademco_packet_id_to_string(ademco_packet_id_t id);

/*
 * ademcoMake*Packet functions
 * if buff != NULL and len >= length needed, return length used and copy data to buff
 * otherwise return 0
 */

ADEMCO_EXPORT_SYMBOL
size_t ademco_make_empty_data_packet(ademco_char_t* dst_buff,
                                     size_t len,
                                     const char* id,
                                     uint16_t seq,
                                     const char* acct,
                                     ademco_id_t ademco_id);

ADEMCO_EXPORT_SYMBOL
size_t ademco_make_adm_empty_data_packet(ademco_char_t* dst_buff,
                                         size_t len,
                                         const char* id,
                                         uint16_t seq,
                                         const char* acct,
                                         ademco_id_t ademco_id);

ADEMCO_EXPORT_SYMBOL
size_t ademco_make_null_packet(ademco_char_t* buff,
                               size_t len,
                               uint16_t seq,
                               const char* acct,
                               ademco_id_t ademco_id);

ADEMCO_EXPORT_SYMBOL
size_t ademco_make_ack_packet(ademco_char_t* buff,
                              size_t len,
                              uint16_t seq,
                              const char* acct,
                              ademco_id_t ademco_id);

ADEMCO_EXPORT_SYMBOL
size_t ademco_make_nak_packet(ademco_char_t* buff,
                              size_t len,
                              uint16_t seq,
                              const char* acct,
                              ademco_id_t ademco_id);

ADEMCO_EXPORT_SYMBOL
size_t ademco_make_hb_packet(ademco_char_t* buff,
                             size_t len,
                             uint16_t seq,
                             const char* acct,
                             ademco_id_t ademco_id,
                             ademco_event_t ademco_event,
                             ademco_gg_t gg,
                             ademco_zone_t zone,
                             const ademco_xdata_t* xdata);

ADEMCO_EXPORT_SYMBOL
size_t ademco_make_adm_packet(ademco_char_t* buff,
                              size_t len,
                              uint16_t seq,
                              const char* acct,
                              ademco_id_t ademco_id,
                              ademco_event_t ademco_event,
                              ademco_gg_t gg,
                              ademco_zone_t zone,
                              const ademco_xdata_t* xdata);

// like upper funcs, store buff and len to pkt->raw, pkt->raw_len
ADEMCO_EXPORT_SYMBOL
size_t ademco_make_null_packet2(ademco_packet_t* pkt,
                                uint16_t seq,
                                const char* acct,
                                ademco_id_t ademco_id);

ADEMCO_EXPORT_SYMBOL
size_t ademco_make_ack_packet2(ademco_packet_t* pkt,
                               uint16_t seq,
                               const char* acct,
                               ademco_id_t ademco_id);

ADEMCO_EXPORT_SYMBOL
size_t ademco_make_nak_packet2(ademco_packet_t* pkt,
                               uint16_t seq,
                               const char* acct,
                               ademco_id_t ademco_id);

ADEMCO_EXPORT_SYMBOL
size_t ademco_make_hb_packet2(ademco_packet_t* pkt,
                              uint16_t seq,
                              const char* acct,
                              ademco_id_t ademco_id,
                              ademco_event_t ademco_event,
                              ademco_gg_t gg,
                              ademco_zone_t zone,
                              const ademco_xdata_t* xdata);

ADEMCO_EXPORT_SYMBOL
size_t ademco_make_adm_packet2(ademco_packet_t* pkt,
                               uint16_t seq,
                               const char* acct,
                               ademco_id_t ademco_id,
                               ademco_event_t ademco_event,
                               ademco_gg_t gg,
                               ademco_zone_t zone,
                               const ademco_xdata_t* xdata);

// parse a ademco packet, if everything is OK, cb_commited is the packet length
// err can be NULL; caller should only check err on got ADEMCO_PARSE_RESULT_ERROR
ADEMCO_EXPORT_SYMBOL
ademco_parse_result_t ademco_parse_packet(const ademco_char_t* buff,
                                          size_t len,
                                          ademco_packet_t* pkt,
                                          size_t* cb_commited,
                                          ademco_parse_error_t* err);

/* CRC16 implementation according to ARC
 * Name                       : CRC-16/ARC
 * Alias					  : ARC, CRC-16, CRC-16/LHA, CRC-IBM
 * Width                      : 16 bit
 * Poly                       : 0x8005 (That is actually x^16 + x^15 + x^2 + 1)
 * Initialization             : 0x0000
 * Reflect Input byte         : True
 * Reflect Output CRC         : True
 * Xor constant to output CRC : 0x0000
 * Output for "123456789"     : 0xBB3D
 */
ADEMCO_EXPORT_SYMBOL
uint16_t ademco_crc16(const ademco_char_t* buff, size_t len);

// 将一串以高低字节表示的十六进制数组转换为10进制数字符串
// 每个字节的高四位和低四位若不大于9,将该四位表示的数字以10进制ascii码填入str,否则停止
// 返回字符串长度
// 注意:函数不会在str末尾补 null terminator
// 调用者应确保str有足够空间,至少len的2倍,否则会崩溃
// 示例:输入数组:0x18 0x24 0x08 0x88 0x10 0x1f 0xff,输出字符串"18240888101"
ADEMCO_EXPORT_SYMBOL
size_t ademco_hilo_array_to_dec_str(ademco_char_t* str,
                                    const uint8_t* arr,
                                    size_t len);

// 将一串以高低字节表示的十六进制数组转换为字符串
// 每个字节的高四位和低四位若不大于9,将该四位表示的数字以10进制ascii码填入str,否则:
// 若定长6字节包含a~f,说明是WiFi主机
// 返回字符串长度
// 注意:函数不会在str末尾补 null terminator
// 调用者应确保str有足够空间,至少len的2倍,否则会崩溃
// 示例:输入数组:0x18 0x24 0x08 0x88 0x10 0x1f 0xff,输出字符串"18240888101"
// 示例:输入数组:0x24 0x94 0x94 0x4c 0x48 0x15 0xff,输出字符串"2494944C4815"
ADEMCO_EXPORT_SYMBOL
size_t ademco_hilo_array_to_hex_str(ademco_char_t* str,
                                    const uint8_t* arr,
                                    size_t len);

// 将一个10进制数字符串转为高低字节表示的数组,节省空间
// str应只包含'0'~'9',否则失败返回0
// str长度若大于len * 2,str[len]及之后的内容将被舍弃以避免溢出
// 转换后的长度若不满len,则以0xF补满。
// 示例:输入字符串"123ABC",返回0
// 示例:输入字符串 "18240888101", len=9, 则arr内容为
// 0x18 0x24 0x08 0x88 0x10 0x1f 0xff 0xff 0xff
// return 9
// 示例:输入字符串 "12345678901234567890", len=9, 则arr内容为
// 0x12 0x34 0x56 0x78 0x90 0x12 0x34 0x56 0x78
// return 9
// 示例:输入NULL,返回 9个 0xFF
ADEMCO_EXPORT_SYMBOL
size_t ademco_dec_str_to_hilo_array(uint8_t* arr,
                                    size_t len,
                                    const char* str);

// 将一个16进制数字符串转为高低字节表示的数组,节省空间
// str应只包含'0'~'9', 'A'~'F', 'a'~'f',否则失败返回0
// str长度若大于len * 2,str[len]及之后的内容将被舍弃以避免溢出
// 转换后的长度若不满len,则以0xF补满。
// 示例:输入字符串"123ABC",len=6, 则 arr 内容为 0x12 0x3a 0xbc 0xff 0xff 0xff
// 示例:输入字符串 "18240888101", len=9, 则arr内容为
// 0x18 0x24 0x08 0x88 0x10 0x1f 0xff 0xff 0xff
// return 9
// 示例:输入字符串 "12345678901234567890", len=9, 则arr内容为
// 0x12 0x34 0x56 0x78 0x90 0x12 0x34 0x56 0x78
// return 9
// 示例:输入NULL,返回 9个 0xFF
ADEMCO_EXPORT_SYMBOL
size_t ademco_hex_str_to_hilo_array(uint8_t* arr,
                                    size_t len,
                                    const char* str);

// 将一串字节流转换为可打印形式
// 返回str长度(len * 2)
// 调用者应确保str有足够的容量,至少len*2
// 注意:函数不会在str末尾补 null terminator
// 示例:输入 arr=[0xEB 0xBA 0x3F], len=3, 则str = "EBBA3F",返回6
// 示例:输入 ary="123", len=3, 则str = "313233",返回6
ADEMCO_EXPORT_SYMBOL
size_t ademco_hex_array_to_str(char* str,
                               const uint8_t* arr,
                               size_t len);

// 将一串字符串(内容为'0'~'9', 'A'~'F', 'a' ~'f')转为字节流
// 若strlen(str)为奇数,以padding补足arr, padding 应 <= 0x0F
// 若str内包含非hex字符串,返回0
// 调用者应确保arr有足够的容量,至少strlen(str)*2
// 示例:输入字符串str="EBBA3F", 输出arr = [0xEB, 0xBA, 0x3F],返回 3
// 示例:输入字符串str="ABC", padding = 0, 输出arr=[0xAB, 0xC0],返回2
// 示例:输入字符串str="ABC", padding = 0x0F, 输出arr=[0xAB, 0xCF],返回2
ADEMCO_EXPORT_SYMBOL
size_t ademco_hex_str_to_array(uint8_t* arr,
                               const char* str,
                               uint8_t padding);

// 功能同ademcoHexStrToArray
// 若strlen(str) > len, str[len]及之后的内容将被舍弃以避免溢出
// 示例:输入字符串str="ABCDE", len = 4 padding = 0x0F, 输出arr=[0xAB, 0xCD], return 2
ADEMCO_EXPORT_SYMBOL
size_t ademco_hex_str_to_array_n(uint8_t* arr,
                                 const char* str,
                                 size_t len, uint8_t padding);

// 同ademcoHexStrToArrayN,但允许str包含非hex字符,
// 即'0'~'9','a'~'f','A'~'F'之外的内容,以 padding 替换
// 示例:str="AB\xFFD", len=4, padding=0x0F, 则 arr=[ 0xAB, 0xFD ], return 2
// 网线主机 0d 00 命令,接警中心账号部分,有可能是这种
ADEMCO_EXPORT_SYMBOL
size_t ademco_hex_str_to_array_n_allow_non_hex_str(uint8_t* arr,
                                                   const char* str,
                                                   size_t len,
                                                   uint8_t padding);

#ifdef __cplusplus
}
#endif

#endif  // __ADEMCO_H__