#include "dy_utils/dy_pp.h"
#include "lauxlib.h"
#include "lua.h"
#include "pp.h"
#if _PP_USE_PYTHON3
  #include "python3.9/Python.h"
#else
  #include "python2.7/Python.h"
#endif
#include "dy_utils/hash_intptr.h"

static int pp_get_rt_data_from_json_str(pp_var_t *var, pp_real_time_data_t *real_data, char *json_str)
{
    int ret = 0;
    char *bin_buff = NULL;
    cJSON *root = cJSON_Parse(json_str);
    if (root)
    {

        char *buf = NULL;
        int len;
        char *tmp;

        buf = (char *)malloc(MAXBUF);
        if (buf == NULL)
        {
            dbg_syslog(LOG_ERR, "malloc failed");
            ret = -1;
            goto out;
        }

        GET_JSON_VALUE_STRING(root, "port", buf);
        real_data->port = port_char2enum(buf);
        GET_JSON_VALUE_INT(root, "instruction_code", real_data->instruction_code);
        GET_JSON_VALUE_INT(root, "mi", real_data->mi);
        GET_JSON_VALUE_INT(root, "ts", real_data->ts);
        GET_JSON_VALUE_INT(root, "len", real_data->len);
        GET_JSON_VALUE_INT(root, "sub_term_addr_len", real_data->sub_term_addr_len);
        GET_JSON_VALUE_INT(root, "start_addr", real_data->start_addr);
        GET_JSON_VALUE_STRING(root, "sub_template_id", real_data->sub_template_id);
        GET_JSON_VALUE_STRING(root, "src_identifier", real_data->src_identifier);
        GET_JSON_VALUE_STRING(root, "sn", real_data->sn);
        GET_JSON_VALUE_STRING(root, "requester", real_data->requester);
        GET_JSON_VALUE_STRING(root, "dtu_sn", real_data->dtu_sn);

        GET_JSON_VALUE_DY_STRING(root, "term_addr_b64", tmp);
        if (tmp != NULL)
        {
            len = b64_decode(tmp, buf, MAXBUF);
            ASSERT(len == sizeof(real_data->term_addr));
            memcpy(real_data->term_addr, buf, sizeof(real_data->term_addr));
            free(tmp);
        }

        GET_JSON_VALUE_DY_STRING(root, "sub_term_addr_b64", tmp);
        if (tmp != NULL)
        {
            len = b64_decode(tmp, buf, MAXBUF);
            ASSERT(len == sizeof(real_data->sub_term_addr));
            memcpy(real_data->sub_term_addr, buf, sizeof(real_data->sub_term_addr));
            free(tmp);
        }

        GET_JSON_VALUE_DY_STRING(root, "data_b64", tmp);
        if (tmp != NULL)
        {
            int bin_len = real_data->len * 0x2 + 1024;
            bin_buff = malloc(bin_len);
            len = b64_decode(tmp, bin_buff, bin_len);
            free(tmp);
            // dbg_syslog(LOG_DEBUG, "bin_len:%d,buff_size:%d, real_data->len:%d", len, bin_len, real_data->len);
        }
        ASSERT(len == real_data->len);
        real_data->data = calloc(1, len + 1);
        if (real_data->data == NULL)
        {
            dbg_syslog(LOG_ERR, "malloc fail len:%d", len);
            free(buf);
            ret = -1;
            goto out;
        }
        memcpy(real_data->data, bin_buff, len);
        free(buf);
    }
    else
    {
        dbg_syslog(LOG_ERR, "json parse error");
        ret = -1;
    }

out:
    cJSON_Delete(root);
    free(bin_buff);
    return ret;
}

int pp_data_exec_crc_info(pp_var_t *var, template_cfg_t *ptemplate, unsigned char *data, int len, unsigned int *crc)
{
    int i;

    if (ptemplate)
    {
        for (i = 0; i < ptemplate->mac_tab->macCnt; i++)
        {
            if (!strcmp(ptemplate->mac_tab->mac[i].sign_mark, "crc"))
            {
                char *raw_data = malloc(len + 8 + 1024);
                if (raw_data == NULL)
                {
                    dbg_syslog(LOG_ERR, "%s:%d,malloc failed!!!", __FILE__, __LINE__);
                    return -1;
                }
                memset(raw_data, 0, len + 8 + 1024);
                int j;

                sprintf(raw_data, "local len = %d local %s = '", len, CRC_RAW_DATA_NAME);
                for (j = 0; j < len; j++)
                {
                    char bin_tmp[8] = {0};
                    sprintf(bin_tmp, "\\%d", data[j]);
                    strcat(raw_data, bin_tmp);
                }
                strcat(raw_data, "' ");
                char tmp[1024] = {0};
                sprintf(tmp, "%s ", ptemplate->mac_tab->mac[i].desc);
                strcat(raw_data, tmp);

                // dbg_syslog(LOG_DEBUG, "raw_data %s ", raw_data);

                if (luaL_dostring(var->lua, raw_data))
                {
                    dbg_syslog(LOG_ERR, "luaL_loadstring %s error!!!", raw_data);
                }

                *crc = lua_tonumber(var->lua, -1);
                lua_pop(var->lua, 1);
                free(raw_data);
                return 0;
            }
        }
    }

    return -1;
}

static void lua_upvalues_update(object_property_table_t * ptab, cJSON * tagnode)
{
    lua_State * L;
    int ntop, ret, idx;
    cJSON * child = NULL;
    struct hash_intptr * hptr;
    const char * func = LNX_UPVALUES_FUNC;

    L = ptab->luast;
    hptr = (struct hash_intptr *) ptab->sign_mark;

    ntop = lua_gettop(L);
    /* pop function `LNX_UPVALUES_FUNC to the top of stack */
    lua_getglobal(L, func);
    ret = lua_gettop(L);
    if (ret != (ntop + 1) || lua_type(L, -1) != LUA_TFUNCTION) {
        dbg_syslog(LOG_ERR, "Error, failed to find function: %s", func);
        lua_settop(L, ntop);
        return;
    }

    for (child = tagnode->child; child != NULL; child = child->next) {
        size_t slen;
        const char * sm;
        const char * signm;

        signm = child->string;
        slen = (signm != NULL) ? strlen(signm) : 0;
        if (slen == 0) {
            dbg_syslog(LOG_ERR, "Error, invalid zero length of sign_mark!");
            continue;
        }

        idx = -1;
        ret = hash_intptr_findint(hptr, signm, (unsigned int) slen, &idx);
        if (ret < 0 || idx < 0) {
            dbg_syslog(LOG_ERR, "Error, sign_mark not found in hashmap: %s", signm);
            continue;
        }

        if (cJSON_IsNumber(child)) {
            lua_pushnumber(L, child->valuedouble);
        } else if (cJSON_IsString(child)) {
            lua_pushstring(L, child->valuestring);
        } else {
            dbg_syslog(LOG_ERR, "Error, invalid type for '%s': %#x",
                signm, (unsigned int) child->type);
            continue;
        }

        sm = lua_setupvalue(L, ntop + 1, idx);
        if (sm == NULL) {
            dbg_syslog(LOG_ERR, "Error, failed to update upvalue '%s'!", signm);
            lua_settop(L, ntop);
        }

        if (sm && strcmp(sm, signm)) {
            dbg_syslog(LOG_ERR, "Error, upvalue name mismatch: %s <=> %s", signm, sm);
        }
    }

    lua_settop(L, ntop);
}

static int script_lua_upvalue_exec(cJSON *jtag_new, object_property_table_t * ptab, object_property_cfg_t *property)
{
    int ntop, ret;
    lua_State * L;
    char expfunc[128];
    const char * pdesc;

    L = ptab->luast;
    if (L == NULL)
        return 0;

    pdesc = property->desc;
    if (pdesc == NULL || pdesc[0] == '\0') {
        dbg_syslog(LOG_ERR, "Error, cannot generate core: %s", property->identifier);
        return -1;
    }

    ntop = lua_gettop(L);
    snprintf(expfunc, sizeof(expfunc), "lxf_%s", property->identifier);
    expfunc[sizeof(expfunc) - 0x1] = '\0';
    lua_getglobal(L, expfunc);
    ret = lua_gettop(L);
    if (ret != (ntop + 1) || lua_type(L, -1) != LUA_TFUNCTION) {
        dbg_syslog(LOG_ERR, "Error, failed to find function '%s'", expfunc);
        if (ret != ntop)
            lua_settop(L, ntop);
        return -1;
    }

    ret = lua_pcall(L, 0, 1, 0);
    if (ret != 0) {
        dbg_syslog(LOG_ERR, "Error, failed to invoke function '%s'", expfunc);
        lua_settop(L, ntop);
        return -1;
    }

    if (property->raw_data_type != TAG_TYPE_VLENGTH) {
        if (lua_isnumber(L, -1)) {
            double tagD = lua_tonumber(L, -1);
            if (!isnan(tagD)) {
                cJSON_AddNumberToObject(jtag_new, property->identifier, tagD);
            }
        }
    } else {
        const char *tagStr = lua_tostring(L, -1);
        if (tagStr) {
            cJSON_AddStringToObject(jtag_new, property->identifier, tagStr);
        }
        dbg_syslog(LOG_INFO, "upvalue-cal identifier %s val %s ", property->identifier, tagStr);
    }

    lua_settop(L, ntop);
    return 1;
}

