#include <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <libubox/utils.h>
#include <linux/ethtool.h>
#include <linux/sockios.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <sys/timerfd.h>
#include <syslog.h>

#include "dy_common.h"
#include "protocol.h"

#define SYSTEM_RUN_RESP_BUFF_LEN 1024

const char *gw_port_name[] =
    {
        "NULL",
        "LORA_DTU_RS485",
        "LORAWAN_DTU_RS485",
        "RS485_1",
        "RS485_2",
        "RS485_3",
        "RS485_4",
        "LORA_1",
        "LORAWAN_1",
        "VIRTUAL_1",
        "VINTF_MQTT",
        "MQTT_DTU_RS485",
        "VINTF_TCP",
        "VINTF_UDP",
        "MODBUS_TCP",
        "CANBUS_0",
        "CANBUS_1",
        "TCP_CLIENT",
        "VINTF_NB",
        "ZIGBEE",
        "RS232_1",
        "DI_1",
        "DO_1",
        "S7_PLC",
        "BLE",
        "LORA_2",
        "RS485_5",
        "RS485_6",
        "RS485_7",
        "RS485_8",
        "REMOTE_CH_01",
        "REMOTE_CH_02",
        "REMOTE_CH_03",
        "REMOTE_CH_04",
        "REMOTE_CH_05",
        "REMOTE_CH_06",
        "REMOTE_CH_07",
        "REMOTE_CH_08",
        "REMOTE_CH_09",
        "REMOTE_CH_10",
        "REMOTE_CH_11",
        "REMOTE_CH_12",
        "REMOTE_CH_13",
        "REMOTE_CH_14",
        "REMOTE_CH_15",
        "REMOTE_CH_16",
        "REMOTE_CH_17",
        "REMOTE_CH_18",
        "REMOTE_CH_19",
        "REMOTE_CH_20",
        "RS485_9",
        "RS485_10",
        "RS485_11",
        "RS485_12",
        "TCPDUMP",
};

const char *gw_socket_type_name[] =
    {
        "TCP",
        "UDP",
        "MQTT",
};

const char *gw_device_type_name[] =
    {
        "NULL",
        "DEV_DTU",
};

const char *tag_data_format_name[] =
    {
        "NULL",
        "INT16",
        "UINT16",
        "INT32",
        "UINT32",
        "FLOAT",

        "INT16I",
        "INT32I",
        "UINT16I",
        "UINT32I",
        "FLOATI",

        "INT8",
        "UINT8",
        "INT64",
        "UINT64",
        "VLENGTH",
};

const char *object_data_format_name[] =
    {
        "NULL",
        "int",
        "int",
        "int",
        "int",
        "float",

        "int",
        "int",
        "int",
        "int",
        "float",

        "int",
        "int",
        "int",
        "int",
        "text",
};

const char *gw_protocol_name[] =
    {
        "NULL",
        "DYWL_LORA_V1",
        "DYWL_RS485_V1",
        "GW_PROTC_MODBUS",
        "DYWL_RTU_V66",
        "WOOLINK_DTU",
};

int lnxall_condvar_init(void * _cond)
{
    int ret;
    pthread_cond_t * condp;
    pthread_condattr_t attr;

    ret = 0;
    condp = (pthread_cond_t *) _cond;
    if (condp == NULL)
        return -1;

    memset(&attr, 0, sizeof(attr));
    ret = pthread_condattr_init(&attr);
    if (ret != 0)
        goto err0;
    ret = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
    if (ret != 0)
        goto err0;

    memset(condp, 0, sizeof(*condp));
    ret = pthread_cond_init(condp, &attr);
    pthread_condattr_destroy(&attr);
    if (ret == 0)
        return 0;

err0:
    dy_syslog(LOG_ERR, "Error in [%s], failed to initialize condvar: %d",
        __func__, ret);
    return -1;
}

int lnxall_condvar_timedwait(void * _condp, void * _mutexp, unsigned int inval)
{
    int ret;
    struct timespec spec;
    pthread_cond_t * condp;
    pthread_mutex_t * mutexp;

    condp = (pthread_cond_t *) _condp;
    mutexp = (pthread_mutex_t *) _mutexp;
    if (condp == NULL || mutexp == NULL)
        return -1;

    spec.tv_sec = 0;
    spec.tv_nsec = 0;
    ret = clock_gettime(CLOCK_MONOTONIC, &spec);
    if (ret == -1) {
        /* nearly impossible, just emit a message */
        dy_syslog(LOG_ERR, "Error, failed to system boot time for condition variable!");
        return -1;
    }

    spec.tv_sec += (time_t) (inval / 1000);
    spec.tv_nsec += (long) ((inval % 1000) * 1000000);
    if (spec.tv_nsec >= 1000000000) {
        spec.tv_sec += (time_t) (spec.tv_nsec / 1000000000);
        spec.tv_nsec %= 1000000000;
    }

    ret = pthread_cond_timedwait(condp, mutexp, &spec);
    if (ret != 0 && ret != ETIMEDOUT) {
        dy_syslog(LOG_ERR, "Error, failed to wait condvar: %d (%s)",
            ret, strerror(ret) ? : "");
    }
    return ret;
}

int lnxall_msleep(unsigned int msec, int noint)
{
	int ret, intno;
	long long nowtim, nextim;

	intno = 0;
	if (msec == 0)
		return intno;

	nowtim = uptime_stamp_ms();
	nextim = nowtim + (long long) msec;
	while (nowtim < nextim) {
		struct timespec spec;
		spec.tv_sec = (time_t) ((nextim - nowtim) / 1000);
		spec.tv_nsec = (long) ((nextim - nowtim) % 1000);
		spec.tv_nsec *= 1000000;
		ret = nanosleep(&spec, NULL); /* Use remainder argument ? */
		if (ret == -1 && errno == EINTR) {
			intno++;
			if (!noint)
				break;
		}
		nowtim = uptime_stamp_ms();
	}
	return intno;
}

