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 UPGRADE_TYPE = "upgrade" local CMD_TYPE = "cmdType" local RESET_STRING = "reset" local SHOW_VERSIONG = "ShowVersion" local SHOW_VERSION_REPLAY = "Show_version" local UPGRADE_START = "StartPrg" local STARTPRG_READY = "Ready" local STARTPRG_BUSY = "Busy" local UPGRADE_END = "EndPrg" local ENDPRG_SUCCESS="Success" local ENDPRG_FAILED = "Failed" local UPGRADE_CMD_STATE = "State" local UPGRADE_PROGRESS = "UpgradeProgress" local UPGRADE_DOING = "Upgrade_doing" local UPGRADE_FINISH = "Upgrade_finish" local UPGRADE_ERROR = "Upgrade_error" local FILE_NOT_EXIST = "File not exsit" local TOPIC_SEND_RGLT_SIGNAL_RAW_DATA="Set_Rglt_Raw" local BINARY_CMD_TOPIC ="binary_cmd" local UPGRADE_CMD = 0xD0 local UPGRADE_REQUEST = 0 local UPGRADE_REPLY = 0XFF local BROADCAST_FLAG = 0x8000 local LAYER_3_OFFSET = 12 local LAYER_2_OFFSET = 7 local MAX_BCU_NUM =32 local BLOCK_SIZE = 128 local LAYER_BAU =3 local LAYER_BCU = 2 local LAYER_BMU = 1 local CAN_PORT = "CANBUS_0" local FRAME_DOWN = 0x6 local FRAME_UP = 0x7 local FRAME_OFFSET = 3 local QOS_LEVEL0= 0 local QOS_LEVEL1=1 local QOS_LEVEL2=2 -- 3 总控 -- 2 主控 -- 1 从控 local BAU_upgrade_cfg = {} local BCU_upgrade_cfg = {} local BCU_upgrade_sub = { id = 0, replay_flag = 0, } local cmd_state = { identifier = "", type = "", destaddr = 0, id = 0 } local currentupgradeinfo = nil local XIENNG_upgrade_cfg = {} local gw_sn = nil local dev_sn = nil local mqttclient = nil local function BAUinit() dev_sn = string.format("%s%02d",gw_sn,1) BAU_upgrade_cfg = { identifier = "", file = "", offset = 0, state = 0, timer = 0, layer = LAYER_BAU, file_data = nil, filecrc =0, type = 0, id = 0 } BCU_upgrade_cfg = { identifier = "", file = "", offset = 0, state = 0, timer = 0, layer = LAYER_BCU, file_data = nil, filecrc =0, type = 0, id = 0, subinfo = {} } XIENNG_upgrade_cfg[LAYER_BAU]= BAU_upgrade_cfg XIENNG_upgrade_cfg[LAYER_BCU]= BCU_upgrade_cfg end -- 注:广播模式lay3是指的是层级号 -- 3 总控 -- -- 2 主控 -- -- 1 从控 local function getDest(broadcast,lay3id,lay2id,lay1id) local desaddr = 0 if broadcast == 1 then desaddr = BROADCAST_FLAG desaddr = bor(desaddr,lshift(lay3id, LAYER_3_OFFSET)) desaddr = bor(desaddr,lay1id) else desaddr = bor(desaddr,lshift(lay3id, LAYER_3_OFFSET)) desaddr = bor(desaddr,lshift(lay2id, LAYER_2_OFFSET)) desaddr = bor(desaddr,lay1id) end return desaddr end local function readfile(filename) local file = io.open(filename, "r") if not file then return nil,nil end local bin_buf = file:read("*a") io.close(file) local reminder = #bin_buf%4 while (reminder ~= 0) do reminder=reminder-1 bin_buf=bpack("AC", bin_buf, 0) end local crc32 = dyutils.CalculateXorCrc(bin_buf, #bin_buf) return bin_buf,crc32 end local function header_analy(header) local cmdtype = rshift(header,13) local frameid = band(0x3f,rshift(header,7)) local devid = band(0x7f,header) print(string.format("0x%x 0x%x 0x%x",cmdtype,frameid,devid)) return cmdtype,frameid,devid end local function attack_frame(desData,data,flag) if flag == 1 then desData = bpack("AA",desData,string.sub(data,FRAME_OFFSET+1,-1)) else desData = bpack("AA",desData,string.sub(data,FRAME_OFFSET,-1)) end return desData end local function get_pack_header_len(data) local _,header,len= bunpack(data, "S>SA",0,0,0,0,#framedata,framedata) -- print(string.toHex(framedata)) mqttclient:publish(topic, framedata,QOS_LEVEL0) end local function upgrade_send_data(buf,offset,block_size,dst) local block_data = string.sub(buf, offset+1, offset+block_size) local block_pkt = bpack("S",block_pkt,crc16); -- print(string.toHex(block_pkt)) send_to_can_bus(gw_sn,CAN_PORT,block_pkt) offset= offset + #block_data return offset -- print(string.format("0x%x, 0x%x",offset,#bin_buf)) end local function upgrade_finish_send(len,crc32,dst) local end_data = string.char(0xFF,0xFF,0xFF,0xFF) end_data = bpack("S",end_data,crc16); send_to_can_bus(gw_sn,CAN_PORT,end_data) -- print(string.toHex(end_data)) end local function cmdSend(dst,cmd) local cmd = string.format("0x%X %s",dst,cmd) -- print(cmd) local send_data = bpack("",flag,offset) if flag == 1 then if offset == currentupgradeinfo.offset then currentupgradeinfo.replay = 1 if currentupgradeinfo.offset <= #currentupgradeinfo.file_data then upgradeSend() else upgradefineshSend() currentupgradeinfo.type = UPGRADE_FINISH end currentupgradeinfo.replay = 0 else if offset < #currentupgradeinfo.file_data then currentupgradeinfo.offset = offset upgradeSend() else upgradefineshSend() currentupgradeinfo.type = UPGRADE_FINISH end log.info("broadcast upgrade_doing_reply:",offset) end service_response_send(UPGRADE_TYPE,UPGRADE_DOING,UPGRADE_PROGRESS,currentupgradeinfo.offset,#currentupgradeinfo.file_data) end end end else if currentupgradeinfo.id == devid then if frameid == 0 then currentupgradeinfo.frame = {} currentupgradeinfo.frame[frameid+1] = data currentupgradeinfo.fnumber = math.ceil((len+1)/6) currentupgradeinfo.flen = len else if frameid+1 < currentupgradeinfo.fnumber then currentupgradeinfo.frame[frameid+1] = data else currentupgradeinfo.frame[frameid+1] = data local flag = 1 for i=1,currentupgradeinfo.fnumber do frame_info = attack_frame(frame_info,currentupgradeinfo.frame[i],flag) flag = 0 end local cmd,addr,type,replylen,id,offset = get_upgrade_reply_info(frame_info) print("offset ---->",offset,currentupgradeinfo.offset,#currentupgradeinfo.file_data) if offset == currentupgradeinfo.offset then currentupgradeinfo.replay = 1 if currentupgradeinfo.offset <= #currentupgradeinfo.file_data then upgradeSend() else upgradefineshSend() currentupgradeinfo.type = UPGRADE_FINISH end currentupgradeinfo.replay = 0 else if offset < #currentupgradeinfo.file_data then currentupgradeinfo.offset = offset upgradeSend() else upgradefineshSend() currentupgradeinfo.type = UPGRADE_FINISH end -- log.info("upgrade_doing_reply:",cmd,addr,type,replylen,id,offset) end service_response_send(UPGRADE_TYPE,UPGRADE_DOING,UPGRADE_PROGRESS,currentupgradeinfo.offset,#currentupgradeinfo.file_data) end end end end end local function upgrade_finish_reply(data,frameid,devid,len) local frame_info = "" if currentupgradeinfo == nil then log.info("upgrade_finish_reply","currentupgradeinfo is nil") return end if currentupgradeinfo.mode.broadcast == 1 then if frameid == 0 then currentupgradeinfo.subinfo[devid] = { frame = {} } currentupgradeinfo.subinfo[devid].frame[frameid+1] = data currentupgradeinfo.subinfo[devid].fnumber = math.ceil((len+1)/6) currentupgradeinfo.subinfo[devid].flen = len else if frameid +1 < currentupgradeinfo.subinfo[devid].fnumber then currentupgradeinfo.subinfo[devid].frame[frameid+1] = data else currentupgradeinfo.subinfo[devid].frame[frameid+1] = data local flag,offset = check_broadcast_upgrade() upgrade_notify_to_dev("stop_upgrade",CAN_PORT) if 0 == offset then currentupgradeinfo.replay = 1 service_response_send(UPGRADE_TYPE,UPGRADE_FINISH,UPGRADE_PROGRESS) else service_response_send(UPGRADE_TYPE,UPGRADE_ERROR,UPGRADE_PROGRESS) log.info("upgrade_finish_reply:",offset) end cmd_state.type = RESET_STRING cmd_state.desaddr = currentupgradeinfo.destaddr cmd_state.id = LAYER_BCU currentupgradeinfo.type="" currentupgradeinfo.URL= "" currentupgradeinfo.state = 0 currentupgradeinfo.offset = 0 currentupgradeinfo.destaddr = 0 currentupgradeinfo.file_data = nil currentupgradeinfo.file = "" currentupgradeinfo.filecrc = 0 currentupgradeinfo.replay = 0 currentupgradeinfo = nil cmdSend(cmd_state.desaddr,RESET_STRING) -- local flag = 1 -- for i=1,currentupgradeinfo.subinfo[devid].fnumber do -- frame_info = attack_frame(frame_info,currentupgradeinfo.subinfo[devid].frame[i],flag) -- flag = 0 -- end -- local cmd,addr,type,replylen,id,offset = get_upgrade_reply_info(frame_info) -- if offset == 0 then -- currentupgradeinfo.subinfo[devid].replay = 1 -- end end end else if currentupgradeinfo.id == devid then if frameid == 0 then currentupgradeinfo.frame = {} currentupgradeinfo.frame[frameid+1] = data currentupgradeinfo.fnumber = math.ceil((len+1)/6) currentupgradeinfo.flen = len else if frameid +1 < currentupgradeinfo.fnumber then currentupgradeinfo.frame[frameid+1] = data else currentupgradeinfo.frame[frameid+1] = data local flag = 1 for i=1,currentupgradeinfo.fnumber do frame_info = attack_frame(frame_info,currentupgradeinfo.frame[i],flag) flag = 0 end local cmd,addr,type,replylen,id,offset = get_upgrade_reply_info(frame_info) upgrade_notify_to_dev("stop_upgrade",CAN_PORT) if 0 == offset then currentupgradeinfo.replay = 1 service_response_send(UPGRADE_TYPE,UPGRADE_FINISH,UPGRADE_PROGRESS) currentupgradeinfo.replay = 0 else service_response_send(UPGRADE_TYPE,UPGRADE_ERROR,UPGRADE_PROGRESS) log.info("upgrade_finish_reply:",cmd,addr,type,replylen,id,offset) end cmd_state.type = RESET_STRING cmd_state.desaddr = currentupgradeinfo.destaddr cmd_state.id = currentupgradeinfo.id cmdSend(cmd_state.desaddr,RESET_STRING) currentupgradeinfo.type="" currentupgradeinfo.URL= "" currentupgradeinfo.offset =0 currentupgradeinfo.state = 0 currentupgradeinfo.destaddr = 0 currentupgradeinfo.file_data = nil currentupgradeinfo.file = "" currentupgradeinfo.filecrc = 0 currentupgradeinfo.replay = 0 currentupgradeinfo = nil -- cmdSend(currentupgradeinfo.destaddr,UPGRADE_END) -- currentupgradeinfo.type = UPGRADE_END end end end end end local function get_can_data(data) local _,dev_lev,addr,func,regaddr,len =bunpack(data, "CCC