#define LUA_SCRIPT_MAXLEN 4096
cJSON *exec_operation_script_lua(pp_var_t *var, cJSON *tag_node, cJSON *jtag_new, object_property_cfg_t *property)
{
    int buflen;
    const char * pdesc;
    char *buf = calloc(1, LUA_SCRIPT_MAXLEN);

    buflen = 0;
    pdesc = property->desc;
    if (pdesc == NULL) {
        free(buf);
        dbg_syslog(LOG_ERR, "Error, about to generate core: %s", property->identifier);
        return NULL;
    }
    cJSON *child = NULL;
    for (child = tag_node->child; child; child = child->next)
    {
        if (child->string)
        {
            char str[512] = {0};

            if (child->valuestring)
            {
                GET_JSON_VALUE_STRING(tag_node, child->string, str);
                if (str[0])
                {
                    buflen += snprintf(buf + buflen, LUA_SCRIPT_MAXLEN - buflen,
                        "local %s = '%s' ", child->string, str);
                }
            }
            else
            {
                double val = 0xFFFFFFFF;
                GET_JSON_VALUE_DOUBLE(tag_node, child->string, val);
                buflen += snprintf(buf + buflen, LUA_SCRIPT_MAXLEN - buflen,
                    "local %s = %1.15g ", child->string, val);
            }

            if (buflen > 4000)
            {
                dbg_syslog(LOG_ERR, "luaL_loadstring are too long !!!");
                goto finish_0;
            }
        }
    }

    if (!strstr(pdesc, "return")) //如果物模型中表达式没有return 加return
    {
        buflen += snprintf(buf + buflen, LUA_SCRIPT_MAXLEN - buflen, "return %s ", pdesc);
    }
    else
    {
        buflen += snprintf(buf + buflen, LUA_SCRIPT_MAXLEN - buflen, "%s ", pdesc);
    }
    if (luaL_dostring(var->lua, buf))
    {
        dbg_syslog(LOG_ERR, "luaL_loadstring %s error!!!", buf);
        lua_pop(var->lua, 1);
        goto finish_0;
    }
    if (property->raw_data_type != TAG_TYPE_VLENGTH)
    {
        if (lua_isnumber(var->lua, -1))
        {
            double tagD = lua_tonumber(var->lua, -1);
            if (!isnan(tagD)) {
                cJSON_AddNumberToObject(jtag_new, property->identifier, tagD);
            }
        }
    }
    else
    {
        const char *tagStr = lua_tostring(var->lua, -1);
        if (tagStr)
        {
            cJSON_AddStringToObject(jtag_new, property->identifier, tagStr);
        }

        dbg_syslog(LOG_INFO, "operation %s identifier %s val %s ", buf, property->identifier, tagStr);
    }

    lua_pop(var->lua, 1);
finish_0:
    free(buf);
    return 0;
}

cJSON *exec_decode_script_lua(pp_var_t *var, lua_State *lua, char *data, unsigned short len)
{
    char *json_str = NULL;
    char error_code = 0;
    unsigned short json_len = 0;
    int ret;
    cJSON *json_data = NULL;

    lua_getglobal(lua, FUN_PROTOCOL_DECODE_NAME);
    lua_pushstring(lua, data);
    lua_pushinteger(lua, len);
    ret = lua_pcall(lua, 2, 3, 0);
    if (ret)
    {
        const char *err_msg = lua_tostring(lua, -1);
        dbg_syslog(LOG_ERR, "lua error:%s", err_msg);
        lua_pop(lua, 1);
        return NULL;
    }
    error_code = lua_tointeger(lua, -3);
    json_len = lua_tointeger(lua, -1);
    if (error_code != 0 || json_len == 0)
    {
        dbg_syslog(LOG_ERR, "error_code %d json_len %d ", error_code, json_len);
        lua_pop(lua, 3);
        return NULL;
    }
    json_str = malloc(json_len + 1);
    if (json_str == NULL)
    {
        dbg_syslog(LOG_ERR, "malloc error, json_len:%d", json_len);
        lua_pop(lua, 3);
        return NULL;
    }
    const char *p = lua_tostring(lua, -2);
    sprintf(json_str, "%s", p);

    // dbg_syslog(LOG_INFO, "error_code %d json_str %s json_len %d ", error_code, json_str, json_len);
    if (!error_code && json_len)
    {
        json_data = cJSON_Parse(json_str);
    }

    lua_pop(lua, 3);

    free(json_str);
    return json_data;
}

cJSON *exec_decode_script_python(pp_var_t *var, char *file_name, unsigned char *data, unsigned short len)
{
    PyObject *pName = NULL;
    PyObject *pModule = NULL;
    PyObject *pDict = NULL;
    PyObject *pFunc = NULL;
    PyObject *pArgs = NULL;
    char *json_str;
    long json_len = 0, error_code = 0;

    dbg_syslog(LOG_INFO, "decode file_name %s data %s len %d", file_name, data, len);

    //加载名为py_add的python脚本

#if _PP_USE_PYTHON3
    pName = PyUnicode_FromString(file_name);
#else
    pName = PyString_FromString(file_name);
#endif
    pModule = PyImport_Import(pName);
    if (!pModule)
    {
        dbg_syslog(LOG_WARNING, "Load %s failed!", file_name);
        return NULL;
    }
    pDict = PyModule_GetDict(pModule);
    if (!pDict)
    {
        dbg_syslog(LOG_WARNING, "Can't find dict in %s!", file_name);
        return NULL;
    }

    pFunc = PyDict_GetItemString(pDict, FUN_PROTOCOL_DECODE_NAME);
    if (!pFunc || !PyCallable_Check(pFunc))
    {
        dbg_syslog(LOG_WARNING, "Can't find function!\n");
        return NULL;
    }

    pArgs = PyTuple_New(2);
    PyTuple_SetItem(pArgs, 0, Py_BuildValue("s", data));
    PyTuple_SetItem(pArgs, 1, Py_BuildValue("i", len));

    PyObject *presult = PyObject_CallObject(pFunc, pArgs);
    if (presult == NULL)
    {
        dbg_syslog(LOG_ERR, "parse failed");
    }
    else
    {
        PyArg_ParseTuple(presult, "isi", &error_code, &json_str, &json_len);
        dbg_syslog(LOG_INFO, "file_name %s error_code %ld json_str %s json_len %d",
            file_name, error_code, json_str, (int) json_len);
    }

    //清理python对象
    if (presult)
    {
        Py_DECREF(presult);
    }
    if (pArgs)
    {
        Py_DECREF(pArgs);
    }
    if (pFunc)
    {
        Py_DECREF(pFunc);
    }
    if (pDict)
    {
        Py_DECREF(pDict);
    }
    if (pModule)
    {
        Py_DECREF(pModule);
    }
    if (pName)
    {
        Py_DECREF(pName);
    }

    if (!error_code && json_len)
    {
        return cJSON_Parse(json_str);
    }

    return NULL;
}

cJSON *exec_decode_script_javascript(pp_var_t *var, char *file_name, unsigned char *data, unsigned short len)
{
    char file[256] = {0};
    char buf[1024] = {0};
    char param_json[1024] = {0};
    char json_str[512] = {0}, json_len = 0, error_code = 0;
    int ret;

    sprintf(file, "%s%s %s ", PARSE_SCRIPT_DIR, file_name, FUN_PROTOCOL_DECODE_NAME);

    // dbg_syslog(LOG_INFO, "decode file %s bin_str %s len %d",file,bin_str,len*2);

    strcat(buf, file);
    sprintf(param_json, "%s %d", data, len);
    strcat(buf, param_json);
    dbg_syslog(LOG_INFO, "js_send:%s", buf);

    ret = send(var->javascript.fd, buf, strlen(buf) + 1, 0);
    memset(buf, 0, sizeof(buf));
    ret = recv(var->javascript.fd, buf, sizeof(buf), 0);
    if (ret > 0)
    {
        dbg_syslog(LOG_INFO, "ret %d js_recv: %s", ret, buf);
        char *p1 = strstr(buf, " ");
        if (p1)
        {
            memcpy(json_str, buf, p1 - buf);
            error_code = atoi(json_str);
            memset(json_str, 0, sizeof(json_str));
        }

        char *p2 = strstr(p1 + 1, " ");
        if (p2)
        {
            memcpy(json_str, p1 + 1, p2 - p1);
        }

        json_len = atoi(p2 + 1);
        if (!error_code && json_len)
        {
            return cJSON_Parse(json_str);
        }
    }
    else if (var->javascript.connect_timer == 0)
    {
        var->javascript.connected = 0;
        var->javascript.connect_timer = my_timer_create();
        if (var->javascript.connect_timer > 0)
        {
            my_timer_set(var->javascript.connect_timer, 1, 1 * 1000);
        }

        if (var->javascript.fd)
        {
            close(var->javascript.fd);
            var->javascript.fd = 0;
        }
    }

    return NULL;
}
cJSON *protocol_decode_script(pp_var_t *var, template_cfg_t *ptemplate, pp_real_time_data_t *rtData, unsigned char dtu)
{
    unsigned short offset = 0;
    int i, bufl = 0;
    char *buf = NULL;
    size_t buflen = 0, dlen = 0;;
    char *file_name = ptemplate->parser_script;
    cJSON *json_data = NULL;

    if (file_name == NULL)
    {
        return NULL;
    }

    if (rtData->port == VIRTUAL_1)
    {
        goto decode_flag_0;
    }

    bufl = 0;
    buflen = (size_t) rtData->len;
    buflen = (buflen << 0x1) + 128;
    buf = calloc(1, buflen);
    if (buf == NULL)
    {
        dbg_syslog(LOG_ERR, "malloc error, len:%d", rtData->len);
        return NULL;
    }

    cJSON *jdecode = cJSON_CreateObject();
    if (dtu == 1 && (rtData->port == LORA_1 || rtData->port == LORAWAN_1))
    {
        offset = 3;
    }
    else if (rtData->port == LORA_1)
    {
        offset = 2;
    }

    for (i = 0; i < rtData->len - offset; i++)
    {
        bufl += snprintf(buf + bufl, buflen - ((size_t) bufl),
            "%02X", (unsigned int) rtData->data[offset + i]);
    }

    cJSON_AddStringToObject(jdecode, "raw_data", buf);
    cJSON_AddStringToObject(jdecode, "identifier", rtData->src_identifier);
    cJSON_AddStringToObject(jdecode, "sn", rtData->sn);

    char *data_str = cJSON_PrintUnformatted(jdecode);
    bufl = 0;
    dlen = data_str ? strlen(data_str) : 0;
    memset(buf, 0x00, buflen);
    if (dlen <= buflen)
    {
        bufl = (int) dlen;
        memcpy(buf, data_str, dlen);
    }
    else
    {
        dbg_syslog(LOG_WARNING, "the json parameters are too long :%d,%d", strlen(data_str), rtData->len);
    }
    free(data_str);
    cJSON_Delete(jdecode);

decode_flag_0:
    if (strstr(file_name, LUA_EXTEND))
    {
        if (rtData->port == VIRTUAL_1) //<虚拟设备,边缘计算
        {
            json_data = exec_decode_script_lua(var, ptemplate->script.lua, (char *) rtData->data, rtData->len);
        }
        else
        {
            json_data = exec_decode_script_lua(var, ptemplate->script.lua, buf, (unsigned short) bufl);
        }
    }
    else if (strstr(file_name, PYTHON_EXTEND))
    {
        char file[128] = {0};
        char *file_t = GetFileName(file_name);
        char *p = strstr(file_t, PYTHON_EXTEND);

        strncpy(file, file_t, p - file_t);
        dbg_syslog(LOG_INFO, "file %s", file);
        if (rtData->port == VIRTUAL_1)
        {
            json_data = exec_decode_script_python(var, file, rtData->data, rtData->len);
        }
        else
        {
            json_data = exec_decode_script_python(var, file, (unsigned char *) buf, (unsigned short) bufl);
        }
    }
    else if (strstr(file_name, JAVASCRIPT_EXTEND))
    {
        if (rtData->port == VIRTUAL_1)
        {
            json_data = exec_decode_script_javascript(var, file_name, rtData->data, rtData->len);
        }
        else
        {
            json_data = exec_decode_script_javascript(var, file_name, (unsigned char *) buf, (unsigned short) bufl);
        }
    }
    else
    {
        dbg_syslog(LOG_WARNING, "script file_name:%s error !!!", file_name);
    }
    free(buf);

    return json_data;
}