/**
 * 转化协议port项中字符类型为内部枚举，
 *
 * @param[c]   input char string.
 * @retval  该字符匹配成功返回：RS485_1/RS485_2/RS485_3/RS485_4/LORA_1;否则返回0
 * @par 标识符
 *      保留
 * @par 其它
 *      全词匹配，不区分大小写
 * @par 修改日志
 *      张国宏于2019-06-20创建
 */
int port_char2enum(char *c)
{
    int i;
    EACH_STRING_INDEX(c, gw_port_name, i);
    return i;
}

/**
 * 转化SOCKET协议类型项中字符类型为内部枚举，
 *
 * @param[c]   input char string.
 * @retval  该字符匹配成功返回：TCP/UDP;否则返回0
 * @par 标识符
 *      保留
 * @par 其它
 *      全词匹配，不区分大小写
 * @par 修改日志
 *      龙文件于2020-04-01创建
 */
int socket_type_char2enum(char *c)
{
    int i;
    EACH_STRING_INDEX(c, gw_socket_type_name, i);
    return i;
}

/**
 * 转化协议port项中内部枚举为字符类型，
 *
 * @param[c]   input char string.
 * @retval  该字符匹配成功返回：RS485_1/RS485_2/RS485_3/RS485_4/LORA_1;否则返回0
 * @par 标识符
 *      保留
 * @par 其它
 *      全词匹配，不区分大小写
 * @par 修改日志
 *      张国宏于2019-06-20创建
 */
const char *port_enum2char(int i)
{
    if (i >= 0 && i < sizeof(gw_port_name) / sizeof(gw_port_name[0]))
    {
        return gw_port_name[i];
    }
    else
    {
        return NULL;
    }
}
/**
 * 转化协议port项中字符类型为内部枚举，
 *
 * @param[c]   input char string.
 * @retval  该字符匹配成功返回：RS485_1/RS485_2/RS485_3/RS485_4/LORA_1;否则返回0
 * @par 标识符
 *      保留
 * @par 其它
 *      全词匹配，不区分大小写
 * @par 修改日志
 *      张国宏于2019-06-20创建
 */
int device_type_char2enum(char *c)
{
    int i;
    EACH_STRING_INDEX(c, gw_device_type_name, i);
    return i;
}

/**
 * 转化协议protocol项中字符类型为内部枚举，
 *
 * @param[c]   input char string.
 * @retval  该字符匹配成功返回：GW_PROTC_NULL/GW_PROTC_DYWL_LORA_V1/GW_PROTC_DYWL_RS485_V1/GW_PROTC_MODBUS;否则返回0
 * @par 标识符
 *      保留
 * @par 其它
 *      全词匹配,不区分大小写
 * @par 修改日志
 *      张国宏于2019-06-20创建
 */
int protocol_char2enum(char *c)
{
    int i;
    EACH_STRING_INDEX(c, gw_protocol_name, i);
    return i;
}

/**
 * 转化协议date_type项中字符类型为内部枚举，
 *
 * @param[c]   input char string.
 * @retval  该字符匹配成功返回：TAG_TYPE_NULL/TAG_TYPE_INT16/TAG_TYPE_UINT16/......;否则返回0
 * @par 标识符
 *      保留
 * @par 其它
 *      全词匹配,不区分大小写
 * @par 修改日志
 *      张国宏于2019-06-20创建
 */
int datatype_char2enum(char *c)
{
    int i;
    EACH_STRING_INDEX(c, tag_data_format_name, i);
    return i;
}

int object_datatype_char2enum(char *c)
{
    int i;
    EACH_STRING_INDEX(c, object_data_format_name, i);
    return i;
}

/**
 * 下载远程http文件
 *
 * @param[path]   下载到本地的路径
 * @param[remote_file] 远程文件资源的url
 * @param[timeout] 指定超时时间
 * @retval  0：成功;其他：失败
 * @par 标识符
 *      保留
 * @par 其它
 *      保留
 * @par 修改日志
 *      张国宏于2019-06-28创建
 */
int download_file(char *path, char *url, int timeout)
{
    int status = 0;
    char exec_cmd[256] = {0};
    if (!path || !url)
    {
        return -1;
    }
    char *file = GetFileName(url);
    sprintf(exec_cmd, "%s/%s", path, file);
    unlink(exec_cmd);
    sprintf(exec_cmd, "wget -q -t 4 -T %d \"%s\" -P %s --no-check-certificate", timeout, url, path);
    dy_syslog(LOG_INFO, "%s", exec_cmd);
    status = system(exec_cmd);
    if (WIFEXITED(status))
    {
        if (WEXITSTATUS(status) == 0)
        {
            dy_syslog(LOG_INFO, "download successful :%s", url);
            return 0;
        }
    }
    dy_syslog(LOG_ERR, "download fail: %s, status=%d", url, WEXITSTATUS(status));
    return 1;
}

int lnxall_exename(char * out, int outlen)
{
    char * tmp;
    ssize_t rl1;
#define EN_TMP_BUFSIZ 2048

    if (out == NULL || outlen <= 0)
        return -1;

    *out = '\0';
    tmp = (char *) malloc(EN_TMP_BUFSIZ);
    if (tmp == NULL)
        return -2;

    rl1 = readlink("/proc/self/exe", tmp, EN_TMP_BUFSIZ - 1);
    if (rl1 > 0) {
        int ret;
        char * p;

        tmp[rl1] = '\0';
        p = strrchr(tmp, '/');
        if (p == NULL) {
            free(tmp);
            return -3;
        }

        for (ret = 0; ret < outlen; ++ret) {
            char cha;

            p++;
            cha = *p;
            if (cha == 0)
                break;
            out[ret] = cha;
        }

        out[ret] = '\0';
        free(tmp);
        return ret;
    }

#undef EN_TMP_BUFSIZ
    free(tmp);
    return -4;
}

