#!/opt/lnxall_app/bin/lua local invoker = require "invoker" local cjson = require "cjson" local comm4g = require "comm4gnet" local gfmt = string.format local g_debug = nil -- disable debugging local g_SIMCARD_EXTERNAL = 0 local g_SIMCARD_INTERNAL = 1 local g_PREINIT_AGAIN = 2025 local g_APN_ALREADY = 2026 local function common_4gmodem_switchsim(self) -- note that self.dualsim must be `false return false -- Not supported, only one SIMcard end local function common_4gmodem_getsim(self) -- note that self.dualsim must be `false -- return g_SIMCARD_INTERNAL -- ?? WHICH ONE SHOULD I RETURN ?? return g_SIMCARD_EXTERNAL -- Not supported, default to external SIMcard end local function common_4gmodem_preinit(self) -- Nothing important TODO!!! return true end local function common_4gmodem_ttypath(self) local jdx, kdx, idx = 0, 0, self.ttyindex while jdx < 32 do local ndev = gfmt("/sys/bus/usb-serial/drivers/option1/ttyUSB%d", jdx) if invoker.statfile(ndev) then ndev = gfmt("/dev/ttyUSB%d", jdx) if invoker.statfile(ndev) == "character" then if kdx >= idx then self.ttypath = ndev return ndev end kdx = kdx + 1 end end jdx = jdx + 1 end self.ttypath = false io.stderr:write(gfmt("Error, failed to find ttydev for %s\n", self.name)) io.stderr:flush() return nil end local function common_4gmodem_reset(self) local ttyp = self.ttypath if not ttyp then ttyp = self:f_ttypath() end if not ttyp then return false end local ttyrw = comm4g.opentty(ttyp) if not ttyrw then return false end ttyrw:write("AT+RESET\r\n") ttyrw:close(); ttyrw = nil return true end local function common_4gmodem_connect(self) io.stderr:write(gfmt("Error, don't known how to connect for %s\n", self.name)) io.stderr:flush() return false end local function common_4gmodem_opentty(self, baudrate) local ttyp = self.ttypath if not ttyp then ttyp = self:f_ttypath() end if not ttyp then return nil end local ttyrw = comm4g.opentty(ttyp, baudrate) if not ttyrw then return nil end return ttyrw end -- Note that return value is a table local function atcmd_write_array(trw, cmds, mdelay) if type(mdelay) ~= "number" or mdelay < 300 then mdelay = 300 end local replies = {} trw:clear() -- clear existing buffer for idx, atcmd in ipairs(cmds) do trw:write(atcmd) -- if trw:haserr() then break end local resp = trw:readany(mdelay, "\nOK", "ERROR") if type(resp) == "string" then replies[idx] = resp else replies[idx] = "" end end return replies end local function atcmd_resp_dump(cmds, replies) for idx, cmd in ipairs(cmds) do cmd = string.gsub(cmd, "[\r\n]+", "") local reply = replies[idx] if type(reply) == "string" and #reply > 0 then reply = string.gsub(reply, "[\r\n]+", " ") else reply = "WTH COMPLAINED THAT, AT COMMAND NO RESPONSE!!!" end io.stdout:write(gfmt("%32s | %s\n", cmd, reply)) io.stdout:flush() end end local function common_4gmodem_iccid(self) local ttyrw = self:f_opentty() if not ttyrw then return false end local atcmds = { "AT\r\n", "AT+QCFG=\"nat\"\r\n", "AT+ICCID\r\n", "AT+QICCID\r\n", "AT+CCID\r\n", } local resp = atcmd_write_array(ttyrw, atcmds, 2000) if g_debug then atcmd_resp_dump(atcmds, resp) end -- resp is a table, shoud not be empty resp = table.concat(resp) local iccid = string.match(resp, "ICCID:%s+([%d%a]+)") if not iccid then iccid = string.match(resp, "CCID:%s+([%d%a]+)") end if not iccid then iccid = "no simcard" end if self.iccid ~= iccid then self.iccid = iccid end -- check for nat configuration if string.find(resp, 'QCFG: "nat"', 1, true) and not string.find(resp, 'QCFG: "nat",1', 1, true) then ttyrw:write("AT+QCFG=\"nat\",1\r\n"); invoker.msleep(300) ttyrw:write("AT+CFUN=1,1\r\n"); invoker.msleep(2500) end ttyrw:close(); ttyrw = nil return iccid end local function common_4gmodem_status(self) local ttyrw = self:f_opentty() if not ttyrw then return false end local atcmds = { [1] = "AT+CPIN?\r\n", [2] = "AT+CREG=2\r\n", [3] = "AT+CCID\r\n", [4] = "AT+COPS?\r\n", [5] = "AT+CREG?\r\n", [6] = "AT+CGREG?\r\n", [7] = "AT+CSQ\r\n", [8] = "AT+CGCONTRDP\r\n", [9] = "AT+GTRNDIS?\r\n", } local resp = atcmd_write_array(ttyrw, atcmds, 3000) if g_debug then atcmd_resp_dump(atcmds, resp) end ttyrw:close(); ttyrw = nil -- resp is a table, should not be empty local privst, reply, str = self.status, nil, {} if type(privst) ~= "table" then privst = {} end reply = resp[1] -- AT+CPIN? if #reply > 0 then privst["AT+CPIN"] = reply privst["HAS_SIMCARD"] = string.find(reply, "CPIN:%s+READY") and true or false if string.match(reply,"%+CPIN:%s*(%w+)%s*OK") then str[#str+1] = string.match(reply,"%+CPIN:%s*(%w+)%s*OK") else str[#str+1] = " " end end reply = resp[3] -- AT+CCID if #reply > 0 then privst["AT+CCID"] = reply str[#str+1] = "0" if string.match(reply, "%+CCID%s+([%d%a]+)") then str[#str+1] = string.match(reply, "%+CCID%s+([%d%a]+)") elseif string.match(reply, "CCID:%s+([%d%a]+)") then str[#str+1] = string.match(reply, "CCID:%s+([%d%a]+)") else str[#str+1] = "" end end reply = resp[4] -- AT+COPS? if #reply > 0 then privst["AT+COPS"] = reply if string.match(reply, '"(.-)"') then str[#str+1] = string.match(reply, '"(.-)"') else str[#str+1] = " " end end reply = resp[5] -- AT+CREG? if #reply > 0 then privst["AT+CREG"] = reply local lac, cid = string.match(reply, '"(.-)","(.-)"') if lac and cid then str[#str+1] = lac .. "," .. cid else str[#str+1] = " " end end reply = resp[6] -- AT+CGREG? if #reply > 0 then privst["AT+CGREG"] = reply privst["HAS_REGISTERD"] = string.find(reply, "CGREG:%s+%d+,1") and true or false local n1, n2 = string.match(reply, "%+CGREG:%s(%d+),(%d+)") if n1 and n2 then str[#str+1] = n1 .. "," .. n2 else str[#str+1] = " " end end reply = resp[7] -- AT+CSQ if #reply > 0 then privst["AT+CSQ"] = reply local sigl = string.match(reply, "CSQ:%s+(%d+),") if sigl then sigl = tonumber(sigl) end if type(sigl) ~= "number" then sigl = 99 end privst["SIGNAL_QUALITY"] = sigl str[#str+1] = sigl end reply = resp[8] -- AT+CGCONTRDP if #reply > 0 then privst["AT+CGCONTRDP"] = reply end reply = resp[9] -- AT+GTRNDIS? if #reply > 0 then privst["AT+GTRNDIS"] = reply end local info = cjson.encode({ ["hassim"] = str[1], ["simno"] = str[2], ["iccid"] = str[3], ["operator"] = str[4], ["area"] = str[5], ["registerd"] = str[6], ["signal"] = str[7] }) self.status = privst return privst, str end local function common_4gmodem_hassim(self) local ttyrw = self:f_opentty() if not ttyrw then return nil end ttyrw:clear() ttyrw:write("AT+CPIN?\r\n") local resp = ttyrw:readany(1500, "OK", "ERROR") if not resp then resp = "" end ttyrw:close(); ttyrw = nil if string.find(resp, "CPIN:%s+READY") then return true end if string.find(resp, "ERROR") then return false end return nil end local function common_4gmodem_setapn(self) -- YET TO BE SUPPORTED return false end local function common_4gmodem_getapn(self) -- YET TO BE SUPPORTED return g_APN_ALREADY end local function common_4gmodem_close(self) if type(self) ~= "table" then return false end self.name = nil self.ttyindex = nil self.dualsim = nil self.ttypath = nil self.isoption1 = nil setmetatable(self, nil) self = nil return true end local function common_modem4g_methods() return { ["f_preinit"] = common_4gmodem_preinit, ["f_hassim"] = common_4gmodem_hassim, ["f_opentty"] = common_4gmodem_opentty, ["f_ttypath"] = common_4gmodem_ttypath, ["f_reset"] = common_4gmodem_reset, ["f_connect"] = common_4gmodem_connect, ["f_status"] = common_4gmodem_status, ["f_iccid"] = common_4gmodem_iccid, ["f_setapn"] = common_4gmodem_setapn, ["f_getapn"] = common_4gmodem_getapn, ["f_switch_sim"] = common_4gmodem_switchsim, -- switch to another SIMcard, ["f_get_cursim"] = common_4gmodem_getsim, -- Get current working SIMcard, ["close"] = common_4gmodem_close, } end local function ec800g_4gmodem_switchsim(self,cardno) local ttyrw = self:f_opentty() if not ttyrw then return nil end ttyrw:clear() ttyrw:write(gfmt("AT+QDSIM=%d\r\n",cardno)) local resp = ttyrw:readany(1500, "OK", "ERROR") if not resp then resp = "" end ttyrw:close(); ttyrw = nil io.stdout:write(gfmt("Switching SIMCARD to %s...\n",cardno)) io.stdout:flush() if string.find(resp, "OK") then return true end if string.find(resp, "ERROR") then return false end return false -- Not supported, only one SIMcard end local function ec800g_4gmodem_getsim(self) local ttyrw = self:f_opentty() if not ttyrw then return nil end ttyrw:clear() ttyrw:write("AT+QDSIM?\r\n") local resp = ttyrw:readany(1500, "OK", "ERROR") if not resp then resp = "" end ttyrw:close(); ttyrw = nil local data = tonumber(string.match(resp,"%+QDSIM:%s*(%d+)")) if data then if data ~= 0 and data ~= 1 then return nil else io.stdout:write(gfmt("Using card %d\n",data)) io.stdout:flush() return data end end if string.find(resp, "ERROR") then return nil end return nil end local function ec800g_4gmodem_info(self,cardno) local ttyrw = self:f_opentty() if not ttyrw then return nil end if not cardno or type(cardno) ~= "number" then cardno = 0 end if cardno and cardno == 1 then oldno = 0 else oldno = 1 end local oldcmd = "AT+QDSIM=" .. oldno .. "\r\n" local newcmd = "AT+QDSIM=" .. cardno .. "\r\n" ttyrw:clear() ttyrw:write(oldcmd); invoker.msleep(6000) ttyrw:write("AT+CPIN?\r\n"); invoker.msleep(500) ttyrw:write("AT+ICCID\r\n"); invoker.msleep(500) local oldresp = ttyrw:read(500) if not oldresp then oldresp = "" end ttyrw:clear() ttyrw:write(newcmd); invoker.msleep(6000) ttyrw:write("AT+CPIN?\r\n"); invoker.msleep(500) ttyrw:write("AT+ICCID\r\n"); invoker.msleep(500) local newresp = ttyrw:read(500) if not newresp then newresp = "" end r0 = string.find(oldresp, "CPIN: READY", 1, true) and true or false r1 = string.find(newresp, "CPIN: READY", 1, true) and true or false id0 = string.match(oldresp, "ICCID:%s+([%d%a]+)") id1 = string.match(newresp, "ICCID:%s+([%d%a]+)") local info = cjson.encode({ ["hassim" .. oldno] = r0, ["hassim" .. cardno] = r1,["ICCID" .. oldno] = id0, ["ICCID" .. cardno] = id1 }) ttyrw:close(); ttyrw = nil return info end local function mc661_4gmodem_preinit(self) local ttyrw = self:f_opentty() if not ttyrw then return nil end ttyrw:clear() ttyrw:write("AT+GTUSBMODE=74\r\n") tty:write("AT+CFUN=1,1\r\n") invoker.msleep(6000) ttyrw:close(); ttyrw = nil return g_PREINIT_AGAIN end local function mc661_4gmodem_switchsim(self,cardno) local ttyrw = self:f_opentty() if not ttyrw then return nil end ttyrw:clear() ttyrw:write(gfmt("AT+GTDUALSIM=%d\r\n",cardno)) local resp = ttyrw:readany(1500, "OK", "ERROR") if not resp then resp = "" end ttyrw:close(); ttyrw = nil io.stdout:write(gfmt("Switching SIMCARD to %s...\n",cardno)) io.stdout:flush() if string.find(resp, "OK)") then return true end if string.find(resp, "ERROR") then return false end return false -- Not supported, only one SIMcard end local function mc661_4gmodem_getsim(self) local ttyrw = self:f_opentty() if not ttyrw then return nil end ttyrw:clear() ttyrw:write("AT+GTDUALSIM?\r\n") local resp = ttyrw:readany(1500, "OK", "ERROR") if not resp then resp = "" end ttyrw:close(); ttyrw = nil local data = tonumber(string.match(resp,"%+GTDUALSIM:%s*(%d+)")) if data then if data ~= 0 and data ~= 1 then return nil else io.stdout:write(gfmt("Using card %d\n", data)) io.stdout:flush() return data end end if string.find(resp, "ERROR") then return nil end return nil end local function mc661_4gmodem_info(self,cardno) local ttyrw = self:f_opentty() if not ttyrw then return nil end if not cardno or type(cardno) ~= "number" then cardno = 0 end if cardno and cardno == 1 then oldno = 0 else oldno = 1 end local oldcmd = "AT+GTDUALSIM=" .. oldno .. "\r\n" local newcmd = "AT+GTDUALSIM=" .. cardno .. "\r\n" ttyrw:clear() ttyrw:write(oldcmd); invoker.msleep(6000) ttyrw:write("AT+CPIN?\r\n"); invoker.msleep(500) ttyrw:write("AT+CCID\r\n"); invoker.msleep(500) local oldresp = ttyrw:read(500) if not oldresp then oldresp = "" end ttyrw:clear() ttyrw:write(newcmd); invoker.msleep(6000) ttyrw:write("AT+CPIN?\r\n"); invoker.msleep(500) ttyrw:write("AT+CCID\r\n"); invoker.msleep(500) local newresp = ttyrw:read(500) if not newresp then newresp = "" end r0 = string.find(oldresp, "CPIN: READY", 1, true) and true or false r1 = string.find(newresp, "CPIN: READY", 1, true) and true or false id0 = string.match(oldresp, "CCID:%s+([%d%a]+)") id1 = string.match(newresp, "CCID:%s+([%d%a]+)") local info = cjson.encode({ ["hassim" .. oldno] = r0, ["hassim" .. cardno] = r1,["ICCID" .. oldno] = id0, ["ICCID" .. cardno] = id1 }) ttyrw:close(); ttyrw = nil return info end local function mc661_4gmodem_status(self) local ttyrw = self:f_opentty() if not ttyrw then return false end local atcmds = { [1] = "AT+CPIN?\r\n", [2] = "AT+GTDUALSIM?\r\n", [3] = "AT+CCID\r\n", [4] = "AT+COPS?\r\n", [5] = "AT+GTCCINFO?\r\n", [6] = "AT+CGREG?\r\n", [7] = "AT+CSQ\r\n", [8] = "AT+CGCONTRDP\r\n", [9] = "AT+GTRNDIS?\r\n", } local resp = atcmd_write_array(ttyrw, atcmds, 3000) if g_debug then atcmd_resp_dump(atcmds, resp) end ttyrw:close(); ttyrw = nil -- resp is a table, should not be empty local privst, reply, str = self.status, nil, {} if type(privst) ~= "table" then privst = {} end reply = resp[1] -- AT+CPIN? if #reply > 0 then privst["AT+CPIN"] = reply privst["HAS_SIMCARD"] = string.find(reply, "CPIN:%s+READY") and true or false if string.match(reply,"%+CPIN:%s*(%w+)%s*OK") then str[#str+1] = string.match(reply,"%+CPIN:%s*(%w+)%s*OK") else str[#str+1] = "" end end reply = resp[2] -- AT+GTDUALSIM? if #reply > 0 then privst["AT+GTDUALSIM"] = reply if string.match(reply,"%+GTDUALSIM:%s*(%d+)") then str[#str+1] = string.match(reply,"%+GTDUALSIM:%s*(%d+)") else str[#str+1] = "" end end reply = resp[3] -- AT+CCID if #reply > 0 then privst["AT+CCID"] = reply if string.match(reply, "%+CCID:%s+([%d%a]+)") then str[#str+1] = string.match(reply, "%+CCID:%s+([%d%a]+)") else str[#str+1] = "" end end reply = resp[4] -- AT+COPS? if #reply > 0 then privst["AT+COPS"] = reply if string.match(reply, '"(.-)"') then str[#str+1] = string.match(reply, '"(.-)"') else str[#str+1] = "" end end reply = resp[5] -- AT+GTCCINFO? if #reply > 0 then privst["AT+GTCCINFO"] = reply local lac, cid = string.match(reply, "LTE service cell:.-,%d+,%d+,%d+,(%x+),(%x+),") if lac and cid then str[#str+1] = lac .. "," .. cid else str[#str+1] = " " end end reply = resp[6] -- AT+CGREG? if #reply > 0 then privst["AT+CGREG"] = reply privst["HAS_REGISTERD"] = string.find(reply, "CGREG:%s+%d+,1") and true or false local n1, n2 = string.match(reply, "%+CGREG:%s(%d+),(%d+)") if n1 and n2 then str[#str+1] = n1 .. "," .. n2 else str[#str+1] = " " end end reply = resp[7] -- AT+CSQ if #reply > 0 then privst["AT+CSQ"] = reply local sigl = string.match(reply, "CSQ:%s+(%d+),") if sigl then sigl = tonumber(sigl) end if type(sigl) ~= "number" then sigl = 99 end privst["SIGNAL_QUALITY"] = sigl str[#str+1] = sigl end reply = resp[8] -- AT+CGCONTRDP if #reply > 0 then privst["AT+CGCONTRDP"] = reply end reply = resp[9] -- AT+GTRNDIS? if #reply > 0 then privst["AT+GTRNDIS"] = reply end local info = cjson.encode({ ["hassim"] = str[1], ["simno"] = str[2],["iccid"] = str[3], ["operator"] = str[4], ["area"] = str[5], ["registerd"] = str[6], ["signal"] = str[7] }) self.status = privst return privst, str end local function l610_4gmodem_status(self) local ttyrw = self:f_opentty() if not ttyrw then return false end local atcmds = { [1] = "AT+CPIN?\r\n", [2] = "AT+CCID\r\n", [3] = "AT+COPS?\r\n", [4] = "AT+GTCCINFO?\r\n", [5] = "AT+CGREG?\r\n", [6] = "AT+CSQ\r\n", [7] = "AT+CGCONTRDP\r\n", [8] = "AT+GTRNDIS?\r\n", } local resp = atcmd_write_array(ttyrw, atcmds, 3000) if g_debug then atcmd_resp_dump(atcmds, resp) end ttyrw:close(); ttyrw = nil -- resp is a table, should not be empty local privst, reply, str = self.status, nil, {} if type(privst) ~= "table" then privst = {} end reply = resp[1] -- AT+CPIN? if #reply > 0 then privst["AT+CPIN"] = reply privst["HAS_SIMCARD"] = string.find(reply, "CPIN:%s+READY") and true or false if string.match(reply,"%+CPIN:%s*(%w+)%s*OK") then str[#str+1] = string.match(reply,"%+CPIN:%s*(%w+)%s*OK") else str[#str+1] = "" end end str[#str+1] = "0" reply = resp[2] -- AT+CCID if #reply > 0 then privst["AT+CCID"] = reply if string.match(reply, "%+CCID:%s+([%d%a]+)") then str[#str+1] = string.match(reply, "%+CCID:%s+([%d%a]+)") else str[#str+1] = "" end end reply = resp[3] -- AT+COPS? if #reply > 0 then privst["AT+COPS"] = reply if string.match(reply, '"(.-)"') then str[#str+1] = string.match(reply, '"(.-)"') else str[#str+1] = "" end end reply = resp[4] -- AT+GTCCINFO? if #reply > 0 then privst["AT+GTCCINFO"] = reply local lac, cid = string.match(reply, "LTE service cell:.-,%d+,%d+,%d+,(%x+),(%x+),") if lac and cid then str[#str+1] = lac .. "," .. cid else str[#str+1] = " " end end reply = resp[5] -- AT+CGREG? if #reply > 0 then privst["AT+CGREG"] = reply privst["HAS_REGISTERD"] = string.find(reply, "CGREG:%s+%d+,1") and true or false local n1, n2 = string.match(reply, "%+CGREG:%s(%d+),(%d+)") if n1 and n2 then str[#str+1] = n1 .. "," .. n2 else str[#str+1] = " " end end reply = resp[6] -- AT+CSQ if #reply > 0 then privst["AT+CSQ"] = reply local sigl = string.match(reply, "CSQ:%s+(%d+),") if sigl then sigl = tonumber(sigl) end if type(sigl) ~= "number" then sigl = 99 end privst["SIGNAL_QUALITY"] = sigl str[#str+1] = sigl end reply = resp[7] -- AT+CGCONTRDP if #reply > 0 then privst["AT+CGCONTRDP"] = reply end reply = resp[8] -- AT+GTRNDIS? if #reply > 0 then privst["AT+GTRNDIS"] = reply end local info = cjson.encode({ ["hassim"] = str[1], ["simno"] = str[2],["iccid"] = str[3], ["operator"] = str[4], ["area"] = str[5], ["registerd"] = str[6], ["signal"] = str[7] }) self.status = privst return privst, str end local function ec800g_4gmodem_status(self) local ttyrw = self:f_opentty() if not ttyrw then return false end local atcmds = { [1] = "AT+CPIN?\r\n", [2] = "AT+QDSIM?\r\n", [3] = "AT+CCID\r\n", [4] = "AT+CREG=2\r\n", [5] = "AT+CREG?\r\n", [6] = "AT+CGREG?\r\n", [7] = "AT+CSQ\r\n", [8] = "AT+CGCONTRDP\r\n", [9] = "AT+GTRNDIS?\r\n", [10] = "AT+COPS?\r\n", } local resp = atcmd_write_array(ttyrw, atcmds, 3000) if g_debug then atcmd_resp_dump(atcmds, resp) end ttyrw:close(); ttyrw = nil -- resp is a table, should not be empty local privst, reply, str = self.status, nil, {} if type(privst) ~= "table" then privst = {} end reply = resp[1] -- AT+CPIN? if #reply > 0 then privst["AT+CPIN"] = reply privst["HAS_SIMCARD"] = string.find(reply, "CPIN:%s+READY") and true or false if string.match(reply,"%+CPIN:%s*(%w+)%s*OK") then str[#str+1] = string.match(reply,"%+CPIN:%s*(%w+)%s*OK") else str[#str+1] = " " end end reply = resp[2] -- AT+QDSIM? if #reply > 0 then privst["AT+QDSIM"] = reply if string.match(reply,"%+QDSIM:%s*(%d+)") then str[#str+1] = string.match(reply,"%+QDSIM:%s*(%d+)") else str[#str+1] = "" end end reply = resp[3] -- AT+CCID if #reply > 0 then privst["AT+CCID"] = reply if string.match(reply, "%+CCID:%s+([%d%a]+)") then str[#str+1] = string.match(reply, "%+CCID:%s+([%d%a]+)") else str[#str+1] = "" end end reply = resp[10] -- AT+COPS? if #reply > 0 then privst["AT+COPS"] = reply if string.match(reply, '"(.-)"') then str[#str+1] = string.match(reply, '"(.-)"') else str[#str+1] = " " end end reply = resp[5] -- AT+CREG? if #reply > 0 then privst["AT+CREG"] = reply local lac, cid = string.match(reply, '"(.-)","(.-)"') if lac and cid then str[#str+1] = lac .. "," .. cid else str[#str+1] = " " end end reply = resp[6] -- AT+CGREG? if #reply > 0 then privst["AT+CGREG"] = reply privst["HAS_REGISTERD"] = string.find(reply, "CGREG:%s+%d+,1") and true or false local n1, n2 = string.match(reply, "%+CGREG:%s(%d+),(%d+)") if n1 and n2 then str[#str+1] = n1 .. "," .. n2 else str[#str+1] = " " end end reply = resp[7] -- AT+CSQ if #reply > 0 then privst["AT+CSQ"] = reply local sigl = string.match(reply, "CSQ:%s+(%d+),") if sigl then sigl = tonumber(sigl) end if type(sigl) ~= "number" then sigl = 99 end privst["SIGNAL_QUALITY"] = sigl str[#str+1] = sigl end reply = resp[8] -- AT+CGCONTRDP if #reply > 0 then privst["AT+CGCONTRDP"] = reply end reply = resp[9] -- AT+GTRNDIS? if #reply > 0 then privst["AT+GTRNDIS"] = reply end local info = cjson.encode({ ["hassim"] = str[1], ["simno"] = str[2],["iccid"] = str[3], ["operator"] = str[4], ["area"] = str[5], ["registerd"] = str[6], ["signal"] = str[7] }) self.status = privst return privst, str end local function ec200a_connect(self) local ttyrw = self:f_opentty() if not ttyrw then return false end local atcmds = { "AT+QCFG=\"usbnet\",1\r\n", "AT+CFUN=1,1\r\n", "AT+QNETDEVCTL=3,1,1\r\n", "AT+QIACT=1\r\n" } local resp = atcmd_write_array(ttyrw, atcmds, 2000) if g_debug then atcmd_resp_dump(atcmds, resp) end ttyrw:close(); ttyrw = nil return true end local function ec200u_connect(self) local ttyrw = self:f_opentty() if not ttyrw then return false end local atcmds = { "AT+QCFG=\"usbnet\",1\r\n", "AT+QNETDEVCTL=1,1,1\r\n", } local resp = atcmd_write_array(ttyrw, atcmds, 2000) if g_debug then atcmd_resp_dump(atcmds, resp) end ttyrw:close(); ttyrw = nil return true end local function ec2x_connect(self) local ttyrw = self:f_opentty() if not ttyrw then return false end local atcmds = { "AT+QCFG=\"usbnet\",1\r\n", "AT+CFUN=1,1\r\n", } local resp = atcmd_write_array(ttyrw, atcmds, 2000) if g_debug then atcmd_resp_dump(atcmds, resp) end ttyrw:close(); ttyrw = nil return true end local function air724_connect(self) local ttyrw = self:f_opentty() if not ttyrw then return false end local atcmds = { "AT+ROUTEIP=192.168.250.1\r\n", "AT+RESET\r\n", "AT+SETUSB=2\r\n", } local resp = atcmd_write_array(ttyrw, atcmds, 2000) if g_debug then atcmd_resp_dump(atcmds, resp) end ttyrw:close(); ttyrw = nil return true end local function ec800g_connect(self) local ttyrw = self:f_opentty() if not ttyrw then return false end local atcmds = { "AT+QCFG=\"usbnet\",1\r\n", "AT+QNETDEVCTL=3,1,1\r\n", "AT+CFUN=1,0\r\n", } local resp = atcmd_write_array(ttyrw, atcmds, 2000) if g_debug then atcmd_resp_dump(atcmds, resp) end ttyrw:close(); ttyrw = nil return true end local function mc661_connect(self) local ttyrw = self:f_opentty() if not ttyrw then return false end local atcmds = { "AT+CGDCONT=1\r\n", "AT+GTRNDIS=1,1\r\n", "AT+CFUN=1,0\r\n", } local resp = atcmd_write_array(ttyrw, atcmds, 2000) if g_debug then atcmd_resp_dump(atcmds, resp) end ttyrw:close(); ttyrw = nil return true end local function l610_connect(self) local ttyrw = self:f_opentty() if not ttyrw then return false end local atcmds = { "AT+GTUSBMODE=32\r\n", "AT+CGDCONT=1\r\n", "AT+GTRNDIS=1,1\r\n", "AT+CFUN=1,0\r\n", } local resp = atcmd_write_array(ttyrw, atcmds, 2000) if g_debug then atcmd_resp_dump(atcmds, resp) end ttyrw:close(); ttyrw = nil return true end local function ec200u_4gmodem_setapn(self,apn) local ttyrw = self:f_opentty() if not ttyrw then return false end if not apn then apn = "internet" end local apncmd = "AT+CGDCONT=1,\"IPV4V6\",\"" .. apn .. "\"\r\n" local atcmds = { "AT+CFUN=0\r\n", "AT+CGDCONT=1\r\n", apncmd, "AT+CFUN=1\r\n", } local resp = atcmd_write_array(ttyrw, atcmds, 2000) if g_debug then atcmd_resp_dump(atcmds, resp) end ttyrw:close(); ttyrw = nil return false end local function ec200u_4gmodem_getapn(self) local ttyrw = self:f_opentty() if not ttyrw then return nil end ttyrw:clear() ttyrw:write("AT+CGDCONT?\r\n") local resp = ttyrw:readany(1500, "OK", "ERROR") if not resp then resp = "" end ttyrw:close(); ttyrw = nil local data = string.match(resp,'%+CGDCONT:%s*1%s*,%s*"[^"]+"%s*,%s*"([^"]+)"%s*') if data then data = data:gsub("[\r\n]+$", "") end if not data or string.find(resp, "ERROR") then return nil end return data end local function init_func_ec200a() local mobj = { name = "EC200A", ttyindex = 2, dualsim = false, ttypath = false, isoption1 = true, } local mtab = common_modem4g_methods() mtab["f_connect"] = ec200a_connect setmetatable(mobj, { __index = mtab, __gc = common_4gmodem_close, }) return mobj end local function init_func_ec200n() local mobj = { name = "EC200N", ttyindex = 1, dualsim = false, ttypath = false, isoption1 = true, } local mtab = common_modem4g_methods() mtab["f_connect"] = ec200a_connect setmetatable(mobj, { __index = mtab, __gc = common_4gmodem_close, }) return mobj end local function init_func_ec200t() local mobj = { name = "EC200T", ttyindex = 2, dualsim = false, ttypath = false, isoption1 = true, } local mtab = common_modem4g_methods() mtab["f_connect"] = ec200a_connect setmetatable(mobj, { __index = mtab, __gc = common_4gmodem_close, }) return mobj end local function init_func_ec200u() local mobj = { name = "EC200U", ttyindex = 0, dualsim = false, ttypath = false, isoption1 = true, } local mtab = common_modem4g_methods() mtab["f_connect"] = ec200u_connect mtab["f_setapn"] = ec200u_4gmodem_setapn mtab["f_getapn"] = ec200u_4gmodem_getapn setmetatable(mobj, { __index = mtab, __gc = common_4gmodem_close, }) return mobj end local function init_func_ec2x() local mobj = { name = "EC2X", ttyindex = 2, dualsim = false, ttypath = false, isoption1 = true, } local mtab = common_modem4g_methods() mtab["f_connect"] = ec2x_connect mtab["f_setapn"] = ec200u_4gmodem_setapn mtab["f_getapn"] = ec200u_4gmodem_getapn setmetatable(mobj, { __index = mtab, __gc = common_4gmodem_close, }) return mobj end local function init_func_ec800g() local mobj = { name = "EC800G", ttyindex = 0, dualsim = true, ttypath = false, isoption1 = true, } local mtab = common_modem4g_methods() mtab["f_connect"] = ec800g_connect mtab["f_cardinfo"] = ec800g_4gmodem_info mtab["f_switch_sim"] = ec800g_4gmodem_switchsim mtab["f_get_cursim"] = ec800g_4gmodem_getsim mtab["f_status"] = ec800g_4gmodem_status setmetatable(mobj, { __index = mtab, __gc = common_4gmodem_close, }) return mobj end local function init_func_air724() local mobj = { name = "Air724UG", ttyindex = 1, dualsim = false, ttypath = false, isoption1 = true, } local mtab = common_modem4g_methods() mtab["f_connect"] = air724_connect setmetatable(mobj, { __index = mtab, __gc = common_4gmodem_close, }) return mobj end local function init_func_mc661() local mobj = { name = "MC661", ttyindex = 0, dualsim = true, ttypath = false, isoption1 = true, } local mtab = common_modem4g_methods() mtab["f_connect"] = mc661_connect mtab["f_cardinfo"] = mc661_4gmodem_info mtab["f_switch_sim"] = mc661_4gmodem_switchsim mtab["f_get_cursim"] = mc661_4gmodem_getsim mtab["f_status"] = mc661_4gmodem_status setmetatable(mobj, { __index = mtab, __gc = common_4gmodem_close, }) return mobj end local function init_func_mc661_0a0a() local mobj = { name = "MC661", ttyindex = 0, dualsim = false, ttypath = false, isoption1 = true, } local mtab = common_modem4g_methods() mtab["f_preinit"] = mc661_4gmodem_preinit setmetatable(mobj, { __index = mtab, __gc = common_4gmodem_close, }) return mobj end local function init_func_l610() local mobj = { name = "L610", ttyindex = 0, dualsim = false, ttypath = false, isoption1 = true, } local mtab = common_modem4g_methods() mtab["f_connect"] = l610_connect mtab["f_status"] = l610_4gmodem_status setmetatable(mobj, { __index = mtab, __gc = common_4gmodem_close, }) return mobj end local net4g_modems = { ["2c7c:6005"] = init_func_ec200a, ["2c7c:6002"] = init_func_ec200n, ["2c7c:6026"] = init_func_ec200t, ["2c7c:0901"] = init_func_ec200u, ["2c7c:0904"] = init_func_ec800g, ["2c7c:0125"] = init_func_ec2x, ["1782:4e00"] = init_func_air724, ["2cb7:0a0a"] = init_func_mc661_0a0a, ["2cb7:0a0b"] = init_func_mc661, ["2cb7:0a0c"] = init_func_mc661_0a0a, ["1782:4d11"] = init_func_l610, } local function detect_4gmodem() local 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 nil end -- function to create 4G modem object local modem_init, usbid = nil, nil -- process USB-ID one by one for uid in string.gmatch(outbuf, "(%x%x%x%x:%x%x%x%x)") do modem_init = net4g_modems[uid] if modem_init then usbid = uid break end end if not modem_init then return nil end -- create 4G modem object: local modemobj = modem_init() if modemobj.isoption1 then -- update new_id for optioin1 driver local optval = string.gsub(usbid, ":", " ") .. " ff\n" local new_id = "/sys/bus/usb-serial/drivers/option1/new_id" local oldval = invoker.readfile(new_id) if optval ~= oldval then local opth = io.open(new_id, "wb") if opth then opth:write(optval); opth:close(); opth = nil end invoker.waitsec(5) end end return modemobj end if os.getenv("MODEM_DEBUG") == "1" then g_debug = true end return { ["detect"] = detect_4gmodem, ["SIMCARD_EXTERNAL"] = g_SIMCARD_EXTERNAL, ["SIMCARD_INTERNAL"] = g_SIMCARD_INTERNAL, ["PREINIT_AGAIN"] = g_PREINIT_AGAIN, ["APN_ALREADY"] = g_APN_ALREADY, }