cJSON *protocol_decode_template_tag(pp_var_t *var, template_cfg_t *ptemplate, tag_cfg_t *ptag, pp_real_time_data_t *rtData, unsigned char flag)
{
    int k;
    unsigned char val[512];
    unsigned char b64[512];
    unsigned short vlength = 0;
    unsigned int tmp_val;
    int tmp_index = flag;
    tag_data_format_e tage = TAG_TYPE_NULL;
    char data_type[16] = {0, 2, 2, 4, 4, 4, 2, 4, 2, 4, 4, 1, 1, 8, 8, 0};
    cJSON *jtag = cJSON_CreateObject();

    dbg_syslog(LOG_INFO, "ptag paramCnt %d", ptag->param_tab->paramCnt);
    for (k = 0; k < ptag->param_tab->paramCnt; k++)
    {
        memset(val, 0, sizeof(val));
        if (flag >= rtData->len)
        {
            cJSON_Delete(jtag);
            jtag = cJSON_CreateObject();
            break;
        }
        tage = ptag->param_tab->param[k].raw_data_type;
        if (tage == TAG_TYPE_VLENGTH)
        {
            GET_JSON_VALUE_INT(jtag, ptag->param_tab->param[k].reference_length, vlength);
        }
        //取数据
        switch (tage)
        {
        case TAG_TYPE_UINT16I:
        case TAG_TYPE_INT16I:
        case TAG_TYPE_INT32I:
        case TAG_TYPE_UINT32I:
        case TAG_TYPE_FLOAT:
        case TAG_TYPE_FLOATI:
        {
            int index;
            for (index = 0; index < data_type[ptag->param_tab->param[k].raw_data_type]; index++)
            {
                val[index] = rtData->data[flag + data_type[tage] - 1 - index];
            }
        }
        break;
        case TAG_TYPE_VLENGTH:
        {
            int index;
            if (vlength == 0)
            {
                dbg_syslog(LOG_WARNING, "sign_mark %s vLength val %d", ptag->param_tab->param[k].sign_mark, vlength);
            }
            for (index = 0; index < vlength; index++)
            {
                val[index] = rtData->data[flag + index];
            }
        }
        break;
        default:
            memcpy(val, rtData->data + flag, data_type[tage]);
            break;
        }

        if (ptemplate->protocol == GW_PROTC_MODBUS && (rtData->data[1] == 0x03 || rtData->data[1] == 0x04 || rtData->data[1] == 0x83 || rtData->data[1] == 0x84))
        {
            if (flag == rtData->len - 2 && strcmp(ptag->param_tab->param[k].sign_mark, CRC_STRING) != 0)
            {
                flag += data_type[tage];
                continue;
            }
        }

        // dbg_syslog(LOG_INFO, "data_type[%d] %d val[%d %d] data[flag %d] %x",ptag->param_tab->param[k].raw_data_type,data_type[ptag->param_tab->param[k].raw_data_type],val[0],val[1],flag,rtData->data[flag]);
        if (tage == TAG_TYPE_VLENGTH)
        {
            b64_encode(val, strlen((const char *) val), b64, sizeof(b64));
            cJSON_AddStringToObject(jtag, ptag->param_tab->param[k].sign_mark, (const char *) b64);
            //偏移
            flag += vlength;
        }
        else if (tage == TAG_TYPE_INT8)
        {
            int8_t *tag_val = (int8_t *)val;
            tmp_val = *tag_val;
            TAG_TO_JSON(ptag->param_tab->param[k], jtag, tag_val);
        }
        else if (tage == TAG_TYPE_INT16 || tage == TAG_TYPE_INT16I)
        {
            int16_t *tag_val = (int16_t *)val;
            tmp_val = *tag_val;
            TAG_TO_JSON(ptag->param_tab->param[k], jtag, tag_val);
        }
        else if (tage == TAG_TYPE_INT32I || tage == TAG_TYPE_INT32)
        {
            int32_t *tag_val = (int32_t *)val;
            tmp_val = *tag_val;
            TAG_TO_JSON(ptag->param_tab->param[k], jtag, tag_val);
        }
        else if (tage == TAG_TYPE_INT64)
        {
            int64_t *tag_val = (int64_t *)val;
            tmp_val = *tag_val;
            TAG_TO_JSON(ptag->param_tab->param[k], jtag, tag_val);
        }
        else if (tage == TAG_TYPE_UINT16 || tage == TAG_TYPE_UINT16I)
        {
            uint16_t *tag_val = (uint16_t *)val;
            tmp_val = *tag_val;
            TAG_TO_JSON(ptag->param_tab->param[k], jtag, tag_val);
        } else if (tage == TAG_TYPE_FLOAT || tage == TAG_TYPE_FLOATI) {
            union pp_uint_float pflt;
            unsigned int * pint = (unsigned int *) val;
            float * tag_val = &pflt.f_val;
            pflt.i_val = *pint;
            if (tage == TAG_TYPE_FLOAT)
                pflt.i_val = __builtin_bswap32(pflt.i_val);
            TAG_TO_JSON(ptag->param_tab->param[k], jtag, tag_val);
        } else {
            unsigned int *tag_val = (unsigned int *)val;
            tmp_val = *tag_val;
            TAG_TO_JSON(ptag->param_tab->param[k], jtag, tag_val);
        }

        if (!strcmp(ptag->param_tab->param[k].sign_mark, CRC_PADDING))
        {
            tmp_index += data_type[ptag->param_tab->param[k].raw_data_type];
        }

        if (ptemplate->protocol != GW_PROTC_MODBUS && ptemplate->protocol != GW_PROTC_DYWL_LORA_V1 && !strcmp(ptag->param_tab->param[k].sign_mark, CRC_STRING))
        {
            unsigned int crc = 0XFFFFFFFF;
            pp_data_exec_crc_info(var, ptemplate, rtData->data + tmp_index, flag - tmp_index, &crc);
            if (crc != tmp_val)
            {
                dbg_syslog(LOG_WARNING, "data crc error crc 0x%x 0x%x!!!", tmp_val, crc);
                cJSON_Delete(jtag);
                jtag = cJSON_CreateObject();
            }
        }

        //偏移
        flag += data_type[ptag->param_tab->param[k].raw_data_type];


    }

    return jtag;
}

