--[[
--provide CRC16, base64 encode/decode--
local dyutils=require("dyutils")
--provide bitwise--
local bit=require("bit")
--provide bpack/bunpack--
local lpack=require("lua_pack")
--provide json encode/decode--
local cjson=require("cjson")
require("base64")
]] --
require("patch")
require ("math")

--记录上次总有功功率值,正向有功电量和反向有功电量，如果两次差值大于设置LIMIT值，整个服务部上报
last_TAG_272F = 0
last_TAG_2734 = 0
last_TAG_2739 = 0
TAG_LIMIT = 2000

loadmeter_serviceup = {{
    identifier = "sanxiangcv",
    tags = {
        TAG_2716 = 0,
        TAG_2717 = 0,
        TAG_2718 = 0,
        TAG_2719 = 0,
        TAG_271A = 0,
        TAG_271B = 0
    }
}, {
    identifier = "sanxianggongluxinxi",
    tags = {
        TAG_272F = 0,
        TAG_271C = 0,
        TAG_271D = 0,
        TAG_271E = 0,
        TAG_2730 = 0,
        TAG_271F = 0,
        TAG_2720 = 0,
        TAG_2721 = 0,
        TAG_2732 = 0,
        TAG_2722 = 0,
        TAG_2723 = 0,
        TAG_2724 = 0
    }
}, {
    identifier = "yougongzongdianliang",
    tags = {
        TAG_2734 = 0,
        TAG_2739 = 0,
        TAG_2728 = 0
    }
}}

function stradd33(hex)
    local out = ''
    for i = 1, #hex do
        out = out .. string.char(string.byte(hex, i, i) + 0x33)
    end
    return out
end


