#!/opt/lnxall_app/bin/lua local bit32 = require 'bit32' local posix = require 'posix' local cjson = require 'cjson' local invoker = require 'invoker' local netdev_4g = "enp0s20f0u7" local wan_dev = "enp1s0" local lan_dev = "enp2s0" local g_tty = { [1] = '/dev/ttyS2', [2] = '/dev/ttyS3', [3] = '/dev/ttyS4', [4] = '/dev/ttyS5' } local function find_4g_netdev() local okay, output = invoker.invoke(invoker.OUTPUT, "ip", "link", "show") if okay ~= 0 or type(output) ~= "string" then return nil end for mdev in string.gmatch(output, "enp[^:\r\n]+:") do local nlen = string.len(mdev) if nlen >= 9 then return mdev:sub(1, nlen - 1) end end return nil end local function netdev_hasipv4(ndev) local okay, output = invoker.invoke(invoker.OUTPUT, "ip", "addr", "show", "dev", ndev) if okay ~= 0 or type(output) ~= "string" then return false end local ipaddr = string.match(output, "inet%s+([%d%.]+)/") if not ipaddr then io.stderr:write(string.format("Error, no ipv4 found for '%s'\n", ndev)) io.stderr:flush() return false end io.stdout:write(string.format("IPv4 address found for '%s': %s\n", ndev, ipaddr)) io.stdout:flush() return true end local function test_rs485(p0, p1) local wtf = posix.stat(p0) if type(wtf) ~= "table" or wtf['type'] ~= 'character device' then io.stderr:write(string.format("Error, invalid RS485 device: %s\n", p0)) io.stderr:flush() return false end wtf = posix.stat(p1) if type(wtf) ~= "table" or wtf['type'] ~= 'character device' then io.stderr:write(string.format("Error, invalid RS485 device: %s\n", p1)) io.stderr:flush() return false end -- for debian based system, we have a very strong `stty invoker.invoke(0, 'stty', '-F', p0, "raw", "9600", "cs8", "-hupcl", "-onlcr", "-iexten", "-echo", "-echoe", "-echok", "-echoctl", "-echoke", "-parenb") invoker.invoke(0, 'stty', '-F', p1, "raw", "9600", "cs8", "-hupcl", "-onlcr", "-iexten", "-echo", "-echoe", "-echok", "-echoctl", "-echoke", "-parenb") local rawstr = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' local rstr = invoker.randstr(0x8, rawstr) local tmpfile = "/tmp/tmp-" .. rstr local catpid = invoker.invoke(invoker.NOWAIT, "/bin/sh", "-c", string.format("TTY_READ=1 exec tty_rw %s > %s", p0, tmpfile)) if type(catpid) ~= "number" then io.stderr:write(string.format("Error, failed to execute 'cat %s'\n", p0)) io.stderr:flush() posix.unlink(tmpfile) return false end invoker.msleep(10) invoker.invoke(0, 'tty_rw', p1, string.format('=%s=%s=\n', rstr, rstr)) invoker.msleep(50) invoker.kill(catpid, posix.SIGKILL) invoker.kill(catpid, posix.SIGTERM) invoker.waitpid(catpid) local output = invoker.readfile(tmpfile, invoker.TRIMEND) posix.unlink(tmpfile) if type(output) ~= "string" or not string.find(output, rstr, 1, true) then io.stderr:write(string.format("Error, test RS485 port has failed: %s => %s\n", p1, p0)) if type(output) == "string" then io.stderr:write(string.format("\tExpected: %s, output: %s\n", rstr, output)) end io.stderr:flush() return false end io.stdout:write(string.format("INFO: test RS485 port OKAY: %s => %s\n", p1, p0)) if type(output) == "string" then io.stdout:write(string.format("\tExpected: %s, output: %s\n", rstr, output)) end io.stdout:flush() return true end local function update_resolv() local res = invoker.readfile('/etc/resolv.conf') local myres = "nameserver 114.114.114.114\nnameserver 8.8.8.8\n" if res ~= myres then io.stdout:write("Updating /etc/resolv.conf...\n") io.stdout:flush() local filp = io.open('/etc/resolv.conf', 'wb') if filp then filp:write(myres) filp:close() filp = nil end end return true end local function ping_with(ifname, host) if not host then host = 'mqtt.lnxall.com' end if not netdev_hasipv4(ifname) then return false end io.stdout:write(string.format("Ping '%s' with interface '%s'...\n", host, ifname)) io.stdout:flush() local cmds = { "ping", "-c5", "-I", ifname, host } local _, output = invoker.invoke(invoker.OUTPUT + invoker.NOSTDIO, cmds) if type(output) == "string" and string.find(output, "packet loss", 1, true) then if string.find(output, "100% packet loss", 1, true) then return false end return true end return false end local function get_lan_host() local ipaddr = {} local arpfile = io.open("/proc/net/arp", "rb") if not arpfile then io.stderr:write("Error, failed to open arp file.\n") io.stderr:flush() return ipaddr end for line in arpfile:lines() do if string.find(line, lan_dev, 1, true) then local ip = string.match(line, "^([%d%.]+)") if invoker.isipv4(ip) then ipaddr[#ipaddr + 1] = ip end end end if #ipaddr == 0 then io.stderr:write("Error, no device connected to LAN\n") io.stderr:flush() end return ipaddr end --add by qyu local function get_moudle_info(datj) print("MOUDLE INFO SETTINGS TEST START!") local eval,finfo = invoker.invoke(invoker.OUTPUT,"troubleshooting") if eval and type(finfo) == "string" then local IMEI = string.gsub(string.match(finfo,"IMEI and Serial Number:([^\r\n]+)"),"%s+","") local Producer = string.gsub(string.match(finfo,"Manufacturer:([^\r\n]+)"),"%s+","") if Producer == "Quectel" then local moudle_4G_SP = Producer _,_,moudle_4G_TYPE = string.find(finfo,'Revision: (%w+)') if not moudle_4G_TYPE then moudle_4G_TYPE = "can't get moudle_4G_TYPE" end local ICCID = string.match(finfo,"+CCID: ([%d\r\n]+)") if not ICCID then ICCID = "can't get ICCID" end start,tail,sim_Producer = string.find(finfo,'COPS:%s%d,%d,(["].-["])') if start and tail then sim_SP = string.sub(sim_Producer,2,tail-start-10) else sim_SP = "can't get sim_SP" end datj["MOUDLE_INFO"] = { ["IMEI"] = IMEI, ["moudle_4G_sp"] = moudle_4G_SP, ["moudle_4G_type"] = moudle_4G_TYPE, ["iccid"] = ICCID, ["sim_sp"] = sim_SP } else local st,en,moudle_4G_Producer = string.find(finfo,'CGMI:%s(["].-["])') if st and en then moudle_4G_SP = string.sub(moudle_4G_Producer,2,en-st-6) else moudle_4G_SP = "can't get moudle_4G_SP" end local a,b,moudle_4G_TYPE = string.find(finfo,'(Air%d+%w+)') if not (a and b) then moudle_4G_TYPE = "can't get moudle_4G_TYPE" end local _,_,ICCID = string.find(finfo,'iccid info:%s*(%d+)') if not ICCID then ICCID = "can't get ICCID" end local c,d,sim_Producer = string.find(finfo,'COPS:%s%d,%d,(["].-["])') if c and d then sim_SP = string.sub(sim_Producer,2,d-c-10) else sim_SP = "can't get sim_SP" end datj["MOUDLE_INFO"] = { ["IMEI"] = IMEI, ["moudle_4G_sp"] = moudle_4G_SP, ["moudle_4G_type"] = moudle_4G_TYPE, ["iccid"] = ICCID, ["sim_sp"] = sim_SP } end else print("MOUDLE INFO SETTINGS TEST FAILED!!") return false end print("MOUDLE INFO SETTINGS TEST OK") return true end local function maindiag() finalsummary = {} local summary = {} local okay, facini = invoker.invoke(invoker.OUTPUT, "factory", "get") if okay ~= 0 or type(facini) ~= "string" then io.stderr:write("Error, 'factory get' has failed.\n") io.stderr:flush() return 1 end local gwsn = string.match(facini, "SN=([^\r\n]+)") local hwver = string.match(facini, "HWVER=([^\r\n]+)") or "" local macaddr = string.match(facini, "MAC=([^\r\n]+)") or "" local gwpro = string.match(facini, "PRODUCT=([^\r\n]+)") if not gwsn or not gwpro then io.stderr:write("Error, gateway SN or PRODUCT not found.\n") io.stderr:flush() return 2 end local softver = invoker.readfile("/lib/dyiot/issue", invoker.TRIMEND) if type(softver) ~= "string" or #softver == 0 then softver = invoker.readfile("/etc/issue", invoker.TRIMEND) if type(softver) ~= "string" or #softver == 0 then softver = "unknown" end end finalsummary["sn"] = gwsn finalsummary["timestamp"] = os.time() finalsummary["MAC"] = macaddr finalsummary["HWVER"] = hwver finalsummary["SWVER"] = softver local ports = {} if test_rs485(g_tty[1], g_tty[2]) then ports[#ports + 1] = { interfaces = "RS485_1", error_msg = "success", error_code = 0 } else ports[#ports + 1] = { interfaces = "RS485_1", error_msg = "CANNOT WORK", error_code = 1 } end if test_rs485(g_tty[2], g_tty[1]) then ports[#ports + 1] = { interfaces = "RS485_2", error_msg = "success", error_code = 0 } else ports[#ports + 1] = { interfaces = "RS485_2", error_msg = "CANNOT WORK", error_code = 1 } end if test_rs485(g_tty[3], g_tty[4]) then ports[#ports + 1] = { interfaces = "RS485_3", error_msg = "success", error_code = 0 } else ports[#ports + 1] = { interfaces = "RS485_3", error_msg = "CANNOT WORK", error_code = 1 } end if test_rs485(g_tty[4], g_tty[3]) then ports[#ports + 1] = { interfaces = "RS485_4", error_msg = "success", error_code = 0 } else ports[#ports + 1] = { interfaces = "RS485_4", error_msg = "CANNOT WORK", error_code = 1 } end summary["OnBoardPort"] = ports local netw = {} update_resolv() invoker.invoke(invoker.OUTPUT, "ifconfig", netdev_4g, "down") if ping_with(wan_dev) or ping_with(wan_dev, '8.8.8.8') or ping_with(wan_dev, '114.114.114.114') then netw[#netw + 1] = { interfaces = "WAN", error_msg = "success", error_code = 0 } else netw[#netw + 1] = { interfaces = "WAN", error_msg = "NOT OKAY", error_code = 1 } end invoker.invoke(invoker.OUTPUT, "ifconfig", netdev_4g, "up") update_resolv() invoker.invoke(invoker.OUTPUT, "ifconfig", wan_dev, "down") if ping_with(netdev_4g) or ping_with(netdev_4g, '8.8.8.8') or ping_with(netdev_4g, '114.114.114.114') then netw[#netw + 1] = { interfaces = "4G-Net", error_msg = "success", error_code = 0 } else netw[#netw + 1] = { interfaces = "4G-Net", error_msg = "NOT OKAY", error_code = 1 } end invoker.invoke(invoker.OUTPUT, "ifconfig", wan_dev, "up") local landevs, lanokay = get_lan_host(), false for _, ip in pairs(landevs) do if ping_with(lan_dev, ip) then lanokay = true break end end if lanokay then netw[#netw + 1] = { interfaces = "LAN", error_msg = "success", error_code = 0 } else netw[#netw + 1] = { interfaces = "LAN", error_msg = "NOT OKAY", error_code = 1 } end summary["NetWork"] = netw get_moudle_info(summary) finalsummary["data"] = summary io.stdout:write("\n---TEST SUMMARY---\ntest_result:") io.stdout:write(cjson.encode(finalsummary)) io.stdout:write("\n") io.stdout:flush() end posix.setenv("PATH", "/opt/lnxall_app/bin:/usr/bin:/usr/sbin:/bin:/sbin", true) netdev_4g = find_4g_netdev() or netdev_4g maindiag() os.exit(0)