cJSON *protocol_decode_template_event(pp_var_t *var, template_cfg_t *ptemplate, event_cfg_t *pevent, pp_real_time_data_t *rtData, unsigned char flag)
{
    int k = 0;
    unsigned char val[512];
    unsigned char b64[512];
    unsigned short vlength = 0;
    int tmp_index = flag;
    unsigned int tmp_val;
    tag_data_format_e tage = TAG_TYPE_NULL;
    char data_type[16] = {0, 2, 2, 4, 4, 4, 2, 4, 2, 4, 4, 1, 1, 8, 8, 0};
    cJSON *jtag = cJSON_CreateObject();

    for (k = 0; k < pevent->param_tab->paramCnt; k++)
    {
        memset(val, 0, sizeof(val));
        tage = pevent->param_tab->param[k].raw_data_type;
        if (tage == TAG_TYPE_VLENGTH)
        {
            GET_JSON_VALUE_INT(jtag, pevent->param_tab->param[k].reference_length, vlength);
        }
        //取数据
        switch (tage)
        {
        case TAG_TYPE_UINT16I:
        case TAG_TYPE_INT16I:
        case TAG_TYPE_INT32I:
        case TAG_TYPE_UINT32I:
        case TAG_TYPE_FLOAT:
        case TAG_TYPE_FLOATI:
        {
            int index;
            for (index = 0; index < data_type[pevent->param_tab->param[k].raw_data_type]; index++)
            {
                val[index] = rtData->data[flag + data_type[tage] - 1 - index];
            }
        }
        break;
        case TAG_TYPE_VLENGTH:
        {
            int index;
            if (vlength == 0)
            {
                dbg_syslog(LOG_WARNING, "sign_mark %s vLength val %d", pevent->param_tab->param[k].sign_mark, vlength);
            }
            for (index = 0; index < vlength; index++)
            {
                val[index] = rtData->data[flag + index];
            }
        }
        break;
        default:
            memcpy(val, rtData->data + flag, data_type[tage]);
            break;
        }
        if (ptemplate->protocol == GW_PROTC_MODBUS && (rtData->data[1] == 0x03 || rtData->data[1] == 0x04 || rtData->data[1] == 0x83 || rtData->data[1] == 0x84))
        {
            if (flag == rtData->len - 2 && strcmp(pevent->param_tab->param[k].sign_mark, CRC_STRING) != 0)
            {
                flag += data_type[tage];
                continue;
            }
        }
        dbg_syslog(LOG_INFO, "data_type[%d] %d val[%d %d]", tage, data_type[tage], val[0], val[1]);
        if (tage == TAG_TYPE_VLENGTH)
        {
            b64_encode(val, strlen((const char *) val), b64, sizeof(b64));
            cJSON_AddStringToObject(jtag, pevent->param_tab->param[k].sign_mark, (const char *) b64);
            //偏移
            flag += vlength;
        }
        else if (tage == TAG_TYPE_INT8)
        {
            int8_t *tag_val = (int8_t *)val;
            tmp_val = *tag_val;
            TAG_TO_JSON(pevent->param_tab->param[k], jtag, tag_val);
        }
        else if (tage == TAG_TYPE_INT16 || tage == TAG_TYPE_INT16I)
        {
            int16_t *tag_val = (int16_t *)val;
            tmp_val = *tag_val;
            TAG_TO_JSON(pevent->param_tab->param[k], jtag, tag_val);
        }
        else if (tage == TAG_TYPE_INT32I || tage == TAG_TYPE_INT32)
        {
            int32_t *tag_val = (int32_t *)val;
            tmp_val = *tag_val;
            TAG_TO_JSON(pevent->param_tab->param[k], jtag, tag_val);
        }
        else if (tage == TAG_TYPE_INT64)
        {
            int64_t *tag_val = (int64_t *)val;
            tmp_val = *tag_val;
            TAG_TO_JSON(pevent->param_tab->param[k], jtag, tag_val);
        }
        else if (tage == TAG_TYPE_UINT16 || tage == TAG_TYPE_UINT16I)
        {
            uint16_t *tag_val = (uint16_t *)val;
            tmp_val = *tag_val;
            TAG_TO_JSON(pevent->param_tab->param[k], jtag, tag_val);
        } else if (tage == TAG_TYPE_FLOAT || tage == TAG_TYPE_FLOATI) {
            union pp_uint_float pflt;
            unsigned int * pint = (unsigned int *) val;
            float * tag_val = &pflt.f_val;
            pflt.i_val = *pint;
            if (tage == TAG_TYPE_FLOAT)
                pflt.i_val = __builtin_bswap32(pflt.i_val);
            TAG_TO_JSON(pevent->param_tab->param[k], jtag, tag_val);
        } else {
            unsigned int *tag_val = (unsigned int *)val;
            tmp_val = *tag_val;
            TAG_TO_JSON(pevent->param_tab->param[k], jtag, tag_val);
        }

        if (pevent->param_tab->param[k].bit_cnt > 0)
        {
            int i;
            for (i = 0; i < pevent->param_tab->param[k].bit_cnt; i++)
            {
                int count = pevent->param_tab->param[k].bit_fields[i].count;
                int start = pevent->param_tab->param[k].bit_fields[i].start;
                int mask = (1 << count) - 1;
                unsigned int val = ((tmp_val >> start) & mask);
                cJSON_AddNumberToObject(jtag, pevent->param_tab->param[k].bit_fields[i].sign_mark, val);
            }
        }

        if (!strcmp(pevent->param_tab->param[k].sign_mark, CRC_PADDING))
        {
            tmp_index += data_type[tage];
        }

        if (ptemplate->protocol != GW_PROTC_MODBUS && ptemplate->protocol != GW_PROTC_DYWL_LORA_V1 && !strcmp(pevent->param_tab->param[k].sign_mark, CRC_STRING))
        {
            unsigned int crc = 0XFFFFFFFF;
            pp_data_exec_crc_info(var, ptemplate, rtData->data + tmp_index, flag - tmp_index, &crc);
            dbg_syslog(LOG_WARNING, "data crc 0x%x 0x%x flag %d tmp_index %d %d=====", tmp_val, crc, flag, tmp_index, flag - tmp_index);
            if (crc != tmp_val)
            {
                dbg_syslog(LOG_WARNING, "data crc error crc 0x%x 0x%x!!!", tmp_val, crc);
                cJSON_Delete(jtag);
                jtag = cJSON_CreateObject();
            }
        }
        //偏移
        flag += data_type[tage];
    }

    return jtag;
}

cJSON *protocol_decode_template_service(pp_var_t *var, template_cfg_t *ptemplate, service_cfg_t *pservice, pp_real_time_data_t *rtData, unsigned char flag)
{
    int k;
    unsigned char val[512];
    unsigned char b64[512];
    unsigned short vlength = 0;
    unsigned int tmp_val;
    int tmp_index = flag;
    tag_data_format_e tage = TAG_TYPE_NULL;
    char data_type[16] = {0, 2, 2, 4, 4, 4, 2, 4, 2, 4, 4, 1, 1, 8, 8, 0};
    unsigned char  bit_mask[8] = {0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff};
    cJSON *jtag = cJSON_CreateObject();
    /* int ext_len = 0;

    if (ptemplate->protocol == GW_PROTC_MODBUS && (rtData->data[1] == 0x03 || rtData->data[1] == 0x04 || rtData->data[1] == 0x83 || rtData->data[1] == 0x84))
        ext_len = 2; */

    for (k = 0; k < pservice->param_tab->paramCnt; k++)
    {
        memset(val, 0, sizeof(val));
        tage = pservice->param_tab->param[k].raw_data_type;
        if (tage == TAG_TYPE_VLENGTH)
        {
            GET_JSON_VALUE_INT(jtag, pservice->param_tab->param[k].reference_length, vlength);
        }
        else if (flag + data_type[tage] > rtData->len)
        {
            // MODBUS允许输出不完整的协议属性
            if (ptemplate->protocol == GW_PROTC_MODBUS && rtData->len >= 5)
            {
                if (!strstr(pservice->param_tab->param[k].sign_mark, "crc"))
                {
                    dbg_syslog(LOG_INFO, "MODBUS data len %d(sign_mark %s flag %d data_len %d) !!!", rtData->len, pservice->param_tab->param[k].sign_mark, flag, data_type[tage]);
                }
                return jtag;
            }
            dbg_syslog(LOG_WARNING, "error data len %d(sign_mark %s flag %d data_len %d) !!!", rtData->len, pservice->param_tab->param[k].sign_mark, flag, data_type[tage]);
            cJSON_Delete(jtag);
            jtag = cJSON_CreateObject();
            return jtag;
        }
        //取数据
        switch (pservice->param_tab->param[k].raw_data_type)
        {
        case TAG_TYPE_UINT16I:
        case TAG_TYPE_INT16I:
        case TAG_TYPE_INT32I:
        case TAG_TYPE_UINT32I:
        case TAG_TYPE_FLOAT:
        case TAG_TYPE_FLOATI:
        {
            int index;
            for (index = 0; index < data_type[tage]; index++)
            {
                val[index] = rtData->data[flag + data_type[tage] - 1 - index];
            }
        }
        break;
        case TAG_TYPE_VLENGTH:
        {
            int index;
            if (vlength == 0)
            {
                dbg_syslog(LOG_WARNING, "sign_mark %s vLength val %d", pservice->param_tab->param[k].sign_mark, vlength);
            }
            for (index = 0; index < vlength; index++)
            {
                val[index] = rtData->data[flag + index];
            }
        }
        break;
        default:
            memcpy(val, rtData->data + flag, data_type[tage]);
            break;
        }
        if (ptemplate->protocol == GW_PROTC_MODBUS && (rtData->data[1] == 0x03 || rtData->data[1] == 0x04 || rtData->data[1] == 0x83 || rtData->data[1] == 0x84))
        {
            if (flag == rtData->len - 2 && strcmp(pservice->param_tab->param[k].sign_mark, CRC_STRING) != 0)
            {
                flag += data_type[tage];
                continue;
            }
        }
        // dbg_syslog(LOG_INFO, "data_type[%d] %d val[%d %d]", pservice->param_tab->param[k].raw_data_type, data_type[pservice->param_tab->param[k].raw_data_type], val[0], val[1]);
        if (tage == TAG_TYPE_VLENGTH)
        {
            b64_encode(val, vlength, b64, sizeof(b64));
            cJSON_AddStringToObject(jtag, pservice->param_tab->param[k].sign_mark, (const char *) b64);
            //偏移
            flag += vlength;
        }
        else if (tage == TAG_TYPE_INT8)
        {
            int8_t *tag_val = (int8_t *)val;
            tmp_val = *tag_val;
            TAG_TO_JSON(pservice->param_tab->param[k], jtag, tag_val);
        }
        else if (tage == TAG_TYPE_INT16 || tage == TAG_TYPE_INT16I)
        {
            int16_t *tag_val = (int16_t *)val;
            tmp_val = *tag_val;
            TAG_TO_JSON(pservice->param_tab->param[k], jtag, tag_val);
        }
        else if (tage == TAG_TYPE_INT32I || tage == TAG_TYPE_INT32)
        {
            int32_t *tag_val = (int32_t *)val;
            tmp_val = *tag_val;
            TAG_TO_JSON(pservice->param_tab->param[k], jtag, tag_val);
        }
        else if (tage == TAG_TYPE_INT64)
        {
            int64_t *tag_val = (int64_t *)val;
            tmp_val = *tag_val;
            TAG_TO_JSON(pservice->param_tab->param[k], jtag, tag_val);
        }
        else if (tage == TAG_TYPE_UINT16 || tage == TAG_TYPE_UINT16I)
        {
            uint16_t *tag_val = (uint16_t *)val;
            tmp_val = *tag_val;
            TAG_TO_JSON(pservice->param_tab->param[k], jtag, tag_val);
        } else if (tage == TAG_TYPE_FLOAT || tage == TAG_TYPE_FLOATI) {
            union pp_uint_float pflt;
            unsigned int * pint = (unsigned int *) val;
            float * tag_val = &pflt.f_val;
            pflt.i_val = *pint;
            if (tage == TAG_TYPE_FLOAT)
                pflt.i_val = __builtin_bswap32(pflt.i_val);
            TAG_TO_JSON(pservice->param_tab->param[k], jtag, tag_val);
        } else {
            unsigned int *tag_val = (unsigned int *)val;
            tmp_val = *tag_val;
            TAG_TO_JSON(pservice->param_tab->param[k], jtag, tag_val);
        }

        if (pservice->param_tab->param[k].bit_cnt > 0)
        {
            int i;
            for (i = 0; i < pservice->param_tab->param[k].bit_cnt; i++)
            {
                int count = pservice->param_tab->param[k].bit_fields[i].count;
                int start = pservice->param_tab->param[k].bit_fields[i].start;
		// int mask = (1 << count) - 1;  zgx 修改 2022/3/12
                if (count < 8 && count > 0)
                {
                    unsigned int val = ((tmp_val >> start) & bit_mask[count - 1]);
                    cJSON_AddNumberToObject(jtag, pservice->param_tab->param[k].bit_fields[i].sign_mark, val);
                }
	    }
        }

        if (!strcmp(pservice->param_tab->param[k].sign_mark, CRC_PADDING))
        {
            tmp_index += data_type[tage];
        }

        if (ptemplate->protocol != GW_PROTC_MODBUS && ptemplate->protocol != GW_PROTC_DYWL_LORA_V1 && !strcmp(pservice->param_tab->param[k].sign_mark, CRC_STRING))
        {
            unsigned int crc = 0XFFFFFFFF;
            pp_data_exec_crc_info(var, ptemplate, rtData->data + tmp_index, flag - tmp_index, &crc);
            if (crc != tmp_val)
            {
                dbg_syslog(LOG_WARNING, "data crc error crc 0x%x 0x%x!!!", tmp_val, crc);
                cJSON_Delete(jtag);
                jtag = cJSON_CreateObject();
            }
        }
        //偏移
        flag += data_type[tage];
    }

    return jtag;
}