function protocol_encode(json_str, len)
    local err_code = 0
    -- 取出入参--
    local obj = cjson.decode(json_str)
    local id = obj.identifier
    local term_addr_str = ''
    for i = #obj.term_addr - 1, 1, -2 do
        term_addr_str = term_addr_str .. string.char(tonumber(string.sub(obj.term_addr, i, i + 1), 16))
    end
    -- '278934'-> '60....'
    local test_data = stradd33(term_addr_str)
    -- 编码--
    local data_id = ''
    local data_id2 = ''
    local format = "C1AC3<I1"
    local data_str = ''
    if (id == 'GetzhengxiangElectricEnergy') then
        data_id = 0x00010000 + 0x33333333
        format = "C1AC3<I1"
        data_str = bpack(format, 0x68, term_addr_str, 0x68, 0x11, 0x04, data_id)
    elseif (id == 'GetfanxiangElectricEnergy') then
        data_id = 0x00020000 + 0x33333333
        format = "C1AC3<I1"
        data_str = bpack(format, 0x68, term_addr_str, 0x68, 0x11, 0x04, data_id)
    elseif (id == 'zuheyougongzongdianneng') then
        data_id = 0x00000000 + 0x33333333
        format = "C1AC3<I1"
        data_str = bpack(format, 0x68, term_addr_str, 0x68, 0x11, 0x04, data_id)
    elseif (id == 'bianbi') then
        data_id = 0x04000306 + 0x33333333
        format = "C1AC3<I1"
        data_str = bpack(format, 0x68, term_addr_str, 0x68, 0x11, 0x04, data_id)
    elseif (id == "dianya") then
        data_id = 0x35343233
        format = "C1AC3<I1"
        data_str = bpack(format, 0x68, term_addr_str, 0x68, 0x11, 0x04, data_id)
    elseif (id == 'dianliu') then
        data_id = 0x35353233
        format = "C1AC3<I1"
        data_str = bpack(format, 0x68, term_addr_str, 0x68, 0x11, 0x04, data_id)
    elseif (id == 'gonglu') then
        data_id = 0x35363233
        format = "C1AC3<I1"
        data_str = bpack(format, 0x68, term_addr_str, 0x68, 0x11, 0x04, data_id)
    elseif (id == 'wugonggonglu') then
        data_id = 0x35373233
        format = "C1AC3<I1"
        data_str = bpack(format, 0x68, term_addr_str, 0x68, 0x11, 0x04, data_id)
    elseif (id == 'gongluyinshu') then
        data_id = 0x35393233
        format = "C1AC3<I1"
        data_str = bpack(format, 0x68, term_addr_str, 0x68, 0x11, 0x04, data_id)
    elseif (id == 'GetAddr') then
        format = "C1AC3"
        local term_addr = "\170\170\170\170\170\170"
        data_str = bpack(format, 0x68, term_addr, 0x68, 0x13, 0x00)
    else
        return -1, nil, 0
    end
    local crc = 0
    for i = 1, #data_str do
        crc = bit.band(crc + string.byte(string.sub(data_str, i, i)), 0xFF)
    end
    format = "AC2"
    local bin_str = bpack(format, data_str, crc, 0x16)
    -- 出参格式化--
    local t_str = ''
    for i = 1, #bin_str do
        t_str = t_str .. (string.format("%02X", string.byte(string.sub(bin_str, i, i))))
    end
    bin_str = t_str
    -- print("encode", err_code, bin_str, #bin_str)
    return err_code, bin_str, #bin_str
end

function protocol_decode(input_str, len)
    local err_code = 0
    -- 取出入参--
    data1 = 0
    data2 = 0
    data3 = 0
    data4 = 0
    data5 = 0
    data6 = 0
    data7 = 0
    data8 = 0
    data9 = 0
    data10 = 0
    data11 = 0
    data12 = 0
    local obj = {}
    local input_obj = cjson.decode(input_str)
    local bin_str = input_obj.raw_data
    local id = input_obj.identifier
    -- 入参中的raw_data的二进制转换--
    local t_str = ''
    for i = 1, #bin_str, 2 do
        t_str = t_str .. string.char(tonumber(string.sub(bin_str, i, i + 1), 16))
    end
    bin_str = t_str
    -- 分割位域--
    if string.sub(bin_str, 1, 4) == string.char(0xFE, 0xFE, 0xFE, 0xFE) then
        bin_str = string.sub(bin_str, 5, #bin_str)
    end
    local format = "C1A6C3<I1C6"
    if (id == 'GetzhengxiangElectricEnergy') or (id == 'GetfanxiangElectricEnergy') or (id == 'zuheyougongzongdianneng') then
        format = "C1A6C3<I1C6"
        _, _, addr, _, control, length, data_id, data1, data2, data3, data4, crc, _ = bunpack(bin_str, format)

    elseif (id == 'dianya') then
        format = "C1A6C3<I1C8"
        _, _, addr, _, control, length, data_id, data1, data2, data3, data4, data5, data6, crc, _ = bunpack(bin_str,
            format)
    elseif (id == 'gongluyinshu') then
        format = "C1A6C3<I1C10"
        _, _, addr, _, control, length, data_id, data1, data2, data3, data4, data5, data6, data7, data8, crc, _ =
            bunpack(bin_str, format)
    elseif (id == 'dianliu') then
        format = "C1A6C3<I1C11"
        _, _, addr, _, control, length, data_id, data1, data2, data3, data4, data5, data6, data7, data8, data9, crc, _ =
            bunpack(bin_str, format)
    elseif (id == 'gonglu') or (id == "wugonggonglu") then
        format = "C1A6C3<I1C14"
        _, _, addr, _, control, length, data_id, data1, data2, data3, data4, data5, data6, data7, data8, data9, data10, data11, data12, crc, _ =
            bunpack(bin_str, format)
    elseif (id == 'bianbi') then
        format = "C1A6C3<I1C5"
        _, _, addr, _, control, length, data_id, data1, data2, data3, crc, _ = bunpack(bin_str, format)
        data4 = 0
    elseif (id == 'GetAddr') then
        format = "C1A6C3A6C2"
        _, _, addr, _, control, length, data1, crc, _ = bunpack(bin_str, format)
    else
        return -1, nil, 0
    end
    if ((id ~= "GetAddr" and control ~= 0x91) or (id == "GetAddr" and control ~= 0x93)) then
        return -2, nil, 0
    end
    local calc_crc = 0
    for i = 1, #bin_str - 2 do
        calc_crc = bit.band(calc_crc + string.byte(string.sub(bin_str, i, i)), 0xFF)
    end
    if (calc_crc ~= crc) then
        return -3, nil, 0
    end
    -- 计算--
    data1 = data1 - 0x33
    data2 = data2 - 0x33
    data3 = data3 - 0x33
    data4 = data4 - 0x33
    data5 = data5 - 0x33
    data6 = data6 - 0x33
    data7 = data7 - 0x33
    data8 = data8 - 0x33
    data9 = data9 - 0x33
    data10 = data10 - 0x33
    data11 = data11 - 0x33
    data12 = data12 - 0x33

    if (id == "gongluyinshu") then
        if bit.band(data2, 0x80) == 0x80 then
            data2 = bit.band(data2, 0x7F)
            data4 = bit.band(data4, 0x7F)
            data6 = bit.band(data6, 0x7F)
            data8 = bit.band(data8, 0x7F)
            fuhao = -1
        else
            fuhao = 1
        end

    elseif (id == 'dianliu') or (id == 'gonglu') or (id == 'wugonggonglu') then
        if bit.band(data3, 0x80) == 0x80 then
            data3 = bit.band(data3, 0x7F)
            data6 = bit.band(data6, 0x7F)
            data9 = bit.band(data9, 0x7F)
            data12 = bit.band(data12, 0x7F)
            fuhao = -1
        else
            fuhao = 1
        end
    end

    data1 = ((bit.rshift(data1, 4)) * 10 + (bit.band(data1, 0x0f)))
    data2 = ((bit.rshift(data2, 4)) * 10 + (bit.band(data2, 0x0f)))
    data3 = ((bit.rshift(data3, 4)) * 10 + (bit.band(data3, 0x0f)))
    data4 = ((bit.rshift(data4, 4)) * 10 + (bit.band(data4, 0x0f)))
    data5 = ((bit.rshift(data5, 4)) * 10 + (bit.band(data5, 0x0f)))
    data6 = ((bit.rshift(data6, 4)) * 10 + (bit.band(data6, 0x0f)))
    data7 = ((bit.rshift(data7, 4)) * 10 + (bit.band(data7, 0x0f)))
    data8 = ((bit.rshift(data8, 4)) * 10 + (bit.band(data8, 0x0f)))
    data9 = ((bit.rshift(data9, 4)) * 10 + (bit.band(data9, 0x0f)))
    data10 = ((bit.rshift(data10, 4)) * 10 + (bit.band(data10, 0x0f)))
    data11 = ((bit.rshift(data11, 4)) * 10 + (bit.band(data11, 0x0f)))
    data12 = ((bit.rshift(data12, 4)) * 10 + (bit.band(data12, 0x0f)))

    if (id == 'GetzhengxiangElectricEnergy') then
        obj.TAG_2734 = (data4 * 1000000 + data3 * 10000 + data2 * 100 + data1) / 100
		if math.abs(obj.TAG_2734) - last_TAG_2734 > TAG_LIMIT and last_TAG_2734 ~= 0 then 
			return err_code,nil,0
		else
			last_TAG_2734 = math.abs(obj.TAG_2734)
		end
 		print("record zhengxiangElectricEnergy",last_TAG_2734,obj.TAG_2734,math.abs(obj.TAG_2734))
        for k, v in pairs(loadmeter_serviceup) do
            if v.identifier == "yougongzongdianliang" then
                v.tags["TAG_2734"] = obj.TAG_2734 * 400
                obj = {}
                obj.identifier = v.identifier
                for kk, vv in pairs(v.tags) do
                    obj[kk] = vv;
                end
                local json_str = cjson.encode(obj)
                -- print("decode:", err_code, json_str, #json_str)
                return err_code, json_str, #json_str
            end
        end

    elseif (id == 'GetfanxiangElectricEnergy') then
        obj.TAG_2739 = (data4 * 1000000 + data3 * 10000 + data2 * 100 + data1) / 100
		if math.abs(obj.TAG_2739) - last_TAG_2739 > TAG_LIMIT and last_TAG_2739 ~= 0 then 
			return err_code,nil,0
		else
			last_TAG_2739 = math.abs(obj.TAG_2739)
		end
 		print("record fanxiangElectricEnergy:",last_TAG_2739,obj.TAG_2739,math.abs(obj.TAG_2739))
        for k, v in pairs(loadmeter_serviceup) do
            if v.identifier == "yougongzongdianliang" then
                v.tags["TAG_2739"] = obj.TAG_2739 * 400
                obj = {}
                obj.identifier = v.identifier
                for kk, vv in pairs(v.tags) do
                    obj[kk] = vv;
                end
                local json_str = cjson.encode(obj)
                -- print("decode:", err_code, json_str, #json_str)
                return err_code, json_str, #json_str
            end
        end
    elseif (id == 'zuheyougongzongdianneng') then
        obj.TAG_2728 = (data4 * 1000000 + data3 * 10000 + data2 * 100 + data1) / 100
        for k, v in pairs(loadmeter_serviceup) do
            if v.identifier == "yougongzongdianliang" then
                v.tags["TAG_2728"] = obj.TAG_2728 * 400
                obj = {}
                obj.identifier = v.identifier
                for kk, vv in pairs(v.tags) do
                    obj[kk] = vv;
                end
                local json_str = cjson.encode(obj)
                -- print("decode:", err_code, json_str, #json_str)
                return err_code, json_str, #json_str
            end
        end
    elseif (id == 'dianya') then
        obj.TAG_2716 = (data2 * 100 + data1) / 10
        obj.TAG_2717 = (data4 * 100 + data3) / 10
        obj.TAG_2718 = (data6 * 100 + data5) / 10
        for k, v in pairs(loadmeter_serviceup) do
            if v.identifier == "sanxiangcv" then
                v.tags["TAG_2716"] = obj.TAG_2716
                v.tags["TAG_2717"] = obj.TAG_2717
                v.tags["TAG_2718"] = obj.TAG_2718
                obj = {}
                obj.identifier = v.identifier
                for kk, vv in pairs(v.tags) do
                    obj[kk] = vv;
                end
                local json_str = cjson.encode(obj)
                -- print("decode:", err_code, json_str, #json_str)
                return err_code, json_str, #json_str
            end
        end
    elseif (id == 'dianliu') then
        obj.TAG_2719 = (data3 * 10000 + data2 * 100 + data1) / 1000  * 400 * fuhao
        obj.TAG_271A = (data6 * 10000 + data5 * 100 + data4) / 1000  * 400 * fuhao
        obj.TAG_271B = (data9 * 10000 + data8 * 100 + data7) / 1000  * 400 * fuhao
        for k, v in pairs(loadmeter_serviceup) do
            if v.identifier == "sanxiangcv" then
                v.tags["TAG_2719"] = obj.TAG_2719
                v.tags["TAG_271A"] = obj.TAG_271A
                v.tags["TAG_271B"] = obj.TAG_271B
                obj = {}
                obj.identifier = v.identifier
                for kk, vv in pairs(v.tags) do
                    obj[kk] = vv;
                end
                local json_str = cjson.encode(obj)
                return err_code, json_str, #json_str
            end
        end
    elseif (id == 'gonglu') then
        obj.TAG_272F = (data3 * 10000 + data2 * 100 + data1) / 10000  * 400 * fuhao
 		if math.abs(obj.TAG_272F) - last_TAG_272F > TAG_LIMIT and last_TAG_272F ~= 0 then 
 			return err_code,nil,0
 		else
 			last_TAG_272F = math.abs(obj.TAG_272F)
 		end
 		print("record gonglu:",last_TAG_272F,obj.TAG_272F,math.abs(obj.TAG_272F))
        obj.TAG_271C = (data6 * 10000 + data5 * 100 + data4) / 10000  * 400 * fuhao
        obj.TAG_271D = (data9 * 10000 + data8 * 100 + data7) / 10000  * 400 * fuhao
        obj.TAG_271E = (data12 * 10000 + data11 * 100 + data10) / 10000  * 400 * fuhao
        for k, v in pairs(loadmeter_serviceup) do
            if v.identifier == "sanxianggongluxinxi" then
                v.tags["TAG_272F"] = obj.TAG_272F 
                v.tags["TAG_271C"] = obj.TAG_271C
                v.tags["TAG_271D"] = obj.TAG_271D
                v.tags["TAG_271E"] = obj.TAG_271E
                obj = {}
                obj.identifier = v.identifier
                for kk, vv in pairs(v.tags) do
                    obj[kk] = vv;
                end
                local json_str = cjson.encode(obj)
                return err_code, json_str, #json_str
            end
        end
    elseif (id == 'wugonggonglu') then
        obj.TAG_2730 = (data3 * 10000 + data2 * 100 + data1) / 10000  * 400 * fuhao
        obj.TAG_271F = (data6 * 10000 + data5 * 100 + data4) / 10000  * 400 * fuhao
        obj.TAG_2720 = (data9 * 10000 + data8 * 100 + data7) / 10000  * 400 * fuhao
        obj.TAG_2721 = (data12 * 10000 + data11 * 100 + data10) / 10000  * 400 * fuhao
        for k, v in pairs(loadmeter_serviceup) do
            if v.identifier == "sanxianggongluxinxi" then
                v.tags["TAG_2730"] = obj.TAG_2730
                v.tags["TAG_271F"] = obj.TAG_271F
                v.tags["TAG_2720"] = obj.TAG_2720
                v.tags["TAG_2721"] = obj.TAG_2721
                obj = {}
                obj.identifier = v.identifier
                for kk, vv in pairs(v.tags) do
                    obj[kk] = vv;
                end
                local json_str = cjson.encode(obj)
                return err_code, json_str, #json_str
            end
        end
    elseif (id == 'gongluyinshu') then
        obj.TAG_2732 = (data2 * 100 + data1) / 1000 * fuhao
        obj.TAG_2722 = (data4 * 100 + data3) / 1000 * fuhao
        obj.TAG_2723 = (data6 * 100 + data5) / 1000 * fuhao
        obj.TAG_2724 = (data8 * 100 + data7) / 1000 * fuhao
        for k, v in pairs(loadmeter_serviceup) do
            if v.identifier == "sanxianggongluxinxi" then
                v.tags["TAG_2732"] = obj.TAG_2732
                v.tags["TAG_2722"] = obj.TAG_2722
                v.tags["TAG_2723"] = obj.TAG_2723
                v.tags["TAG_2724"] = obj.TAG_2724
                obj = {}
                obj.identifier = v.identifier
                for kk, vv in pairs(v.tags) do
                    obj[kk] = vv;
                end
                local json_str = cjson.encode(obj)
                return err_code, json_str, #json_str
            end
        end

    elseif (id == 'bianbi') then
        obj.ct = (data * 10000 + data2 * 100 + data1)
    end
    -- 出参格式化--
    obj.term_addr = ''
    for i = #addr, 1, -1 do
        obj.term_addr = obj.term_addr .. (string.format("%02X", string.byte(string.sub(addr, i, i))))
    end
    obj.identifier = id
    obj.ammeterAddr = obj.term_addr
    local json_str = cjson.encode(obj)
    print("decode:", err_code, json_str, #json_str)
    return err_code, json_str, #json_str
end
-- protocol_encode('{"term_addr":"053602000000","identifier":"GetTotalElectricEnergy"}',36)
-- protocol_decode('{"raw_data":"FEFEFEFE6836170630196768910833333333333333330416","identifier":"GetTotalElectricEnergy"}',36)