int download_file1(const char *path, char *url, int timeout)
{
    int status = 0;
    char exec_cmd[384] = {0};
    if (!path || !url)
    {
        return -1;
    }
    unlink(path); /* delete output file if already exists */
    sprintf(exec_cmd, "wget -q -t 4 -T %d \"%s\" -O %s --no-check-certificate", timeout, url, path);
    dy_syslog(LOG_INFO, "%s", exec_cmd);
    status = system(exec_cmd);
    if (WIFEXITED(status))
    {
        if (WEXITSTATUS(status) == 0)
        {
            dy_syslog(LOG_INFO, "download successful :%s", url);
            return 0;
        }
    }
    dy_syslog(LOG_ERR, "download fail: %s, status=%d", url, WEXITSTATUS(status));
    return 1;
}

/**
 * 校验文件的MD5
 *
 * @param[file]   文件的本地的路径
 * @param[r_md5sum] 用来比较的MD5
 * @retval  0：匹配成功;其他：失败
 * @par 标识符
 *      保留
 * @par 其它
 *      保留
 * @par 修改日志
 *      张国宏于2019-06-28创建
 */
int check_md5sum_file(char *file, char *r_md5sum)
{

    char exec_cmd[256] = {0};
    char *result_cmd = NULL;
    if (!file || !r_md5sum)
    {
        return -1;
    }
    sprintf(exec_cmd, "md5sum -b \"%s\"", file);
    int ret = system_reply(exec_cmd, &result_cmd);
    if (ret != 0)
    {
        return -1;
    }
    dy_syslog(LOG_INFO, "r_md5sum:%s, result_cmd:%s\n", r_md5sum, result_cmd);
    ret = strncasecmp(result_cmd, r_md5sum, strlen(r_md5sum));
    free(result_cmd);
    return ret;
}

/**
 * 读取json文件中mi字段作为消息流水号
 *
 * @param[str] json string
 * @retval  0：没有读取到mi;-1：读取错误
 * @par 标识符
 *      保留
 * @par 其它
 *      保留
 * @par 修改日志
 *      张国宏于2019-07-03创建
 */
int json_pkt_json_mi(const char *str)
{
    if (!str)
    {
        return -1;
    }
    cJSON *root = cJSON_Parse(str);
    if (!root)
    {
        return -1;
    }
    int mi = 0;
    GET_JSON_VALUE_INT(root, "mi", mi);
    cJSON_Delete(root);
    return mi;
}

/**
 * 读取json文件中URL字段
 *
 * @param[str] json string
 * @param[url_v] version buffer size
 * @retval  0：没有读取到version;-1：读取错误
 * @par 标识符
 *      保留
 * @par 其它
 *      保留
 * @par 修改日志
 *      张国宏于2019-08-09创建
 */
int json_pkt_json_url(const char *str, char *url_v)
{
    char buff[256];
    cJSON *root = NULL;

    if (!str || !url_v)
        return -1;

	root = cJSON_Parse(str);
    if (!root)
        return -1;

    memset(buff, 0, sizeof(buff));
    GET_JSON_VALUE_STRING(root, "URL", buff);
    if (buff[0] == '\0') {
        cJSON_Delete(root);
        return -1;
    }

    strncpy(url_v, buff, strlen(buff));
    cJSON_Delete(root);
    return 0;
}

/**
 * 为任意json字段添加mi,若字段中有mi，则会被覆盖
 *
 * @param[in] json string
 * @param[mi] json string
 * @retval  NULL：str指针内容非json结构;其他返回json字符指针，需要调用方free
 * @par 标识符
 *      保留
 * @par 其它
 *      保留
 * @par 修改日志
 *      张国宏于2019-09-03创建
 */
char *json_pkt_add_mi2str(char *in, int mi)
{
    char *out = NULL;
    if (!in)
    {
        goto error;
    }
    cJSON *root = cJSON_Parse(in);
    if (!root)
    {
        goto error;
    }
    char *ssid = cJSON_GetItemString(root, "mi");
    if (ssid)
    {
        cJSON_DeleteItemFromObject(root, "mi");
    }
    cJSON_AddNumberToObject(root, "mi", mi);
    out = cJSON_Print(root);
    cJSON_Delete(root);

error:
    return out;
}

/**
 * bytes to string
 *
 * @param[uint] bytes input point
 * @param[str] string output
 * @param[size] bytes input size
 * @retval  void
 * @par 标识符
 *      保留
 * @par 其它
 *      保留
 * @par 修改日志
 *      张国宏于2019-09-30创建
 */
void i82hexstr(unsigned char *uint, char *str, int size)
{
    /*in case that the str has a value,strcat() seems not safe*/
    int i;
    char tempstr[3];
    memset(str, '\0', size * 2 + 1);
    for (i = 0; i < size; i++)
    {
        snprintf(tempstr, sizeof(tempstr), "%02X", uint[i]);
        strcat(str, tempstr);
    }
}

/**
 * bytes to string
 *
 * @param[dest] bytes output point
 * @param[src] string input
 * @param[len] bytes converlenght
 * @retval  void
 * @par 标识符
 *      保留
 * @par 其它
 *      保留
 * @par 修改日志
 *      张国宏于2019-09-30创建
 */
void str2hex(unsigned char *dest, char *src, int len)
{
    int i;
    char ch1;
    char ch2;
    unsigned char ui1;
    unsigned char ui2;

    for (i = 0; i < len; i++)
    {
        ch1 = src[i * 2];
        ch2 = src[i * 2 + 1];
        ui1 = toupper(ch1) - 0x30;
        if (ui1 > 9)
        {
            ui1 -= 7;
        }
        ui2 = toupper(ch2) - 0x30;
        if (ui2 > 9)
        {
            ui2 -= 7;
        }
        dest[i] = ui1 * 16 + ui2;
    }
}

char *cJSON_GetItemString(const void *const object, const char *const string)
{
    cJSON *__item = cJSON_GetObjectItem(object, string);
    if (__item)
    {
        return __item->valuestring;
    }
    return NULL;
}

void mq_resource()
{
    int ret;
    struct rlimit resource;

    resource.rlim_cur = 30000000;
    resource.rlim_max = 30000000;
    ret = setrlimit(RLIMIT_MSGQUEUE, &resource);

    ret = getrlimit(RLIMIT_MSGQUEUE, &resource);
    if (ret == 0)
    {
        //dy_syslog(LOG_INFO, "cur %ld, max %ld", resource.rlim_cur, resource.rlim_max);
    }
}