void find_template_report_period(pp_var_t *var, template_cfg_t *ptemplate, tag_table_t *ptag)
{
    int j;
    unsigned char find = 0;

    // LoRa数据通道
    for (j = 0; j < ptemplate->tag_tab->tagCnt; j++)
    {
        if (!strcmp(ptemplate->tag_tab->tag[j].identifier, ptag->identifier))
        {
            find = 1;
            ptag->data_type = DATA_TYPE_PROPERTY;
            ptag->report_period = ptemplate->tag_tab->tag[j].report_period;
            break;
        }
    }
    if (find == 0)
    {
        //事件解析
        for (j = 0; j < ptemplate->event_tab->eventCnt; j++)
        {
            if (!strcmp(ptemplate->event_tab->event[j].identifier, ptag->identifier))
            {
                find = 1;
                ptag->data_type = DATA_TYPE_EVENT;
                ptag->report_period = ptemplate->event_tab->event[j].report_period;
                break;
            }
        }
    }
    if (find == 0)
    {
        // dbg_syslog(LOG_DEBUG, "serviceCnt %d", ptemplate->service_tab->serviceCnt);
        //服务解析
        for (j = 0; j < ptemplate->service_tab->serviceCnt; j++)
        {
            if (!strcmp(ptemplate->service_tab->service[j].identifier, ptag->identifier))
            {
                find = 1;
                // dbg_syslog(LOG_DEBUG, "identifier:%s", ptemplate->service_tab->service[j].identifier);
                ptag->data_type = DATA_TYPE_SERVICE;
                ptag->report_period = ptemplate->service_tab->service[j].report_period;
                break;
            }
        }
    }

    if (find == 0)
    {
        ptag->data_type = DATA_TYPE_SERVICE;
        /* ptag->report_period; */
    }
}

void parser_tag_info(pp_var_t *var, template_cfg_t *ptemplate, pp_real_time_data_t *rtData, tag_table_t *ptag, unsigned char flag, unsigned char dtu)
{
    int j;
    unsigned char find = 0;
    cJSON *jtag = NULL;

    if (rtData->ts == 0)
    {
        ptag->time = time(NULL);
    }
    else
    {
        ptag->time = rtData->ts;
    }

    // LoRa数据通道
    for (j = 0; j < ptemplate->tag_tab->tagCnt; j++)
    {
        if ((!strlen(rtData->src_identifier) && ptemplate->tag_tab->tag[j].instruction_code == rtData->instruction_code) ||
            (strlen(rtData->src_identifier) && !strcmp(ptemplate->tag_tab->tag[j].identifier, rtData->src_identifier)))
        {
            find = 1;
            ptag->data_type = DATA_TYPE_PROPERTY;
            ptag->report_period = ptemplate->tag_tab->tag[j].report_period;
            jtag = protocol_decode_template_tag(var, ptemplate, &ptemplate->tag_tab->tag[j], rtData, flag);

            if (strlen(ptemplate->tag_tab->tag[j].identifier))
            {
                strncpy(ptag->identifier, ptemplate->tag_tab->tag[j].identifier, sizeof(ptemplate->tag_tab->tag[j].identifier));
            }
            break;
        }
    }
    if (find == 0)
    {
        //事件解析
        for (j = 0; j < ptemplate->event_tab->eventCnt; j++)
        {
            if ((!strlen(rtData->src_identifier) && ptemplate->event_tab->event[j].instruction_code == rtData->instruction_code) ||
                (strlen(rtData->src_identifier) && !strcmp(ptemplate->event_tab->event[j].identifier, rtData->src_identifier)))
            {
                find = 1;
                ptag->data_type = DATA_TYPE_EVENT;
                ptag->report_period = ptemplate->event_tab->event[j].report_period;
                jtag = protocol_decode_template_event(var, ptemplate, &ptemplate->event_tab->event[j], rtData, flag);

                if (strlen(ptemplate->event_tab->event[j].identifier))
                {
                    strncpy(ptag->identifier, ptemplate->event_tab->event[j].identifier, sizeof(ptemplate->event_tab->event[j].identifier));
                }
                break;
            }
        }
    }
    if (find == 0)
    {
        //服务解析
        for (j = 0; j < ptemplate->service_tab->serviceCnt; j++)
        {
            if (ptemplate->service_tab->service[j].direction == 1 &&
                ((!strlen(rtData->src_identifier) && ptemplate->service_tab->service[j].instruction_code == rtData->instruction_code) ||
                 (strlen(rtData->src_identifier) && !strcmp(ptemplate->service_tab->service[j].identifier, rtData->src_identifier))))
            {
                find = 1;
                ptag->data_type = DATA_TYPE_SERVICE;
                ptag->report_period = ptemplate->service_tab->service[j].report_period;

                jtag = protocol_decode_template_service(var, ptemplate, &ptemplate->service_tab->service[j], rtData, flag);

                if (strlen(ptemplate->service_tab->service[j].identifier))
                {
                    strncpy(ptag->identifier, ptemplate->service_tab->service[j].identifier, sizeof(ptemplate->service_tab->service[j].identifier));
                }

                break;
            }
        }
    }
    // dbg_syslog(LOG_INFO, "data_type %d find %d jtag %p", ptag->data_type, find, jtag);
    if (jtag)
    {
        ptag->tag_node = cJSON_PrintUnformatted(jtag);
        cJSON_Delete(jtag);
    }
    else
    {
        dbg_syslog(LOG_WARNING, "data parser error rtData->src_identifier:%s find:%d ptag->data_type:%d!!! ", rtData->src_identifier, find, ptag->data_type);
    }
}

object_cfg_t *pp_find_object(pp_var_t *var, char *object_model_id)
{
    int i;
    for (i = 0; i < var->object_table->object_cnt; i++)
    {
        if (strcmp(object_model_id, var->object_table->object[i].object_model_id) == 0)
        {
            return &(var->object_table->object[i]);
        }
    }

    return NULL;
}

