#!/opt/lnxall_app/bin/lua

-- Created by jiaqiang.ye@lnxall.com
-- Fast 4G modem trouble shooting
-- 2025/04/21

local invoker = require "invoker"
local gfmt = string.format

local function open_tty(ttypath)
	invoker.invoke(0, 'stty', '-F', ttypath, "raw", "cs8", "-hupcl",
		"-onlcr", "-iexten", "-echo", "-echoe", "-echok", "-echoctl", "-echoke")

	local oflags = 526594 -- O_RDWR | O_NONBLOCK | O_NOCTTY | O_CLOEXEC
	local fd, errn = invoker.open(ttypath, oflags)
	if not fd then
		if type(errn) ~= "number" then errn = 2025 end
		io.stderr:write(gfmt("Error, failed to open(%s): %d\n", ttypath, errn))
		io.stderr:flush()
		return nil
	end
	return fd
end

local function clear_tty(fd)
	while true do
		local res = invoker.readfd(fd, 2048)
		if not res or #res == 0 then break end
	end
	return true
end

local function read_print(fd, timeout)
	local now = invoker.uptimsec()
	local endtim = now + timeout
	while now < endtim do
		invoker.msleep(120)
		local out = invoker.readfd(fd, 2048)
		if type(out) == "string" and #out > 0 then
			io.stdout:write(out)
			io.stdout:flush()
			if string.find(out, "\nOK", 1, true) then
				return true
			end
			if string.find(out, "ERROR", 1, true) then
				return false
			end
		end
		now = invoker.uptimsec()
	end
	return true
end

local function write_tty(fd, fdat)
	local flen = type(fdat) == "string" and string.len(fdat) or 0
	if flen > 0 then
		if flen ~= invoker.writefd(fd, fdat) then
			io.stderr:write(gfmt("Error, write(%d) has failed: %s\n", fd, fdat))
			io.stderr:flush()
			return false
		end
		return true
	end
	return false
end

local function seperate_line(flush)
	io.stdout:write("=====================================================\n")
	if flush then io.stdout:flush() end
end

local function tty_write_read(fd, atcmd, timeo)
	if type(timeo) ~= "number" or timeo < 1000 then
		timeo = 2000
	end
	seperate_line()
	io.stdout:write(gfmt("%s----------\n", atcmd))
	io.stdout:flush()
	write_tty(fd, atcmd)
	read_print(fd, timeo)
	return true
end

local function mainfunc()
	local ttypath = invoker.readfile("/tmp/4g_modem_tty", invoker.TRIMEND)
	if type(ttypath) ~= "string" or #ttypath == 0 then
		io.stderr:write("Error, failed to read 4g_modem_tty.\n")
		io.stderr:flush()
		os.exit(1)
	end

	if invoker.statfile(ttypath) ~= "character" then
		io.stderr:write(gfmt("Error, not a real tty device: %s\n", ttypath))
		io.stderr:flush()
		os.exit(2)
	end

	local tfd = open_tty(ttypath)
	if not tfd then
		io.stderr:write(gfmt("Error, failed to open tty device: %s\n", ttypath))
		io.stderr:flush()
		os.exit(3)
	end
	clear_tty(tfd)

	tty_write_read(tfd, "ATI\r\n")
	tty_write_read(tfd, "AT+CPIN?\r\n")
	tty_write_read(tfd, "AT+COPS?\r\n")
	tty_write_read(tfd, "AT+CREG?\r\n")
	tty_write_read(tfd, "AT+CSQ\r\n")
	tty_write_read(tfd, "AT+CGSN\r\n")
	tty_write_read(tfd, "AT+CIMI\r\n")
	tty_write_read(tfd, "AT+CCID\r\n")
	tty_write_read(tfd, "AT+ICCID\r\n")
	tty_write_read(tfd, "AT+QICCID\r\n")
	tty_write_read(tfd, "AT+CGMI\r\n")
	tty_write_read(tfd, "AT+CGATT?\r\n")
	tty_write_read(tfd, "AT+QPING=1,\"mqtt.lnxall.com\"\r\n")
	tty_write_read(tfd, "AT+CGDCONT?\r\n")
	tty_write_read(tfd, "AT+CGCONTRDP\r\n")
	invoker.closefd(tfd)

	seperate_line(true)
	invoker.invoke(0, "ip", "addr", "show")
	seperate_line(true)
	invoker.invoke(0, "ip", "route", "show")
end

mainfunc()