void get_clock(p_clock_t *clock)
{
    struct tm tmp;
    time_t tt = time(0);

    localtime_r(&tt, &tmp);

    clock->year = tmp.tm_year + 1900;
    clock->month = tmp.tm_mon + 1;
    clock->day = tmp.tm_mday;
    clock->hour = tmp.tm_hour;
    clock->min = tmp.tm_min;
    clock->second = tmp.tm_sec;
}

time_t clock2time(p_clock_t *clock)
{
    time_t stime;
    struct tm p = {0};

    p.tm_sec = clock->second;
    p.tm_min = clock->min;
    p.tm_hour = clock->hour;
    p.tm_mday = clock->day;
    p.tm_mon = clock->month - 1;
    p.tm_year = clock->year - 1900;

    stime = mktime(&p);
    return stime;
}

void time2clock(time_t *time, p_clock_t *clock)
{
    struct tm tmp;

    localtime_r(time, &tmp);

    clock->year = tmp.tm_year + 1900;
    clock->month = tmp.tm_mon + 1;
    clock->day = tmp.tm_mday;
    clock->hour = tmp.tm_hour;
    clock->min = tmp.tm_min;
    clock->second = tmp.tm_sec;
}

/*
检查当前系统时间，并判断是否超时。如果超时，更新基准时间
timeout为差异时间，单位为毫秒
[return] 0无超时，1超时
*/
int check_timeout(struct timespec *prev, int timeout_ms)
{
    struct timespec ts;

    clock_gettime(CLOCK_MONOTONIC, &ts);

    if (((long long)ts.tv_sec * 1000 + ts.tv_nsec / 1000000) -
            ((long long)prev->tv_sec * 1000 + prev->tv_nsec / 1000000) <
        timeout_ms)
    {
        return 0;
    }

    *prev = ts;

    return 1;
}

int check_timeout_second(time_t now, time_t *prev, int timeout_s)
{
    if (now - (*prev) < timeout_s)
    {
        return 0;
    }

    *prev = now;

    return 1;
}

int check_timeout_msecond(long long now, long long *prev, int timeout_ms)
{
    if (now - (*prev) < timeout_ms)
    {
        return 0;
    }

    *prev = now;

    return 1;
}


