require "sys" require "utils" require "patch" cjson=require("cjson") MQTT=require("mqtt_library") base64=require("base64") dyutils=require("dyutils") bit=require("bit") lpack=require("lua_pack") syslog=require("syslog") bcd=require("bcd") require "internal_api" bnot = bit.bnot band, bor, bxor = bit.band, bit.bor, bit.bxor lshift, rshift, rol = bit.lshift, bit.rshift, bit.rol local TOPIC_SEND_RGLT_SIGNAL_RAW_DATA="Set_Rglt_Raw" local CAN_PORT = "CANBUS_0" local SN_REG = 0x00 -- from 0x00 to ox0f local SELT_TEST_RESULT_REG = 0x50 local QOS_LEVEL0= 0 local QOS_LEVEL1=1 local QOS_LEVEL2=2 local WRITE = 1 local WRITE_RSP = 2 local READ = 3 local READ_RSP = 4 local GATEWAY_DEV_LEVEL = 4 local GATEWAY_DEV_ID = 0 local FUN_CODE = 0x04 local UART_PORT = "RS485_1" local cmdtype,devlev,devid local sn_regs = {{reg = 0x0000, value = 0}, {reg = 0x0001,value = 0}, {reg = 0x0002, value = 0}, {reg = 0x0003, value = 0}, {reg = 0x0004, value = 0}, {reg = 0x0005,value = 0}, {reg = 0x0006, value = 0}, {reg = 0x0007, value = 0}, {reg = 0x0008, value = 0}, {reg = 0x0009,value = 0}, {reg = 0x000a, value = 0}, {reg = 0x000b, value = 0}, {reg = 0x000c, value = 0}, {reg = 0x000d,value = 0}, {reg = 0x000e, value = 0}, {reg = 0x000f, value = 0} } local seft_test_result_regs = { {reg = SELT_TEST_RESULT_REG, value = 0x0000} } local gw_sn = nil local client = nil local function handler() local pid, status, code = syswait.wait(-1, syswait.WNOHANG) log.error('system exit', pid, status, code) --打印不出来 os.exit(0) end local function parse_can_data(can_data, len) if len == 8 then local _,header,reg1_addr,reg1_val,reg2_val = bunpack(can_data, "S>S>S") log.info(string.format("header: %x, reg1_addr: %x, reg1_addr: %x, reg2_val: %x",header, reg1_addr, reg1_val, reg2_val)) return header, reg1_addr, reg1_val, reg2_val elseif len == 6 then local _,header,reg1_addr,reg1_val = bunpack(can_data, "S>S") log.info(string.format("header: %x, reg1_addr: %x, reg1_addr: %x",header, reg1_addr, reg1_val)) return header,reg1_addr,reg1_val else log.warn("Invalid can_date len") return end end local function parse_header(header) local cmdtype = rshift(header,13) local devlev = band(0x07,rshift(header,10)) local devid = band(0x7f,header) -- print(string.format("0x%x 0x%x 0x%x",cmdtype,devlev,devid)) log.info(string.format("cmdtype: %x, devlev: %x, devid: %x",cmdtype, devlev, devid)) return cmdtype, devlev, devid end local function send_to_can_bus(gw_sn,port,data) local topic = string.format( "to_dev/%s/%s/data/"..TOPIC_SEND_RGLT_SIGNAL_RAW_DATA,gw_sn,port) log.info(nil,"send to can bus:",topic,string.toHex(data)) local framedata = bpack("CCC>S>SA",0,0,0,0,#data,data) log.info(nil, string.toHex(framedata)) client:publish(topic, framedata, QOS_LEVEL0) end local function get_can_data(data) local can_data = string.sub(data,8,-3) local len = #can_data log.info("get_can_data",string.toHex(can_data)) if len~=6 and len~=8 then log.warn(string.format("Invalid len of can data: %d",len)) return end return can_data, len end local function get_sn() local sn = '' for _, v in pairs(sn_regs) do -- show print(v.reg, " ", string.format("0x%x", v.value)) sn = sn .. string.char(v.value) -- print(v.value) end -- print(sn) return sn end local function get_product_from_sn(sn) local product = string.sub(sn, 2, 5) return product end local function write_sn_product_to_gateway() local sn = get_sn() local product = get_product_from_sn(sn) -- product = sn[2-5] local cmd = string.format("factory set -sn %s -product %s", sn, product) log.info(string.format("cmd: %s",cmd)) os.execute(cmd) end local function handle_write_sn(reg1_addr, len, reg1_val, reg2_val) if len == 6 then for _, v in pairs(sn_regs) do -- write value to first register if v.reg == reg1_addr then v.value = reg1_val end end elseif len == 8 then -- write value to second register local reg2_addr = reg1_addr + 1 for _, v in pairs(sn_regs) do if v.reg == reg1_addr then v.value = reg1_val elseif v.reg == reg2_addr then v.value = reg2_val end end end -- for _, v in pairs(sn_regs) do -- show -- log.info(nil, v.reg, " ", string.format("0x%x", v.value)) -- end if len == 8 and reg1_addr == 0x0E then write_sn_product_to_gateway() elseif len == 6 and reg1_addr == 0x0F then write_sn_product_to_gateway() end end local function ex_pack(addr, func, regaddr, regsize, data) log.info("485cache_api", addr, func, string.format("0x%04X", regaddr),regsize, data and string.toHex(data)) local raw_data = nil if not addr or not func or not regaddr or not regsize then log.warn("ex_pack", "修改设备层级") return nil end raw_data = bpack("CC>S>S", addr, func, regaddr, regsize) -- 有数据增加二进制数据 if data and #data > 0 then if func == 0x01 and #data ~= regsize / 2 then log.warn("ex_pack",string.format("buff size and regsize are conflict, size:%d,regsize:%d",#data, regsize)) return nil end for i = 1, #data do raw_data = raw_data .. bpack("C", data:byte(i)) end end raw_data = raw_data .. bpack(">S", dyutils.CRC16(raw_data, #raw_data)) last_cmd = {time = os.time(), func = func, addr = addr, regaddr = regaddr} return raw_data end local function send_modbusrtu_req(gw_sn,port,dev_sn,identifier,addr,regaddr,regsize,mi) -- local topic = "to_Front/218800002001_TCP50001/transprent" local hex = ex_pack(addr, FUN_CODE, regaddr, regsize) log.info("read data:",string.toHex(hex)) internal_api.pp2south(gw_sn,dev_sn,port,identifier,hex,0,mi) end local function kill_process_ts_print() local cmd = "ps" local f = assert(io.popen(cmd)) local s = nil if f then s = assert(f:read('*a')) end f:close() if string.find(s,"ts_print") then os.execute("killall -9 ts_print\n") log.info(nil, "killall -9 ts_print") end end local function start_detect_screen_input() kill_process_ts_print() local f = io.open("screen_input.txt", "r") if(f ~= nil ) then os.remove("screen_input.txt") log.info(nil, "remove screen_input.txt") end os.execute("export TSLIB_TSDEVICE=/dev/input/event1; ts_print >> screen_input.txt &") end local function screen_input_test_result_check() local f = io.open("screen_input.txt", "r") if(f == nil ) then log.error(nil, "There is no checking file screen_input.txt") return false end local cmd = "head -1 screen_input.txt | awk -F \' \' \'{print $3}\'" log.info(nil, "cmd: ", cmd) local f = assert(io.popen(cmd)) local s = nil if f then s = assert(f:read('*a')) end f:close() if (s == "") then log.error(nil, "file is empty") return end if (s == "0\n") then log.error(nil, "s == 0") else seft_test_result_regs[1].value = bor(seft_test_result_regs[1].value,lshift(0x01,6)) log.info(nil, "seft_test_result_regs[1].value: ", string.format("0x%x", seft_test_result_regs[1].value)) log.info(nil, "s: ", s) end end local function modbusrtu_selftest() local dev_sn = gw_sn .. "01" local identifier = "ClusterInformationRequest" local slave_dev_addr = 1 local reg_addr = 0x01 local len = 1 local mi = 0 send_modbusrtu_req(gw_sn, UART_PORT, dev_sn, identifier, slave_dev_addr, reg_addr, len, mi) end local function wan_lan_wifi_4g_sdcard_udisk_sefltest() local cmd = "./wan_4g_lan_wifi_udisk_sdcard_selftest.sh" local f = assert(io.popen(cmd)) local s = nil if f then s = assert(f:read('*a')) end f:close() if string.find(s,"WAN=PASSED") then seft_test_result_regs[1].value = bor(seft_test_result_regs[1].value,0x01) log.info(nil, "WAN=PASSED") end if string.find(s,"4G=PASSED") then seft_test_result_regs[1].value = bor(seft_test_result_regs[1].value,lshift(0x01,1)) log.info(nil, "4G=PASSED") end if string.find(s,"LAN=PASSED") then seft_test_result_regs[1].value = bor(seft_test_result_regs[1].value,lshift(0x01,2)) log.info(nil, "LAN=PASSED") end if string.find(s,"WIFI0=PASSED") then seft_test_result_regs[1].value = bor(seft_test_result_regs[1].value,lshift(0x01,3)) log.info(nil, "WIFI0=PASSED") end if string.find(s,"/dev/sda=PASSED") then seft_test_result_regs[1].value = bor(seft_test_result_regs[1].value,lshift(0x01,4)) log.info(nil, "/dev/sda=PASSED") end if string.find(s,"tfcard=PASSED") then seft_test_result_regs[1].value = bor(seft_test_result_regs[1].value,lshift(0x01,5)) log.info(nil, "tfcard=PASSED") end end local function handle_start_selftest(reg1_val) if reg1_val == 1 then seft_test_result_regs[1].value = 0x0000 log.info(nil, "start selftest") start_detect_screen_input() modbusrtu_selftest() wan_lan_wifi_4g_sdcard_udisk_sefltest() end end local function generate_can_resp_head(cmd_code, devlev, devid) local head = 0x0000 head = bor(head, cmd_code) head = bor(lshift(head,3), devlev) head = bor(lshift(head,10), devid) -- print("head: ", string.format("0x%x", head)) return head end local function prepare_can_write_resp(can_write_resp_head, reg1_addr, len, reg1_val, reg2_val) if len == 8 then local can_data_resp = bpack("S>S>S", can_write_resp_head, reg1_addr, reg1_val, reg2_val) return can_data_resp elseif len == 6 then local can_data_resp = bpack("S>S", can_write_resp_head, reg1_addr, reg1_val) return can_data_resp else -- do nothing end end local function send_write_resp(reg1_addr, len, reg1_val, reg2_val) local can_write_resp_head = generate_can_resp_head(WRITE_RSP, devlev, devid) local can_write_resp_data = prepare_can_write_resp(can_write_resp_head, reg1_addr, len, reg1_val, reg2_val) send_to_can_bus(gw_sn, CAN_PORT, can_write_resp_data) end local function handle_write_actions(reg1_addr, len, reg1_val, reg2_val) send_write_resp(reg1_addr, len, reg1_val, reg2_val) sys.wait(300) -- waitting for send mqtt message if reg1_addr >= 0x0000 and reg1_addr <=0x000F then handle_write_sn(reg1_addr, len, reg1_val, reg2_val) elseif reg1_addr == 0x0040 then handle_start_selftest(reg1_val) else log.error("handle_write_actions","Invalid addr: ",string.format("0x%x", reg1_addr)) end end local function handle_read_selftest_result(gw_sn, can_port, addr, len) if addr ~= seft_test_result_regs[1].reg or len ~= 1 then log.warn("Invalid len of read selftest result: ", len) return end kill_process_ts_print() screen_input_test_result_check() local can_read_resp_head = generate_can_resp_head(READ_RSP, devlev, devid) local can_data_resp = bpack("S>S", can_read_resp_head, seft_test_result_regs[1].reg, seft_test_result_regs[1].value) send_to_can_bus(gw_sn, can_port, can_data_resp) end local function handle_read_sn(gw_sn, can_port, addr, len) if addr ~= sn_regs[1].reg or len ~= 16 then log.warn("Invalid len of read sn: ", len) return end for i=1,16,1 do local value = string.byte(gw_sn,i,i) sn_regs[i].value = value end for _, v in pairs(sn_regs) do log.debug(string.format("%d:0x%x", v.reg, v.value)) end local can_read_resp_head = generate_can_resp_head(READ_RSP, devlev, devid) for i=1,16,2 do local can_data_resp = bpack("S>S>S", can_read_resp_head, sn_regs[i].reg, sn_regs[i].value, sn_regs[i+1].value) send_to_can_bus(gw_sn, can_port, can_data_resp) end end local function handle_read_actions(gw_sn, can_port, addr, len) if addr == SELT_TEST_RESULT_REG then handle_read_selftest_result(gw_sn, can_port, addr, len) elseif addr == SN_REG then handle_read_sn(gw_sn, can_port, addr, len) else log.warn("Invalid addr: ", addr) end end --! @param framedata: The structure of framedata is as follows: -- 00000700000000000102030405FFFF0E5B -- The definations of each field are like follows, they are defined in xieneng_can -- typedef struct -- { -- unsigned char layer; -- unsigned char dev_id; -- unsigned char func; -- unsigned char start_addr_hi; -- unsigned char start_addr_lo; -- unsigned char reg_cnt_hi; -- unsigned char reg_cnt_lo; -- unsigned char data[0]; -- } __attribute__((packed)) xieneng_header_t; -- The last two bytes of framedata are CRC check -- So the can_data = string.sub(framedata,8,-3), it is 000102030405FFFF local function port2pp(framedata,lenth) local can_data, len = get_can_data(framedata) if not can_data or not len then return end local header, reg1_addr, reg1_val, reg2_val = parse_can_data(can_data, len) cmdtype,devlev,devid = parse_header(header) if devlev ~= GATEWAY_DEV_LEVEL or devid ~= GATEWAY_DEV_ID then log.error("port2pp","Invalid devlev or devid:",string.format("devlev:%d, devid:%d", devlev, devid)) return end if cmdtype == WRITE then handle_write_actions(reg1_addr, len, reg1_val, reg2_val) elseif cmdtype == READ then handle_read_actions(gw_sn, CAN_PORT, reg1_addr, reg1_val) else log.error("port2pp","recv packet err:",string.format("cmdtype:0x%x,devlev:%d,devid:%d",cmdtype,devlev,devid)) end end local function modbus_receive(input) local obj = cjson.decode(input) if obj.port == UART_PORT and obj.instruction_code == FUN_CODE then log.info(nil, "modbus test passed!") seft_test_result_regs[1].value = bor(seft_test_result_regs[1].value,lshift(0x01,7)) log.info(nil, "seft_test_result_regs[1].value: ", string.format("0x%x", seft_test_result_regs[1].value)) end end local function on_mqtt_msg(topic, payload) if string.find(topic,"data/binary_cmd") then local ret,err = pcall(port2pp,payload,#payload) if not ret then log.warn("mqtt.recv",err) end elseif string.find(topic, "data/raw_data") then -- log.info(nil,"twin", topic, payload) modbus_receive(payload) else log.info("due message:",topic, payload) end end local function main(sn) gw_sn = sn if not gw_sn then gw_sn = io.getGatewayID() -- gw_sn = "21012C00FFFF" log.info("main_loop", string.format("Try Run At Shell\nsn='%s'\n",gw_sn or "NOT SN")) end siganl.signal(siganl.SIGKILL,handler) siganl.signal(siganl.SIGHUP,handler) local subscribe = { string.format("dev/+/%s/data/binary_cmd",CAN_PORT), string.format("ipc/%s/RS485_1/device/+/data/raw_data", gw_sn) } client = internal_api.mqtt_session("localhost", 1883, nil, nil, subscribe, on_mqtt_msg) sys.taskInit(function() local start_time = os.time() while true do sys.wait(1000) if (os.difftime(os.time(), start_time) >= 60*30) then kill_process_ts_print() return end end end) sys.init(0, 0) sys.run() end main(arg[1])