#!/usr/bin/lua local posix = require 'posix' local invoker = require 'invoker' -- global variables local g_ttydev = nil -- path of controlling ttyUSB for 4G modem local moudle_type = nil local renum = 5 local gfmt = string.format local function ts_init() if posix.access('/usr/bin/lua') == 0 then posix.setenv('PATH', '/opt/lnxall_app/bin:/usr/bin:/usr/sbin:/bin:/sbin', true) end return true end local function judge_moudle() okay, outbuf = invoker.invoke(invoker.OUTPUT, "lsusb") if okay ~= 0 or type(outbuf) ~= "string" or string.len(outbuf) == 0 then io.stderr:write("Error, failed to invoke `lsusb!\n") io.stderr:flush() return false end -- process line by line for output in string.gmatch(outbuf, "([^\r\n]+)") do usbid = string.match(output, "(%x%x%x%x:%x%x%x%x)") if string.find(usbid,"2c7c") then moudle_type = "Quectel" return usbid end if string.find(usbid,"1782") or string.find(usbid,"19d1") then moudle_type = "AirM2M" return usbid end moudle_type = "no_modem" end if not usbid then io.stderr:write("Warning, no 4G network modem found!\n") io.stderr:flush() return false end end local function get_vid_pid(device_path) -- get the Vendor and Product ID from the real device path local vid, pid local path = device_path if path == nil then return nil, nil end repeat local uevent_file = io.open(path .. "/uevent") -- make sure the V and P id is saved in uevent, of course uedvadm also will get the information from uevent file if uevent_file then for line in uevent_file:lines() do local key, value = line:match("(%a+)=(.+)") if key == "PRODUCT" then vid, pid = value:match("(%x+)%/(%x+)%/(%x+)") if vid and pid then vid = string.format("%04x", tonumber(vid, 16)) pid = string.format("%04x", tonumber(pid, 16)) return vid .. ":" .. pid end end end uevent_file:close() end path = path:match("(.+)/[^/]+") -- if not found, next step is to check the parent directory. until not path or path == "" return nil, nil end local function find_device_path(device_name) local device_path -- unfortunately, this method is strong depends on kernel version. As far as I know it can't work on 2.4 kernel. for class in io.popen("ls " .. "/sys/class/"):lines() do local path = "/sys/class/" .. class .. "/" .. device_name if io.open(path) then local link = io.popen("readlink -f " .. path):read("*line") -- get the link path if link then while link:match("%.%./") do link = link:gsub("/[^/]+/%.%./", "/") -- get the real path end device_path = link break end end end return device_path end local function sleep() local file = io.popen("sleep 1") file:close() end local function operating_serial_device (dev_name, command) os.execute("stty -F " .. dev_name .. " raw cs8") -- open device with nonblock mode. local serial_device = posix.open(dev_name, posix.O_RDWR+posix.O_NONBLOCK+posix.O_NOCTTY) command = "\r" .. command .. "\r\n" if serial_device then posix.write(serial_device, command) sleep() local data = posix.read (serial_device, 256) posix.close(serial_device) if command == "\rAT+CGSN\r\n" then if #string.match(data,"%d+") < 15 then if renum > 0 then renum = renum - 1 data = operating_serial_device(g_ttydev,"AT+CGSN") else return nil end else renum = 5 data = "imei info: " .. string.match(data,"%d+") .. "\n" end end if command == "\rAT+CCID\r\n" then if #string.match(data,"+CCID:%s*(%S+)") < 20 then if renum > 0 then renum = renum - 1 data = operating_serial_device(g_ttydev,"AT+CCID") else return nil end else renum = 5 data = "iccid info: " .. string.match(data,"+CCID:%s*(%S+)") .. "\n" end end if command == "\rAT+CSQ\r\n" then data = "signal info: " .. string.match(data,"%d+") .. "\n" end io.stdout:flush();io.stderr:flush() io.stdout:write(data) return data end return nil end local function moudle_reply() local jdx = 0 local usbid = judge_moudle() if usbid then while jdx < 3 do if string.find(usbid,"19d1") then g_ttydev = find_device_path (gfmt ("ttyACM%d", jdx)) else g_ttydev = find_device_path (gfmt ("ttyUSB%d", jdx)) end local vpid = get_vid_pid (g_ttydev) if vpid == usbid then if posix.access(g_ttydev) == 0 then if string.find(usbid,"19d1") then g_ttydev = gfmt("/dev/ttyACM%d", jdx) else g_ttydev = gfmt("/dev/ttyUSB%d", jdx) end local info = posix.stat(g_ttydev) if type(info) == "table" and info.st_mode and info.st_mode == 8576 then local reply = operating_serial_device(g_ttydev,"AT") if string.find(reply,"OK") and moudle_type == "Quectel" then operating_serial_device(g_ttydev,"ATI") return true end if string.find(reply,"OK") and moudle_type == "AirM2M" then operating_serial_device(g_ttydev,"AT+CGMM") return true end end end end jdx = jdx + 1 end else return false end end local function ts_main() flag = ts_init() reply_flag = moudle_reply() if flag and reply_flag then io.stdout:write("Producer: " .. '"' .. moudle_type ..'"'.. "\n") operating_serial_device(g_ttydev,"AT+COPS?") operating_serial_device(g_ttydev,"AT+CGSN") operating_serial_device(g_ttydev,"AT+CCID") operating_serial_device(g_ttydev,"AT+CSQ") return true else io.stdout:write("Producer: " .. '"' .. moudle_type ..'"'.. "\n") return false end end ts_main() os.exit(0)