long long clock_get_ms()
{
    struct timespec ts;

    clock_gettime(CLOCK_MONOTONIC, &ts);

    return ((long long)ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
}

int clock_diff_ms(struct timespec *now, struct timespec *prev)
{
    int d = ((long long)now->tv_sec * 1000 + now->tv_nsec / 1000000) - ((long long)prev->tv_sec * 1000 + prev->tv_nsec / 1000000);

    return d;
}

unsigned int clock_get_second()
{
    struct timespec ts;

    clock_gettime(CLOCK_MONOTONIC, &ts);

    return ts.tv_sec;
}

/*
忙等待，cpu处于忙状态
*/
void busy_wait(unsigned int us)
{
    int cnt = 0;
    struct timespec start_time, stop_time;

    clock_gettime(CLOCK_MONOTONIC, &start_time);

    while (1)
    {
        clock_gettime(CLOCK_MONOTONIC, &stop_time);
        cnt++;

        unsigned int d = ((long long)stop_time.tv_sec * 1000000 + stop_time.tv_nsec / 1000) - ((long long)start_time.tv_sec * 1000000 + start_time.tv_nsec / 1000);

        if (d >= us)
        {
            break;
        }
    }
}

/*
start_sec秒后首次触发，间隔为interval_ms毫秒，如果interval_ms == -1 则只触发一次
*/
int my_timer_set(int timer, int start_sec, int interval_ms)
{
    struct itimerspec new_value;

    new_value.it_value.tv_sec = start_sec;
    new_value.it_value.tv_nsec = 0;

    if (interval_ms >= 1000)
    {
        new_value.it_interval.tv_sec = interval_ms / 1000;
        new_value.it_interval.tv_nsec = 0;
    }
    else if (interval_ms == -1)
    {
        new_value.it_interval.tv_sec = 0;
        new_value.it_interval.tv_nsec = 0;
    }
    else
    {
        new_value.it_interval.tv_sec = 0;
        new_value.it_interval.tv_nsec = interval_ms * 1000000;
    }

    if (timerfd_settime(timer, 0, &new_value, NULL) == -1)
    {
        dy_syslog(LOG_INFO, "timerfd_settime, errno %d", errno);
        return -3;
    }

    return 0;
}

/*
参考系统时钟，start_sec秒后触发，且只触发一次
*/
int my_timer_set2(int timer, int start_sec)
{
    struct itimerspec new_value;

    struct timeval tv;

    gettimeofday(&tv, 0);

    new_value.it_value.tv_sec = tv.tv_sec + start_sec;
    new_value.it_value.tv_nsec = tv.tv_usec * 1000;

    new_value.it_interval.tv_sec = 0;
    new_value.it_interval.tv_nsec = 0;

    if (timerfd_settime(timer, TFD_TIMER_ABSTIME, &new_value, NULL) == -1)
    {
        dy_syslog(LOG_INFO, "timerfd_settime2, errno %d", errno);
        return -3;
    }

    return 0;
}

/*
start_msec毫秒后首次触发，间隔为interval_ms毫秒，如果interval_ms == -1 则只触发一次
*/
int my_timer_set_ms(int timer, int start_msec, int interval_ms)
{
    struct itimerspec new_value;

    if (start_msec < 1000)
    {
        new_value.it_value.tv_sec = 0;
        new_value.it_value.tv_nsec = start_msec * 1000000;
    }
    else
    {
        new_value.it_value.tv_sec = start_msec / 1000;
        new_value.it_value.tv_nsec = (start_msec % 1000) * 1000000;
    }

    if (interval_ms >= 1000)
    {
        new_value.it_interval.tv_sec = interval_ms / 1000;
        new_value.it_interval.tv_nsec = 0;
    }
    else if (interval_ms == -1)
    {
        new_value.it_interval.tv_sec = 0;
        new_value.it_interval.tv_nsec = 0;
    }
    else
    {
        new_value.it_interval.tv_sec = 0;
        new_value.it_interval.tv_nsec = interval_ms * 1000000;
    }

    if (timerfd_settime(timer, 0, &new_value, NULL) == -1)
    {
        dy_syslog(LOG_ERR, "timerfd_settime3, errno %d", errno);
        return -3;
    }

    return 0;
}

int my_timer_create()
{
    int fd = -1;

    int retry = 3;
    while (retry--)
    {
        fd = timerfd_create(CLOCK_REALTIME, O_NONBLOCK);
        if (fd == -1)
        {
            dy_syslog(LOG_ERR, "%s:%d timerfd_create, errno %d", __FUNCTION__, __LINE__, errno);
            return -2;
        }
        if (fd > 2)
        {
            break;
        }
        dy_syslog(LOG_WARNING, "%s:%d timerfd_create retry !!!!! ,fd %d", __FUNCTION__, __LINE__, fd);
    }

    return fd;
}

int my_timer_delete(int timer)
{
    return close(timer);
}

/*
定时器触发后的处理
*/
int my_timer_read(int timer)
{
    uint64_t exp;
    ssize_t s;

    s = read(timer, &exp, sizeof(uint64_t));
    if (s != sizeof(uint64_t))
    {
        dy_syslog(LOG_ERR, "tid %ld, timer %d read, errno %d", syscall(SYS_gettid), timer, errno);
        return -1;
    }

    return 0;
}

/*
* 内存映射方式打开文件以备读取
*/
int file_read_map(char *file_path, char **addr, int *len)
{
    struct stat file_stat;
    char *file_addr = MAP_FAILED;
    int fd, ret;

    fd = open(file_path, O_RDONLY, 0666);
    if (fd > 0)
    {
        ret = fstat(fd, &file_stat);
        if ((ret == 0) && file_stat.st_size > 0)
        {
            file_addr = mmap(0, file_stat.st_size, PROT_READ, MAP_SHARED, fd, 0);
        }
    }

    if (file_addr == MAP_FAILED)
    {
        if (fd > 0)
        {
            close(fd);
            fd = -1;
        }
    }
    else
    {
        *addr = file_addr;
        *len = file_stat.st_size;
    }

    return fd;
}

/*
* 关闭内存映射方式打开的文件
*/
void file_read_unmap(int fd, char *addr, int len)
{
    if ((addr != MAP_FAILED) && len > 0)
    {
        munmap(addr, len);
    }

    if (fd != -1)
    {
        close(fd);
    }
}

int file_set_hole(int fd, int len)
{
    int ret;

    ret = lseek(fd, len - 4, SEEK_SET);
    if (ret == -1)
    {
        dy_syslog(LOG_INFO, "hole:seek, errno %d", errno);
        return -1;
    }

    ret = 0;
    ret = write(fd, &ret, sizeof(ret));
    if (ret != sizeof(ret))
    {
        dy_syslog(LOG_INFO, "hole:write error, errno %d", errno);
        return -1;
    }

    ret = lseek(fd, 0, SEEK_SET);
    if (ret == -1)
    {
        dy_syslog(LOG_INFO, "hole:seek error 2, errno %d", errno);
        return -1;
    }

    return 0;
}

int tcp_connect_host(int fd, unsigned char server_ip[4], unsigned short server_port)
{
    int ret, connected = 0;
    struct sockaddr_in servaddr;

    memcpy(&servaddr.sin_addr.s_addr, server_ip, sizeof(servaddr.sin_addr.s_addr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(server_port);

    ret = connect(fd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    if ((ret == 0) || ((ret == -1) && (errno == EISCONN)))
    {
        connected = 1;
    }

    return connected;
}

int tcp_create_fd()
{
    int fd;

    fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (fd < 0)
    {
        dy_syslog(LOG_INFO, "create socket fail ret %d, errno %d", fd, errno);
        return -1;
    }

    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);

    return fd;
}

//基本等同于write，但当发生EINTR或EAGAIN时，等待10毫秒后重试，重试最多10次
int nwrite(int fd, void *data, int len)
{
    int ret = -1, written = 0, retry = 0;

    while (retry++ < 10)
    {
        ret = write(fd, data + written, len - written);
        if (ret < 0)
        {
            dy_syslog(LOG_INFO, "nwrite errno %d", errno);

            if (errno == EINTR)
            {
                continue;
            }
            else if (errno == EAGAIN)
            {
                usleep(10000);
                continue;
            }
            else
            {
                return -1;
            }
        }
        else if (ret > 0)
        {
            written += ret;
            if (written >= len)
            {
                break;
            }
        }
        else
        {
            break;
        }
    }

    return written;
}

//基本等同于read，但当发生EINTR或EAGAIN时，等待10毫秒后重试，重试最多10次
int nread(int fd, void *data, int len)
{
    int ret = -1, n = 0, retry = 0;

    while (retry++ < 10)
    {
        ret = read(fd, data + n, len - n);
        if (ret < 0)
        {
            dy_syslog(LOG_INFO, "nread errno %d", errno);

            if (errno == EINTR)
            {
                continue;
            }
            else if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
            {
                usleep(10000);
                continue;
            }
            else
            {
                return -1;
            }
        }
        else if (ret > 0)
        {
            n += ret;
            if (n >= len)
            {
                break;
            }
        }
        else
        {
            break;
        }
    }

    return n;
}

int net_set_mac(char *ifname, unsigned char mac[6])
{
    int sock, ret = -1;
    struct ifreq ifr;

    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0)
    {
        dy_syslog(LOG_INFO, "socket, errno %d", errno);
        return -1;
    }

    memset(&ifr, 0, sizeof(ifr));
    strcpy(ifr.ifr_name, ifname);

    if (ioctl(sock, SIOCGIFFLAGS, &ifr))
    {
        dy_syslog(LOG_INFO, "SIOCGIFFLAGS, errno %d", errno);
        goto l_err2;
    }

    strcpy(ifr.ifr_name, ifname);
    ifr.ifr_flags &= ~IFF_UP;
    if (ioctl(sock, SIOCSIFFLAGS, &ifr))
    {
        dy_syslog(LOG_INFO, "if down, errno %d", errno);
        goto l_err2;
    }

    strcpy(ifr.ifr_name, ifname);
    ifr.ifr_hwaddr.sa_family = AF_UNIX;
    memcpy(ifr.ifr_hwaddr.sa_data, mac, 6);

    ret = ioctl(sock, SIOCSIFHWADDR, &ifr, sizeof(ifr));
    if (ret)
    {
        dy_syslog(LOG_INFO, "SIOCSIFHWADDR, errno %d", errno);
        goto l_err2;
    }

    strcpy(ifr.ifr_name, ifname);
    ifr.ifr_flags |= IFF_UP;
    if (ioctl(sock, SIOCSIFFLAGS, &ifr))
    {
        dy_syslog(LOG_INFO, "if up, errno %d", errno);
        goto l_err2;
    }

    ret = 0;

l_err2:
    if (sock > 0)
    {
        close(sock);
    }
    return ret;
}

int net_get_ipv4_addr(char *ifname, unsigned int *ip)
{
    struct ifreq ifr;
    int sockfd;
    struct sockaddr_in *addr;

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    strcpy(ifr.ifr_name, ifname);

    if (ioctl(sockfd, SIOCGIFADDR, &ifr) == -1)
    {
        //perror("ioctl error");
        close(sockfd);
        return -1;
    }

    addr = (struct sockaddr_in *)&(ifr.ifr_addr);
    *ip = addr->sin_addr.s_addr;
    close(sockfd);
    return 0;
}

int net_set_ipv4_addr(char *ifname, unsigned char ip_addr[4], unsigned char mask_addr[4])
{
    int fd, ret;
    unsigned long ip, mask, broadcast;
    struct ifreq ifr;
    struct sockaddr_in sin;

    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        return -1;
    }

    /*ip address*/
    strcpy(ifr.ifr_name, ifname);
    memset(&sin, 0, sizeof(struct sockaddr));
    sin.sin_family = AF_INET;
    memcpy(&sin.sin_addr.s_addr, ip_addr, sizeof(sin.sin_addr.s_addr));
    ip = sin.sin_addr.s_addr;

    memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));

    if (ioctl(fd, SIOCSIFADDR, &ifr) < 0)
    {
        dy_syslog(LOG_INFO, "SIOCSIFADDR, errno %d", errno);
        ret = -1;
        goto l_err3;
    }

    /*net mask*/
    strcpy(ifr.ifr_name, ifname);
    memset(&sin, 0, sizeof(struct sockaddr));
    sin.sin_family = AF_INET;
    memcpy(&sin.sin_addr.s_addr, mask_addr, sizeof(sin.sin_addr.s_addr));
    mask = sin.sin_addr.s_addr;
    memcpy(&ifr.ifr_netmask, &sin, sizeof(struct sockaddr));
    if (ioctl(fd, SIOCSIFNETMASK, &ifr) < 0)
    {
        dy_syslog(LOG_INFO, "SIOCSIFNETMASK, errno %d", errno);
        ret = -1;
        goto l_err3;
    }

    /*broadcast*/
    broadcast = ip | (~mask);
    strcpy(ifr.ifr_name, ifname);
    memset(&sin, 0, sizeof(struct sockaddr));
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = broadcast;
    memcpy((char *)&ifr.ifr_broadaddr, &sin, sizeof(struct sockaddr));
    if (ioctl(fd, SIOCSIFBRDADDR, &ifr) < 0)
    {
        dy_syslog(LOG_INFO, "SIOCSIFBRDADDR, errno %d", errno);
        ret = -1;
        goto l_err3;
    }

    ret = 0;