// 输出
// term_addr
// addr_len
// rtData->instruction_code
int pp_data_get_mac_info(pp_var_t *var, pp_real_time_data_t *rtData, char *sub_template_id, char *term_addr, char *addr_len, int offset)
{
    int i;
    unsigned char *data = rtData->data + offset;
    template_cfg_t *ptemplate = NULL;
    char data_type[16] = {0, 2, 2, 4, 4, 4, 2, 4, 2, 4, 4, 1, 1, 8, 8, 0};

    ptemplate = pp_find_template(var->template_table, sub_template_id);
    if (ptemplate == NULL)
    {
        return -1;
    }

    for (i = 0; i < ptemplate->mac_tab->macCnt; i++)
    {
        tag_data_format_e raw_data_type = ptemplate->mac_tab->mac[i].raw_data_type;
        if (!strcmp(ptemplate->mac_tab->mac[i].sign_mark, "term_addr"))
        {
            memcpy(term_addr, data + ptemplate->mac_tab->mac[i].offset, data_type[raw_data_type]);
            *addr_len = data_type[raw_data_type];
        }
        else if (!strcmp(ptemplate->mac_tab->mac[i].sign_mark, "instruction_code"))
        {
            unsigned char val[10];
            //取数据
            switch (ptemplate->mac_tab->mac[i].raw_data_type)
            {
            case TAG_TYPE_UINT16I:
            case TAG_TYPE_INT16I:
            case TAG_TYPE_INT32I:
            case TAG_TYPE_UINT32I:
            case TAG_TYPE_FLOATI:
            {
                int index;
                for (index = 0; index < data_type[raw_data_type]; index++)
                {
                    val[index] = data[ptemplate->mac_tab->mac[i].offset + data_type[raw_data_type] - 1 - index];
                }
            }
            break;
            default:
                memcpy(val, data + ptemplate->mac_tab->mac[i].offset, data_type[raw_data_type]);
                break;
            }

            if (raw_data_type == TAG_TYPE_INT8 || raw_data_type == TAG_TYPE_UINT8)
            {
                rtData->instruction_code = *((uint8_t *)val);
            }
            else if (raw_data_type == TAG_TYPE_INT16 || raw_data_type == TAG_TYPE_INT16I)
            {
                rtData->instruction_code = *((int16_t *)val);
            }
            else if (raw_data_type == TAG_TYPE_INT32I || raw_data_type == TAG_TYPE_INT32)
            {
                rtData->instruction_code = *((int32_t *)val);
            }
            else if (raw_data_type == TAG_TYPE_INT64)
            {
                rtData->instruction_code = *((int64_t *)val);
            }
            else if (raw_data_type == TAG_TYPE_UINT16 || raw_data_type == TAG_TYPE_UINT16I)
            {
                rtData->instruction_code = *((uint16_t *)val);
            }
            else
            {
                rtData->instruction_code = *((unsigned int *)val);
            }
        }
    }

    return 0;
}

static node_cfg_t *pp_get_data_device(pp_var_t *var, pp_real_time_data_t *rtData, int *flag, int *dtu)
{
    char addr_len = 0;
    char term_addr[8] = {0};
    node_cfg_t *node = NULL;
    int ret = 0;
    int i;

    // 有SN，优先查询SN
    if (rtData->sn != 0 && strlen(rtData->sn) != 0)
    {
        for (i = 0; i < var->nodes_cfg_table->node_cnt; i++)
        {
            if (strcmp(var->nodes_cfg_table->node[i].sn, rtData->sn) == 0)
            {
                node = &var->nodes_cfg_table->node[i];
                // return node;
                break;
            }
        }
    }

    // 没有SN，根据上报端口找出数据中的addr信息
    if (rtData->port == LORA_1)
    {
        addr_len = 2;
        memcpy(term_addr, rtData->data, addr_len);
    }
    else if (rtData->port == LORAWAN_1)
    {
        addr_len = 8;
        str2hex((unsigned char *) term_addr, (char *) rtData->term_addr, addr_len);
    }
    else if (rtData->port == RS485_1 || rtData->port == RS485_2 || rtData->port == RS485_3 || rtData->port == RS485_4 ||
        rtData->port == RS485_5 || rtData->port == RS485_6 || rtData->port == RS485_7 || rtData->port == RS485_8 ||
        (rtData->port >= REMOTE_CH_01 && rtData->port <= REMOTE_CH_20) ||
        rtData->port == RS485_9 || rtData->port == RS485_10 || rtData->port == RS485_11 || rtData->port == RS485_12)
    {
        addr_len = 1;
        memcpy(term_addr, rtData->data, addr_len);
        dbg_syslog(LOG_DEBUG, "%s term_addr:%02x", rtData->sn, term_addr[0]);
    }

    if (strlen(rtData->sub_template_id) != 0)
    {
        ret = pp_data_get_mac_info(var, rtData, rtData->sub_template_id, term_addr, &addr_len, 0);
        if (ret == -1)
        {
            dbg_syslog(LOG_ERR, "get mac info error");
            goto out;
        }
    }
    if (node == NULL)
    {
        for (i = 0; i < var->nodes_cfg_table->node_cnt; i++)
        {
            if (rtData->port == var->nodes_cfg_table->node[i].port &&
                memcmp(term_addr, var->nodes_cfg_table->node[i].term_addr, addr_len) == 0)
            {
                node = &var->nodes_cfg_table->node[i];
                break;
            }
        }
    }

    if (node == NULL)
    {
        return NULL;
    }

    if (rtData->instruction_code == 0) //如果没有找到instruction code在mac info中找找
    {

        int data_offset = 0;
        ret = pp_data_get_mac_info(var, rtData, node->template_id, term_addr, &addr_len, data_offset);
        if (ret == -1)
        {
            dbg_syslog(LOG_ERR, "get mac info error");
            goto out;
        }
    }

    if (rtData->port == VINTF_MQTT && node->device_type == DEV_DTU)
    {
        ret = pp_data_get_mac_info(var, rtData, node->sub_template_id, term_addr, &addr_len, 0);
        if (ret == -1)
        {
            dbg_syslog(LOG_ERR, "get mac info error");
            goto out;
        }
        for (i = 0; i < var->nodes_cfg_table->node_cnt; i++)
        {
            if (var->nodes_cfg_table->node[i].depth == 1 && strcmp(var->nodes_cfg_table->node[i].dtu_sn, node->sn) == 0 &&
                memcmp(term_addr, var->nodes_cfg_table->node[i].term_addr, addr_len) == 0)
            {
                node = &var->nodes_cfg_table->node[i];
                return node;
            }
        }
    }

    if ((rtData->port == LORA_1) || (rtData->port == LORAWAN_1))
    {
        int instruction_offset = 0;
        int data_offset = 3;

        if (rtData->port == LORA_1)
        {
            instruction_offset = 2;
        }

        //透传,LoRa和LoRaWan的DTU data[instruction_offset]是功能码
        if (node->device_type == DEV_DTU && rtData->data[instruction_offset] & 0x3F)
        {
            ret = pp_data_get_mac_info(var, rtData, node->sub_template_id, term_addr, &addr_len, data_offset);
            if (ret == -1)
            {
                dbg_syslog(LOG_ERR, "get mac info error");
                goto out;
            }
            for (i = 0; i < var->nodes_cfg_table->node_cnt; i++)
            {
                if (var->nodes_cfg_table->node[i].depth == 1 && strcmp(var->nodes_cfg_table->node[i].dtu_sn, node->sn) == 0 &&
                    memcmp(term_addr, var->nodes_cfg_table->node[i].term_addr, addr_len) == 0)
                {
                    node = &var->nodes_cfg_table->node[i];
                    *flag = 3; // 解析数据时跳过多少字节
                    *dtu = 1;  //是否DTU
                    return node;
                }
            }
        }
    }

    return node;

out:
    return NULL;
}