l_err3:
    if (fd > 0)
    {
        close(fd);
    }
    return ret;
}

// if_name like "ath0", "eth0". Notice: call this function
// need root privilege.
// return value:
// -1 -- error , details can check errno
// 1 -- interface link up
// 0 -- interface link down.
int get_netlink_status(char *if_name)
{
    int skfd;
    struct ifreq ifr;
    struct ethtool_value edata;

    edata.cmd = ETHTOOL_GLINK;
    edata.data = 0;
    memset(&ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name) - 1);
    ifr.ifr_data = (char *)&edata;
    if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        return -1;
    }

    if (ioctl(skfd, SIOCETHTOOL, &ifr) == -1)
    {
        close(skfd);
        return -1;
    }

    close(skfd);
    return edata.data;
}

int get_exec_info(char *command, char *res, int buf_len)
{
    FILE *fp;

    fp = popen(command, "r");
    if (!fp)
    {
        return -1;
    }

    sleep(1);

    fgets(res, buf_len - 1, fp);

    pclose(fp);

    return 0;
}

int system_reply(char *command, char **rsp_command)
{
    FILE *fp;
    int timeout = 30;
    time_t start = time(NULL);
    fp = popen(command, "r");
    if (!fp)
    {
        return -1;
    }

    char *total = (char *)malloc(SYSTEM_RUN_RESP_BUFF_LEN);
    memset(total, 0, SYSTEM_RUN_RESP_BUFF_LEN);
    sleep(1);
    while (!(timeout && (time(NULL) > start + timeout)))
    {
        char *b = (char *)malloc(SYSTEM_RUN_RESP_BUFF_LEN);
        if (fgets(b, SYSTEM_RUN_RESP_BUFF_LEN, fp))
        {
            unsigned int expect_len = strlen(total) + strlen(b);
            if (expect_len > SYSTEM_RUN_RESP_BUFF_LEN)
            {
                char *tmp = total;
                total = realloc(tmp, expect_len + 1);
                if (!total)
                {
                    free(b);
                    free(tmp);
                    pclose(fp);
                    return -1;
                }
            }
            total = strcat(total, b);
            if (total)
            {
                total[expect_len] = 0;
            }
            free(b);
        }
        else
        {
            free(b);
            break;
        }
    }
    pclose(fp);
    if (rsp_command)
        *rsp_command = total;
    else
        free(total);
    return 0;
}