// 其他协议里面，设备的term_addr隐藏在数据里面，需要脚本解析出来的情况，需要先解析，然后根据解析出来的term_addr查找设备节点
static node_cfg_t *pp_get_data_device_by_tag(pp_var_t *var, tag_table_t *ptag, pp_real_time_data_t *rtData)
{
    char buff[64] = {0};
    char addr[8] = {0};
    int addr_len = 0;
    cJSON *jtag = NULL;
    node_cfg_t *node = NULL;
    int i = 0;

    jtag = cJSON_Parse(ptag->tag_node);
    if (jtag == NULL)
    {
        dbg_syslog(LOG_WARNING, "failed to parse tag_node");
        return NULL;
    }
    GET_JSON_VALUE_STRING(jtag, "sn", buff);
    if (strlen(buff) > 0)
    {
        for (i = 0; i < var->nodes_cfg_table->node_cnt; i++)
        {
            if (strcmp(var->nodes_cfg_table->node[i].sn, buff) == 0)
            {
                node = &var->nodes_cfg_table->node[i];
                break;
            }
        }
    }
    else
    {
        GET_JSON_VALUE_STRING(jtag, "term_addr", buff);
        if (strlen(buff))
        {
            int ret = sscanf(buff, "%02X%02X%02X%02X%02X%02X%02X%02X", &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], &addr[5], &addr[6], &addr[7]);
            addr_len = ret;
        }

        for (i = 0; i < var->nodes_cfg_table->node_cnt; i++)
        {
            if ((rtData->port == var->nodes_cfg_table->node[i].port || strcmp(var->nodes_cfg_table->node[i].dtu_sn, rtData->sn) == 0) &&
                memcmp(addr, var->nodes_cfg_table->node[i].term_addr, addr_len) == 0)
            {
                node = &var->nodes_cfg_table->node[i];
                break;
            }
        }
    }

    cJSON_Delete(jtag);

    return node;
}
static int pp_map_to_object(pp_var_t *var, node_cfg_t *node, tag_table_t *ptag, tag_table_t *ptag_post, int use_parser_url)
{
    int j, k;

    //协议映射物模型
    if (ptag->tag_node != NULL && strlen(ptag->tag_node) > 5)
    {
        ptag->other_platform = node->other_platform;
        if (strlen(node->device_secret))
        {
            ptag->other_platform = 2;
        }

        object_cfg_t *pobject = pp_find_object(var, node->product_key);
        if (pobject)
        {
            char find = 0;

            cJSON *tag_node = cJSON_Parse(ptag->tag_node);
            if (!tag_node)
            {
                dbg_syslog(LOG_ERR, "cJSON_Parse ptag->tag_node error!!!");
                return 1;
            }
            for (j = 0; j < pobject->service_tab->serviceCnt; j++)
            {
                object_service_cfg_t * svrcfg;
                svrcfg = &(pobject->service_tab->service[j]);
                if (!strcmp(svrcfg->identifier, ptag->identifier))
                {
                    cJSON * jtag_new = NULL;
                    object_property_table_t * pout;

                    pout = svrcfg->poutput;
                    ptag->data_type = DATA_TYPE_SERVICE;
                    find = 1;
                    if (use_parser_url != SCRIPT_NONE)
                        break;

                    /* update upvalues for fast Lua expression execution: */
                    if (pout->luast && pout->sign_mark)
                        lua_upvalues_update(pout, tag_node);

                    jtag_new = cJSON_CreateObject();
                    for (k = 0; k < pout->propertyCnt; k++)
                    {
                        if (pout->property[k].need_calc)
                        {
                            if (script_lua_upvalue_exec(jtag_new, pout, &pout->property[k]) < 0) {
                                /* TODO: what to do now? */
                                dbg_syslog(LOG_ERR, "Error, upvalue execution has failed for '%s'", pout->property[k].identifier);
                            }
                        }
                        else
                        {
                            double val;

                            cJSON *val_json = cJSON_GetObjectItem(tag_node, pout->property[k].desc);
                            if (val_json != NULL)
                            {
                                if (val_json->valuestring)
                                {
                                    char tmp[128] = {0};
                                    GET_JSON_VALUE_STRING(tag_node, pout->property[k].desc, tmp);
                                    cJSON_AddStringToObject(jtag_new, pout->property[k].identifier, tmp);
                                }
                                else
                                {
                                    GET_JSON_VALUE_DOUBLE(tag_node, pout->property[k].desc, val);
                                    cJSON_AddNumberToObject(jtag_new, pout->property[k].identifier, val);
                                }
                            }
                            else
                            {
                                dbg_syslog(LOG_ERR, "no item %s", pout->property[k].desc);
                            }
                        }
                    }

                    free(ptag->tag_node);
                    ptag->tag_node = cJSON_PrintUnformatted(jtag_new);
                    cJSON_Delete(jtag_new);
                    break;
                }
            }
            if (!find)
            {
                for (j = 0; j < pobject->event_tab->eventCnt; j++)
                {
                    if (!strcmp(pobject->event_tab->event[j].identifier, ptag->identifier))
                    {
                        ptag->data_type = DATA_TYPE_EVENT;
                        find = 1;
                        if (use_parser_url != SCRIPT_NONE)
                        {
                            break;
                        }
                        cJSON *jtag_new = cJSON_CreateObject();
                        for (k = 0; k < pobject->event_tab->event[j].poutput->propertyCnt; k++)
                        {
                            if (pobject->event_tab->event[j].poutput->property[k].need_calc)
                            {
                                exec_operation_script_lua(var, tag_node, jtag_new, &pobject->event_tab->event[j].poutput->property[k]);
                            } else {
                                double val = 0;

                                cJSON *val_json = cJSON_GetObjectItem(tag_node, pobject->event_tab->event[j].poutput->property[k].desc);

                                if (val_json->valuestring)
                                {
                                    char tmp[128] = {0};
                                    GET_JSON_VALUE_STRING(tag_node, pobject->event_tab->event[j].poutput->property[k].desc, tmp);
                                    cJSON_AddStringToObject(jtag_new, pobject->event_tab->event[j].poutput->property[k].identifier, tmp);
                                }
                                else
                                {
                                    GET_JSON_VALUE_DOUBLE(tag_node, pobject->event_tab->event[j].poutput->property[k].desc, val);
                                    cJSON_AddNumberToObject(jtag_new, pobject->event_tab->event[j].poutput->property[k].identifier, val);
                                }
                            }
                        }

                        free(ptag->tag_node);
                        ptag->tag_node = cJSON_PrintUnformatted(jtag_new);
                        cJSON_Delete(jtag_new);
                        break;
                    }
                }
            }
            if (find && ptag->data_type != DATA_TYPE_PROPERTY)
            {
                for (j = 0; j < pobject->event_tab->eventCnt; j++)
                {
                    if (!strcmp(pobject->event_tab->event[j].identifier, "post"))
                    {
                        cJSON *jtag_new = cJSON_CreateObject();
                        cJSON *jtag_object = cJSON_Parse(ptag->tag_node);
                        cJSON *jtag_tmp = cJSON_Parse(ptag->tag_node);
                        cJSON *child = NULL;

                        for (child = jtag_object->child; child; child = child->next)
                        {
                            if (child->string)
                            {
                                for (k = 0; k < pobject->event_tab->event[j].poutput->propertyCnt; k++)
                                {
                                    if (strcmp(pobject->event_tab->event[j].poutput->property[k].identifier, child->string))
                                    {
                                        continue;
                                    }

                                    if (child->valuestring)
                                    {
                                        char str[512] = {0};
                                        GET_JSON_VALUE_STRING(jtag_object, child->string, str);
                                        if (strlen(str))
                                        {
                                            cJSON_AddStringToObject(jtag_new, child->string, str);
                                        }
                                    }
                                    else
                                    {
                                        double val = 0xFFFFFFFF;
                                        GET_JSON_VALUE_DOUBLE(jtag_object, child->string, val);
                                        if ((pobject->event_tab->event[j].poutput->property[k].max || pobject->event_tab->event[j].poutput->property[k].min) && (val > pobject->event_tab->event[j].poutput->property[k].max || val < pobject->event_tab->event[j].poutput->property[k].min))
                                        {
                                            dbg_syslog(LOG_WARNING, "exception %s value max %1.15g min %1.15g tagD %1.15g ", child->string, pobject->event_tab->event[j].poutput->property[k].max, pobject->event_tab->event[j].poutput->property[k].min, val);
                                            cJSON_DeleteItemFromObject(jtag_tmp, child->string);
                                        }
                                        else
                                            cJSON_AddNumberToObject(jtag_new, child->string, val);
                                    }
                                }
                            }
                        }
                        memcpy(ptag_post, ptag, sizeof(tag_table_t));
                        ptag_post->report_period = 0;
                        memset(ptag_post->identifier, 0, sizeof(ptag_post->identifier));
                        strcpy(ptag_post->identifier, "post");

                        ptag_post->data_type = DATA_TYPE_PROPERTY;
                        ptag_post->tag_node = cJSON_PrintUnformatted(jtag_new);
                        if (ptag_post->tag_node != NULL && strlen(ptag_post->tag_node) < 5)
                        {
                            free(ptag_post->tag_node);
                            ptag_post->tag_node = NULL;
                            memset(ptag_post->sn, 0, sizeof(ptag_post->sn));
                            ptag_post->time = 0;
                        }
                        //过滤数据后的结果
                        free(ptag->tag_node);
                        ptag->tag_node = cJSON_PrintUnformatted(jtag_tmp);
                        cJSON_Delete(jtag_new);
                        cJSON_Delete(jtag_object);
                        cJSON_Delete(jtag_tmp);
                        break;
                    }
                }
            }
            cJSON_Delete(tag_node);
        }
    }
    else if (ptag->tag_node != NULL && strlen(ptag->tag_node) <= 5)
    {
        free(ptag->tag_node);
        ptag->tag_node = NULL;
        memset(ptag->sn, 0, sizeof(ptag->sn));
        ptag->time = 0;
    }

    // dbg_syslog(LOG_INFO, "tag_node len %d  tag_node %p %s", (ptag->tag_node) ? strlen(ptag->tag_node) : 0, ptag->tag_node, ptag->tag_node);
    return 0;
}

static int pp_parse_data(pp_var_t *var, template_cfg_t *ptemplate, pp_real_time_data_t *rtData, tag_table_t *ptag, unsigned char flag, unsigned char dtu)
{

    if (ptemplate->use_parser_url == SCRIPT_NONE)
    {
        // MODBUS读操作去掉crc，避免把crc当有效数据解析
        // if (ptemplate->protocol == GW_PROTC_MODBUS && (rtData->data[1] == 0x03 || rtData->data[1] == 0x04 || rtData->data[1] == 0x83 || rtData->data[1] == 0x84))
        //     rtData->len = rtData->len - 2;
        ptag->data_type = DATA_TYPE_EVENT;
        parser_tag_info(var, ptemplate, rtData, ptag, flag, dtu);
    }
    else if (ptemplate->use_parser_url == SCRIPT_PARSER)
    {
        //使用全脚本解析
        cJSON *jtag = NULL;
        jtag = protocol_decode_script(var, ptemplate, rtData, dtu);
        // dbg_syslog(LOG_INFO, "jtag %p", jtag);
        if (jtag)
        {
            ptag->time = time(NULL);
            // sn,identifier
            GET_JSON_VALUE_STRING(jtag, "identifier", ptag->identifier);

            if (!strlen(ptag->identifier) && strlen(rtData->src_identifier))
            {
                strncpy(ptag->identifier, rtData->src_identifier, sizeof(ptag->identifier));
            }

            cJSON *type = cJSON_GetObjectItem(jtag, "data_type");
            if (type != NULL)
            {
                GET_JSON_VALUE_INT(jtag, "data_type", ptag->data_type);
                if (ptag->data_type != DATA_TYPE_SERVICE && ptag->data_type != DATA_TYPE_EVENT && ptag->data_type != DATA_TYPE_PROPERTY)
                {
                    ptag->data_type = DATA_TYPE_SERVICE;
                }
            }
            else
            {
                ptag->data_type = DATA_TYPE_SERVICE;
            }

            if (ptag->mi == 0)
            {
                int mi;
                GET_JSON_VALUE_INT(jtag, "mi", mi);
                // dbg_syslog(LOG_DEBUG, "from tag mi:%d", mi);
                ptag->mi = mi;
            }

            ptag->tag_node = cJSON_PrintUnformatted(jtag);

            cJSON_Delete(jtag);

            find_template_report_period(var, ptemplate, ptag);
        }
        else
        {
            dbg_syslog(LOG_WARNING, "data parser error !!! tag_node %s", ptag->tag_node);
        }
    }
    return ptemplate->use_parser_url;
}

int pp_parse_data_by_template(pp_var_t *var, template_cfg_t *ptemplate, node_cfg_t *node, pp_real_time_data_t *rtData, unsigned char flag, unsigned char dtu)
{
    tag_table_t ptag = {0};
    tag_table_t ptag_post = {0};
    int use_parser_url = 0;
    int ret = 0;

    ptag.mi = rtData->mi;
    use_parser_url = pp_parse_data(var, ptemplate, rtData, &ptag, flag, dtu);

    //模板细分周期优先
    if (ptag.report_period == 0)
        ptag.report_period = ptemplate->report_period;
    if (node == NULL)
    {
        // 其他协议里面，设备的term_addr隐藏在数据里面，需要脚本解析出来的情况，需要先解析，然后根据解析出来的term_addr查找设备节点
        node = pp_get_data_device_by_tag(var, &ptag, rtData);
        if (node == NULL)
        {
            dbg_syslog(LOG_WARNING, "cannot get the device");
            ret = -1;
            goto out;
        }
    }
    strcpy(ptag.sn, node->sn);
    ret = pp_map_to_object(var, node, &ptag, &ptag_post, use_parser_url);
    ptag.port = rtData->port;
    ptag_post.port = rtData->port;
    strcpy(ptag.requester, rtData->requester);
    strcpy(ptag_post.requester, rtData->requester);
    strncpy(ptag.app_key, node->app_key, MAX_APP_KEY_LEN);
    strncpy(ptag_post.app_key, node->app_key, MAX_APP_KEY_LEN);
    if (rtData->mi)
    {
        ptag.report_period = 0;
    }

    // dbg_syslog(LOG_DEBUG, "parse result:%s post:%s", ptag.tag_node, ptag_post.tag_node);
    if (ptag.tag_node != NULL)
    {
        pp_send_tag_data(var->session, &ptag);
        free(ptag.tag_node);
    }
    if (ptag_post.tag_node != NULL)
    {
        pp_send_tag_data(var->session, &ptag_post);
        free(ptag_post.tag_node);
    }

out:
    free(rtData->data);
    free(rtData);
    return ret;
}

static int pp_data_parser(pp_var_t *var, pp_real_time_data_t *rtData)
{
    node_cfg_t *node = NULL;
    template_cfg_t *ptemplate = NULL;
    int flag = 0;
    int dtu = 0;
    int ret = 0;

    if (strlen(rtData->sub_template_id) != 0)
    {
        // 独占端口的情况，直接根据带上来的sub_template_id找模板
        ptemplate = pp_find_template(var->template_table, rtData->sub_template_id);
        if (ptemplate == NULL)
        {
            dbg_syslog(LOG_ERR, "cannot find template id:%s", rtData->sub_template_id);
            ret = -1;
            goto out;
        }
                // 有SN，优先查询SN
        if (rtData->sn != 0 && strlen(rtData->sn) != 0)
        {
            for (int i = 0; i < var->nodes_cfg_table->node_cnt; i++)
            {//比较sn，找到就比较模板是否一致
                if (strcmp(var->nodes_cfg_table->node[i].sn, rtData->sn)==0)
                {
                    if (strcmp(var->nodes_cfg_table->node[i].template_id,rtData->sub_template_id) != 0)
                    {
                        dbg_syslog(LOG_ERR, "iot template_id %s ,cfg template_id %s, Can not bind more than one device in this iot port:%s", rtData->sub_template_id,var->nodes_cfg_table->node[i].template_id,port_enum2char(rtData->port));
                        ret = -1;
                        goto out;
                    }
                    else
                    {
                        node = &(var->nodes_cfg_table->node[i]);
                        break;
                    }
                }
	    }
        }
    }
    else
    {
        char *template_id = NULL;

        node = pp_get_data_device(var, rtData, &flag, &dtu);
        if (node == NULL)
        {
            dbg_syslog(LOG_ERR, "cannot get the device");
            ret = -1;
            goto out;
        }

        if (node->device_type == DEV_DTU)
        {
            template_id = node->sub_template_id;
            node = NULL;
            dtu = 1;
        }
        else
        {
            template_id = node->template_id;
        }

        ptemplate = pp_find_template(var->template_table, template_id);
        if (ptemplate == NULL)
        {
            dbg_syslog(LOG_ERR, "cannot find template id:%s", node->template_id);
            ret = -1;
            goto out;
        }
    }
#if 1
    // MODBUS CRC校验
    if (ptemplate->protocol == GW_PROTC_MODBUS)
    {
        int data_offset = 0;
        unsigned short crc_calculated;
        if (rtData->port == LORA_1)
            data_offset = 3;

        unsigned char func = rtData->data[data_offset + 1];
        unsigned char nums = rtData->data[data_offset + 2];

        if (func & 0x80)
        {
            dbg_syslog(LOG_ERR, "modbus error code: 0x%X",(rtData->data[ data_offset + 3 ] << 8)|(rtData->data[ data_offset + 4 ]));
            ret = -1;
            goto out;
        }
        else if (func != 0x05 && func != 0x06 && func !=0x0f && func !=0x10 && nums != rtData->len - data_offset -5)
        {
            dbg_syslog(LOG_ERR, "data length error expect: 0x%x real: 0x%x, sn: %s", nums,rtData->len - data_offset - 5, node->sn);
            ret = -1;
            goto out;
        }
        else if (func == 0x03)
        {
            crc_calculated = modbus_data_check_crc(rtData->data + data_offset, rtData->data[data_offset + 2] + 5);
        }
        else
        {
            crc_calculated = modbus_data_check_crc(rtData->data + data_offset, rtData->len - data_offset);
        }

        if (crc_calculated)
        {
            dbg_syslog(LOG_ERR, "modbus crc error 0x%x", crc_calculated);
            ret = -1;
            goto out;
        }
        // int nodeDataLen = rtData->len - data_offset;
        // if (data_offset > 0 && nodeDataLen > 0)
        // {
        //     memmove(rtData->data,&rtData->data[data_offset],nodeDataLen);
        //     rtData->len = nodeDataLen;
        // }
        // }
    #endif
    }

    if (ptemplate->use_parser_url == SCRIPT_PARSER)
    {
        script_data_t script_data;
        script_data.data_decode.rtData = rtData;
        script_data.data_decode.dtu = dtu;
        script_data.data_decode.flag = flag;
        pp_send_data_to_script(var, ptemplate, &script_data, node, SCRIPT_DECODE);
    }
    else if (ptemplate->use_parser_url == SCRIPT_NONE)
    {
        pp_parse_data_by_template(var, ptemplate, node, rtData, flag, dtu);
    }

    return 0;

out:
    free(rtData->data);
    free(rtData);
    return ret;
}

int pp_parse_realtime_data(pp_var_t *var, ipc_msg_t *msg)
{
    pp_real_time_data_t *real_data = NULL;
    int ret = 0;

    real_data = calloc(1, sizeof(pp_real_time_data_t));

    ret = pp_get_rt_data_from_json_str(var, real_data, msg->payload);
    if (ret == -1)
    {
        dbg_syslog(LOG_ERR, "parse real data structure failed");
        return -1;
    }

    if (strcmp(real_data->src_identifier, "__transparent") == 0)
    {
        // don't send report out for internal identifier
        return 0;
    }
    //添加透传通道
    if (strcmp(real_data->src_identifier, "transparent") == 0)
    {
        cJSON *pp_data = cJSON_CreateObject();
        if (pp_data)
        {
            unsigned int UTC = (unsigned int)time(0);

            cJSON_AddStringToObject(pp_data, "sn", real_data->sn);
            cJSON_AddNumberToObject(pp_data, "mi", real_data->mi);
            cJSON_AddNumberToObject(pp_data, "time", UTC);
            cJSON_AddStringToObject(pp_data, "identifier", real_data->src_identifier);

            char *buf = (char *)malloc(MAXBUF);
            if (buf == NULL)
            {
                dbg_syslog(LOG_ERR, "malloc fail");
                free(pp_data);
                return -1;
            }

            b64_encode(real_data->data, real_data->len, buf, MAXBUF);
            cJSON_AddStringToObject(pp_data, "raw_data", buf);
            free(buf);

            char topic[TOPIC_MAX_LEN] = {0};
            char *data_tmp = cJSON_Print(pp_data);
            snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/%s/device/%s/data_filtered/service/%s", var->sn_str, port_enum2char(real_data->port), real_data->sn, real_data->src_identifier);
            ipc_session_publish(var->session, topic, (unsigned char *) data_tmp, (int) strlen(data_tmp));
            free(data_tmp);
            cJSON_Delete(pp_data);
        }
        free(real_data->data);
        free(real_data);
    }
    else
    {
        pp_data_parser(var, real_data);
    }

    return ret;
}