static int cmd_is_exist(const char *cmd)
{
    char buff[64] = {0};
    char rx_buff[96] = {0};
    snprintf(buff, sizeof(buff), "type %s", cmd);
    FILE *fp = popen(buff, "r");
    int read_len = fread(rx_buff, 1, sizeof(rx_buff), fp);
    pclose(fp);

    snprintf(buff, sizeof(buff), "%s is ", cmd);
    if (strstr(rx_buff, buff) == rx_buff)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

int get_product_name(char *product_name)
{
    int ret = -1;
    char buff[255] = {0};
    char *string = NULL;
    if (cmd_is_exist("factory"))
    {
        snprintf(buff, sizeof(buff), "factory get | grep -i ^product= | awk -F '=' '{print $2}' | tr -d '\n'");
    }
    else if (cmd_is_exist("fw_printenv"))
    {
        snprintf(buff, sizeof(buff), "fw_printenv | grep -i ^product= | awk -F '=' '{print $2}' | tr -d '\n'");
    }
    else
    {
        return 2;
    }
    ret = system_reply(buff, &string);
    if (ret == 0)
    {
        if (!string)
            return -1;
        strncpy(product_name, string, PRODUCT_NAME_LEN);
        free(string);
    }
    return ret;
}

char *get_board_mac()
{
    static char *mac = NULL;

    if (mac == NULL)
    {
        system_reply("factory get | grep -i ^MAC | awk -F = '{print $2}' | tr '\\n' '\\0'", &mac);
    }
    return mac;
}

void check_make_dir(char *dir)
{
    int ret;
    struct stat stat_info;

    ret = stat(dir, &stat_info);
    if (ret == 0)
    {
        return;
    }

    ret = mkdir(dir, 0777);
    if (ret)
    {
        dy_syslog(LOG_INFO, "mkdir %s fail, errno %d", dir, errno);
    }
}

void get_ip(unsigned char ip[4], const char *ip_string)
{
    int i, cnt = 0;
    char *p = (char *)ip_string;

    for (i = 0; p[i]; i++)
    {
        if (p[i] == '.')
        {
            p[i] = 0;
            cnt++;
        }
    }

    if (cnt > 3)
    {
        cnt = 3;
    }

    for (i = 0; i <= cnt; i++)
    {
        ip[i] = atoi(p);
        p += strlen(p) + 1;
    }
}

//bitmap为指定长度的unsigned char数组，可设置或清除指定bit，可顺序返回置位bit的index
//使用实例: 多包文件接收，每接收到一个包，根据包序号，设置bitmap中的bit，接收结束后检查是否缺包，缺哪些包。

typedef struct _bitmask_t
{
    unsigned char *buf;
    int len; //buf的字节数
} bitmask_t;

//创建bitmask，包含元素数量为index_cnt个，index_cnt为8的倍数
void *bm_open(int index_cnt)
{
    int len = index_cnt / 8;
    bitmask_t *bm = (bitmask_t *)malloc(sizeof(bitmask_t));
    if (!bm)
    {
        return (void *)-1;
    }

    bm->buf = (unsigned char *)malloc(len);
    if (!bm->buf)
    {
        free(bm);
        return (void *)-1;
    }

    memset(bm->buf, 0, len);
    bm->len = len;
    return bm;
}

void bm_close(void *bm_handle)
{
    bitmask_t *bm = (bitmask_t *)bm_handle;

    if (!bm)
    {
        return;
    }

    if (bm->buf)
    {
        free(bm->buf);
    }

    free(bm);
}

int bm_set(void *bm_handle, int index)
{
    int i, j;
    bitmask_t *bm = (bitmask_t *)bm_handle;

    if (!bm || index < 0 || index >= (bm->len * 8))
    {
        return -1;
    }

    i = index / 8;
    j = index % 8;

    bm->buf[i] |= (1 << j);
    return 0;
}

int bm_clear(void *bm_handle, int index)
{
    int i, j;
    bitmask_t *bm = (bitmask_t *)bm_handle;

    if (!bm || index < 0 || index >= (bm->len * 8))
    {
        return -1;
    }

    i = index / 8;
    j = index % 8;

    bm->buf[i] &= ~(1 << j);
    return 0;
}

//从*index开始查，如果无置位的标志则返回索引号
int bm_read(void *bm_handle, int *index)
{
    int i, j;
    bitmask_t *bm = (bitmask_t *)bm_handle;

    if (!bm || *index < 0 || *index >= (bm->len * 8))
    {
        return -1;
    }

    i = (*index) / 8;
    j = (*index) % 8;

    for (; i < bm->len; i++)
    {
        for (; j < 8; j++)
        {
            if (!(bm->buf[i] & (1 << j)))
            {
                *index = i * 8 + j + 1;
                return (i * 8 + j);
            }
        }

        j = 0;
    }

    return -2;
}

char *GetFileName(char *path)
{
    int i, plen;
    char *p = path;
    char *pos = p;
    if (!p)
    {
        return NULL;
    }
    plen = (int) strlen(path);
    for (i = 0; i < plen; i++)
    {
        if (*p == '/')
        {
            pos = p + 1;
        }
        p++;
    }
    return pos;
}
/* Table of CRC values for high-order byte */
static const uint8_t table_crc_hi[] =
    {
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
        0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
        0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
        0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
        0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
        0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
        0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
        0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
        0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
        0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40};

/* Table of CRC values for low-order byte */
static const uint8_t table_crc_lo[] =
    {
        0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
        0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
        0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
        0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
        0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
        0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
        0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
        0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
        0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
        0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
        0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
        0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
        0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
        0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
        0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
        0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
        0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
        0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
        0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
        0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
        0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
        0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
        0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
        0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
        0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
        0x43, 0x83, 0x41, 0x81, 0x80, 0x40};

uint16_t crc16(uint8_t *buffer, uint16_t buffer_length)
{
    uint8_t crc_hi = 0xFF; /* high CRC byte initialized */
    uint8_t crc_lo = 0xFF; /* low CRC byte initialized */
    unsigned int i;        /* will index into CRC lookup */

    /* pass through message buffer */
    while (buffer_length--)
    {
        i = crc_hi ^ *buffer++; /* calculate the CRC  */
        crc_hi = crc_lo ^ table_crc_hi[i];
        crc_lo = table_crc_lo[i];
    }

    return (crc_hi << 8 | crc_lo);
}

int calculate_crc(uint8_t *req, int nb)
{
    int len = nb;
    uint16_t crc = crc16(req, len);

    req[len++] = crc >> 8;
    req[len++] = crc & 0x00FF;

    return len;
}

int modbus_data_check_crc(uint8_t *msg, int msg_length)
{
    uint16_t crc_calculated;
    uint16_t crc_received;

    if (msg_length < 5)
        return -1;

    crc_calculated = crc16(msg, msg_length - 2);
    crc_received = (msg[msg_length - 2] << 8) | msg[msg_length - 1];

    /* Check CRC of msg */
    if (crc_calculated != crc_received)
        return crc_calculated;

    return 0;
}
int replace_sub_str(const char *str, const char *srcSubStr, const char *dstSubStr, char *out)
{
    char *p;
    char *_out = out;
    const char *_str = str;
    const char *_src = srcSubStr;
    const char *_dst = dstSubStr;
    int src_size;
    int dst_size;
    int len = 0;

    if (str == NULL || out == NULL || srcSubStr == NULL || dstSubStr == NULL)
    {
        dy_syslog(LOG_ERR, "invalid argument");
        return -1;
    }
    src_size = strlen(_src);
    dst_size = strlen(_dst);

    do
    {
        p = strstr(_str, _src);
        if (p == 0)
        {
            strcpy(_out, _str);
            return 0;
        }
        len = p - _str;
        memcpy(_out, _str, len);
        memcpy(_out + len, _dst, dst_size);
        _str = p + src_size;
        _out = _out + len + dst_size;

    } while (p);

    return 0;
}

long long uptime_stamp_ms()
{
    int ret;
    struct timespec ts;
    unsigned long long rval;

    ts.tv_sec = 0;
    ts.tv_nsec = 0;
    ret = clock_gettime(CLOCK_BOOTTIME, &ts);
    if (ret == -1) {
        ts.tv_sec = 0;
        ts.tv_nsec = 0;
        clock_gettime(CLOCK_MONOTONIC, &ts);
    }

    rval = (unsigned long long) ts.tv_sec;
    rval = (rval * 1000) + (unsigned long long) (ts.tv_nsec / 1000000);
    return (long long) rval;
}

long long uptime_stamp_us()
{
    int ret;
    struct timespec ts;
    unsigned long long rval;

    ts.tv_sec = 0;
    ts.tv_nsec = 0;
    ret = clock_gettime(CLOCK_BOOTTIME, &ts);
    if (ret == -1) {
        ts.tv_sec = 0;
        ts.tv_nsec = 0;
        clock_gettime(CLOCK_MONOTONIC, &ts);
    }

    rval = (unsigned long long) ts.tv_sec;
    rval = (rval * 1000000) + (unsigned long long) (ts.tv_nsec / 1000);
    return (long long) rval;
}

long long get_time_stamp_ms()
{
    struct timeval tv;
    gettimeofday(&tv, NULL); //该函数在sys/time.h头文件中
    return (long long)tv.tv_sec * 1000ll + (long long)tv.tv_usec / 1000ll;
}

long long get_time_stamp_us()
{
    struct timeval tv;
    gettimeofday(&tv, NULL); //该函数在sys/time.h头文件中
    return (long long)tv.tv_sec * 1000000ll + (long long)tv.tv_usec;
}

int mqtt_tls_file_overlow(char *url, char *path, char *script, int len)
{
    char buff[100];
    struct stat stat_info;
    int ret;
    int retry_cnt = 0;
    char *file = NULL;

    file = GetFileName(url);
    snprintf(buff, sizeof(buff), "%s/%s", path, file);

retry:
    ret = stat(buff, &stat_info);
    if (ret == 0 && stat_info.st_size > 0)
    {
        snprintf(script, len, "%s", buff);
        return 0;
    }
    else
    {
        // file not exist
        download_file(path, url, 5);
        retry_cnt++;
        if (retry_cnt < 10)
        {
            goto retry;
        }
    }
    memset(script, 0, len);
    dy_syslog(LOG_ERR, "mqtt_tls %s ,can't find !", buff);
    return -1;
}

char *download_url_data(char *data, char *cfg_file)
{
    char url[384] = {0};

    if (json_pkt_json_url(data, url) == 0)
    {
        int ret;
        char filen[192];
        const char * filp;
        char *url_v = NULL;

        filp = GetFileName(url);
        if (filp == NULL || filp[0] == '\0') {
            dy_syslog(LOG_ERR, "Error, invalid download URL: %s", url);
            return NULL;
        }

        if (strlen(filp) > 100) {
            dy_syslog(LOG_ERR, "Error, download filename too long: %s", url);
            return NULL;
        }

        ret = snprintf(filen, sizeof(filen), "/tmp/%s.", filp);
        lnxall_exename(&filen[ret], (int) (sizeof(filen) - ret - 1));

        ret = download_file1(filen, url, 10);
        if (ret != 0)
        {
            unlink(filen);
            dy_syslog(LOG_ERR, "download file fail: %s", filen);
            return NULL;
        }

        url_v = read_file_data(filen);
        unlink(filen);
        if (url_v == NULL)
        {
            dy_syslog(LOG_INFO, "read file fail");
            return NULL;
        }
        {
            cJSON *tmp = cJSON_Parse(url_v);
            if (tmp == NULL) {
                free(url_v);
                return NULL;
            }
            cJSON_Delete(tmp);
        }
        write_file_data(cfg_file, url_v, strlen(url_v));

        return url_v;
    }
    return NULL;
}
